Skip to content

Commit c32a077

Browse files
Pierre Michaudalindsay-ampere
authored andcommitted
Modify gshareN_ahead so that indexing does not depend on the predictor's outputs (as we did in gshareN).
1 parent cea8b50 commit c32a077

1 file changed

Lines changed: 94 additions & 73 deletions

File tree

predictors/gshareN_ahead.hpp

Lines changed: 94 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ using namespace hcm;
2323
// To use lanes evenly, the lane depends on some bits XL of B1's address via XORing.
2424

2525

26-
template<u64 LOGG=19, u64 GHIST=10, u64 N=4>
26+
template<u64 LOGG=19, u64 GHIST=12, u64 N=4>
2727
struct gshareN_ahead : predictor {
2828
// gshare with 2^LOGG entries, single prediction level (no overriding)
2929
// global history of GHIST bits
@@ -44,63 +44,97 @@ struct gshareN_ahead : predictor {
4444

4545
// pipelined over 2 cycles ([0]=current block, [1]=previous block)
4646
reg<index_bits> index[2];
47-
reg<LOGBANKS> XB[2]; // address bits for selecting the bank
48-
reg<LOGLANES> XL; // address bits for selecting the lane (current block)
49-
reg<LOGBANKS> path; // path out of previous block
47+
reg<LOGBANKS> XB[2]; // for using banks evenly
48+
reg<LANES> XL; // for using lanes evenly
49+
reg<LOGBANKS> path[2]; // path out of previous block
5050

5151
arr<reg<LANES>,BANKS> block_pred[2]; // read block predictions
52-
arr<reg<1>,LANES> unordered_pred; // read prediction bits for the current block, unordered
52+
reg<LANES> unordered_pred; // read prediction bits for the current block, unordered
5353
arr<reg<1>,LANES> pred; // read prediction bits for the current block, ordered
5454

55-
ram<arr<val<LANES>,BANKS>,(1<<index_bits)> ctr_hi; // prediction bits
55+
// a true block is a block whose length is the same whether or not there is a mispredict
56+
reg<1> true_block = 1;
57+
reg<1> condbr_taken = 1;
58+
59+
// for detecting the line boundary and the last available prediction
60+
reg<LINEINST> block_entry; // one-hot vector pointing to entry point in the line
61+
reg<N> rank; // one-hot bit vector telling the rank of the current branch in the block
5662

5763
// simulation artifacts, hardware cost not modeled accurately
58-
reg<1> true_block = 1;
59-
reg<LINEINST> block_entry; // one-hot vector
6064
u64 num_branch = 0; // number of conditional branches in block so far
6165
u64 block_size = 0; // instructions in current block so far
6266
arr<reg<1>,N> branch_dir; // actual branch direction
6367

64-
zone UPDATE_ONLY;
68+
// RAMs
69+
ram<arr<val<LANES>,BANKS>,(1<<index_bits)> ctr_hi; // prediction bits
6570
ram<val<1>,(BANKS<<index_bits)> ctr_lo[LANES]; // hysteresis bit (1=weak, 0=strong)
6671

72+
val<1> line_end()
73+
{
74+
return block_entry >> (LINEINST-block_size);
75+
}
76+
77+
val<1> last_pred()
78+
{
79+
return rank.rotate_left(num_branch);
80+
}
81+
6782
val<1> predict1([[maybe_unused]] val<64> inst_pc)
6883
{
69-
// new block
70-
assert(num_branch==0);
71-
block_size = 1;
72-
index[1] = index[0];
73-
val<index_bits> pc_bits = inst_pc >> (LOGBANKS+2);
74-
if constexpr (GHIST <= index_bits) {
75-
index[0] = pc_bits.fo1() ^ (val<index_bits>{global_history}<<(index_bits-GHIST));
76-
} else {
77-
index[0] = global_history.make_array(val<index_bits>{}).append(pc_bits.fo1()).fold_xor();
78-
}
79-
index[0].fanout(hard<2>{});
80-
XL = inst_pc >> 2;
84+
inst_pc.fanout(hard<3>{});
85+
global_history.fanout(hard<2>{});
86+
true_block.fanout(hard<6>{});
87+
88+
// if the previous block was not a true block, we continue using the previous block predictions
89+
// (golden rule: never make a predictor's inputs depend on its outputs)
90+
91+
block_entry = select(true_block,
92+
val<LOGLINEINST>{inst_pc>>2}.decode().concat(),
93+
block_entry<<block_size);
94+
block_entry.fanout(hard<LINEINST+N+1>{});
95+
96+
rank = select(true_block, val<N>{1}, rank.rotate_left(num_branch));
97+
98+
XL = select(true_block,
99+
val<LOGLANES>{inst_pc>>2}.decode().concat(),
100+
XL.rotate_left(num_branch));
81101
XL.fanout(hard<LANES>{});
82-
XB[1] = XB[0].fo1();
83-
XB[0] = inst_pc >> 2;
84-
XB[1].fanout(hard<2>{});
85-
block_pred[1] = block_pred[0].fo1();
86-
block_pred[0] = ctr_hi.read(index[0]);
87-
block_pred[1].fanout(hard<2>{});
88-
unordered_pred = block_pred[1].select(path^XB[1]).make_array(val<1>{});
89-
unordered_pred.fanout(hard<LANES>{});
102+
103+
execute_if(true_block, [&](){
104+
index[1] = index[0];
105+
val<index_bits> pc_bits = inst_pc >> (LOGBANKS+2);
106+
if constexpr (GHIST <= index_bits) {
107+
index[0] = pc_bits.fo1() ^ (val<index_bits>{global_history}<<(index_bits-GHIST));
108+
} else {
109+
index[0] = global_history.make_array(val<index_bits>{}).append(pc_bits.fo1()).fold_xor();
110+
}
111+
block_pred[1] = block_pred[0].fo1();
112+
block_pred[0] = ctr_hi.read(index[0]);
113+
XB[1] = XB[0].fo1();
114+
XB[0] = inst_pc >> 2;
115+
path[1] = (path[0] + num_branch) & condbr_taken.replicate(hard<LOGBANKS>{}).concat();
116+
path[1].fanout(hard<3>{});
117+
unordered_pred = block_pred[1].select(path[1]^XB[1]);
118+
unordered_pred.fanout(hard<LANES>{});
119+
});
120+
121+
path[0] = select(true_block, val<LOGBANKS>{0}, val<LOGBANKS>{path[0]+num_branch});
122+
path[0].fanout(hard<2>{});
123+
90124
for (u64 i=0; i<LANES; i++) {
91-
pred[i] = unordered_pred.select(i^XL);
125+
pred[i] = (unordered_pred & XL.rotate_left(i)) != hard<0>{};
92126
}
93127
pred.fanout(hard<LINEINST*2>{});
94-
block_entry = val<LOGLINEINST>{inst_pc>>2}.decode().concat();
95-
block_entry.fanout(hard<LINEINST>{});
96-
reuse_prediction(~val<1>{block_entry>>(LINEINST-1)});
97-
return pred[0];
128+
block_size = 1;
129+
num_branch = 0;
130+
reuse_prediction(~line_end());
131+
return pred[num_branch];
98132
};
99133

100134
val<1> reuse_predict1([[maybe_unused]] val<64> inst_pc)
101135
{
102-
reuse_prediction(~val<1>{block_entry>>(LINEINST-1-block_size)});
103136
block_size++;
137+
reuse_prediction(~line_end());
104138
return pred[num_branch];
105139
};
106140

@@ -119,10 +153,7 @@ struct gshareN_ahead : predictor {
119153
assert(num_branch<N);
120154
branch_dir[num_branch] = taken.fo1();
121155
num_branch++;
122-
if (num_branch == N) {
123-
// this was the last branch for which we have a prediction: end the block
124-
reuse_prediction(0);
125-
}
156+
reuse_prediction(~(line_end() | last_pred()));
126157
}
127158

128159
void update_cycle([[maybe_unused]] instruction_info &block_end_info)
@@ -131,15 +162,9 @@ struct gshareN_ahead : predictor {
131162
val<64> &next_pc = block_end_info.next_pc;
132163
if (num_branch == 0) {
133164
// no conditional branch in this block
134-
// update global history if previous block ended on a mispredicted not-taken branch
135-
// (we are still in the same line, this is the last chunk)
136-
// or if the block ends on an unconditional jump
137-
val<1> uncond_jump = block_end_info.is_taken & ~block_end_info.is_conditional;
138-
execute_if(~true_block | uncond_jump.fo1(), [&](){
139-
global_history = (global_history << 1) ^ val<GHIST>{next_pc.fo1()>>2};
140-
true_block = 1;
141-
});
142-
path = 0;
165+
global_history = (global_history << 1) ^ val<GHIST>{next_pc.fo1()>>2};
166+
condbr_taken = 0;
167+
true_block = 1;
143168
return; // stop here
144169
}
145170
static_assert(LANES<=64);
@@ -148,41 +173,38 @@ struct gshareN_ahead : predictor {
148173
branch_dir[num_branch-1].fanout(hard<LANES+LOGBANKS+1>{});
149174
mispredict.fanout(hard<4>{});
150175

151-
// determine the lanes that are accessed
152-
arr<val<LANES>,LANES> lane = [&](u64 i) -> val<LANES> {
153-
return (XL^i).decode().concat();
154-
};
155-
lane.fanout(hard<2>{});
156-
arr<val<1>,LANES> access = [&](u64 i) -> val<1> {
157-
return (lane[i]>>num_branch) == hard<0>{};
158-
};
176+
// access = mask telling which lanes are accessed by branches in the block
177+
arr<val<1>,LANES> access = arr<val<LANES>,LANES> { [&](u64 i){
178+
return XL.rotate_left(i) & val<LANES>{-(i<num_branch)};
179+
}}.fold_or().make_array(val<1>{});
159180

160-
// determine the lane corresponding to the mispredicted branch
161-
val<LANES> misp_lane = execute_if(mispredict, [&]() -> val<LANES> {
162-
return lane[num_branch-1];
163-
});
164-
arr<val<1>,LANES> mispredicted = misp_lane.fo1().make_array(val<1>{});
181+
// misp bank = bit vector pointing to the lane accessed by the mispredicted branch
182+
// (all zero if no mispredict)
183+
val<LANES> misp_bank = XL.rotate_left(num_branch-1) & mispredict.replicate(hard<LANES>{}).concat();
184+
arr<val<1>,LANES> mispredicted = misp_bank.fo1().make_array(val<1>{});
165185
mispredicted.fanout(hard<2>{});
166186

167187
// determine the bank to update
168-
val<LOGBANKS> bank = path ^ XB[1];
188+
val<LOGBANKS> bank = path[1] ^ XB[1];
169189
bank.fanout(hard<2*LANES+BANKS>{});
170190

171-
// read hysteresis bit if lane corresponds to mispredicted branch
191+
// read hysteresis bit iff mispredict
192+
// weak[i] = 1 iff bank #i corresponds to mispredicted branch and hysteresis is weak
172193
arr<val<1>,LANES> weak = [&](u64 i){
173194
return execute_if(mispredicted[i], [&](){
174-
// return 1 iff mispredict and hysteresis is weak
175195
return ctr_lo[i].read(concat(index[1],bank));
176196
});
177197
};
178198

179199
// we need an extra cycle if there is a mispredict
180200
need_extra_cycle(mispredict);
201+
181202
// update prediction if mispredict and the hysteresis bit is weak
182203
execute_if(mispredict, [&](){
204+
arr<val<1>,N> stored_pred = unordered_pred.make_array(val<1>{});
183205
val<LANES> block_bundle = arr<val<1>,LANES>{
184206
[&](u64 i){
185-
return select(weak[i].fo1(),branch_dir[num_branch-1],unordered_pred[i]);
207+
return select(weak[i].fo1(),branch_dir[num_branch-1],stored_pred[i].fo1());
186208
}
187209
}.concat();
188210
block_bundle.fanout(hard<BANKS>{});
@@ -199,17 +221,16 @@ struct gshareN_ahead : predictor {
199221
});
200222
}
201223

202-
// update the global history
203-
val<1> line_end = block_entry >> (LINEINST-block_size);
204-
true_block = (~mispredict & (num_branch<N)) | branch_dir[num_branch-1] | line_end.fo1();
224+
condbr_taken = branch_dir[num_branch-1];
225+
226+
// update the global history if this is a true block
227+
true_block = arr<val<1>,4> {
228+
~mispredict, condbr_taken, last_pred(), line_end()
229+
}.fold_or();
230+
205231
execute_if(true_block, [&](){
206232
global_history = (global_history << 1) ^ val<GHIST>{next_pc.fo1()>>2};
207233
});
208234

209-
// record the path: if last cond branch not-taken, then path=0, else path=num_branch
210-
path = num_branch & branch_dir[num_branch-1].replicate(hard<LOGBANKS>{}).concat();
211-
path.fanout(hard<2>{});
212-
213-
num_branch = 0;
214235
}
215236
};

0 commit comments

Comments
 (0)