Skip to content

Commit 3375c6f

Browse files
bors[bot]vext01
andauthored
27: Return from direct recursion disambiguation r=ptersilie a=vext01 Co-authored-by: Edd Barrett <[email protected]>
2 parents 5bbd767 + ce869db commit 3375c6f

File tree

2 files changed

+108
-12
lines changed

2 files changed

+108
-12
lines changed

llvm/lib/Target/X86/X86FastISel.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2590,6 +2590,8 @@ bool X86FastISel::TryEmitSmallMemcpy(X86AddressMode DestAM,
25902590

25912591
// Add an annotation to an intrinsic instruction, specifying whether the
25922592
// intrinsic has been inlined or not.
2593+
//
2594+
// This is only necessary for intrinsics which may emit machine code.
25932595
void annotateIntrinsic(const IntrinsicInst *II, bool Inlined) {
25942596
IntrinsicInst *CI = const_cast<IntrinsicInst *>(II);
25952597
LLVMContext& C = CI->getContext();

llvm/lib/Transforms/Yk/BlockDisambiguate.cpp

Lines changed: 106 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
//===- BlockDisambiguate.cpp - Unambiguous block mapping for yk ----===//
22
//
33
// 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+
// ------------------------------------
511
//
612
// In the JIT runtime, the mapping stage converts the *machine* basic blocks of
713
// a trace back to high-level basic blocks (the ones in LLVM IR). A problem
@@ -108,18 +114,74 @@
108114
// The former unambiguously expresses that `bbA` was executed twice. The latter
109115
// unambiguously expresses that `bbA` was executed only once.
110116
//
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+
//
111173
// The pass runs after high-level IR optimisations (and requires some backend
112174
// optimisations disabled) to ensure that LLVM doesn't undo our work, by
113175
// folding the machine block for `bbB` back into its predecessor in `bbA`.
114176
//
115177
// Alternative approaches that we dismissed, and why:
116178
//
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.
123185
//
124186
// - Mark (in the machine IR) which branches are exits to the high-level IR
125187
// block and encode this is the basic block map somehow. This is more
@@ -132,7 +194,8 @@
132194
// likely that some LLVM IR constructs require internal control flow for
133195
// correct semantics.
134196
//
135-
// Footnotes:
197+
// Footnotes
198+
// ---------
136199
//
137200
// [0]: For some targets, a single high-level LLVM IR instruction can even
138201
// lower to a machine-IR-level loop, for example `cmpxchng` on some ARM
@@ -142,6 +205,10 @@
142205
// a potentially unbounded number of machine blocks can be executed
143206
// within the confines of a single high-level basic block.
144207
//
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+
//
145212
//===----------------------------------------------------------------------===//
146213

147214
#include "llvm/Transforms/Yk/BlockDisambiguate.h"
@@ -178,8 +245,9 @@ class YkBlockDisambiguate : public ModulePass {
178245
}
179246

180247
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) {
183251
BasicBlock *DBB = BasicBlock::Create(Context, "");
184252
NewBBs.push_back(DBB);
185253
IRBuilder<> Builder(DBB);
@@ -202,7 +270,7 @@ class YkBlockDisambiguate : public ModulePass {
202270
SuccIdx++) {
203271
BasicBlock *SuccBB = BI->getSuccessor(SuccIdx);
204272
if (SuccBB == &BB) {
205-
BasicBlock *DBB = makeDisambiguationBB(Context, &BB, NewBBs);
273+
BasicBlock *DBB = makeBranchDisambiguationBB(Context, &BB, NewBBs);
206274
BI->setSuccessor(SuccIdx, DBB);
207275
BB.replacePhiUsesWith(&BB, DBB);
208276
}
@@ -213,11 +281,37 @@ class YkBlockDisambiguate : public ModulePass {
213281
SuccIdx++) {
214282
BasicBlock *SuccBB = SI->getSuccessor(SuccIdx);
215283
if (SuccBB == &BB) {
216-
BasicBlock *DBB = makeDisambiguationBB(Context, &BB, NewBBs);
284+
BasicBlock *DBB = makeBranchDisambiguationBB(Context, &BB, NewBBs);
217285
SI->setSuccessor(SuccIdx, DBB);
218286
BB.replacePhiUsesWith(&BB, DBB);
219287
}
220288
}
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);
221315
}
222316
}
223317

0 commit comments

Comments
 (0)