aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp')
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp105
1 files changed, 65 insertions, 40 deletions
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
index 87e5f8e..745b97f 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
@@ -80,8 +80,12 @@ class WebAssemblyCFGStackify final : public MachineFunctionPass {
void removeUnnecessaryInstrs(MachineFunction &MF);
// Wrap-up
- unsigned getDepth(const SmallVectorImpl<const MachineBasicBlock *> &Stack,
- const MachineBasicBlock *MBB);
+ using EndMarkerInfo =
+ std::pair<const MachineBasicBlock *, const MachineInstr *>;
+ unsigned getBranchDepth(const SmallVectorImpl<EndMarkerInfo> &Stack,
+ const MachineBasicBlock *MBB);
+ unsigned getDelegateDepth(const SmallVectorImpl<EndMarkerInfo> &Stack,
+ const MachineBasicBlock *MBB);
void rewriteDepthImmediates(MachineFunction &MF);
void fixEndsAtEndOfFunction(MachineFunction &MF);
void cleanupFunctionData(MachineFunction &MF);
@@ -1399,21 +1403,6 @@ void WebAssemblyCFGStackify::recalculateScopeTops(MachineFunction &MF) {
}
}
-unsigned WebAssemblyCFGStackify::getDepth(
- const SmallVectorImpl<const MachineBasicBlock *> &Stack,
- const MachineBasicBlock *MBB) {
- if (MBB == FakeCallerBB)
- return Stack.size();
- 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;
-}
-
/// In normal assembly languages, when the end of a function is unreachable,
/// because the function ends in an infinite loop or a noreturn call or similar,
/// it isn't necessary to worry about the function return type at the end of
@@ -1515,48 +1504,85 @@ void WebAssemblyCFGStackify::placeMarkers(MachineFunction &MF) {
}
}
+unsigned WebAssemblyCFGStackify::getBranchDepth(
+ const SmallVectorImpl<EndMarkerInfo> &Stack, const MachineBasicBlock *MBB) {
+ unsigned Depth = 0;
+ for (auto X : reverse(Stack)) {
+ if (X.first == MBB)
+ break;
+ ++Depth;
+ }
+ assert(Depth < Stack.size() && "Branch destination should be in scope");
+ return Depth;
+}
+
+unsigned WebAssemblyCFGStackify::getDelegateDepth(
+ const SmallVectorImpl<EndMarkerInfo> &Stack, const MachineBasicBlock *MBB) {
+ if (MBB == FakeCallerBB)
+ return Stack.size();
+ // Delegate's destination is either a catch or a another delegate BB. When the
+ // destination is another delegate, we can compute the argument in the same
+ // way as branches, because the target delegate BB only contains the single
+ // delegate instruction.
+ if (!MBB->isEHPad()) // Target is a delegate BB
+ return getBranchDepth(Stack, MBB);
+
+ // When the delegate's destination is a catch BB, we need to use its
+ // corresponding try's end_try BB because Stack contains each marker's end BB.
+ // Also we need to check if the end marker instruction matches, because a
+ // single BB can contain multiple end markers, like this:
+ // bb:
+ // END_BLOCK
+ // END_TRY
+ // END_BLOCK
+ // END_TRY
+ // ...
+ //
+ // In case of branches getting the immediate that targets any of these is
+ // fine, but delegate has to exactly target the correct try.
+ unsigned Depth = 0;
+ const MachineInstr *EndTry = BeginToEnd[EHPadToTry[MBB]];
+ for (auto X : reverse(Stack)) {
+ if (X.first == EndTry->getParent() && X.second == EndTry)
+ break;
+ ++Depth;
+ }
+ assert(Depth < Stack.size() && "Delegate destination should be in scope");
+ return Depth;
+}
+
void WebAssemblyCFGStackify::rewriteDepthImmediates(MachineFunction &MF) {
// Now rewrite references to basic blocks to be depth immediates.
- SmallVector<const MachineBasicBlock *, 8> Stack;
- SmallVector<const MachineBasicBlock *, 8> DelegateStack;
+ SmallVector<EndMarkerInfo, 8> Stack;
for (auto &MBB : reverse(MF)) {
for (auto I = MBB.rbegin(), E = MBB.rend(); I != E; ++I) {
MachineInstr &MI = *I;
switch (MI.getOpcode()) {
case WebAssembly::BLOCK:
case WebAssembly::TRY:
- assert(ScopeTops[Stack.back()->getNumber()]->getNumber() <=
+ assert(ScopeTops[Stack.back().first->getNumber()]->getNumber() <=
MBB.getNumber() &&
"Block/try marker should be balanced");
Stack.pop_back();
- DelegateStack.pop_back();
break;
case WebAssembly::LOOP:
- assert(Stack.back() == &MBB && "Loop top should be balanced");
+ assert(Stack.back().first == &MBB && "Loop top should be balanced");
Stack.pop_back();
- DelegateStack.pop_back();
break;
case WebAssembly::END_BLOCK:
- Stack.push_back(&MBB);
- DelegateStack.push_back(&MBB);
+ Stack.push_back(std::make_pair(&MBB, &MI));
break;
case WebAssembly::END_TRY:
// We handle DELEGATE in the default level, because DELEGATE has
- // immediate operands to rewirte.
- Stack.push_back(&MBB);
+ // immediate operands to rewrite.
+ Stack.push_back(std::make_pair(&MBB, &MI));
break;
case WebAssembly::END_LOOP:
- Stack.push_back(EndToBegin[&MI]->getParent());
- DelegateStack.push_back(EndToBegin[&MI]->getParent());
- break;
-
- case WebAssembly::CATCH:
- case WebAssembly::CATCH_ALL:
- DelegateStack.push_back(&MBB);
+ Stack.push_back(std::make_pair(EndToBegin[&MI]->getParent(), &MI));
break;
default:
@@ -1569,18 +1595,17 @@ void WebAssemblyCFGStackify::rewriteDepthImmediates(MachineFunction &MF) {
if (MO.isMBB()) {
if (MI.getOpcode() == WebAssembly::DELEGATE)
MO = MachineOperand::CreateImm(
- getDepth(DelegateStack, MO.getMBB()));
+ getDelegateDepth(Stack, MO.getMBB()));
else
- MO = MachineOperand::CreateImm(getDepth(Stack, MO.getMBB()));
+ MO = MachineOperand::CreateImm(
+ getBranchDepth(Stack, MO.getMBB()));
}
MI.addOperand(MF, MO);
}
}
- if (MI.getOpcode() == WebAssembly::DELEGATE) {
- Stack.push_back(&MBB);
- DelegateStack.push_back(&MBB);
- }
+ if (MI.getOpcode() == WebAssembly::DELEGATE)
+ Stack.push_back(std::make_pair(&MBB, &MI));
break;
}
}