aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
diff options
context:
space:
mode:
authorHeejin Ahn <aheejin@gmail.com>2020-04-10 16:46:39 -0700
committerHeejin Ahn <aheejin@gmail.com>2020-04-13 15:50:01 -0700
commitba40896f99f2996c20d68f45b0151309406935a5 (patch)
treee22293672615f8b49ff255ce5a9c4fad24308a92 /llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
parent9b1a0d300e5e8ef295be760e6dd36598e8c14935 (diff)
downloadllvm-ba40896f99f2996c20d68f45b0151309406935a5.zip
llvm-ba40896f99f2996c20d68f45b0151309406935a5.tar.gz
llvm-ba40896f99f2996c20d68f45b0151309406935a5.tar.bz2
[WebAssembly] Fix try placement in fixing unwind mismatches
Summary: In CFGStackify, `fixUnwindMismatches` function fixes unwind destination mismatches created by `try` marker placement. For example, ``` try ... call @qux ;; This should throw to the caller! catch ... end ``` When `call @qux` is supposed to throw to the caller, it is possible that it is wrapped inside a `catch` so in case it throws it ends up unwinding there incorrectly. (Also it is possible `call @qux` is supposed to unwind to another `catch` within the same function.) To fix this, we wrap this inner `call @qux` with a nested `try`-`catch`-`end` sequence, and within the nested `catch` body, branch to the right destination: ``` block $l0 try ... try ;; new nested try call @qux catch ;; new nested catch local.set n ;; store exnref to a local br $l0 end catch ... end end local.get n ;; retrieve exnref back rethrow ;; rethrow to the caller ``` The previous algorithm placed the nested `try` right before the `call`. But it is possible that there are stackified instructions before the call from which the call takes arguments. ``` try ... i32.const 5 call @qux ;; This should throw to the caller! catch ... end ``` In this case we have to place `try` before those stackified instructions. ``` block $l0 try ... try ;; this should go *before* 'i32.const 5' i32.const 5 call @qux catch local.set n br $l0 end catch ... end end local.get n rethrow ``` We correctly handle this in the first normal `try` placement phase (`placeTryMarker` function), but failed to handle this in this `fixUnwindMismatches`. Reviewers: dschuff Subscribers: sbc100, jgravelle-google, hiraditya, sunfish, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D77950
Diffstat (limited to 'llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp')
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp23
1 files changed, 22 insertions, 1 deletions
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
index 7e867ed..989c3da 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
@@ -1109,6 +1109,9 @@ bool WebAssemblyCFGStackify::fixUnwindMismatches(MachineFunction &MF) {
MachineInstr *RangeBegin = nullptr, *RangeEnd = nullptr;
std::tie(RangeBegin, RangeEnd) = Range;
auto *MBB = RangeBegin->getParent();
+ // Store the first function call from this range, because RangeBegin can
+ // be moved to point EH_LABEL before the call
+ MachineInstr *RangeBeginCall = RangeBegin;
// Include possible EH_LABELs in the range
if (RangeBegin->getIterator() != MBB->begin() &&
@@ -1126,9 +1129,27 @@ bool WebAssemblyCFGStackify::fixUnwindMismatches(MachineFunction &MF) {
}
}
+ // Local expression tree before the first call of this range should go
+ // after the nested TRY.
+ SmallPtrSet<const MachineInstr *, 4> AfterSet;
+ AfterSet.insert(RangeBegin);
+ AfterSet.insert(RangeBeginCall);
+ for (auto I = MachineBasicBlock::iterator(RangeBeginCall),
+ E = MBB->begin();
+ I != E; --I) {
+ if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition())
+ continue;
+ if (WebAssembly::isChild(*std::prev(I), MFI))
+ AfterSet.insert(&*std::prev(I));
+ else
+ break;
+ }
+
// Create the nested try instruction.
+ auto InsertPos = getLatestInsertPos(
+ MBB, SmallPtrSet<const MachineInstr *, 4>(), AfterSet);
MachineInstr *NestedTry =
- BuildMI(*MBB, *RangeBegin, RangeBegin->getDebugLoc(),
+ BuildMI(*MBB, InsertPos, RangeBegin->getDebugLoc(),
TII.get(WebAssembly::TRY))
.addImm(int64_t(WebAssembly::BlockType::Void));