1
1
// <Decode.cpp> -*- C++ -*-
2
2
3
-
4
- #include < algorithm>
5
-
6
3
#include " Decode.hpp"
4
+ #include " fusion/FusionTypes.hpp"
7
5
8
6
#include " sparta/events/StartupEvent.hpp"
9
7
#include " sparta/utils/LogUtils.hpp"
10
8
9
+ #include < algorithm>
10
+ #include < iostream>
11
+
12
+ using namespace std ;
13
+
11
14
namespace olympia
12
15
{
13
16
constexpr char Decode::name[];
14
17
15
- Decode::Decode (sparta::TreeNode * node,
16
- const DecodeParameterSet * p) :
18
+ Decode::Decode (sparta::TreeNode* node, const DecodeParameterSet* p) :
17
19
sparta::Unit (node),
20
+
18
21
fetch_queue_ (" FetchQueue" , p->fetch_queue_size, node->getClock (), &unit_stat_set_),
19
- num_to_decode_(p->num_to_decode)
22
+
23
+ fusion_num_fuse_instructions_(&unit_stat_set_, " fusion_num_fuse_instructions" ,
24
+ " The number of custom instructions created by fusion" ,
25
+ sparta::Counter::COUNT_NORMAL),
26
+
27
+ fusion_num_ghost_instructions_(&unit_stat_set_, " fusion_num_ghost_instructions" ,
28
+ " The number of instructions eliminated by fusion" ,
29
+ sparta::Counter::COUNT_NORMAL),
30
+
31
+ fusion_num_groups_defined_(&unit_stat_set_, " fusion_num_groups_defined" ,
32
+ " Number of fusion groups compiled or read at run time" ,
33
+ sparta::Counter::COUNT_LATEST),
34
+
35
+ fusion_num_groups_utilized_(&unit_stat_set_, " fusion_num_groups_utilized" ,
36
+ " Incremented on first use of a fusion group" ,
37
+ sparta::Counter::COUNT_LATEST),
38
+
39
+ fusion_pred_cycles_saved_(&unit_stat_set_, " fusion_pred_cycles_saved" ,
40
+ " Optimistic prediction of the cycles saved by fusion" ,
41
+ sparta::Counter::COUNT_NORMAL),
42
+
43
+ num_to_decode_(p->num_to_decode),
44
+ fusion_enable_(p->fusion_enable),
45
+ fusion_debug_(p->fusion_debug),
46
+ fusion_enable_register_(p->fusion_enable_register),
47
+ fusion_max_latency_(p->fusion_max_latency),
48
+ fusion_match_max_tries_(p->fusion_match_max_tries),
49
+ fusion_max_group_size_(p->fusion_max_group_size),
50
+ fusion_summary_report_(p->fusion_summary_report),
51
+ fusion_group_definitions_(p->fusion_group_definitions)
20
52
{
53
+ initializeFusion_ ();
54
+
21
55
fetch_queue_.enableCollection (node);
22
56
23
- fetch_queue_write_in_.
24
- registerConsumerHandler ( CREATE_SPARTA_HANDLER_WITH_DATA (Decode, fetchBufferAppended_, InstGroupPtr));
25
- uop_queue_credits_in_.
26
- registerConsumerHandler ( CREATE_SPARTA_HANDLER_WITH_DATA (Decode, receiveUopQueueCredits_, uint32_t ));
27
- in_reorder_flush_.
28
- registerConsumerHandler ( CREATE_SPARTA_HANDLER_WITH_DATA (Decode, handleFlush_, FlushManager::FlushingCriteria));
57
+ fetch_queue_write_in_.registerConsumerHandler (
58
+ CREATE_SPARTA_HANDLER_WITH_DATA (Decode, fetchBufferAppended_, InstGroupPtr));
59
+ uop_queue_credits_in_.registerConsumerHandler (
60
+ CREATE_SPARTA_HANDLER_WITH_DATA (Decode, receiveUopQueueCredits_, uint32_t ));
61
+ in_reorder_flush_.registerConsumerHandler (
62
+ CREATE_SPARTA_HANDLER_WITH_DATA (Decode, handleFlush_, FlushManager::FlushingCriteria));
29
63
30
64
sparta::StartupEvent (node, CREATE_SPARTA_HANDLER (Decode, sendInitialCredits_));
31
65
}
32
66
33
67
// Send fetch the initial credit count
34
- void Decode::sendInitialCredits_ ()
68
+ void Decode::sendInitialCredits_ () { fetch_queue_credits_outp_.send (fetch_queue_.capacity ()); }
69
+
70
+ // -------------------------------------------------------------------
71
+ // -------------------------------------------------------------------
72
+ void Decode::initializeFusion_ ()
35
73
{
36
- fetch_queue_credits_outp_.send (fetch_queue_.capacity ());
74
+ if (fusion_enable_)
75
+ {
76
+ fuser_ = std::make_unique<FusionType>(fusion_group_definitions_);
77
+ hcache_ = fusion::HCache (FusionGroupType::jenkins_1aat);
78
+ fusion_num_groups_defined_ = fuser_->getFusionGroupContainer ().size ();
79
+ }
80
+ else
81
+ {
82
+ fuser_ = nullptr ;
83
+ }
37
84
}
38
85
39
86
// Receive Uop credits from Dispatch
40
- void Decode::receiveUopQueueCredits_ (const uint32_t & credits) {
87
+ void Decode::receiveUopQueueCredits_ (const uint32_t & credits)
88
+ {
41
89
uop_queue_credits_ += credits;
42
- if (fetch_queue_.size () > 0 ) {
90
+ if (fetch_queue_.size () > 0 )
91
+ {
43
92
ev_decode_insts_event_.schedule (sparta::Clock::Cycle (0 ));
44
93
}
45
94
@@ -52,12 +101,13 @@ namespace olympia
52
101
void Decode::fetchBufferAppended_ (const InstGroupPtr & insts)
53
102
{
54
103
// Cache the instructions in the instruction queue if we can't decode this cycle
55
- for (auto & i : *insts)
104
+ for (auto & i : *insts)
56
105
{
57
106
fetch_queue_.push (i);
58
107
ILOG (" Received: " << i);
59
108
}
60
- if (uop_queue_credits_ > 0 ) {
109
+ if (uop_queue_credits_ > 0 )
110
+ {
61
111
ev_decode_insts_event_.schedule (sparta::Clock::Cycle (0 ));
62
112
}
63
113
}
@@ -76,25 +126,76 @@ namespace olympia
76
126
uint32_t num_decode = std::min (uop_queue_credits_, fetch_queue_.size ());
77
127
num_decode = std::min (num_decode, num_to_decode_);
78
128
79
- if (num_decode > 0 )
129
+ // buffer to maximize the chances of a group match limited
130
+ // by max allowed latency, bounded by max group size
131
+ if (fusion_enable_)
132
+ {
133
+ if (num_decode < fusion_max_group_size_ && latency_count_ < fusion_max_latency_)
134
+ {
135
+ ++latency_count_;
136
+ return ;
137
+ }
138
+ }
139
+
140
+ latency_count_ = 0 ;
141
+
142
+ if (num_decode > 0 )
80
143
{
81
144
InstGroupPtr insts =
82
145
sparta::allocate_sparta_shared_pointer<InstGroup>(instgroup_allocator);
146
+
147
+ InstUidListType uids;
83
148
// Send instructions on their way to rename
84
- for (uint32_t i = 0 ; i < num_decode; ++i) {
149
+ for (uint32_t i = 0 ; i < num_decode; ++i)
150
+ {
85
151
const auto & inst = fetch_queue_.read (0 );
86
152
insts->emplace_back (inst);
87
153
inst->setStatus (Inst::Status::DECODED);
88
154
155
+ if (fusion_enable_)
156
+ {
157
+ uids.push_back (inst->getMavisUid ());
158
+ }
159
+
89
160
ILOG (" Decoded: " << inst);
90
161
91
162
fetch_queue_.pop ();
92
163
}
93
164
165
+ if (fusion_enable_)
166
+ {
167
+ MatchInfoListType matches;
168
+ uint32_t max_itrs = 0 ;
169
+ FusionGroupContainerType & container = fuser_->getFusionGroupContainer ();
170
+ do
171
+ {
172
+ matchFusionGroups_ (matches, insts, uids, container);
173
+ processMatches_ (matches, insts, uids);
174
+ // Future feature whereIsEgon(insts,numGhosts);
175
+ ++max_itrs;
176
+ } while (matches.size () > 0 && max_itrs < fusion_match_max_tries_);
177
+
178
+ if (max_itrs >= fusion_match_max_tries_)
179
+ {
180
+ throw sparta::SpartaException (" Fusion group match watch dog exceeded." );
181
+ }
182
+ }
183
+
184
+ // Debug statement
185
+ if (fusion_debug_ && fusion_enable_)
186
+ infoInsts_ (cout, insts);
94
187
// Send decoded instructions to rename
95
188
uop_queue_outp_.send (insts);
96
189
190
+ // TODO: whereisegon() would remove the ghosts,
191
+ // Commented out for now, in practice insts
192
+ // would be smaller due to the fused ops
193
+ // uint32_t unfusedInstsSize = insts->size();
194
+
97
195
// Decrement internal Uop Queue credits
196
+ sparta_assert (uop_queue_credits_ >= insts->size (),
197
+ " Attempt to decrement d0q credits below what is available" );
198
+
98
199
uop_queue_credits_ -= insts->size ();
99
200
100
201
// Send credits back to Fetch to get more instructions
@@ -103,8 +204,9 @@ namespace olympia
103
204
104
205
// If we still have credits to send instructions as well as
105
206
// instructions in the queue, schedule another decode session
106
- if (uop_queue_credits_ > 0 && fetch_queue_.size () > 0 ) {
207
+ if (uop_queue_credits_ > 0 && fetch_queue_.size () > 0 )
208
+ {
107
209
ev_decode_insts_event_.schedule (1 );
108
210
}
109
211
}
110
- }
212
+ } // namespace olympia
0 commit comments