[WebAssembly] Exception handling: Switch to the new proposal
Summary:
This switches the EH implementation to the new proposal:
https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md
(The previous proposal was
https://github.com/WebAssembly/exception-handling/blob/master/proposals/old/Exceptions.md)
- Instruction changes
- Now we have one single `catch` instruction that returns a except_ref
value
- `throw` now can take variable number of operations
- `rethrow` does not have 'depth' argument anymore
- `br_on_exn` queries an except_ref to see if it matches the tag and
branches to the given label if true.
- `extract_exception` is a pseudo instruction that simulates popping
values from wasm stack. This is to make `br_on_exn`, a very special
instruction, work: `br_on_exn` puts values onto the stack only if it
is taken, and the # of values can vay depending on the tag.
- Now there's only one `catch` per `try`, this patch removes all special
handling for terminate pad with a call to `__clang_call_terminate`.
Before it was the only case there are two catch clauses (a normal
`catch` and `catch_all` per `try`).
- Make `rethrow` act as a terminator like `throw`. This splits BB after
`rethrow` in WasmEHPrepare, and deletes an unnecessary `unreachable`
after `rethrow` in LateEHPrepare.
- Now we stop at all catchpads (because we add wasm `catch` instruction
that catches all exceptions), this creates new
`findWasmUnwindDestinations` function in SelectionDAGBuilder.
- Now we use `br_on_exn` instrution to figure out if an except_ref
matches the current tag or not, LateEHPrepare generates this sequence
for catch pads:
```
catch
block i32
br_on_exn $__cpp_exception
end_block
extract_exception
```
- Branch analysis for `br_on_exn` in WebAssemblyInstrInfo
- Other various misc. changes to switch to the new proposal.
Reviewers: dschuff
Subscribers: sbc100, jgravelle-google, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D57134
llvm-svn: 352598
diff --git a/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp b/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp
index c708900..225f4f2 100644
--- a/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp
@@ -122,61 +122,48 @@
}
break;
- case WebAssembly::CATCH_I32:
- case WebAssembly::CATCH_I32_S:
- case WebAssembly::CATCH_I64:
- case WebAssembly::CATCH_I64_S:
- case WebAssembly::CATCH_ALL:
- case WebAssembly::CATCH_ALL_S:
- // There can be multiple catch instructions for one try instruction, so we
- // print a label only for the first 'catch' label.
- if (LastSeenEHInst != CATCH) {
- if (EHPadStack.empty()) {
- printAnnotation(OS, "try-catch mismatch!");
- } else {
- printAnnotation(OS,
- "catch" + utostr(EHPadStack.pop_back_val()) + ':');
- }
+ case WebAssembly::CATCH:
+ case WebAssembly::CATCH_S:
+ if (EHPadStack.empty()) {
+ printAnnotation(OS, "try-catch mismatch!");
+ } else {
+ printAnnotation(OS, "catch" + utostr(EHPadStack.pop_back_val()) + ':');
}
- LastSeenEHInst = CATCH;
break;
}
// Annotate any control flow label references.
- unsigned NumFixedOperands = Desc.NumOperands;
- SmallSet<uint64_t, 8> Printed;
- for (unsigned i = 0, e = MI->getNumOperands(); i < e; ++i) {
- // See if this operand denotes a basic block target.
- if (i < NumFixedOperands) {
- // A non-variable_ops operand, check its type.
- if (Desc.OpInfo[i].OperandType != WebAssembly::OPERAND_BASIC_BLOCK)
- continue;
+
+ // rethrow instruction does not take any depth argument and rethrows to the
+ // nearest enclosing catch scope, if any. If there's no enclosing catch
+ // scope, it throws up to the caller.
+ if (Opc == WebAssembly::RETHROW || Opc == WebAssembly::RETHROW_S) {
+ if (EHPadStack.empty()) {
+ printAnnotation(OS, "to caller");
} else {
- // A variable_ops operand, which currently can be immediates (used in
- // br_table) which are basic block targets, or for call instructions
- // when using -wasm-keep-registers (in which case they are registers,
- // and should not be processed).
- if (!MI->getOperand(i).isImm())
- continue;
+ printAnnotation(OS, "down to catch" + utostr(EHPadStack.back()));
}
- uint64_t Depth = MI->getOperand(i).getImm();
- if (!Printed.insert(Depth).second)
- continue;
- if (Opc == WebAssembly::RETHROW || Opc == WebAssembly::RETHROW_S) {
- if (Depth > EHPadStack.size()) {
- printAnnotation(OS, "Invalid depth argument!");
- } else if (Depth == EHPadStack.size()) {
- // This can happen when rethrow instruction breaks out of all nests
- // and throws up to the current function's caller.
- printAnnotation(OS, utostr(Depth) + ": " + "to caller");
+ } else {
+ unsigned NumFixedOperands = Desc.NumOperands;
+ SmallSet<uint64_t, 8> Printed;
+ for (unsigned I = 0, E = MI->getNumOperands(); I < E; ++I) {
+ // See if this operand denotes a basic block target.
+ if (I < NumFixedOperands) {
+ // A non-variable_ops operand, check its type.
+ if (Desc.OpInfo[I].OperandType != WebAssembly::OPERAND_BASIC_BLOCK)
+ continue;
} else {
- uint64_t CatchNo = EHPadStack.rbegin()[Depth];
- printAnnotation(OS, utostr(Depth) + ": " + "down to catch" +
- utostr(CatchNo));
+ // A variable_ops operand, which currently can be immediates (used in
+ // br_table) which are basic block targets, or for call instructions
+ // when using -wasm-keep-registers (in which case they are registers,
+ // and should not be processed).
+ if (!MI->getOperand(I).isImm())
+ continue;
}
-
- } else {
+ uint64_t Depth = MI->getOperand(I).getImm();
+ if (!Printed.insert(Depth).second)
+ continue;
if (Depth >= ControlFlowStack.size()) {
printAnnotation(OS, "Invalid depth argument!");
} else {