1
1
// ===- BlockDisambiguate.cpp - Unambiguous block mapping for yk ----===//
2
2
//
3
3
// This pass ensures that yk is able to unambiguously map machine blocks back
4
- // to LLVM IR blocks.
4
+ // to LLVM IR blocks. Specifically it does two separate, but related, things:
5
+ //
6
+ // - Inserts blocks to disambiguate intra-function branching.
7
+ // - Inserts blocks to disambiguate returning from direct recursion.
8
+ //
9
+ // Intra-function branch disambiguation
10
+ // ------------------------------------
5
11
//
6
12
// In the JIT runtime, the mapping stage converts the *machine* basic blocks of
7
13
// a trace back to high-level basic blocks (the ones in LLVM IR). A problem
108
114
// The former unambiguously expresses that `bbA` was executed twice. The latter
109
115
// unambiguously expresses that `bbA` was executed only once.
110
116
//
117
+ // Return from direct recursion disambiguation
118
+ // -------------------------------------------
119
+ //
120
+ // A similar case that requires disambiguation is where a function recursively
121
+ // calls itself (i.e. the function is "directly recursive") immediately before
122
+ // returning.
123
+ //
124
+ // When a series of recursive calls bubble up from the recursion
125
+ // we will get repeated entries for the high-level block containing the
126
+ // return statement. But since the return block may include other instructions
127
+ // which may themselves lower to multiple machine basic blocks, we need to do
128
+ // something in order to differentiate recursive returning from non-recursive
129
+ // returning when we see repeated entries for a block containing a return
130
+ // statement.
131
+ //
132
+ // In other words, given the return block for a function `myself()` shown in
133
+ // Fig 3b. and the high-level trace `[bbRet, bbRet, bbRet, bbRet]`, how many
134
+ // times have we returned from recursive calls? We can't say because
135
+ // `<instructions>` may generate multiple machine basic blocks that all map
136
+ // back to `bbRet` [1].
137
+ //
138
+ // Our solution is to insert a (high-level) padding block between the return
139
+ // statement and the instructions preceding it.
140
+ //
141
+ // ┌────────────────┐ ┌────────────────┐
142
+ // │bbRet: │ │bbRet1: │
143
+ // │ <instructions>│ │ <instructions>│
144
+ // │ call @myself()│ │ call @myself()│
145
+ // │ ret │ │ br %bbRet2 │
146
+ // └────────────────┘ └────────────────┘
147
+ // │
148
+ // (Fig 3a, above) ▼
149
+ // Return block before ┌────────────┐
150
+ // transformation. │bbRet2: │
151
+ // │ br %bbRet3│
152
+ // └────────────┘
153
+ // │
154
+ // (Fig 3b, right) ▼
155
+ // Return block after transformation ┌───────┐
156
+ // with padding block. │bbRet3:│
157
+ // │ ret │
158
+ // └───────┘
159
+ //
160
+ // After transformation, repeated entries for a block can only occur in the
161
+ // mapped trace if `<instructions>` becomes multiple machine blocks during
162
+ // code-gen (e.g. `[bbRet1, bbRet1, bbRet1, bbRet1]`), whereas returning from
163
+ // direct recursion will cause sequences of `bbRet2, bbRet3` to appear in the
164
+ // mapped trace.
165
+ //
166
+ // As with intra-function branch disambiguation, the mapper is then free to
167
+ // collapse repeated entries for the same block when constructing the mapped
168
+ // trace.
169
+ //
170
+ // Discussion
171
+ // ----------
172
+ //
111
173
// The pass runs after high-level IR optimisations (and requires some backend
112
174
// optimisations disabled) to ensure that LLVM doesn't undo our work, by
113
175
// folding the machine block for `bbB` back into its predecessor in `bbA`.
114
176
//
115
177
// Alternative approaches that we dismissed, and why:
116
178
//
117
- // - Consider branches back to the entry machine block of a high-level block
118
- // as a re-execution of the high-level block. Even assuming that we can
119
- // identify the entry machine block for a high-level block, this is flawed.
120
- // As can be seen in the example above, both internal and non-internal
121
- // control flow can branch back to the entry block. Additionally, there may
122
- // not be a unique entry machine basic block.
179
+ // - For intra-function branches, consider branches back to the entry machine
180
+ // block of a high-level block as a re-execution of the high-level block.
181
+ // Even assuming that we can identify the entry machine block for a
182
+ // high-level block, this is flawed. As can be seen in the example above,
183
+ // both internal and non-internal control flow can branch back to the entry
184
+ // block. Additionally, there may not be a unique entry machine basic block.
123
185
//
124
186
// - Mark (in the machine IR) which branches are exits to the high-level IR
125
187
// block and encode this is the basic block map somehow. This is more
132
194
// likely that some LLVM IR constructs require internal control flow for
133
195
// correct semantics.
134
196
//
135
- // Footnotes:
197
+ // Footnotes
198
+ // ---------
136
199
//
137
200
// [0]: For some targets, a single high-level LLVM IR instruction can even
138
201
// lower to a machine-IR-level loop, for example `cmpxchng` on some ARM
142
205
// a potentially unbounded number of machine blocks can be executed
143
206
// within the confines of a single high-level basic block.
144
207
//
208
+ // [1]: Futher those machine blocks may branch to the same address that a
209
+ // return from direct recursion would land at, adding another layer of
210
+ // ambiguity.
211
+ //
145
212
// ===----------------------------------------------------------------------===//
146
213
147
214
#include " llvm/Transforms/Yk/BlockDisambiguate.h"
@@ -178,8 +245,9 @@ class YkBlockDisambiguate : public ModulePass {
178
245
}
179
246
180
247
private:
181
- BasicBlock *makeDisambiguationBB (LLVMContext &Context, BasicBlock *BB,
182
- std::vector<BasicBlock *> &NewBBs) {
248
+ // Create a block for intra-function branch disambiguation.
249
+ BasicBlock *makeBranchDisambiguationBB (LLVMContext &Context, BasicBlock *BB,
250
+ std::vector<BasicBlock *> &NewBBs) {
183
251
BasicBlock *DBB = BasicBlock::Create (Context, " " );
184
252
NewBBs.push_back (DBB);
185
253
IRBuilder<> Builder (DBB);
@@ -202,7 +270,7 @@ class YkBlockDisambiguate : public ModulePass {
202
270
SuccIdx++) {
203
271
BasicBlock *SuccBB = BI->getSuccessor (SuccIdx);
204
272
if (SuccBB == &BB) {
205
- BasicBlock *DBB = makeDisambiguationBB (Context, &BB, NewBBs);
273
+ BasicBlock *DBB = makeBranchDisambiguationBB (Context, &BB, NewBBs);
206
274
BI->setSuccessor (SuccIdx, DBB);
207
275
BB.replacePhiUsesWith (&BB, DBB);
208
276
}
@@ -213,11 +281,37 @@ class YkBlockDisambiguate : public ModulePass {
213
281
SuccIdx++) {
214
282
BasicBlock *SuccBB = SI->getSuccessor (SuccIdx);
215
283
if (SuccBB == &BB) {
216
- BasicBlock *DBB = makeDisambiguationBB (Context, &BB, NewBBs);
284
+ BasicBlock *DBB = makeBranchDisambiguationBB (Context, &BB, NewBBs);
217
285
SI->setSuccessor (SuccIdx, DBB);
218
286
BB.replacePhiUsesWith (&BB, DBB);
219
287
}
220
288
}
289
+ } else if (isa<ReturnInst>(TI)) {
290
+ // Apply return from direct recursion disambiguation.
291
+ //
292
+ // YKFIXME: We do this even if the function is not directly recursive.
293
+ // If we can prove that it is not, then we can skip this step.
294
+
295
+ // Make the New Return Block (NRBB) and the Padding Block (PBB).
296
+ BasicBlock *NRBB = BasicBlock::Create (Context, " " );
297
+ BasicBlock *PBB = BasicBlock::Create (Context, " " );
298
+
299
+ // Make the original return block branch to the padding block.
300
+ IRBuilder<> Builder (Context);
301
+ Builder.SetInsertPoint (TI);
302
+ Builder.CreateBr (PBB);
303
+
304
+ // Make the padding block branch to the new return block.
305
+ Builder.SetInsertPoint (PBB);
306
+ Builder.CreateBr (NRBB);
307
+
308
+ // Move the original return instruction into the new return block.
309
+ Builder.SetInsertPoint (NRBB);
310
+ TI->removeFromParent ();
311
+ Builder.Insert (TI);
312
+
313
+ NewBBs.push_back (NRBB);
314
+ NewBBs.push_back (PBB);
221
315
}
222
316
}
223
317
0 commit comments