diff options
author | Dan Gohman <dan433584@gmail.com> | 2016-01-12 19:14:46 +0000 |
---|---|---|
committer | Dan Gohman <dan433584@gmail.com> | 2016-01-12 19:14:46 +0000 |
commit | 1d68e80f26f94a3a9338037efd70d5fbab099bc8 (patch) | |
tree | 876455385e68c6a0b0aa98bd2d26bf9e4addc652 /llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp | |
parent | 1279881315fbce28e3aacc40a3d19dd8be6cf927 (diff) | |
download | bcm5719-llvm-1d68e80f26f94a3a9338037efd70d5fbab099bc8.tar.gz bcm5719-llvm-1d68e80f26f94a3a9338037efd70d5fbab099bc8.zip |
[WebAssembly] Make CFG stackification independent of basic-block labels.
This patch changes the way labels are referenced. Instead of referencing the
basic-block label name (eg. .LBB0_0), instructions now just have an immediate
which indicates the depth in the control-flow stack to find a label to jump to.
This makes them much closer to what we expect to have in the binary encoding,
and avoids the problem of basic-block label names not being explicit in the
binary encoding.
Also, it terminates blocks and loops with end_block and end_loop instructions,
rather than basic-block label names, for similar reasons.
This will also fix problems where two constructs appear to have the same label,
because we no longer explicitly use labels, so consumers that need labels will
presumably create their own labels, and presumably they won't reuse labels
when they do.
This patch does make the code a little more awkward to read; as a partial
mitigation, this patch also introduces comments showing where the labels are,
and comments on each branch showing where it's branching to.
llvm-svn: 257505
Diffstat (limited to 'llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp')
-rw-r--r-- | llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp | 147 |
1 files changed, 84 insertions, 63 deletions
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp index 0080dc09e8a..7876a1e1832 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp @@ -326,13 +326,21 @@ static void PlaceBlockMarker(MachineBasicBlock &MBB, MachineFunction &MF, InsertPos = Header->getFirstTerminator(); while (InsertPos != Header->begin() && prev(InsertPos)->definesRegister(WebAssembly::EXPR_STACK) && - prev(InsertPos)->getOpcode() != WebAssembly::LOOP) + prev(InsertPos)->getOpcode() != WebAssembly::LOOP && + prev(InsertPos)->getOpcode() != WebAssembly::END_BLOCK && + prev(InsertPos)->getOpcode() != WebAssembly::END_LOOP) --InsertPos; } // Add the BLOCK. - BuildMI(*Header, InsertPos, DebugLoc(), TII.get(WebAssembly::BLOCK)) - .addMBB(&MBB); + BuildMI(*Header, InsertPos, DebugLoc(), TII.get(WebAssembly::BLOCK)); + + // Mark the end of the block. + InsertPos = MBB.begin(); + while (InsertPos != MBB.end() && + InsertPos->getOpcode() == WebAssembly::END_LOOP) + ++InsertPos; + BuildMI(MBB, InsertPos, DebugLoc(), TII.get(WebAssembly::END_BLOCK)); // Track the farthest-spanning scope that ends at this point. int Number = MBB.getNumber(); @@ -342,10 +350,11 @@ static void PlaceBlockMarker(MachineBasicBlock &MBB, MachineFunction &MF, } /// Insert a LOOP marker for a loop starting at MBB (if it's a loop header). -static void PlaceLoopMarker(MachineBasicBlock &MBB, MachineFunction &MF, - SmallVectorImpl<MachineBasicBlock *> &ScopeTops, - const WebAssemblyInstrInfo &TII, - const MachineLoopInfo &MLI) { +static void PlaceLoopMarker( + MachineBasicBlock &MBB, MachineFunction &MF, + SmallVectorImpl<MachineBasicBlock *> &ScopeTops, + DenseMap<const MachineInstr *, const MachineBasicBlock *> &LoopTops, + const WebAssemblyInstrInfo &TII, const MachineLoopInfo &MLI) { MachineLoop *Loop = MLI.getLoopFor(&MBB); if (!Loop || Loop->getHeader() != &MBB) return; @@ -362,14 +371,19 @@ static void PlaceLoopMarker(MachineBasicBlock &MBB, MachineFunction &MF, Iter = next(MachineFunction::iterator(Bottom)); } MachineBasicBlock *AfterLoop = &*Iter; - BuildMI(MBB, MBB.begin(), DebugLoc(), TII.get(WebAssembly::LOOP)) - .addMBB(AfterLoop); - // Emit a special no-op telling the asm printer that we need a label to close - // the loop scope, even though the destination is only reachable by - // fallthrough. - if (!Bottom->back().isBarrier()) - BuildMI(*Bottom, Bottom->end(), DebugLoc(), TII.get(WebAssembly::LOOP_END)); + // Mark the beginning of the loop (after the end of any existing loop that + // ends here). + auto InsertPos = MBB.begin(); + while (InsertPos != MBB.end() && + InsertPos->getOpcode() == WebAssembly::END_LOOP) + ++InsertPos; + BuildMI(MBB, InsertPos, DebugLoc(), TII.get(WebAssembly::LOOP)); + + // Mark the end of the loop. + MachineInstr *End = BuildMI(*AfterLoop, AfterLoop->begin(), DebugLoc(), + TII.get(WebAssembly::END_LOOP)); + LoopTops[End] = &MBB; assert((!ScopeTops[AfterLoop->getNumber()] || ScopeTops[AfterLoop->getNumber()]->getNumber() < MBB.getNumber()) && @@ -378,6 +392,19 @@ static void PlaceLoopMarker(MachineBasicBlock &MBB, MachineFunction &MF, ScopeTops[AfterLoop->getNumber()] = &MBB; } +static unsigned +GetDepth(const SmallVectorImpl<const MachineBasicBlock *> &Stack, + const MachineBasicBlock *MBB) { + unsigned Depth = 0; + for (auto X : reverse(Stack)) { + if (X == MBB) + break; + ++Depth; + } + assert(Depth < Stack.size() && "Branch destination should be in scope"); + return Depth; +} + /// Insert LOOP and BLOCK markers at appropriate places. static void PlaceMarkers(MachineFunction &MF, const MachineLoopInfo &MLI, const WebAssemblyInstrInfo &TII, @@ -389,25 +416,57 @@ static void PlaceMarkers(MachineFunction &MF, const MachineLoopInfo &MLI, // we may insert at the end. SmallVector<MachineBasicBlock *, 8> ScopeTops(MF.getNumBlockIDs() + 1); + // For eacn LOOP_END, the corresponding LOOP. + DenseMap<const MachineInstr *, const MachineBasicBlock *> LoopTops; + for (auto &MBB : MF) { // Place the LOOP for MBB if MBB is the header of a loop. - PlaceLoopMarker(MBB, MF, ScopeTops, TII, MLI); + PlaceLoopMarker(MBB, MF, ScopeTops, LoopTops, TII, MLI); // Place the BLOCK for MBB if MBB is branched to from above. PlaceBlockMarker(MBB, MF, ScopeTops, TII, MLI, MDT); } -} -#ifndef NDEBUG -static bool -IsOnStack(const SmallVectorImpl<std::pair<MachineBasicBlock *, bool>> &Stack, - const MachineBasicBlock *MBB) { - for (const auto &Pair : Stack) - if (Pair.first == MBB) - return true; - return false; + // Now rewrite references to basic blocks to be depth immediates. + SmallVector<const MachineBasicBlock *, 8> Stack; + for (auto &MBB : reverse(MF)) { + for (auto &MI : reverse(MBB)) { + switch (MI.getOpcode()) { + case WebAssembly::BLOCK: + assert(ScopeTops[Stack.back()->getNumber()] == &MBB && + "Block should be balanced"); + Stack.pop_back(); + break; + case WebAssembly::LOOP: + assert(Stack.back() == &MBB && "Loop top should be balanced"); + Stack.pop_back(); + Stack.pop_back(); + break; + case WebAssembly::END_BLOCK: + Stack.push_back(&MBB); + break; + case WebAssembly::END_LOOP: + Stack.push_back(&MBB); + Stack.push_back(LoopTops[&MI]); + break; + default: + if (MI.isTerminator()) { + // Rewrite MBB operands to be depth immediates. + SmallVector<MachineOperand, 4> Ops(MI.operands()); + while (MI.getNumOperands() > 0) + MI.RemoveOperand(MI.getNumOperands() - 1); + for (auto MO : Ops) { + if (MO.isMBB()) + MO = MachineOperand::CreateImm(GetDepth(Stack, MO.getMBB())); + MI.addOperand(MF, MO); + } + } + break; + } + } + } + assert(Stack.empty() && "Control flow should be balanced"); } -#endif bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) { DEBUG(dbgs() << "********** CFG Stackifying **********\n" @@ -427,43 +486,5 @@ bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) { // Place the BLOCK and LOOP markers to indicate the beginnings of scopes. PlaceMarkers(MF, MLI, TII, MDT); -#ifndef NDEBUG - // Verify that block and loop beginnings and endings are in LIFO order, and - // that all references to blocks are to blocks on the stack at the point of - // the reference. - SmallVector<std::pair<MachineBasicBlock *, bool>, 0> Stack; - for (auto &MBB : MF) { - while (!Stack.empty() && Stack.back().first == &MBB) - if (Stack.back().second) { - assert(Stack.size() >= 2); - Stack.pop_back(); - Stack.pop_back(); - } else { - assert(Stack.size() >= 1); - Stack.pop_back(); - } - for (auto &MI : MBB) - switch (MI.getOpcode()) { - case WebAssembly::LOOP: - Stack.push_back(std::make_pair(&MBB, false)); - Stack.push_back(std::make_pair(MI.getOperand(0).getMBB(), true)); - break; - case WebAssembly::BLOCK: - Stack.push_back(std::make_pair(MI.getOperand(0).getMBB(), false)); - break; - default: - // Verify that all referenced blocks are in scope. A reference to a - // block with a negative number is invalid, but can happen with inline - // asm, so we shouldn't assert on it, but instead let CodeGen properly - // fail on it. - for (const MachineOperand &MO : MI.explicit_operands()) - if (MO.isMBB() && MO.getMBB()->getNumber() >= 0) - assert(IsOnStack(Stack, MO.getMBB())); - break; - } - } - assert(Stack.empty()); -#endif - return true; } |