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
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
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
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
180247private:
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