[llvm] r352598 - [WebAssembly] Exception handling: Switch to the new proposal
Heejin Ahn via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 29 19:21:57 PST 2019
Author: aheejin
Date: Tue Jan 29 19:21:57 2019
New Revision: 352598
URL: http://llvm.org/viewvc/llvm-project?rev=352598&view=rev
Log:
[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
Added:
llvm/trunk/test/MC/WebAssembly/annotations.s
Removed:
llvm/trunk/test/CodeGen/WebAssembly/annotations.mir
llvm/trunk/test/CodeGen/WebAssembly/cfg-stackify-eh.mir
Modified:
llvm/trunk/include/llvm/IR/IntrinsicsWebAssembly.td
llvm/trunk/lib/CodeGen/AsmPrinter/WasmException.cpp
llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
llvm/trunk/lib/CodeGen/WasmEHPrepare.cpp
llvm/trunk/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp
llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
llvm/trunk/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
llvm/trunk/lib/Target/WebAssembly/WebAssemblyEHRestoreStackPointer.cpp
llvm/trunk/lib/Target/WebAssembly/WebAssemblyExceptionInfo.cpp
llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h
llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrControl.td
llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp
llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
llvm/trunk/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp
llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
llvm/trunk/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp
llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.h
llvm/trunk/test/CodeGen/WebAssembly/cfg-stackify-eh.ll
llvm/trunk/test/CodeGen/WebAssembly/exception.ll
llvm/trunk/test/CodeGen/WebAssembly/wasmehprepare.ll
llvm/trunk/test/MC/WebAssembly/basic-assembly.s
llvm/trunk/unittests/Target/WebAssembly/WebAssemblyExceptionInfoTest.cpp
Modified: llvm/trunk/include/llvm/IR/IntrinsicsWebAssembly.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/IntrinsicsWebAssembly.td?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/IntrinsicsWebAssembly.td (original)
+++ llvm/trunk/include/llvm/IR/IntrinsicsWebAssembly.td Tue Jan 29 19:21:57 2019
@@ -49,11 +49,12 @@ def int_wasm_get_exception : Intrinsic<[
[IntrHasSideEffects]>;
def int_wasm_get_ehselector : Intrinsic<[llvm_i32_ty], [llvm_token_ty],
[IntrHasSideEffects]>;
-
-// wasm.catch returns the pointer to the exception object caught by wasm 'catch'
-// instruction.
-def int_wasm_catch : Intrinsic<[llvm_ptr_ty], [llvm_i32_ty],
- [IntrHasSideEffects]>;
+// This is the same as llvm.wasm.get.exception except that it does not take a
+// token operand. This is only for instruction selection purpose.
+// TODO Remove this redundant intrinsic and do custom lowering on
+// int_wasm_get_exception instead
+def int_wasm_extract_exception : Intrinsic<[llvm_ptr_ty], [],
+ [IntrHasSideEffects]>;
// WebAssembly EH must maintain the landingpads in the order assigned to them
// by WasmEHPrepare pass to generate landingpad table in EHStreamer. This is
Modified: llvm/trunk/lib/CodeGen/AsmPrinter/WasmException.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/WasmException.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/WasmException.cpp (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/WasmException.cpp Tue Jan 29 19:21:57 2019
@@ -18,10 +18,10 @@
using namespace llvm;
void WasmException::endModule() {
- // This is the symbol used in 'throw' and 'if_except' instruction to denote
+ // This is the symbol used in 'throw' and 'br_on_exn' instruction to denote
// this is a C++ exception. This symbol has to be emitted somewhere once in
// the module. Check if the symbol has already been created, i.e., we have at
- // least one 'throw' or 'if_except' instruction in the module, and emit the
+ // least one 'throw' or 'br_on_exn' instruction in the module, and emit the
// symbol only if so.
SmallString<60> NameStr;
Mangler::getNameWithPrefix(NameStr, "__cpp_exception", Asm->getDataLayout());
Modified: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp (original)
+++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp Tue Jan 29 19:21:57 2019
@@ -1456,6 +1456,36 @@ void SelectionDAGBuilder::visitCleanupPa
}
}
+// For wasm, there's alwyas a single catch pad attached to a catchswitch, and
+// the control flow always stops at the single catch pad, as it does for a
+// cleanup pad. In case the exception caught is not of the types the catch pad
+// catches, it will be rethrown by a rethrow.
+static void findWasmUnwindDestinations(
+ FunctionLoweringInfo &FuncInfo, const BasicBlock *EHPadBB,
+ BranchProbability Prob,
+ SmallVectorImpl<std::pair<MachineBasicBlock *, BranchProbability>>
+ &UnwindDests) {
+ while (EHPadBB) {
+ const Instruction *Pad = EHPadBB->getFirstNonPHI();
+ if (isa<CleanupPadInst>(Pad)) {
+ // Stop on cleanup pads.
+ UnwindDests.emplace_back(FuncInfo.MBBMap[EHPadBB], Prob);
+ UnwindDests.back().first->setIsEHScopeEntry();
+ break;
+ } else if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(Pad)) {
+ // Add the catchpad handlers to the possible destinations. We don't
+ // continue to the unwind destination of the catchswitch for wasm.
+ for (const BasicBlock *CatchPadBB : CatchSwitch->handlers()) {
+ UnwindDests.emplace_back(FuncInfo.MBBMap[CatchPadBB], Prob);
+ UnwindDests.back().first->setIsEHScopeEntry();
+ }
+ break;
+ } else {
+ continue;
+ }
+ }
+}
+
/// When an invoke or a cleanupret unwinds to the next EH pad, there are
/// many places it could ultimately go. In the IR, we have a single unwind
/// destination, but in the machine CFG, we enumerate all the possible blocks.
@@ -1476,6 +1506,11 @@ static void findUnwindDestinations(
bool IsWasmCXX = Personality == EHPersonality::Wasm_CXX;
bool IsSEH = isAsynchronousEHPersonality(Personality);
+ if (IsWasmCXX) {
+ findWasmUnwindDestinations(FuncInfo, EHPadBB, Prob, UnwindDests);
+ return;
+ }
+
while (EHPadBB) {
const Instruction *Pad = EHPadBB->getFirstNonPHI();
BasicBlock *NewEHPadBB = nullptr;
@@ -1488,8 +1523,7 @@ static void findUnwindDestinations(
// personalities.
UnwindDests.emplace_back(FuncInfo.MBBMap[EHPadBB], Prob);
UnwindDests.back().first->setIsEHScopeEntry();
- if (!IsWasmCXX)
- UnwindDests.back().first->setIsEHFuncletEntry();
+ UnwindDests.back().first->setIsEHFuncletEntry();
break;
} else if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(Pad)) {
// Add the catchpad handlers to the possible destinations.
Modified: llvm/trunk/lib/CodeGen/WasmEHPrepare.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/WasmEHPrepare.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/WasmEHPrepare.cpp (original)
+++ llvm/trunk/lib/CodeGen/WasmEHPrepare.cpp Tue Jan 29 19:21:57 2019
@@ -7,7 +7,8 @@
//===----------------------------------------------------------------------===//
//
// This transformation is designed for use by code generators which use
-// WebAssembly exception handling scheme.
+// WebAssembly exception handling scheme. This currently supports C++
+// exceptions.
//
// WebAssembly exception handling uses Windows exception IR for the middle level
// representation. This pass does the following transformation for every
@@ -22,53 +23,20 @@
//
// - After:
// catchpad ...
-// exn = wasm.catch(0); // 0 is a tag for C++
-// wasm.landingpad.index(index);
+// exn = wasm.extract.exception();
// // Only add below in case it's not a single catch (...)
+// wasm.landingpad.index(index);
// __wasm_lpad_context.lpad_index = index;
// __wasm_lpad_context.lsda = wasm.lsda();
// _Unwind_CallPersonality(exn);
-// int selector = __wasm.landingpad_context.selector;
+// selector = __wasm.landingpad_context.selector;
// ...
//
-// Also, does the following for a cleanuppad block with a call to
-// __clang_call_terminate():
-// - Before:
-// cleanuppad ...
-// exn = wasm.get.exception();
-// __clang_call_terminate(exn);
-//
-// - After:
-// cleanuppad ...
-// exn = wasm.catch(0); // 0 is a tag for C++
-// __clang_call_terminate(exn);
-//
-//
-// * Background: WebAssembly EH instructions
-// WebAssembly's try and catch instructions are structured as follows:
-// try
-// instruction*
-// catch (C++ tag)
-// instruction*
-// ...
-// catch_all
-// instruction*
-// try_end
-//
-// A catch instruction in WebAssembly does not correspond to a C++ catch clause.
-// In WebAssembly, there is a single catch instruction for all C++ exceptions.
-// There can be more catch instructions for exceptions in other languages, but
-// they are not generated for now. catch_all catches all exceptions including
-// foreign exceptions (e.g. JavaScript). We turn catchpads into catch (C++ tag)
-// and cleanuppads into catch_all, with one exception: cleanuppad with a call to
-// __clang_call_terminate should be both in catch (C++ tag) and catch_all.
-//
//
// * Background: Direct personality function call
// In WebAssembly EH, the VM is responsible for unwinding the stack once an
// exception is thrown. After the stack is unwound, the control flow is
-// transfered to WebAssembly 'catch' instruction, which returns a caught
-// exception object.
+// transfered to WebAssembly 'catch' instruction.
//
// Unwinding the stack is not done by libunwind but the VM, so the personality
// function in libcxxabi cannot be called from libunwind during the unwinding
@@ -137,18 +105,18 @@ class WasmEHPrepare : public FunctionPas
Value *SelectorField = nullptr; // selector
Function *ThrowF = nullptr; // wasm.throw() intrinsic
- Function *CatchF = nullptr; // wasm.catch.extract() intrinsic
+ Function *RethrowF = nullptr; // wasm.rethrow() intrinsic
Function *LPadIndexF = nullptr; // wasm.landingpad.index() intrinsic
Function *LSDAF = nullptr; // wasm.lsda() intrinsic
Function *GetExnF = nullptr; // wasm.get.exception() intrinsic
+ Function *ExtractExnF = nullptr; // wasm.extract.exception() intrinsic
Function *GetSelectorF = nullptr; // wasm.get.ehselector() intrinsic
Function *CallPersonalityF = nullptr; // _Unwind_CallPersonality() wrapper
- Function *ClangCallTermF = nullptr; // __clang_call_terminate() function
bool prepareEHPads(Function &F);
bool prepareThrows(Function &F);
- void prepareEHPad(BasicBlock *BB, unsigned Index);
+ void prepareEHPad(BasicBlock *BB, bool NeedLSDA, unsigned Index = 0);
void prepareTerminateCleanupPad(BasicBlock *BB);
public:
@@ -208,25 +176,29 @@ bool WasmEHPrepare::prepareThrows(Functi
// wasm.throw() intinsic, which will be lowered to wasm 'throw' instruction.
ThrowF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_throw);
-
- // Insert an unreachable instruction after a call to @llvm.wasm.throw and
- // delete all following instructions within the BB, and delete all the dead
- // children of the BB as well.
- for (User *U : ThrowF->users()) {
- // A call to @llvm.wasm.throw() is only generated from
- // __builtin_wasm_throw() builtin call within libcxxabi, and cannot be an
- // InvokeInst.
- auto *ThrowI = cast<CallInst>(U);
- if (ThrowI->getFunction() != &F)
- continue;
- Changed = true;
- auto *BB = ThrowI->getParent();
- SmallVector<BasicBlock *, 4> Succs(succ_begin(BB), succ_end(BB));
- auto &InstList = BB->getInstList();
- InstList.erase(std::next(BasicBlock::iterator(ThrowI)), InstList.end());
- IRB.SetInsertPoint(BB);
- IRB.CreateUnreachable();
- eraseDeadBBsAndChildren(Succs);
+ // wasm.rethrow() intinsic, which will be lowered to wasm 'rethrow'
+ // instruction.
+ RethrowF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_rethrow);
+
+ // Insert an unreachable instruction after a call to @llvm.wasm.throw /
+ // @llvm.wasm.rethrow and delete all following instructions within the BB, and
+ // delete all the dead children of the BB as well.
+ for (auto L : {ThrowF->users(), RethrowF->users()}) {
+ for (User *U : L) {
+ // A call to @llvm.wasm.throw() is only generated from __cxa_throw()
+ // builtin call within libcxxabi, and cannot be an InvokeInst.
+ auto *ThrowI = cast<CallInst>(U);
+ if (ThrowI->getFunction() != &F)
+ continue;
+ Changed = true;
+ auto *BB = ThrowI->getParent();
+ SmallVector<BasicBlock *, 4> Succs(succ_begin(BB), succ_end(BB));
+ auto &InstList = BB->getInstList();
+ InstList.erase(std::next(BasicBlock::iterator(ThrowI)), InstList.end());
+ IRB.SetInsertPoint(BB);
+ IRB.CreateUnreachable();
+ eraseDeadBBsAndChildren(Succs);
+ }
}
return Changed;
@@ -262,8 +234,6 @@ bool WasmEHPrepare::prepareEHPads(Functi
SelectorField = IRB.CreateConstGEP2_32(LPadContextTy, LPadContextGV, 0, 2,
"selector_gep");
- // wasm.catch() intinsic, which will be lowered to wasm 'catch' instruction.
- CatchF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_catch);
// wasm.landingpad.index() intrinsic, which is to specify landingpad index
LPadIndexF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_landingpad_index);
// wasm.lsda() intrinsic. Returns the address of LSDA table for the current
@@ -274,75 +244,70 @@ bool WasmEHPrepare::prepareEHPads(Functi
GetExnF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_get_exception);
GetSelectorF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_get_ehselector);
+ // wasm.extract.exception() is the same as wasm.get.exception() but it does
+ // not take a token argument. This will be lowered down to EXTRACT_EXCEPTION
+ // pseudo instruction in instruction selection, which will be expanded using
+ // 'br_on_exn' instruction later.
+ ExtractExnF =
+ Intrinsic::getDeclaration(&M, Intrinsic::wasm_extract_exception);
+
// _Unwind_CallPersonality() wrapper function, which calls the personality
CallPersonalityF = cast<Function>(M.getOrInsertFunction(
"_Unwind_CallPersonality", IRB.getInt32Ty(), IRB.getInt8PtrTy()));
CallPersonalityF->setDoesNotThrow();
- // __clang_call_terminate() function, which is inserted by clang in case a
- // cleanup throws
- ClangCallTermF = M.getFunction("__clang_call_terminate");
-
unsigned Index = 0;
for (auto *BB : CatchPads) {
auto *CPI = cast<CatchPadInst>(BB->getFirstNonPHI());
// In case of a single catch (...), we don't need to emit LSDA
if (CPI->getNumArgOperands() == 1 &&
cast<Constant>(CPI->getArgOperand(0))->isNullValue())
- prepareEHPad(BB, -1);
+ prepareEHPad(BB, false);
else
- prepareEHPad(BB, Index++);
+ prepareEHPad(BB, true, Index++);
}
- if (!ClangCallTermF)
- return !CatchPads.empty();
-
- // Cleanuppads will turn into catch_all later, but cleanuppads with a call to
- // __clang_call_terminate() is a special case. __clang_call_terminate() takes
- // an exception object, so we have to duplicate call in both 'catch <C++ tag>'
- // and 'catch_all' clauses. Here we only insert a call to catch; the
- // duplication will be done later. In catch_all, the exception object will be
- // set to null.
+ // Cleanup pads don't need LSDA.
for (auto *BB : CleanupPads)
- for (auto &I : *BB)
- if (auto *CI = dyn_cast<CallInst>(&I))
- if (CI->getCalledValue() == ClangCallTermF)
- prepareEHPad(BB, -1);
+ prepareEHPad(BB, false);
return true;
}
-void WasmEHPrepare::prepareEHPad(BasicBlock *BB, unsigned Index) {
+// Prepare an EH pad for Wasm EH handling. If NeedLSDA is false, Index is
+// ignored.
+void WasmEHPrepare::prepareEHPad(BasicBlock *BB, bool NeedLSDA,
+ unsigned Index) {
assert(BB->isEHPad() && "BB is not an EHPad!");
IRBuilder<> IRB(BB->getContext());
-
IRB.SetInsertPoint(&*BB->getFirstInsertionPt());
- // The argument to wasm.catch() is the tag for C++ exceptions, which we set to
- // 0 for this module.
- // Pseudocode: void *exn = wasm.catch(0);
- Instruction *Exn = IRB.CreateCall(CatchF, IRB.getInt32(0), "exn");
- // Replace the return value of wasm.get.exception() with the return value from
- // wasm.catch().
+
auto *FPI = cast<FuncletPadInst>(BB->getFirstNonPHI());
Instruction *GetExnCI = nullptr, *GetSelectorCI = nullptr;
for (auto &U : FPI->uses()) {
if (auto *CI = dyn_cast<CallInst>(U.getUser())) {
if (CI->getCalledValue() == GetExnF)
GetExnCI = CI;
- else if (CI->getCalledValue() == GetSelectorF)
+ if (CI->getCalledValue() == GetSelectorF)
GetSelectorCI = CI;
}
}
- assert(GetExnCI && "wasm.get.exception() call does not exist");
- GetExnCI->replaceAllUsesWith(Exn);
+ // Cleanup pads w/o __clang_call_terminate call do not have any of
+ // wasm.get.exception() or wasm.get.ehselector() calls. We need to do nothing.
+ if (!GetExnCI) {
+ assert(!GetSelectorCI &&
+ "wasm.get.ehselector() cannot exist w/o wasm.get.exception()");
+ return;
+ }
+
+ Instruction *ExtractExnCI = IRB.CreateCall(ExtractExnF, {}, "exn");
+ GetExnCI->replaceAllUsesWith(ExtractExnCI);
GetExnCI->eraseFromParent();
// In case it is a catchpad with single catch (...) or a cleanuppad, we don't
// need to call personality function because we don't need a selector.
- if (FPI->getNumArgOperands() == 0 ||
- (FPI->getNumArgOperands() == 1 &&
- cast<Constant>(FPI->getArgOperand(0))->isNullValue())) {
+ if (!NeedLSDA) {
if (GetSelectorCI) {
assert(GetSelectorCI->use_empty() &&
"wasm.get.ehselector() still has uses!");
@@ -350,7 +315,7 @@ void WasmEHPrepare::prepareEHPad(BasicBl
}
return;
}
- IRB.SetInsertPoint(Exn->getNextNode());
+ IRB.SetInsertPoint(ExtractExnCI->getNextNode());
// This is to create a map of <landingpad EH label, landingpad index> in
// SelectionDAGISel, which is to be used in EHStreamer to emit LSDA tables.
@@ -372,8 +337,8 @@ void WasmEHPrepare::prepareEHPad(BasicBl
IRB.CreateStore(IRB.CreateCall(LSDAF), LSDAField);
// Pseudocode: _Unwind_CallPersonality(exn);
- CallInst *PersCI =
- IRB.CreateCall(CallPersonalityF, Exn, OperandBundleDef("funclet", CPI));
+ CallInst *PersCI = IRB.CreateCall(CallPersonalityF, ExtractExnCI,
+ OperandBundleDef("funclet", CPI));
PersCI->setDoesNotThrow();
// Pseudocode: int selector = __wasm.landingpad_context.selector;
@@ -387,15 +352,15 @@ void WasmEHPrepare::prepareEHPad(BasicBl
}
void llvm::calculateWasmEHInfo(const Function *F, WasmEHFuncInfo &EHInfo) {
+ // If an exception is not caught by a catchpad (i.e., it is a foreign
+ // exception), it will unwind to its parent catchswitch's unwind destination.
+ // We don't record an unwind destination for cleanuppads because every
+ // exception should be caught by it.
for (const auto &BB : *F) {
if (!BB.isEHPad())
continue;
const Instruction *Pad = BB.getFirstNonPHI();
- // If an exception is not caught by a catchpad (i.e., it is a foreign
- // exception), it will unwind to its parent catchswitch's unwind
- // destination. We don't record an unwind destination for cleanuppads
- // because every exception should be caught by it.
if (const auto *CatchPad = dyn_cast<CatchPadInst>(Pad)) {
const auto *UnwindBB = CatchPad->getCatchSwitch()->getUnwindDest();
if (!UnwindBB)
Modified: llvm/trunk/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp Tue Jan 29 19:21:57 2019
@@ -122,61 +122,48 @@ void WebAssemblyInstPrinter::printInst(c
}
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 {
Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp Tue Jan 29 19:21:57 2019
@@ -43,6 +43,8 @@ using namespace llvm;
#define DEBUG_TYPE "asm-printer"
+extern cl::opt<bool> WasmKeepRegisters;
+
//===----------------------------------------------------------------------===//
// Helpers.
//===----------------------------------------------------------------------===//
@@ -304,6 +306,14 @@ void WebAssemblyAsmPrinter::EmitInstruct
OutStreamer->AddBlankLine();
}
break;
+ case WebAssembly::EXTRACT_EXCEPTION_I32:
+ case WebAssembly::EXTRACT_EXCEPTION_I32_S:
+ // These are pseudo instructions that simulates popping values from stack.
+ // We print these only when we have -wasm-keep-registers on for assembly
+ // readability.
+ if (!WasmKeepRegisters)
+ break;
+ LLVM_FALLTHROUGH;
default: {
WebAssemblyMCInstLower MCInstLowering(OutContext, *this);
MCInst TmpInst;
Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp Tue Jan 29 19:21:57 2019
@@ -37,6 +37,7 @@
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
+#include <cstring>
using namespace llvm;
#define DEBUG_TYPE "wasm-cfg-stackify"
@@ -110,11 +111,9 @@ FunctionPass *llvm::createWebAssemblyCFG
static bool ExplicitlyBranchesTo(MachineBasicBlock *Pred,
MachineBasicBlock *MBB) {
for (MachineInstr &MI : Pred->terminators())
- // Even if a rethrow takes a BB argument, it is not a branch
- if (!WebAssembly::isRethrow(MI))
- for (MachineOperand &MO : MI.explicit_operands())
- if (MO.isMBB() && MO.getMBB() == MBB)
- return true;
+ for (MachineOperand &MO : MI.explicit_operands())
+ if (MO.isMBB() && MO.getMBB() == MBB)
+ return true;
return false;
}
@@ -217,12 +216,20 @@ void WebAssemblyCFGStackify::placeBlockM
// which reduces overall stack height.
MachineBasicBlock *Header = nullptr;
bool IsBranchedTo = false;
+ bool IsBrOnExn = false;
+ MachineInstr *BrOnExn = nullptr;
int MBBNumber = MBB.getNumber();
for (MachineBasicBlock *Pred : MBB.predecessors()) {
if (Pred->getNumber() < MBBNumber) {
Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred;
- if (ExplicitlyBranchesTo(Pred, &MBB))
+ if (ExplicitlyBranchesTo(Pred, &MBB)) {
IsBranchedTo = true;
+ if (Pred->getFirstTerminator()->getOpcode() == WebAssembly::BR_ON_EXN) {
+ IsBrOnExn = true;
+ assert(!BrOnExn && "There should be only one br_on_exn per block");
+ BrOnExn = &*Pred->getFirstTerminator();
+ }
+ }
}
}
if (!Header)
@@ -299,11 +306,27 @@ void WebAssemblyCFGStackify::placeBlockM
}
// Add the BLOCK.
+
+ // 'br_on_exn' extracts except_ref object and pushes variable number of values
+ // depending on its tag. For C++ exception, its a single i32 value, and the
+ // generated code will be in the form of:
+ // block i32
+ // br_on_exn 0, $__cpp_exception
+ // rethrow
+ // end_block
+ WebAssembly::ExprType ReturnType = WebAssembly::ExprType::Void;
+ if (IsBrOnExn) {
+ const char *TagName = BrOnExn->getOperand(1).getSymbolName();
+ if (std::strcmp(TagName, "__cpp_exception") != 0)
+ llvm_unreachable("Only C++ exception is supported");
+ ReturnType = WebAssembly::ExprType::I32;
+ }
+
auto InsertPos = GetLatestInsertPos(Header, BeforeSet, AfterSet);
MachineInstr *Begin =
BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos),
TII.get(WebAssembly::BLOCK))
- .addImm(int64_t(WebAssembly::ExprType::Void));
+ .addImm(int64_t(ReturnType));
// Decide where in Header to put the END_BLOCK.
BeforeSet.clear();
@@ -416,11 +439,6 @@ void WebAssemblyCFGStackify::placeTryMar
if (!MBB.isEHPad())
return;
- // catch_all terminate pad is grouped together with catch terminate pad and
- // does not need a separate TRY and END_TRY marker.
- if (WebAssembly::isCatchAllTerminatePad(MBB))
- return;
-
MachineFunction &MF = *MBB.getParent();
auto &MDT = getAnalysis<MachineDominatorTree>();
const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
@@ -529,7 +547,8 @@ void WebAssemblyCFGStackify::placeTryMar
// throw.
if (MBB.isPredecessor(Header)) {
auto TermPos = Header->getFirstTerminator();
- if (TermPos == Header->end() || !WebAssembly::isRethrow(*TermPos)) {
+ if (TermPos == Header->end() ||
+ TermPos->getOpcode() != WebAssembly::RETHROW) {
for (const auto &MI : reverse(*Header)) {
if (MI.isCall()) {
AfterSet.insert(&MI);
@@ -674,7 +693,6 @@ static void AppendEndToFunction(MachineF
/// Insert LOOP/TRY/BLOCK markers at appropriate places.
void WebAssemblyCFGStackify::placeMarkers(MachineFunction &MF) {
- const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo();
// We allocate one more than the number of blocks in the function to
// accommodate for the possible fake block we may insert at the end.
ScopeTops.resize(MF.getNumBlockIDs() + 1);
@@ -682,6 +700,7 @@ void WebAssemblyCFGStackify::placeMarker
for (auto &MBB : MF)
placeLoopMarker(MBB);
// Place the TRY for MBB if MBB is the EH pad of an exception.
+ const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo();
if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm &&
MF.getFunction().hasPersonalityFn())
for (auto &MBB : MF)
@@ -692,12 +711,8 @@ void WebAssemblyCFGStackify::placeMarker
}
void WebAssemblyCFGStackify::rewriteDepthImmediates(MachineFunction &MF) {
- const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
// Now rewrite references to basic blocks to be depth immediates.
- // We need two stacks: one for normal scopes and the other for EH pad scopes.
- // EH pad stack is used to rewrite depths in rethrow instructions.
SmallVector<const MachineBasicBlock *, 8> Stack;
- SmallVector<const MachineBasicBlock *, 8> EHPadStack;
for (auto &MBB : reverse(MF)) {
for (auto I = MBB.rbegin(), E = MBB.rend(); I != E; ++I) {
MachineInstr &MI = *I;
@@ -714,26 +729,6 @@ void WebAssemblyCFGStackify::rewriteDept
MBB.getNumber() &&
"Block/try marker should be balanced");
Stack.pop_back();
- EHPadStack.pop_back();
- break;
-
- case WebAssembly::CATCH_I32:
- case WebAssembly::CATCH_I64:
- case WebAssembly::CATCH_ALL:
- // Currently the only case there are more than one catch for a try is
- // for catch terminate pad, in the form of
- // try
- // catch
- // call @__clang_call_terminate
- // unreachable
- // catch_all
- // call @std::terminate
- // unreachable
- // end
- // So we shouldn't push the current BB for the second catch_all block
- // here.
- if (!WebAssembly::isCatchAllTerminatePad(MBB))
- EHPadStack.push_back(&MBB);
break;
case WebAssembly::LOOP:
@@ -750,23 +745,6 @@ void WebAssemblyCFGStackify::rewriteDept
Stack.push_back(EndToBegin[&MI]->getParent());
break;
- case WebAssembly::RETHROW: {
- // Rewrite MBB operands to be depth immediates.
- unsigned EHPadDepth = GetDepth(EHPadStack, MI.getOperand(0).getMBB());
- MI.RemoveOperand(0);
- MI.addOperand(MF, MachineOperand::CreateImm(EHPadDepth));
- break;
- }
-
- case WebAssembly::RETHROW_TO_CALLER: {
- MachineInstr *Rethrow =
- BuildMI(MBB, MI, MI.getDebugLoc(), TII.get(WebAssembly::RETHROW))
- .addImm(EHPadStack.size());
- MI.eraseFromParent();
- I = MachineBasicBlock::reverse_iterator(Rethrow);
- break;
- }
-
default:
if (MI.isTerminator()) {
// Rewrite MBB operands to be depth immediates.
Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyEHRestoreStackPointer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyEHRestoreStackPointer.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyEHRestoreStackPointer.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyEHRestoreStackPointer.cpp Tue Jan 29 19:21:57 2019
@@ -77,7 +77,7 @@ bool WebAssemblyEHRestoreStackPointer::r
// function uses the red zone, but that only happens with leaf functions,
// and we don't restore __stack_pointer in leaf functions anyway.
auto InsertPos = MBB.begin();
- if (WebAssembly::isCatch(*MBB.begin()))
+ if (MBB.begin()->getOpcode() == WebAssembly::CATCH)
InsertPos++;
FrameLowering->writeSPToGlobal(WebAssembly::SP32, MF, MBB, InsertPos,
MBB.begin()->getDebugLoc());
Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyExceptionInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyExceptionInfo.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyExceptionInfo.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyExceptionInfo.cpp Tue Jan 29 19:21:57 2019
@@ -50,10 +50,6 @@ void WebAssemblyExceptionInfo::recalcula
MachineBasicBlock *EHPad = DomNode->getBlock();
if (!EHPad->isEHPad())
continue;
- // We group catch & catch-all terminate pads together, so skip the second
- // one
- if (WebAssembly::isCatchAllTerminatePad(*EHPad))
- continue;
auto *WE = new WebAssemblyException(EHPad);
discoverAndMapException(WE, MDT, MDF);
Exceptions.push_back(WE);
@@ -104,16 +100,6 @@ void WebAssemblyExceptionInfo::discoverA
// Map blocks that belong to a catchpad / cleanuppad
MachineBasicBlock *EHPad = WE->getEHPad();
-
- // We group catch & catch-all terminate pads together within an exception
- if (WebAssembly::isCatchTerminatePad(*EHPad)) {
- assert(EHPad->succ_size() == 1 &&
- "Catch terminate pad has more than one successors");
- changeExceptionFor(EHPad, WE);
- changeExceptionFor(*(EHPad->succ_begin()), WE);
- return;
- }
-
SmallVector<MachineBasicBlock *, 8> WL;
WL.push_back(EHPad);
while (!WL.empty()) {
Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp Tue Jan 29 19:21:57 2019
@@ -884,13 +884,13 @@ SDValue WebAssemblyTargetLowering::Lower
return LowerFRAMEADDR(Op, DAG);
case ISD::CopyToReg:
return LowerCopyToReg(Op, DAG);
- case ISD::INTRINSIC_WO_CHAIN:
- return LowerINTRINSIC_WO_CHAIN(Op, DAG);
case ISD::EXTRACT_VECTOR_ELT:
case ISD::INSERT_VECTOR_ELT:
return LowerAccessVectorElement(Op, DAG);
case ISD::INTRINSIC_VOID:
- return LowerINTRINSIC_VOID(Op, DAG);
+ case ISD::INTRINSIC_WO_CHAIN:
+ case ISD::INTRINSIC_W_CHAIN:
+ return LowerIntrinsic(Op, DAG);
case ISD::SIGN_EXTEND_INREG:
return LowerSIGN_EXTEND_INREG(Op, DAG);
case ISD::BUILD_VECTOR:
@@ -1035,17 +1035,28 @@ SDValue WebAssemblyTargetLowering::Lower
MachinePointerInfo(SV), 0);
}
-SDValue
-WebAssemblyTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
- SelectionDAG &DAG) const {
- unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
+SDValue WebAssemblyTargetLowering::LowerIntrinsic(SDValue Op,
+ SelectionDAG &DAG) const {
+ MachineFunction &MF = DAG.getMachineFunction();
+ unsigned IntNo;
+ switch (Op.getOpcode()) {
+ case ISD::INTRINSIC_VOID:
+ case ISD::INTRINSIC_W_CHAIN:
+ IntNo = cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue();
+ break;
+ case ISD::INTRINSIC_WO_CHAIN:
+ IntNo = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
+ break;
+ default:
+ llvm_unreachable("Invalid intrinsic");
+ }
SDLoc DL(Op);
+
switch (IntNo) {
default:
return {}; // Don't custom lower most intrinsics.
case Intrinsic::wasm_lsda: {
- MachineFunction &MF = DAG.getMachineFunction();
EVT VT = Op.getValueType();
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout());
@@ -1055,43 +1066,26 @@ WebAssemblyTargetLowering::LowerINTRINSI
return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
DAG.getMCSymbol(S, PtrVT));
}
- }
-}
-
-SDValue
-WebAssemblyTargetLowering::LowerINTRINSIC_VOID(SDValue Op,
- SelectionDAG &DAG) const {
- MachineFunction &MF = DAG.getMachineFunction();
- unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue();
- SDLoc DL(Op);
-
- switch (IntNo) {
- default:
- return {}; // Don't custom lower most intrinsics.
case Intrinsic::wasm_throw: {
+ // We only support C++ exceptions for now
int Tag = cast<ConstantSDNode>(Op.getOperand(2).getNode())->getZExtValue();
- switch (Tag) {
- case CPP_EXCEPTION: {
- const TargetLowering &TLI = DAG.getTargetLoweringInfo();
- MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout());
- const char *SymName = MF.createExternalSymbolName("__cpp_exception");
- SDValue SymNode =
- DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT,
- DAG.getTargetExternalSymbol(
- SymName, PtrVT, WebAssemblyII::MO_SYMBOL_EVENT));
- return DAG.getNode(WebAssemblyISD::THROW, DL,
- MVT::Other, // outchain type
- {
- Op.getOperand(0), // inchain
- SymNode, // exception symbol
- Op.getOperand(3) // thrown value
- });
- }
- default:
+ if (Tag != CPP_EXCEPTION)
llvm_unreachable("Invalid tag!");
- }
- break;
+ const TargetLowering &TLI = DAG.getTargetLoweringInfo();
+ MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout());
+ const char *SymName = MF.createExternalSymbolName("__cpp_exception");
+ SDValue SymNode =
+ DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT,
+ DAG.getTargetExternalSymbol(
+ SymName, PtrVT, WebAssemblyII::MO_SYMBOL_EVENT));
+ return DAG.getNode(WebAssemblyISD::THROW, DL,
+ MVT::Other, // outchain type
+ {
+ Op.getOperand(0), // inchain
+ SymNode, // exception symbol
+ Op.getOperand(3) // thrown value
+ });
}
}
}
Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h Tue Jan 29 19:21:57 2019
@@ -96,8 +96,7 @@ private:
SDValue LowerJumpTable(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerCopyToReg(SDValue Op, SelectionDAG &DAG) const;
- SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const;
- SDValue LowerINTRINSIC_VOID(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerIntrinsic(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerSIGN_EXTEND_INREG(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) const;
Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrControl.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrControl.td?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrControl.td (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrControl.td Tue Jan 29 19:21:57 2019
@@ -141,23 +141,11 @@ let Predicates = [HasExceptionHandling]
// Throwing an exception: throw / rethrow
let isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in {
-defm THROW_I32 : I<(outs), (ins event_op:$tag, I32:$val),
- (outs), (ins event_op:$tag),
- [(WebAssemblythrow (WebAssemblywrapper texternalsym:$tag),
- I32:$val)],
- "throw \t$tag, $val", "throw \t$tag",
- 0x08>;
-defm THROW_I64 : I<(outs), (ins event_op:$tag, I64:$val),
- (outs), (ins event_op:$tag),
- [(WebAssemblythrow (WebAssemblywrapper texternalsym:$tag),
- I64:$val)],
- "throw \t$tag, $val", "throw \t$tag",
- 0x08>;
-defm RETHROW : NRI<(outs), (ins bb_op:$dst), [], "rethrow \t$dst", 0x09>;
-let isCodeGenOnly = 1 in
-// This is used when the destination for rethrow is the caller function. This
-// will be converted to a rethrow in CFGStackify.
-defm RETHROW_TO_CALLER : NRI<(outs), (ins), [], "rethrow">;
+defm THROW : I<(outs), (ins event_op:$tag, variable_ops),
+ (outs), (ins event_op:$tag),
+ [(WebAssemblythrow (WebAssemblywrapper texternalsym:$tag))],
+ "throw \t$tag", "throw \t$tag", 0x08>;
+defm RETHROW : NRI<(outs), (ins), [(int_wasm_rethrow)], "rethrow", 0x09>;
} // isTerminator = 1, hasCtrlDep = 1, isBarrier = 1
// Region within which an exception is caught: try / end_try
@@ -166,24 +154,33 @@ defm TRY : NRI<(outs), (ins Signatur
defm END_TRY : NRI<(outs), (ins), [], "end_try", 0x0b>;
} // Uses = [VALUE_STACK], Defs = [VALUE_STACK]
-// Catching an exception: catch / catch_all
-let hasCtrlDep = 1, hasSideEffects = 1 in {
-defm CATCH_I32 : I<(outs I32:$dst), (ins i32imm:$tag),
- (outs), (ins i32imm:$tag),
- [(set I32:$dst, (int_wasm_catch imm:$tag))],
- "i32.catch \t$dst, $tag", "i32.catch \t$tag", 0x07>;
-defm CATCH_I64 : I<(outs I64:$dst), (ins i32imm:$tag),
- (outs), (ins i32imm:$tag),
- [(set I64:$dst, (int_wasm_catch imm:$tag))],
- "i64.catch \t$dst, $tag", "i64.catch \t$tag", 0x07>;
-defm CATCH_ALL : NRI<(outs), (ins), [], "catch_all", 0x05>;
-}
+// Catching an exception: catch / extract_exception
+let hasCtrlDep = 1, hasSideEffects = 1 in
+defm CATCH : I<(outs EXCEPT_REF:$dst), (ins), (outs), (ins), [],
+ "catch \t$dst", "catch", 0x07>;
+
+// Querying / extracing exception: br_on_exn
+// br_on_exn queries an except_ref to see if it matches the corresponding
+// exception tag index. If true it branches to the given label and pushes the
+// corresponding argument values of the exception onto the stack.
+let isBranch = 1, isTerminator = 1, hasCtrlDep = 1 in
+defm BR_ON_EXN : I<(outs), (ins bb_op:$dst, event_op:$tag, EXCEPT_REF:$exn),
+ (outs), (ins bb_op:$dst, event_op:$tag), [],
+ "br_on_exn \t$dst, $tag, $exn", "br_on_exn \t$dst, $tag",
+ 0x0a>;
+// This is a pseudo instruction that simulates popping a value from stack, which
+// has been pushed by br_on_exn
+let isCodeGenOnly = 1, hasSideEffects = 1 in
+defm EXTRACT_EXCEPTION_I32 : NRI<(outs I32:$dst), (ins),
+ [(set I32:$dst, (int_wasm_extract_exception))],
+ "extract_exception\t$dst">;
// Pseudo instructions: cleanupret / catchret
let isTerminator = 1, hasSideEffects = 1, isBarrier = 1, hasCtrlDep = 1,
- isCodeGenOnly = 1, isEHScopeReturn = 1 in {
- defm CLEANUPRET : NRI<(outs), (ins), [(cleanupret)], "", 0>;
+ isPseudo = 1, isEHScopeReturn = 1 in {
+ defm CLEANUPRET : NRI<(outs), (ins), [(cleanupret)], "cleanupret", 0>;
defm CATCHRET : NRI<(outs), (ins bb_op:$dst, bb_op:$from),
- [(catchret bb:$dst, bb:$from)], "", 0>;
-}
+ [(catchret bb:$dst, bb:$from)], "catchret", 0>;
+} // isTerminator = 1, hasSideEffects = 1, isBarrier = 1, hasCtrlDep = 1,
+ // isPseudo = 1, isEHScopeReturn = 1
}
Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp Tue Jan 29 19:21:57 2019
@@ -134,6 +134,17 @@ bool WebAssemblyInstrInfo::analyzeBranch
else
FBB = MI.getOperand(0).getMBB();
break;
+ case WebAssembly::BR_ON_EXN:
+ if (HaveCond)
+ return true;
+ // If we're running after CFGStackify, we can't optimize further.
+ if (!MI.getOperand(0).isMBB())
+ return true;
+ Cond.push_back(MachineOperand::CreateImm(true));
+ Cond.push_back(MI.getOperand(2));
+ TBB = MI.getOperand(0).getMBB();
+ HaveCond = true;
+ break;
}
if (MI.isBarrier())
break;
@@ -179,9 +190,22 @@ unsigned WebAssemblyInstrInfo::insertBra
assert(Cond.size() == 2 && "Expected a flag and a successor block");
+ MachineFunction &MF = *MBB.getParent();
+ auto &MRI = MF.getRegInfo();
+ bool IsBrOnExn = Cond[1].isReg() && MRI.getRegClass(Cond[1].getReg()) ==
+ &WebAssembly::EXCEPT_REFRegClass;
+
if (Cond[0].getImm()) {
- BuildMI(&MBB, DL, get(WebAssembly::BR_IF)).addMBB(TBB).add(Cond[1]);
+ if (IsBrOnExn) {
+ const char *CPPExnSymbol = MF.createExternalSymbolName("__cpp_exception");
+ BuildMI(&MBB, DL, get(WebAssembly::BR_ON_EXN))
+ .addMBB(TBB)
+ .addExternalSymbol(CPPExnSymbol, WebAssemblyII::MO_SYMBOL_EVENT)
+ .add(Cond[1]);
+ } else
+ BuildMI(&MBB, DL, get(WebAssembly::BR_IF)).addMBB(TBB).add(Cond[1]);
} else {
+ assert(!IsBrOnExn && "br_on_exn does not have a reversed condition");
BuildMI(&MBB, DL, get(WebAssembly::BR_UNLESS)).addMBB(TBB).add(Cond[1]);
}
if (!FBB)
@@ -193,7 +217,15 @@ unsigned WebAssemblyInstrInfo::insertBra
bool WebAssemblyInstrInfo::reverseBranchCondition(
SmallVectorImpl<MachineOperand> &Cond) const {
- assert(Cond.size() == 2 && "Expected a flag and a successor block");
+ assert(Cond.size() == 2 && "Expected a flag and a condition expression");
+
+ // br_on_exn's condition cannot be reversed
+ MachineFunction &MF = *Cond[1].getParent()->getParent()->getParent();
+ auto &MRI = MF.getRegInfo();
+ if (Cond[1].isReg() &&
+ MRI.getRegClass(Cond[1].getReg()) == &WebAssembly::EXCEPT_REFRegClass)
+ return true;
+
Cond.front() = MachineOperand::CreateImm(!Cond.front().getImm());
return false;
}
Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.td?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.td (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.td Tue Jan 29 19:21:57 2019
@@ -66,7 +66,7 @@ def SDT_WebAssemblyArgument : SDTypeProf
def SDT_WebAssemblyReturn : SDTypeProfile<0, -1, []>;
def SDT_WebAssemblyWrapper : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>,
SDTCisPtrTy<0>]>;
-def SDT_WebAssemblyThrow : SDTypeProfile<0, 2, [SDTCisPtrTy<0>]>;
+def SDT_WebAssemblyThrow : SDTypeProfile<0, -1, [SDTCisPtrTy<0>]>;
//===----------------------------------------------------------------------===//
// WebAssembly-specific DAG Nodes.
@@ -94,7 +94,7 @@ def WebAssemblyreturn : SDNode<"WebAss
def WebAssemblywrapper : SDNode<"WebAssemblyISD::Wrapper",
SDT_WebAssemblyWrapper>;
def WebAssemblythrow : SDNode<"WebAssemblyISD::THROW", SDT_WebAssemblyThrow,
- [SDNPHasChain]>;
+ [SDNPHasChain, SDNPVariadic]>;
//===----------------------------------------------------------------------===//
// WebAssembly-specific Operands.
Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp Tue Jan 29 19:21:57 2019
@@ -15,6 +15,7 @@
#include "WebAssembly.h"
#include "WebAssemblySubtarget.h"
#include "WebAssemblyUtilities.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/WasmEHFuncInfo.h"
#include "llvm/MC/MCAsmInfo.h"
@@ -25,19 +26,14 @@ using namespace llvm;
namespace {
class WebAssemblyLateEHPrepare final : public MachineFunctionPass {
StringRef getPassName() const override {
- return "WebAssembly Prepare Exception";
+ return "WebAssembly Late Prepare Exception";
}
bool runOnMachineFunction(MachineFunction &MF) override;
-
bool removeUnnecessaryUnreachables(MachineFunction &MF);
bool replaceFuncletReturns(MachineFunction &MF);
- bool hoistCatches(MachineFunction &MF);
- bool addCatchAlls(MachineFunction &MF);
- bool addRethrows(MachineFunction &MF);
- bool ensureSingleBBTermPads(MachineFunction &MF);
- bool mergeTerminatePads(MachineFunction &MF);
- bool addCatchAllTerminatePads(MachineFunction &MF);
+ bool addCatches(MachineFunction &MF);
+ bool addExceptionExtraction(MachineFunction &MF);
public:
static char ID; // Pass identification, replacement for typeid
@@ -112,15 +108,11 @@ bool WebAssemblyLateEHPrepare::runOnMach
bool Changed = false;
Changed |= removeUnnecessaryUnreachables(MF);
- Changed |= addRethrows(MF);
if (!MF.getFunction().hasPersonalityFn())
return Changed;
Changed |= replaceFuncletReturns(MF);
- Changed |= hoistCatches(MF);
- Changed |= addCatchAlls(MF);
- Changed |= ensureSingleBBTermPads(MF);
- Changed |= mergeTerminatePads(MF);
- Changed |= addCatchAllTerminatePads(MF);
+ Changed |= addCatches(MF);
+ Changed |= addExceptionExtraction(MF);
return Changed;
}
@@ -129,7 +121,8 @@ bool WebAssemblyLateEHPrepare::removeUnn
bool Changed = false;
for (auto &MBB : MF) {
for (auto &MI : MBB) {
- if (!WebAssembly::isThrow(MI))
+ if (MI.getOpcode() != WebAssembly::THROW &&
+ MI.getOpcode() != WebAssembly::RETHROW)
continue;
Changed = true;
@@ -152,7 +145,6 @@ bool WebAssemblyLateEHPrepare::removeUnn
bool WebAssemblyLateEHPrepare::replaceFuncletReturns(MachineFunction &MF) {
bool Changed = false;
const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
- auto *EHInfo = MF.getWasmEHFuncInfo();
for (auto &MBB : MF) {
auto Pos = MBB.getFirstTerminator();
@@ -173,13 +165,7 @@ bool WebAssemblyLateEHPrepare::replaceFu
}
case WebAssembly::CLEANUPRET: {
// Replace a cleanupret with a rethrow
- if (EHInfo->hasThrowUnwindDest(&MBB))
- BuildMI(MBB, TI, TI->getDebugLoc(), TII.get(WebAssembly::RETHROW))
- .addMBB(EHInfo->getThrowUnwindDest(&MBB));
- else
- BuildMI(MBB, TI, TI->getDebugLoc(),
- TII.get(WebAssembly::RETHROW_TO_CALLER));
-
+ BuildMI(MBB, TI, TI->getDebugLoc(), TII.get(WebAssembly::RETHROW));
TI->eraseFromParent();
Changed = true;
break;
@@ -189,233 +175,158 @@ bool WebAssemblyLateEHPrepare::replaceFu
return Changed;
}
-// Hoist catch instructions to the beginning of their matching EH pad BBs in
-// case,
-// (1) catch instruction is not the first instruction in EH pad.
-// ehpad:
-// some_other_instruction
-// ...
-// %exn = catch 0
-// (2) catch instruction is in a non-EH pad BB. For example,
-// ehpad:
-// br bb0
-// bb0:
-// %exn = catch 0
-bool WebAssemblyLateEHPrepare::hoistCatches(MachineFunction &MF) {
- bool Changed = false;
- SmallVector<MachineInstr *, 16> Catches;
- for (auto &MBB : MF)
- for (auto &MI : MBB)
- if (WebAssembly::isCatch(MI))
- Catches.push_back(&MI);
-
- for (auto *Catch : Catches) {
- MachineBasicBlock *EHPad = getMatchingEHPad(Catch);
- assert(EHPad && "No matching EH pad for catch");
- if (EHPad->begin() == Catch)
- continue;
- Changed = true;
- EHPad->insert(EHPad->begin(), Catch->removeFromParent());
- }
- return Changed;
-}
-
-// Add catch_all to beginning of cleanup pads.
-bool WebAssemblyLateEHPrepare::addCatchAlls(MachineFunction &MF) {
+// Add catch instruction to beginning of catchpads and cleanuppads.
+bool WebAssemblyLateEHPrepare::addCatches(MachineFunction &MF) {
bool Changed = false;
const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
-
+ MachineRegisterInfo &MRI = MF.getRegInfo();
for (auto &MBB : MF) {
- if (!MBB.isEHPad())
- continue;
- // This runs after hoistCatches(), so we assume that if there is a catch,
- // that should be the first instruction in an EH pad.
- if (!WebAssembly::isCatch(*MBB.begin())) {
+ if (MBB.isEHPad()) {
Changed = true;
+ unsigned DstReg =
+ MRI.createVirtualRegister(&WebAssembly::EXCEPT_REFRegClass);
BuildMI(MBB, MBB.begin(), MBB.begin()->getDebugLoc(),
- TII.get(WebAssembly::CATCH_ALL));
+ TII.get(WebAssembly::CATCH), DstReg);
}
}
return Changed;
}
-// Add a 'rethrow' instruction after __cxa_rethrow() call
-bool WebAssemblyLateEHPrepare::addRethrows(MachineFunction &MF) {
- bool Changed = false;
+// Wasm uses 'br_on_exn' instruction to check the tag of an exception. It takes
+// except_ref type object returned by 'catch', and branches to the destination
+// if it matches a given tag. We currently use __cpp_exception symbol to
+// represent the tag for all C++ exceptions.
+//
+// block $l (result i32)
+// ...
+// ;; except_ref $e is on the stack at this point
+// br_on_exn $l $e ;; branch to $l with $e's arguments
+// ...
+// end
+// ;; Here we expect the extracted values are on top of the wasm value stack
+// ... Handle exception using values ...
+//
+// br_on_exn takes an except_ref object and branches if it matches the given
+// tag. There can be multiple br_on_exn instructions if we want to match for
+// another tag, but for now we only test for __cpp_exception tag, and if it does
+// not match, i.e., it is a foreign exception, we rethrow it.
+//
+// In the destination BB that's the target of br_on_exn, extracted exception
+// values (in C++'s case a single i32, which represents an exception pointer)
+// are placed on top of the wasm stack. Because we can't model wasm stack in
+// LLVM instruction, we use 'extract_exception' pseudo instruction to retrieve
+// it. The pseudo instruction will be deleted later.
+bool WebAssemblyLateEHPrepare::addExceptionExtraction(MachineFunction &MF) {
const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
auto *EHInfo = MF.getWasmEHFuncInfo();
-
- for (auto &MBB : MF)
+ SmallVector<MachineInstr *, 16> ExtractInstrs;
+ for (auto &MBB : MF) {
for (auto &MI : MBB) {
- // Check if it is a call to __cxa_rethrow()
- if (!MI.isCall())
- continue;
- MachineOperand &CalleeOp = MI.getOperand(0);
- if (!CalleeOp.isGlobal() ||
- CalleeOp.getGlobal()->getName() != WebAssembly::CxaRethrowFn)
- continue;
-
- // Now we have __cxa_rethrow() call
- Changed = true;
- auto InsertPt = std::next(MachineBasicBlock::iterator(MI));
- while (InsertPt != MBB.end() && InsertPt->isLabel()) // Skip EH_LABELs
- ++InsertPt;
- MachineInstr *Rethrow = nullptr;
- if (EHInfo->hasThrowUnwindDest(&MBB))
- Rethrow = BuildMI(MBB, InsertPt, MI.getDebugLoc(),
- TII.get(WebAssembly::RETHROW))
- .addMBB(EHInfo->getThrowUnwindDest(&MBB));
- else
- Rethrow = BuildMI(MBB, InsertPt, MI.getDebugLoc(),
- TII.get(WebAssembly::RETHROW_TO_CALLER));
-
- // Because __cxa_rethrow does not return, the instruction after the
- // rethrow should be an unreachable or a branch to another BB that should
- // eventually lead to an unreachable. Delete it because rethrow itself is
- // a terminator, and also delete non-EH pad successors if any.
- MBB.erase(std::next(MachineBasicBlock::iterator(Rethrow)), MBB.end());
- SmallVector<MachineBasicBlock *, 8> NonPadSuccessors;
- for (auto *Succ : MBB.successors())
- if (!Succ->isEHPad())
- NonPadSuccessors.push_back(Succ);
- for (auto *Succ : NonPadSuccessors)
- MBB.removeSuccessor(Succ);
- eraseDeadBBsAndChildren(NonPadSuccessors);
+ if (MI.getOpcode() == WebAssembly::EXTRACT_EXCEPTION_I32) {
+ if (MI.getOperand(0).isDead())
+ MI.eraseFromParent();
+ else
+ ExtractInstrs.push_back(&MI);
+ }
}
- return Changed;
-}
-
-// Terminate pads are an single-BB EH pad in the form of
-// termpad:
-// %exn = catch 0
-// call @__clang_call_terminate(%exn)
-// unreachable
-// (There can be local.set and local.gets before the call if we didn't run
-// RegStackify)
-// But code transformations can change or add more control flow, so the call to
-// __clang_call_terminate() function may not be in the original EH pad anymore.
-// This ensures every terminate pad is a single BB in the form illustrated
-// above.
-bool WebAssemblyLateEHPrepare::ensureSingleBBTermPads(MachineFunction &MF) {
- const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
+ }
+ if (ExtractInstrs.empty())
+ return false;
- // Find calls to __clang_call_terminate()
- SmallVector<MachineInstr *, 8> ClangCallTerminateCalls;
- for (auto &MBB : MF)
- for (auto &MI : MBB)
+ // Find terminate pads.
+ SmallSet<MachineBasicBlock *, 8> TerminatePads;
+ for (auto &MBB : MF) {
+ for (auto &MI : MBB) {
if (MI.isCall()) {
const MachineOperand &CalleeOp = MI.getOperand(0);
if (CalleeOp.isGlobal() && CalleeOp.getGlobal()->getName() ==
WebAssembly::ClangCallTerminateFn)
- ClangCallTerminateCalls.push_back(&MI);
+ TerminatePads.insert(getMatchingEHPad(&MI));
}
-
- bool Changed = false;
- for (auto *Call : ClangCallTerminateCalls) {
- MachineBasicBlock *EHPad = getMatchingEHPad(Call);
- assert(EHPad && "No matching EH pad for catch");
-
- // If it is already the form we want, skip it
- if (Call->getParent() == EHPad &&
- Call->getNextNode()->getOpcode() == WebAssembly::UNREACHABLE)
- continue;
-
- // In case the __clang_call_terminate() call is not in its matching EH pad,
- // move the call to the end of EH pad and add an unreachable instruction
- // after that. Delete all successors and their children if any, because here
- // the program terminates.
- Changed = true;
- MachineInstr *Catch = &*EHPad->begin();
- // This runs after hoistCatches(), so catch instruction should be at the top
- assert(WebAssembly::isCatch(*Catch));
- // Takes the result register of the catch instruction as argument. There may
- // have been some other local.set/local.gets in between, but at this point
- // we don't care.
- Call->getOperand(1).setReg(Catch->getOperand(0).getReg());
- auto InsertPos = std::next(MachineBasicBlock::iterator(Catch));
- EHPad->insert(InsertPos, Call->removeFromParent());
- BuildMI(*EHPad, InsertPos, Call->getDebugLoc(),
- TII.get(WebAssembly::UNREACHABLE));
- EHPad->erase(InsertPos, EHPad->end());
- SmallVector<MachineBasicBlock *, 8> Succs(EHPad->succ_begin(),
- EHPad->succ_end());
- for (auto *Succ : Succs)
- EHPad->removeSuccessor(Succ);
- eraseDeadBBsAndChildren(Succs);
+ }
}
- return Changed;
-}
-// In case there are multiple terminate pads, merge them into one for code size.
-// This runs after ensureSingleBBTermPads() and assumes every terminate pad is a
-// single BB.
-// In principle this violates EH scope relationship because it can merge
-// multiple inner EH scopes, each of which is in different outer EH scope. But
-// getEHScopeMembership() function will not be called after this, so it is fine.
-bool WebAssemblyLateEHPrepare::mergeTerminatePads(MachineFunction &MF) {
- SmallVector<MachineBasicBlock *, 8> TermPads;
- for (auto &MBB : MF)
- if (WebAssembly::isCatchTerminatePad(MBB))
- TermPads.push_back(&MBB);
- if (TermPads.empty())
- return false;
+ for (auto *Extract : ExtractInstrs) {
+ MachineBasicBlock *EHPad = getMatchingEHPad(Extract);
+ assert(EHPad && "No matching EH pad for extract_exception");
+ MachineInstr *Catch = &*EHPad->begin();
+ if (Catch->getNextNode() != Extract)
+ EHPad->insert(Catch->getNextNode(), Extract->removeFromParent());
- MachineBasicBlock *UniqueTermPad = TermPads.front();
- for (auto *TermPad :
- llvm::make_range(std::next(TermPads.begin()), TermPads.end())) {
- SmallVector<MachineBasicBlock *, 2> Preds(TermPad->pred_begin(),
- TermPad->pred_end());
- for (auto *Pred : Preds)
- Pred->replaceSuccessor(TermPad, UniqueTermPad);
- TermPad->eraseFromParent();
+ // - Before:
+ // ehpad:
+ // %exnref:except_ref = catch
+ // %exn:i32 = extract_exception
+ // ... use exn ...
+ //
+ // - After:
+ // ehpad:
+ // %exnref:except_ref = catch
+ // br_on_exn %thenbb, $__cpp_exception, %exnref
+ // br %elsebb
+ // elsebb:
+ // rethrow
+ // thenbb:
+ // %exn:i32 = extract_exception
+ // ... use exn ...
+ unsigned ExnRefReg = Catch->getOperand(0).getReg();
+ auto *ThenMBB = MF.CreateMachineBasicBlock();
+ auto *ElseMBB = MF.CreateMachineBasicBlock();
+ MF.insert(std::next(MachineFunction::iterator(EHPad)), ElseMBB);
+ MF.insert(std::next(MachineFunction::iterator(ElseMBB)), ThenMBB);
+ ThenMBB->splice(ThenMBB->end(), EHPad, Extract, EHPad->end());
+ ThenMBB->transferSuccessors(EHPad);
+ EHPad->addSuccessor(ThenMBB);
+ EHPad->addSuccessor(ElseMBB);
+
+ DebugLoc DL = Extract->getDebugLoc();
+ const char *CPPExnSymbol = MF.createExternalSymbolName("__cpp_exception");
+ BuildMI(EHPad, DL, TII.get(WebAssembly::BR_ON_EXN))
+ .addMBB(ThenMBB)
+ .addExternalSymbol(CPPExnSymbol, WebAssemblyII::MO_SYMBOL_EVENT)
+ .addReg(ExnRefReg);
+ BuildMI(EHPad, DL, TII.get(WebAssembly::BR)).addMBB(ElseMBB);
+
+ // When this is a terminate pad with __clang_call_terminate() call, we don't
+ // rethrow it anymore and call __clang_call_terminate() with a nullptr
+ // argument, which will call std::terminate().
+ //
+ // - Before:
+ // ehpad:
+ // %exnref:except_ref = catch
+ // %exn:i32 = extract_exception
+ // call @__clang_call_terminate(%exn)
+ // unreachable
+ //
+ // - After:
+ // ehpad:
+ // %exnref:except_ref = catch
+ // br_on_exn %thenbb, $__cpp_exception, %exnref
+ // br %elsebb
+ // elsebb:
+ // call @__clang_call_terminate(0)
+ // unreachable
+ // thenbb:
+ // %exn:i32 = extract_exception
+ // call @__clang_call_terminate(%exn)
+ // unreachable
+ if (TerminatePads.count(EHPad)) {
+ Function *ClangCallTerminateFn =
+ MF.getFunction().getParent()->getFunction(
+ WebAssembly::ClangCallTerminateFn);
+ assert(ClangCallTerminateFn &&
+ "There is no __clang_call_terminate() function");
+ BuildMI(ElseMBB, DL, TII.get(WebAssembly::CALL_VOID))
+ .addGlobalAddress(ClangCallTerminateFn)
+ .addImm(0);
+ BuildMI(ElseMBB, DL, TII.get(WebAssembly::UNREACHABLE));
+
+ } else {
+ BuildMI(ElseMBB, DL, TII.get(WebAssembly::RETHROW));
+ if (EHInfo->hasEHPadUnwindDest(EHPad))
+ EHInfo->setThrowUnwindDest(ElseMBB, EHInfo->getEHPadUnwindDest(EHPad));
+ }
}
- return true;
-}
-
-// Terminate pads are cleanup pads, so they should start with a 'catch_all'
-// instruction. But in the Itanium model, when we have a C++ exception object,
-// we pass them to __clang_call_terminate function, which calls __cxa_end_catch
-// with the passed exception pointer and then std::terminate. This is the reason
-// that terminate pads are generated with not a catch_all but a catch
-// instruction in clang and earlier llvm passes. Here we append a terminate pad
-// with a catch_all after each existing terminate pad so we can also catch
-// foreign exceptions. For every terminate pad:
-// %exn = catch 0
-// call @__clang_call_terminate(%exn)
-// unreachable
-// We append this BB right after that:
-// catch_all
-// call @std::terminate()
-// unreachable
-bool WebAssemblyLateEHPrepare::addCatchAllTerminatePads(MachineFunction &MF) {
- const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
- SmallVector<MachineBasicBlock *, 8> TermPads;
- for (auto &MBB : MF)
- if (WebAssembly::isCatchTerminatePad(MBB))
- TermPads.push_back(&MBB);
- if (TermPads.empty())
- return false;
- Function *StdTerminateFn =
- MF.getFunction().getParent()->getFunction(WebAssembly::StdTerminateFn);
- assert(StdTerminateFn && "There is no std::terminate() function");
- for (auto *CatchTermPad : TermPads) {
- DebugLoc DL = CatchTermPad->findDebugLoc(CatchTermPad->begin());
- auto *CatchAllTermPad = MF.CreateMachineBasicBlock();
- MF.insert(std::next(MachineFunction::iterator(CatchTermPad)),
- CatchAllTermPad);
- CatchAllTermPad->setIsEHPad();
- BuildMI(CatchAllTermPad, DL, TII.get(WebAssembly::CATCH_ALL));
- BuildMI(CatchAllTermPad, DL, TII.get(WebAssembly::CALL_VOID))
- .addGlobalAddress(StdTerminateFn);
- BuildMI(CatchAllTermPad, DL, TII.get(WebAssembly::UNREACHABLE));
-
- // Actually this CatchAllTermPad (new terminate pad with a catch_all) is not
- // a successor of an existing terminate pad. CatchAllTermPad should have all
- // predecessors CatchTermPad has instead. This is a hack to force
- // CatchAllTermPad be always sorted right after CatchTermPad; the correct
- // predecessor-successor relationships will be restored in CFGStackify pass.
- CatchTermPad->addSuccessor(CatchAllTermPad);
- }
return true;
}
Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp Tue Jan 29 19:21:57 2019
@@ -36,7 +36,7 @@ using namespace llvm;
// This disables the removal of registers when lowering into MC, as required
// by some current tests.
-static cl::opt<bool>
+cl::opt<bool>
WasmKeepRegisters("wasm-keep-registers", cl::Hidden,
cl::desc("WebAssembly: output stack registers in"
" instruction output for test purposes only."),
Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp Tue Jan 29 19:21:57 2019
@@ -317,6 +317,18 @@ static bool IsSafeToMove(const MachineIn
AliasAnalysis &AA, const MachineRegisterInfo &MRI) {
assert(Def->getParent() == Insert->getParent());
+ // 'catch' and 'extract_exception' should be the first instruction of a BB and
+ // cannot move.
+ if (Def->getOpcode() == WebAssembly::CATCH ||
+ Def->getOpcode() == WebAssembly::EXTRACT_EXCEPTION_I32) {
+ const MachineBasicBlock *MBB = Def->getParent();
+ auto NextI = std::next(MachineBasicBlock::const_iterator(Def));
+ for (auto E = MBB->end(); NextI != E && NextI->isDebugInstr(); ++NextI)
+ ;
+ if (NextI != Insert)
+ return false;
+ }
+
// Check for register dependencies.
SmallVector<unsigned, 4> MutableRegisters;
for (const MachineOperand &MO : Def->operands()) {
@@ -819,6 +831,24 @@ bool WebAssemblyRegStackify::runOnMachin
if (WebAssembly::isArgument(*Def))
continue;
+ // Currently catch's return value register cannot be stackified, because
+ // the wasm LLVM backend currently does not support live-in values
+ // entering blocks, which is a part of multi-value proposal.
+ //
+ // Once we support live-in values of wasm blocks, this can be:
+ // catch ; push except_ref value onto stack
+ // block except_ref -> i32
+ // br_on_exn $__cpp_exception ; pop the except_ref value
+ // end_block
+ //
+ // But because we don't support it yet, the catch instruction's dst
+ // register should be assigned to a local to be propagated across
+ // 'block' boundary now.
+ //
+ // TODO Fix this once we support the multi-value proposal.
+ if (Def->getOpcode() == WebAssembly::CATCH)
+ continue;
+
// Decide which strategy to take. Prefer to move a single-use value
// over cloning it, and prefer cloning over introducing a tee.
// For moving, we require the def to be in the same block as the use;
Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp Tue Jan 29 19:21:57 2019
@@ -301,8 +301,10 @@ void WebAssemblyPassConfig::addPreEmitPa
addPass(createWebAssemblyFixIrreducibleControlFlow());
// Do various transformations for exception handling.
+ // Every CFG-changing optimizations should come before this.
addPass(createWebAssemblyLateEHPrepare());
+ // Preparations and optimizations related to register stackification.
if (getOptLevel() != CodeGenOpt::None) {
// LiveIntervals isn't commonly run this late. Re-establish preconditions.
addPass(createWebAssemblyPrepareForLiveIntervals());
Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.cpp Tue Jan 29 19:21:57 2019
@@ -242,50 +242,10 @@ bool WebAssembly::isMarker(const Machine
}
}
-bool WebAssembly::isThrow(const MachineInstr &MI) {
- switch (MI.getOpcode()) {
- case WebAssembly::THROW_I32:
- case WebAssembly::THROW_I32_S:
- case WebAssembly::THROW_I64:
- case WebAssembly::THROW_I64_S:
- return true;
- default:
- return false;
- }
-}
-
-bool WebAssembly::isRethrow(const MachineInstr &MI) {
- switch (MI.getOpcode()) {
- case WebAssembly::RETHROW:
- case WebAssembly::RETHROW_S:
- case WebAssembly::RETHROW_TO_CALLER:
- case WebAssembly::RETHROW_TO_CALLER_S:
- return true;
- default:
- return false;
- }
-}
-
-bool WebAssembly::isCatch(const MachineInstr &MI) {
- switch (MI.getOpcode()) {
- 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:
- return true;
- default:
- return false;
- }
-}
-
bool WebAssembly::mayThrow(const MachineInstr &MI) {
switch (MI.getOpcode()) {
- case WebAssembly::THROW_I32:
- case WebAssembly::THROW_I32_S:
- case WebAssembly::THROW_I64:
- case WebAssembly::THROW_I64_S:
+ case WebAssembly::THROW:
+ case WebAssembly::THROW_S:
case WebAssembly::RETHROW:
case WebAssembly::RETHROW_S:
return true;
@@ -308,41 +268,3 @@ bool WebAssembly::mayThrow(const Machine
return false;
return true;
}
-
-bool WebAssembly::isCatchTerminatePad(const MachineBasicBlock &MBB) {
- if (!MBB.isEHPad())
- return false;
- bool SeenCatch = false;
- for (auto &MI : MBB) {
- if (MI.getOpcode() == WebAssembly::CATCH_I32 ||
- MI.getOpcode() == WebAssembly::CATCH_I64 ||
- MI.getOpcode() == WebAssembly::CATCH_I32_S ||
- MI.getOpcode() == WebAssembly::CATCH_I64_S)
- SeenCatch = true;
- if (SeenCatch && MI.isCall()) {
- const MachineOperand &CalleeOp = MI.getOperand(getCalleeOpNo(MI));
- if (CalleeOp.isGlobal() &&
- CalleeOp.getGlobal()->getName() == ClangCallTerminateFn)
- return true;
- }
- }
- return false;
-}
-
-bool WebAssembly::isCatchAllTerminatePad(const MachineBasicBlock &MBB) {
- if (!MBB.isEHPad())
- return false;
- bool SeenCatchAll = false;
- for (auto &MI : MBB) {
- if (MI.getOpcode() == WebAssembly::CATCH_ALL ||
- MI.getOpcode() == WebAssembly::CATCH_ALL_S)
- SeenCatchAll = true;
- if (SeenCatchAll && MI.isCall()) {
- const MachineOperand &CalleeOp = MI.getOperand(getCalleeOpNo(MI));
- if (CalleeOp.isGlobal() &&
- CalleeOp.getGlobal()->getName() == StdTerminateFn)
- return true;
- }
- }
- return false;
-}
Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.h?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.h (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.h Tue Jan 29 19:21:57 2019
@@ -30,22 +30,12 @@ bool isChild(const MachineInstr &MI, con
bool isCallDirect(const MachineInstr &MI);
bool isCallIndirect(const MachineInstr &MI);
bool isMarker(const MachineInstr &MI);
-bool isThrow(const MachineInstr &MI);
-bool isRethrow(const MachineInstr &MI);
-bool isCatch(const MachineInstr &MI);
bool mayThrow(const MachineInstr &MI);
/// Returns the operand number of a callee, assuming the argument is a call
/// instruction.
unsigned getCalleeOpNo(const MachineInstr &MI);
-/// Returns if the given BB is a single BB terminate pad which starts with a
-/// 'catch' instruction.
-bool isCatchTerminatePad(const MachineBasicBlock &MBB);
-/// Returns if the given BB is a single BB terminate pad which starts with a
-/// 'catch_all' insrtruction.
-bool isCatchAllTerminatePad(const MachineBasicBlock &MBB);
-
// Exception-related function names
extern const char *const ClangCallTerminateFn;
extern const char *const CxaBeginCatchFn;
Removed: llvm/trunk/test/CodeGen/WebAssembly/annotations.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/annotations.mir?rev=352597&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/annotations.mir (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/annotations.mir (removed)
@@ -1,94 +0,0 @@
-# RUN: llc -mtriple=wasm32-unknown-unknown -start-after xray-instrumentation -wasm-keep-registers %s -o - | FileCheck %s
-
----
-# Tests if block/loop/try/catch/end instructions are correctly printed with
-# their annotations.
-
-# CHECK: test0:
-# CHECK: block
-# CHECK: try
-# CHECK: br 0 # 0: down to label1
-# CHECK: catch_all # catch0:
-# CHECK: block
-# CHECK: br_if 0, 1 # 0: down to label2
-# CHECK: loop # label3:
-# CHECK: br_if 0, 1 # 0: up to label3
-# CHECK: end_loop
-# CHECK: end_block # label2:
-# CHECK: try
-# CHECK: rethrow 0 # 0: down to catch1
-# CHECK: catch_all # catch1:
-# CHECK: block
-# CHECK: try
-# CHECK: br 0 # 0: down to label6
-# CHECK: catch_all # catch2:
-# CHECK: unreachable
-# CHECK: end_try # label6:
-# CHECK: end_block # label5:
-# CHECK: rethrow 0 # 0: to caller
-# CHECK: end_try # label4:
-# CHECK: end_try # label1:
-# CHECK: end_block # label0:
-
-name: test0
-liveins:
- - { reg: '$arguments', reg: '$value_stack' }
-body: |
- bb.0:
- successors: %bb.7, %bb.1
- BLOCK 64, implicit-def $value_stack, implicit $value_stack
- TRY 64, implicit-def $value_stack, implicit $value_stack
- BR 0, implicit-def $arguments
-
- bb.1 (landing-pad):
- ; predecessors: %bb.0
- successors: %bb.2, %bb.3
-
- CATCH_ALL implicit-def $arguments
- BLOCK 64, implicit-def $value_stack, implicit $value_stack
- BR_IF 0, 1, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack
-
- bb.2:
- ; predecessors: %bb.1, %bb.2
- successors: %bb.2, %bb.3
-
- LOOP 64, implicit-def $value_stack, implicit $value_stack
- BR_IF 0, 1, implicit-def $arguments
-
- bb.3:
- ; predecessors: %bb.1, %bb.2
- successors: %bb.4
-
- END_LOOP implicit-def $value_stack, implicit $value_stack
- END_BLOCK implicit-def $value_stack, implicit $value_stack
- TRY 64, implicit-def $value_stack, implicit $value_stack
- RETHROW 0, implicit-def $arguments
-
- bb.4 (landing-pad):
- ; predecessors: %bb.3
- successors: %bb.6, %bb.5
-
- CATCH_ALL implicit-def $arguments
- BLOCK 64, implicit-def $value_stack, implicit $value_stack
- TRY 64, implicit-def $value_stack, implicit $value_stack
- BR 0, implicit-def $arguments
-
- bb.5 (landing-pad):
- ; predecessors: %bb.4
- CATCH_ALL implicit-def $arguments
- UNREACHABLE implicit-def dead $arguments
-
- bb.6:
- ; predecessors: %bb.4
- END_TRY implicit-def $value_stack, implicit $value_stack
- END_BLOCK implicit-def $value_stack, implicit $value_stack
- RETHROW 0, implicit-def $arguments
-
- bb.7:
- ; predecessors: %bb.0
- END_TRY implicit-def $value_stack, implicit $value_stack
- END_TRY implicit-def $value_stack, implicit $value_stack
- END_BLOCK implicit-def $value_stack, implicit $value_stack
- FALLTHROUGH_RETURN_VOID implicit-def dead $arguments
- END_FUNCTION implicit-def $value_stack, implicit $value_stack
-...
Modified: llvm/trunk/test/CodeGen/WebAssembly/cfg-stackify-eh.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/cfg-stackify-eh.ll?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/cfg-stackify-eh.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/cfg-stackify-eh.ll Tue Jan 29 19:21:57 2019
@@ -7,21 +7,25 @@ target triple = "wasm32-unknown-unknown"
@_ZTId = external constant i8*
; Simple test case with two catch clauses
+; void test0() {
+; try {
+; foo();
+; } catch (int n) {
+; bar();
+; } catch (double d) {
+; }
+; }
; CHECK-LABEL: test0
+; CHECK: try
; CHECK: call foo at FUNCTION
-; CHECK: .LBB0_1:
-; CHECK: i32.catch
+; CHECK: catch $[[EXCEPT_REF:[0-9]+]]=
+; CHECK: block i32
+; CHECK: br_on_exn 0, __cpp_exception at EVENT, $[[EXCEPT_REF]]
+; CHECK: rethrow
+; CHECK: end_block
; CHECK: i32.call $drop=, _Unwind_CallPersonality at FUNCTION
-; CHECK: i32.call $drop=, __cxa_begin_catch at FUNCTION
-; CHECK: call bar at FUNCTION
-; CHECK: call __cxa_end_catch at FUNCTION
-; CHECK: .LBB0_3:
-; CHECK: i32.call $drop=, __cxa_begin_catch at FUNCTION
-; CHECK: call __cxa_end_catch at FUNCTION
-; CHECK: .LBB0_5:
-; CHECK: call __cxa_rethrow at FUNCTION
-; CHECK: .LBB0_6:
+; CHECK: end_try
; CHECK: return
define void @test0() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
entry:
@@ -68,39 +72,45 @@ try.cont:
}
; Nested try-catches within a catch
+; void test1() {
+; try {
+; foo();
+; } catch (int n) {
+; try {
+; foo();
+; } catch (int n) {
+; foo();
+; }
+; }
+; }
; CHECK-LABEL: test1
+; CHECK: try
; CHECK: call foo at FUNCTION
-; CHECK: .LBB1_1:
-; CHECK: i32.catch $0=, 0
-; CHECK: i32.call $drop=, _Unwind_CallPersonality at FUNCTION, $0
-; CHECK: i32.call $drop=, __cxa_begin_catch at FUNCTION, $0
-; CHECK: call foo at FUNCTION
-; CHECK: .LBB1_3:
-; CHECK: i32.catch $0=, 0
-; CHECK: i32.call $drop=, _Unwind_CallPersonality at FUNCTION, $0
-; CHECK: i32.call $drop=, __cxa_begin_catch at FUNCTION, $0
+; CHECK: catch
+; CHECK: br_on_exn 0, __cpp_exception at EVENT
+; CHECK: rethrow
+; CHECK: i32.call $drop=, _Unwind_CallPersonality at FUNCTION
+; CHECK: try
; CHECK: call foo at FUNCTION
-; CHECK: .LBB1_5:
-; CHECK: catch_all
-; CHECK: call __cxa_end_catch at FUNCTION
+; CHECK: catch
+; CHECK: br_on_exn 0, __cpp_exception at EVENT
; CHECK: rethrow
-; CHECK: .LBB1_6:
-; CHECK: call __cxa_rethrow at FUNCTION
+; CHECK: i32.call $drop=, _Unwind_CallPersonality at FUNCTION
+; CHECK: try
+; CHECK: i32.call $drop=, __cxa_begin_catch at FUNCTION
+; CHECK: try
+; CHECK: call foo at FUNCTION
+; CHECK: catch $drop=
; CHECK: rethrow
-; CHECK: .LBB1_7:
-; CHECK: call __cxa_end_catch at FUNCTION
-; CHECK: .LBB1_8:
-; CHECK: catch_all
-; CHECK: call __cxa_end_catch at FUNCTION
-; CHECK: .LBB1_9:
-; CHECK: call __cxa_rethrow at FUNCTION
+; CHECK: end_try
+; CHECK: catch $drop=
; CHECK: rethrow
-; CHECK: .LBB1_10:
-; CHECK: call __cxa_end_catch at FUNCTION
-; CHECK: .LBB1_11:
+; CHECK: end_try
+; CHECK: end_try
+; CHECK: end_try
; CHECK: return
-define hidden void @test1() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
+define void @test1() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
entry:
invoke void @foo()
to label %try.cont11 unwind label %catch.dispatch
@@ -175,30 +185,38 @@ unreachable:
}
; Nested loop within a catch clause
+; void test2() {
+; try {
+; foo();
+; } catch (...) {
+; for (int i = 0; i < 50; i++)
+; foo();
+; }
+; }
; CHECK-LABEL: test2
+; CHECK: try
; CHECK: call foo at FUNCTION
-; CHECK: .LBB2_1:
-; CHECK: i32.catch
-; CHECK: i32.call $drop=, __cxa_begin_catch at FUNCTION
-; CHECK: .LBB2_2:
+; CHECK: catch
+; CHECK: br_on_exn 0, __cpp_exception at EVENT
+; CHECK: rethrow
+; CHECK: loop
+; CHECK: try
; CHECK: call foo at FUNCTION
-; CHECK: .LBB2_4:
-; CHECK: catch_all
+; CHECK: catch $drop=
+; CHECK: try
; CHECK: call __cxa_end_catch at FUNCTION
-; CHECK: .LBB2_5:
-; CHECK: i32.catch
-; CHECK: call __clang_call_terminate at FUNCTION
+; CHECK: catch
+; CHECK: br_on_exn 0, __cpp_exception at EVENT
+; CHECK: call __clang_call_terminate at FUNCTION, 0
; CHECK: unreachable
-; CHECK: .LBB2_6:
-; CHECK: catch_all
-; CHECK: call _ZSt9terminatev at FUNCTION
+; CHECK: call __clang_call_terminate at FUNCTION
; CHECK: unreachable
-; CHECK: .LBB2_7:
+; CHECK: end_try
; CHECK: rethrow
-; CHECK: .LBB2_8:
-; CHECK: call __cxa_end_catch at FUNCTION
-; CHECK: .LBB2_10:
+; CHECK: end_try
+; CHECK: end_loop
+; CHECK: end_try
; CHECK: return
define void @test2() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
entry:
Removed: llvm/trunk/test/CodeGen/WebAssembly/cfg-stackify-eh.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/cfg-stackify-eh.mir?rev=352597&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/cfg-stackify-eh.mir (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/cfg-stackify-eh.mir (removed)
@@ -1,322 +0,0 @@
-# RUN: llc -mtriple=wasm32-unknown-unknown -exception-model=wasm -run-pass wasm-cfg-stackify %s -o - | FileCheck %s
-
---- |
- target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
- target triple = "wasm32-unknown-unknown"
-
- @__wasm_lpad_context = external global { i32, i8*, i32 }
-
- declare void @may_throw()
- ; Function Attrs: nounwind
- declare void @dont_throw() #0
- declare i8* @__cxa_begin_catch(i8*)
- declare void @__cxa_end_catch()
- declare void @__cxa_rethrow()
- ; Function Attrs: nounwind
- declare i32 @__gxx_wasm_personality_v0(...)
- declare i32 @_Unwind_CallPersonality(i8*) #0
-
- define void @test0() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
- unreachable
- }
- define void @test1() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
- unreachable
- }
- define void @test2() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
- unreachable
- }
- define void @test3() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
- unreachable
- }
-
- attributes #0 = { nounwind }
-
----
-# Simplest try-catch
-# try {
-# may_throw();
-# } catch (...) {
-# }
-name: test0
-# CHECK-LABEL: name: test0
-liveins:
- - { reg: '$arguments', reg: '$value_stack' }
-body: |
- bb.0:
- successors: %bb.2, %bb.1
-
- CALL_VOID @may_throw, implicit-def dead $arguments, implicit $sp32, implicit $sp64
- BR %bb.2, implicit-def $arguments
- ; CHECK-LABEL: bb.0:
- ; CHECK: TRY
- ; CHECK-NEXT: CALL_VOID @may_throw
-
- bb.1 (landing-pad):
- ; predecessors: %bb.0
- successors: %bb.2
-
- %2:i32 = CATCH_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
- %3:i32 = CALL_I32 @__cxa_begin_catch, %2:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64, implicit-def $value_stack, implicit $value_stack
- DROP_I32 killed %3:i32, implicit-def $arguments
- CALL_VOID @__cxa_end_catch, implicit-def dead $arguments, implicit $sp32, implicit $sp64
-
- bb.2:
- ; predecessors: %bb.0, %bb.1
-
- RETURN_VOID implicit-def dead $arguments
- ; CHECK-LABEL: bb.2:
- ; CHECK-NEXT: END_TRY
- ; CHECK: RETURN_VOID
-...
----
-
-# Nested try-catch inside another catch
-# try {
-# may_throw();
-# } catch (int n) {
-# try {
-# may_throw();
-# } catch (int n) {
-# }
-# }
-name: test1
-# CHECK-LABEL: name: test1
-liveins:
- - { reg: '$arguments', reg: '$value_stack' }
-body: |
- bb.0:
- successors: %bb.9, %bb.1
-
- CALL_VOID @may_throw, implicit-def dead $arguments, implicit $sp32, implicit $sp64
- BR %bb.9, implicit-def $arguments
- ; CHECK-LABEL: bb.0:
- ; CHECK: TRY
- ; CHECK-NEXT: CALL_VOID @may_throw
-
- bb.1 (landing-pad):
- ; predecessors: %bb.0
- successors: %bb.2, %bb.7
-
- %30:i32 = CATCH_I32 0, implicit-def dead $arguments
- LOCAL_SET_I32 0, %30:i32, implicit-def $arguments
- %16:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
- %27:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
- STORE_I32 2, @__wasm_lpad_context + 4, %16:i32, %27:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack :: (store 4 into `i8** getelementptr inbounds ({ i32, i8*, i32 }, { i32, i8*, i32 }* @__wasm_lpad_context, i32 0, i32 1)`)
- %26:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
- %25:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
- STORE_I32 2, @__wasm_lpad_context, %26:i32, %25:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack :: (store 4 into `i32* getelementptr inbounds ({ i32, i8*, i32 }, { i32, i8*, i32 }* @__wasm_lpad_context, i32 0, i32 0)`)
- %32:i32 = LOCAL_GET_I32 0, implicit-def $arguments
- %31:i32 = CALL_I32 @_Unwind_CallPersonality, %32:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64
- DROP_I32 killed %31:i32, implicit-def $arguments
- %24:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
- %17:i32 = LOAD_I32 2, @__wasm_lpad_context + 8, %24:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack :: (dereferenceable load 4 from `i32* getelementptr inbounds ({ i32, i8*, i32 }, { i32, i8*, i32 }* @__wasm_lpad_context, i32 0, i32 2)`)
- %18:i32 = CONST_I32 1, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
- %19:i32 = NE_I32 %17:i32, %18:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
- BR_IF %bb.7, %19:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack
-
- bb.2:
- ; predecessors: %bb.1
- successors: %bb.8, %bb.3, %bb.6
-
- %34:i32 = LOCAL_GET_I32 0, implicit-def $arguments
- %33:i32 = CALL_I32 @__cxa_begin_catch, %34:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64
- DROP_I32 killed %33:i32, implicit-def $arguments
- CALL_VOID @may_throw, implicit-def dead $arguments, implicit $sp32, implicit $sp64
- BR %bb.8, implicit-def $arguments
- ; CHECK-LABEL: bb.2:
- ; CHECK: DROP_I32
- ; CHECK-NEXT: TRY
- ; CHECK-NEXT: TRY
- ; CHECK-NEXT: CALL_VOID @may_throw
-
- bb.3 (landing-pad):
- ; predecessors: %bb.2
- successors: %bb.4, %bb.5
-
- %35:i32 = CATCH_I32 0, implicit-def dead $arguments
- LOCAL_SET_I32 0, %35:i32, implicit-def $arguments
- %21:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
- %20:i32 = CONST_I32 1, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
- STORE_I32 2, @__wasm_lpad_context, %21:i32, %20:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack :: (store 4 into `i32* getelementptr inbounds ({ i32, i8*, i32 }, { i32, i8*, i32 }* @__wasm_lpad_context, i32 0, i32 0)`)
- %37:i32 = LOCAL_GET_I32 0, implicit-def $arguments
- %36:i32 = CALL_I32 @_Unwind_CallPersonality, %37:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64
- DROP_I32 killed %36:i32, implicit-def $arguments
- %29:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
- %22:i32 = LOAD_I32 2, @__wasm_lpad_context + 8, %29:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack :: (dereferenceable load 4 from `i32* getelementptr inbounds ({ i32, i8*, i32 }, { i32, i8*, i32 }* @__wasm_lpad_context, i32 0, i32 2)`)
- %28:i32 = CONST_I32 1, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
- %23:i32 = NE_I32 %22:i32, %28:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
- BR_IF %bb.5, %23:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack
-
- bb.4:
- ; predecessors: %bb.3
- successors: %bb.8
-
- %39:i32 = LOCAL_GET_I32 0, implicit-def $arguments
- %38:i32 = CALL_I32 @__cxa_begin_catch, %39:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64
- DROP_I32 killed %38:i32, implicit-def $arguments
- CALL_VOID @__cxa_end_catch, implicit-def dead $arguments, implicit $sp32, implicit $sp64
- BR %bb.8, implicit-def $arguments
-
- bb.5:
- ; predecessors: %bb.3
- successors: %bb.6
-
- CALL_VOID @__cxa_rethrow, implicit-def dead $arguments, implicit $sp32, implicit $sp64
- RETHROW %bb.6, implicit-def $arguments
-
- bb.6 (landing-pad):
- ; predecessors: %bb.2, %bb.5
-
- CATCH_ALL implicit-def $arguments
- CALL_VOID @__cxa_end_catch, implicit-def dead $arguments, implicit $sp32, implicit $sp64
- RETHROW_TO_CALLER implicit-def $arguments
- ; CHECK-LABEL: bb.6 (landing-pad):
- ; CHECK-NEXT: END_TRY
-
- bb.7:
- ; predecessors: %bb.1
-
- CALL_VOID @__cxa_rethrow, implicit-def dead $arguments, implicit $sp32, implicit $sp64
- RETHROW_TO_CALLER implicit-def $arguments
- ; CHECK-LABEL: bb.7:
- ; CHECK-NEXT: END_TRY
- ; CHECK: RETHROW 0
-
- bb.8:
- ; predecessors: %bb.2, %bb.4
- successors: %bb.9
-
- CALL_VOID @__cxa_end_catch, implicit-def dead $arguments, implicit $sp32, implicit $sp64
-
- bb.9:
- ; predecessors: %bb.0, %bb.8
-
- RETURN_VOID implicit-def dead $arguments
- ; CHECK-LABEL: bb.9:
- ; CHECK-NEXT: END_TRY
-...
----
-
-# A loop within a try.
-# try {
-# for (int i = 0; i < n; ++i)
-# may_throw();
-# } catch (...) {
-# }
-name: test2
-# CHECK-LABEL: name: test2
-liveins:
- - { reg: '$arguments', reg: '$value_stack' }
-body: |
- bb.0:
- successors: %bb.1, %bb.4
-
- %18:i32 = CONST_I32 0, implicit-def dead $arguments
- LOCAL_SET_I32 1, %18:i32, implicit-def $arguments
- %14:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
- %19:i32 = LOCAL_GET_I32 0, implicit-def $arguments
- %9:i32 = GE_S_I32 %14:i32, %19:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
- BR_IF %bb.4, %9:i32, implicit-def $arguments
-
- bb.1:
- ; predecessors: %bb.0, %bb.3
- successors: %bb.3, %bb.2
-
- CALL_VOID @may_throw, implicit-def dead $arguments, implicit $sp32, implicit $sp64
- BR %bb.3, implicit-def $arguments
- ; CHECK-LABEL: bb.1:
- ; CHECK: LOOP
- ; CHECK: TRY
- ; CHECK-NEXT: CALL_VOID @may_throw
-
- bb.2 (landing-pad):
- ; predecessors: %bb.1
- successors: %bb.4
-
- %11:i32 = CATCH_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
- %22:i32 = CALL_I32 @__cxa_begin_catch, %11:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64, implicit-def $value_stack, implicit $value_stack
- DROP_I32 killed %22:i32, implicit-def $arguments
- CALL_VOID @__cxa_end_catch, implicit-def dead $arguments, implicit $sp32, implicit $sp64
- BR %bb.4, implicit-def $arguments
-
- bb.3:
- ; predecessors: %bb.1
- successors: %bb.1, %bb.4
-
- %20:i32 = LOCAL_GET_I32 1, implicit-def $arguments
- %17:i32 = CONST_I32 1, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
- %16:i32 = ADD_I32 %20:i32, %17:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
- %15:i32 = LOCAL_TEE_I32 1, %16:i32, implicit-def $arguments
- %21:i32 = LOCAL_GET_I32 0, implicit-def $arguments
- %10:i32 = GE_S_I32 %15:i32, %21:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
- BR_UNLESS %bb.1, %10:i32, implicit-def $arguments
- ; CHECK-LABEL: bb.3:
- ; CHECK: END_TRY
-
- bb.4:
- ; predecessors: %bb.2, %bb.0, %bb.3
-
- RETURN_VOID implicit-def dead $arguments
-...
----
-
-# A loop within a catch
-# try {
-# may_throw();
-# } catch (...) {
-# for (int i = 0; i < n; ++i)
-# dont_throw();
-# }
-name: test3
-# CHECK-LABEL: name: test3
-liveins:
- - { reg: '$arguments', reg: '$value_stack' }
-body: |
- bb.0:
- successors: %bb.4, %bb.1
-
- CALL_VOID @may_throw, implicit-def dead $arguments, implicit $sp32, implicit $sp64
- BR %bb.4, implicit-def $arguments
- ; CHECK-LABEL: bb.0:
- ; CHECK: TRY
- ; CHECK-NEXT: CALL_VOID @may_throw
-
- bb.1 (landing-pad):
- ; predecessors: %bb.0
- successors: %bb.2, %bb.3
-
- %9:i32 = CATCH_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
- %18:i32 = CALL_I32 @__cxa_begin_catch, %9:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64, implicit-def $value_stack, implicit $value_stack
- DROP_I32 killed %18:i32, implicit-def $arguments
- %19:i32 = CONST_I32 0, implicit-def dead $arguments
- LOCAL_SET_I32 1, %19:i32, implicit-def $arguments
- %14:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
- %20:i32 = LOCAL_GET_I32 0, implicit-def $arguments
- %10:i32 = GE_S_I32 %14:i32, %20:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
- BR_IF %bb.3, %10:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack
-
- bb.2:
- ; predecessors: %bb.1, %bb.2
- successors: %bb.2, %bb.3
-
- CALL_VOID @dont_throw, implicit-def dead $arguments, implicit $sp32, implicit $sp64
- %21:i32 = LOCAL_GET_I32 1, implicit-def $arguments
- %17:i32 = CONST_I32 1, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
- %16:i32 = ADD_I32 %21:i32, %17:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
- %15:i32 = LOCAL_TEE_I32 1, %16:i32, implicit-def $arguments
- %22:i32 = LOCAL_GET_I32 0, implicit-def $arguments
- %11:i32 = GE_S_I32 %15:i32, %22:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
- BR_UNLESS %bb.2, %11:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack
-
- bb.3:
- ; predecessors: %bb.1, %bb.2
- successors: %bb.4
-
- CALL_VOID @__cxa_end_catch, implicit-def dead $arguments, implicit $sp32, implicit $sp64
-
- bb.4:
- ; predecessors: %bb.0, %bb.3
-
- RETURN_VOID implicit-def dead $arguments
- ; CHECK-LABEL: bb.4:
- ; CHECK: END_TRY
Modified: llvm/trunk/test/CodeGen/WebAssembly/exception.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/exception.ll?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/exception.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/exception.ll Tue Jan 29 19:21:57 2019
@@ -1,5 +1,5 @@
; RUN: not llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -exception-model=wasm
-; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -exception-model=wasm -mattr=+exception-handling -verify-machineinstrs | FileCheck -allow-deprecated-dag-overlap %s
+; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -exception-model=wasm -mattr=+exception-handling -verify-machineinstrs | FileCheck -allow-deprecated-dag-overlap %s
; RUN: llc < %s -disable-wasm-fallthrough-return-opt -wasm-keep-registers -exception-model=wasm -mattr=+exception-handling
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
@@ -9,30 +9,39 @@ target triple = "wasm32-unknown-unknown"
@_ZTIi = external constant i8*
-declare void @llvm.wasm.throw(i32, i8*)
-
; CHECK-LABEL: test_throw:
-; CHECK: local.get $push0=, 0
-; CHECK-NEXT: throw __cpp_exception at EVENT, $pop0
+; CHECK: throw __cpp_exception at EVENT, $0
; CHECK-NOT: unreachable
define void @test_throw(i8* %p) {
call void @llvm.wasm.throw(i32 0, i8* %p)
ret void
}
+; CHECK-LABEL: test_rethrow:
+; CHECK: rethrow
+; CHECK-NOT: unreachable
+define void @test_rethrow(i8* %p) {
+ call void @llvm.wasm.rethrow()
+ ret void
+}
+
; CHECK-LABEL: test_catch_rethrow:
-; CHECK: global.get $push{{.+}}=, __stack_pointer at GLOBAL
+; CHECK: global.get ${{.+}}=, __stack_pointer at GLOBAL
; CHECK: try
; CHECK: call foo at FUNCTION
-; CHECK: i32.catch $push{{.+}}=, 0
+; CHECK: catch $[[EXCEPT_REF:[0-9]+]]=
+; CHECK: block i32
+; CHECK: br_on_exn 0, __cpp_exception at EVENT, $[[EXCEPT_REF]]
+; CHECK: rethrow
+; CHECK: end_block
+; CHECK: extract_exception $[[EXN:[0-9]+]]=
; CHECK: global.set __stack_pointer at GLOBAL
; CHECK-DAG: i32.store __wasm_lpad_context
; CHECK-DAG: i32.store __wasm_lpad_context+4
-; CHECK: i32.call $push{{.+}}=, _Unwind_CallPersonality at FUNCTION
-; CHECK: i32.call $push{{.+}}=, __cxa_begin_catch at FUNCTION
+; CHECK: i32.call $drop=, _Unwind_CallPersonality at FUNCTION, $[[EXN]]
+; CHECK: i32.call $drop=, __cxa_begin_catch at FUNCTION
; CHECK: call __cxa_end_catch at FUNCTION
; CHECK: call __cxa_rethrow at FUNCTION
-; CHECK-NEXT: rethrow
; CHECK: end_try
define void @test_catch_rethrow() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
entry:
@@ -66,9 +75,9 @@ try.cont:
; CHECK-LABEL: test_cleanup:
; CHECK: try
; CHECK: call foo at FUNCTION
-; CHECK: catch_all
+; CHECK: catch
; CHECK: global.set __stack_pointer at GLOBAL
-; CHECK: i32.call $push{{.+}}=, _ZN7CleanupD1Ev at FUNCTION
+; CHECK: i32.call $drop=, _ZN7CleanupD1Ev at FUNCTION
; CHECK: rethrow
; CHECK: end_try
define void @test_cleanup() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
@@ -87,71 +96,51 @@ ehcleanup:
cleanupret from %0 unwind to caller
}
-; - Tests multple terminate pads are merged into one
-; - Tests a catch_all terminate pad is created after a catch terminate pad
-
; CHECK-LABEL: test_terminatepad
-; CHECK: i32.catch
-; CHECK: call __clang_call_terminate at FUNCTION
-; CHECK: unreachable
-; CHECK: catch_all
-; CHECK: call _ZSt9terminatev at FUNCTION
-; CHECK-NOT: call __clang_call_terminate at FUNCTION
-define hidden i32 @test_terminatepad() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
+; CHECK: catch
+; CHECK: block i32
+; CHECK: br_on_exn 0, __cpp_exception at EVENT
+; CHECK: call __clang_call_terminate at FUNCTION, 0
+; CHECK: unreachable
+; CHECK: end_block
+; CHECK: extract_exception
+; CHECK: call __clang_call_terminate at FUNCTION
+; CHECK: unreachable
+define void @test_terminatepad() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
entry:
- %c = alloca %struct.Cleanup, align 1
- %c1 = alloca %struct.Cleanup, align 1
invoke void @foo()
- to label %invoke.cont unwind label %ehcleanup
-
-invoke.cont: ; preds = %entry
- %call = invoke %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* %c1)
to label %try.cont unwind label %catch.dispatch
-ehcleanup: ; preds = %entry
- %0 = cleanuppad within none []
- %call4 = invoke %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* %c1) [ "funclet"(token %0) ]
- to label %invoke.cont3 unwind label %terminate
+catch.dispatch: ; preds = %entry
+ %0 = catchswitch within none [label %catch.start] unwind to caller
-invoke.cont3: ; preds = %ehcleanup
- cleanupret from %0 unwind label %catch.dispatch
+catch.start: ; preds = %catch.dispatch
+ %1 = catchpad within %0 [i8* null]
+ %2 = call i8* @llvm.wasm.get.exception(token %1)
+ %3 = call i32 @llvm.wasm.get.ehselector(token %1)
+ %4 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
+ invoke void @foo() [ "funclet"(token %1) ]
+ to label %invoke.cont1 unwind label %ehcleanup
-catch.dispatch: ; preds = %invoke.cont3, %invoke.cont
- %1 = catchswitch within none [label %catch.start] unwind label %ehcleanup7
+invoke.cont1: ; preds = %catch.start
+ call void @__cxa_end_catch() [ "funclet"(token %1) ]
+ catchret from %1 to label %try.cont
-catch.start: ; preds = %catch.dispatch
- %2 = catchpad within %1 [i8* null]
- %3 = call i8* @llvm.wasm.get.exception(token %2)
- %4 = call i32 @llvm.wasm.get.ehselector(token %2)
- %5 = call i8* @__cxa_begin_catch(i8* %3) [ "funclet"(token %2) ]
- invoke void @__cxa_end_catch() [ "funclet"(token %2) ]
- to label %invoke.cont5 unwind label %ehcleanup7
-
-invoke.cont5: ; preds = %catch.start
- catchret from %2 to label %try.cont
-
-try.cont: ; preds = %invoke.cont5, %invoke.cont
- %call6 = call %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* %c)
- ret i32 0
-
-ehcleanup7: ; preds = %catch.start, %catch.dispatch
- %6 = cleanuppad within none []
- %call9 = invoke %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* %c) [ "funclet"(token %6) ]
- to label %invoke.cont8 unwind label %terminate10
+try.cont: ; preds = %entry, %invoke.cont1
+ ret void
-invoke.cont8: ; preds = %ehcleanup7
- cleanupret from %6 unwind to caller
+ehcleanup: ; preds = %catch.start
+ %5 = cleanuppad within %1 []
+ invoke void @__cxa_end_catch() [ "funclet"(token %5) ]
+ to label %invoke.cont2 unwind label %terminate
-terminate: ; preds = %ehcleanup
- %7 = cleanuppad within %0 []
- %8 = call i8* @llvm.wasm.get.exception(token %7)
- call void @__clang_call_terminate(i8* %8) [ "funclet"(token %7) ]
- unreachable
+invoke.cont2: ; preds = %ehcleanup
+ cleanupret from %5 unwind to caller
-terminate10: ; preds = %ehcleanup7
- %9 = cleanuppad within %6 []
- %10 = call i8* @llvm.wasm.get.exception(token %9)
- call void @__clang_call_terminate(i8* %10) [ "funclet"(token %9) ]
+terminate: ; preds = %ehcleanup
+ %6 = cleanuppad within %5 []
+ %7 = call i8* @llvm.wasm.get.exception(token %6)
+ call void @__clang_call_terminate(i8* %7) [ "funclet"(token %6) ]
unreachable
}
@@ -164,12 +153,12 @@ terminate10:
; CHECK-LABEL: test_no_prolog_epilog_in_ehpad
; CHECK: try
; CHECK: call foo at FUNCTION
-; CHECK: i32.catch
+; CHECK: catch
; CHECK-NOT: global.get $push{{.+}}=, __stack_pointer at GLOBAL
; CHECK: global.set __stack_pointer at GLOBAL
; CHECK: try
; CHECK: call foo at FUNCTION
-; CHECK: catch_all
+; CHECK: catch
; CHECK-NOT: global.get $push{{.+}}=, __stack_pointer at GLOBAL
; CHECK: global.set __stack_pointer at GLOBAL
; CHECK: call __cxa_end_catch at FUNCTION
@@ -251,6 +240,8 @@ try.cont:
declare void @foo()
declare void @bar(i32*)
declare i32 @__gxx_wasm_personality_v0(...)
+declare void @llvm.wasm.throw(i32, i8*)
+declare void @llvm.wasm.rethrow()
declare i8* @llvm.wasm.get.exception(token)
declare i32 @llvm.wasm.get.ehselector(token)
declare i32 @llvm.eh.typeid.for(i8*)
@@ -258,7 +249,6 @@ declare i8* @__cxa_begin_catch(i8*)
declare void @__cxa_end_catch()
declare void @__cxa_rethrow()
declare void @__clang_call_terminate(i8*)
-declare void @_ZSt9terminatev()
declare %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* returned)
; CHECK: __cpp_exception:
Modified: llvm/trunk/test/CodeGen/WebAssembly/wasmehprepare.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/wasmehprepare.ll?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/wasmehprepare.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/wasmehprepare.ll Tue Jan 29 19:21:57 2019
@@ -29,7 +29,7 @@ catch.start:
br i1 %matches, label %catch, label %rethrow
; CHECK: catch.start:
; CHECK-NEXT: %[[CATCHPAD:.*]] = catchpad
-; CHECK-NEXT: %[[EXN:.*]] = call i8* @llvm.wasm.catch(i32 0)
+; CHECK-NEXT: %[[EXN:.*]] = call i8* @llvm.wasm.extract.exception()
; CHECK-NEXT: call void @llvm.wasm.landingpad.index(token %[[CATCHPAD]], i32 0)
; CHECK-NEXT: store i32 0, i32* getelementptr inbounds ({ i32, i8*, i32 }, { i32, i8*, i32 }* @__wasm_lpad_context, i32 0, i32 0)
; CHECK-NEXT: %[[LSDA:.*]] = call i8* @llvm.wasm.lsda()
@@ -76,7 +76,6 @@ catch.start:
catchret from %1 to label %try.cont
; CHECK: catch.start:
; CHECK-NEXT: catchpad within %0 [i8* null]
-; CHECK-NEXT: call i8* @llvm.wasm.catch(i32 0)
; CHECK-NOT: call void @llvm.wasm.landingpad.index
; CHECK-NOT: store {{.*}} @__wasm_lpad_context
; CHECK-NOT: call i8* @llvm.wasm.lsda()
@@ -178,7 +177,6 @@ ehcleanup:
cleanupret from %12 unwind to caller
; CHECK: ehcleanup:
; CHECK-NEXT: cleanuppad
-; CHECK-NOT: call i8* @llvm.wasm.catch(i32 0)
; CHECK-NOT: call void @llvm.wasm.landingpad.index
; CHECK-NOT: store {{.*}} @__wasm_lpad_context
; CHECK-NOT: call i8* @llvm.wasm.lsda()
@@ -191,7 +189,7 @@ unreachable:
; A cleanuppad with a call to __clang_call_terminate().
; A call to wasm.catch() should be generated after the cleanuppad.
-define hidden void @test3() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
+define void @test3() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
; CHECK-LABEL: @test3
entry:
invoke void @foo()
@@ -230,14 +228,14 @@ terminate:
unreachable
; CHECK: terminate:
; CHECK-NEXT: cleanuppad
-; CHECK-NEXT: %[[EXN:.*]] = call i8* @llvm.wasm.catch(i32 0)
+; CHECK-NEXT: %[[EXN:.*]] = call i8* @llvm.wasm.extract.exception
; CHECK-NEXT: call void @__clang_call_terminate(i8* %[[EXN]])
}
; PHI demotion test. Only the phi before catchswitch should be demoted; the phi
; before cleanuppad should NOT.
-define void @test5() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
-; CHECK-LABEL: @test5
+define void @test4() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
+; CHECK-LABEL: @test4
entry:
%c = alloca %struct.Cleanup, align 1
invoke void @foo()
@@ -301,8 +299,8 @@ try.cont10:
; Tests if instructions after a call to @llvm.wasm.throw are deleted and the
; BB's dead children are deleted.
-; CHECK-LABEL: @test6
-define i32 @test6(i1 %b, i8* %p) {
+; CHECK-LABEL: @test5
+define i32 @test5(i1 %b, i8* %p) {
entry:
br i1 %b, label %bb.true, label %bb.false
@@ -326,6 +324,34 @@ merge:
ret i32 0
}
+; Tests if instructions after a call to @llvm.wasm.rethrow are deleted and the
+; BB's dead children are deleted.
+
+; CHECK-LABEL: @test6
+define i32 @test6(i1 %b, i8* %p) {
+entry:
+ br i1 %b, label %bb.true, label %bb.false
+
+; CHECK: bb.true:
+; CHECK-NEXT: call void @llvm.wasm.rethrow()
+; CHECK-NEXT: unreachable
+bb.true: ; preds = %entry
+ call void @llvm.wasm.rethrow()
+ br label %bb.true.0
+
+; CHECK-NOT: bb.true.0
+bb.true.0: ; preds = %bb.true
+ br label %merge
+
+; CHECK: bb.false
+bb.false: ; preds = %entry
+ br label %merge
+
+; CHECK: merge
+merge: ; preds = %bb.true.0, %bb.false
+ ret i32 0
+}
+
declare void @foo()
declare void @func(i32)
declare %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* returned)
@@ -334,12 +360,12 @@ declare i8* @llvm.wasm.get.exception(tok
declare i32 @llvm.wasm.get.ehselector(token)
declare i32 @llvm.eh.typeid.for(i8*)
declare void @llvm.wasm.throw(i32, i8*)
+declare void @llvm.wasm.rethrow()
declare i8* @__cxa_begin_catch(i8*)
declare void @__cxa_end_catch()
declare void @__cxa_rethrow()
declare void @__clang_call_terminate(i8*)
-; CHECK-DAG: declare i8* @llvm.wasm.catch(i32)
; CHECK-DAG: declare void @llvm.wasm.landingpad.index(token, i32)
; CHECK-DAG: declare i8* @llvm.wasm.lsda()
; CHECK-DAG: declare i32 @_Unwind_CallPersonality(i8*)
Added: llvm/trunk/test/MC/WebAssembly/annotations.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/WebAssembly/annotations.s?rev=352598&view=auto
==============================================================================
--- llvm/trunk/test/MC/WebAssembly/annotations.s (added)
+++ llvm/trunk/test/MC/WebAssembly/annotations.s Tue Jan 29 19:21:57 2019
@@ -0,0 +1,71 @@
+# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+exception-handling < %s | FileCheck %s
+
+# Tests if block/loop/try/catch/end/branch/rethrow instructions are correctly
+# printed with their annotations.
+
+ .text
+ .section .text.test_annotation,"",@
+ .type test_annotation, at function
+test_annotation:
+ .functype test_annotation () -> ()
+ .eventtype __cpp_exception i32
+ try
+ br 0
+ catch
+ block
+ br_if 0
+ loop
+ br_if 1
+ end_loop
+ end_block
+ try
+ rethrow
+ catch
+ block
+ try
+ br 0
+ catch
+ local.set 0
+ block i32
+ local.get 0
+ br_on_exn 0, __cpp_exception at EVENT
+ rethrow
+ end_block
+ end_try
+ end_block
+ rethrow
+ end_try
+ end_try
+ end_function
+
+
+# CHECK: test_annotation:
+# CHECK: try
+# CHECK-NEXT: br 0 # 0: down to label0
+# CHECK-NEXT: catch # catch0:
+# CHECK-NEXT: block
+# CHECK-NEXT: br_if 0 # 0: down to label1
+# CHECK-NEXT: loop # label2:
+# CHECK-NEXT: br_if 1 # 1: down to label1
+# CHECK-NEXT: end_loop
+# CHECK-NEXT: end_block # label1:
+# CHECK-NEXT: try
+# CHECK-NEXT: rethrow # down to catch1
+# CHECK-NEXT: catch # catch1:
+# CHECK-NEXT: block
+# CHECK-NEXT: try
+# CHECK-NEXT: br 0 # 0: down to label5
+# CHECK-NEXT: catch # catch2:
+# CHECK-NEXT: local.set 0
+# CHECK-NEXT: block i32
+# CHECK-NEXT: local.get 0
+# CHECK-NEXT: br_on_exn 0, __cpp_exception at EVENT # 0: down to label6
+# CHECK-NEXT: rethrow # to caller
+# CHECK-NEXT: end_block # label6:
+# CHECK-NEXT: end_try # label5:
+# CHECK-NEXT: end_block # label4:
+# CHECK-NEXT: rethrow # to caller
+# CHECK-NEXT: end_try # label3:
+# CHECK-NEXT: end_try # label0:
+# CHECK-NEXT: end_function
+
Modified: llvm/trunk/test/MC/WebAssembly/basic-assembly.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/WebAssembly/basic-assembly.s?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/test/MC/WebAssembly/basic-assembly.s (original)
+++ llvm/trunk/test/MC/WebAssembly/basic-assembly.s Tue Jan 29 19:21:57 2019
@@ -71,11 +71,18 @@ test0:
i32.trunc_f32_s
try except_ref
.LBB0_3:
- i32.catch 0
+ catch
+ local.set 0
+ block i32
+ local.get 0
+ br_on_exn 0, __cpp_exception at EVENT
+ rethrow
.LBB0_4:
- catch_all
-.LBB0_5:
+ end_block
end_try
+ i32.const 0
+ throw 0
+.LBB0_5:
#i32.trunc_sat_f32_s
global.get __stack_pointer at GLOBAL
end_function
@@ -143,11 +150,18 @@ test0:
# CHECK-NEXT: i32.trunc_f32_s
# CHECK-NEXT: try except_ref
# CHECK-NEXT: .LBB0_3:
-# CHECK-NEXT: i32.catch 0
+# CHECK-NEXT: catch
+# CHECK-NEXT: local.set 0
+# CHECK-NEXT: block i32
+# CHECK-NEXT: local.get 0
+# CHECK-NEXT: br_on_exn 0, __cpp_exception at EVENT
+# CHECK-NEXT: rethrow
# CHECK-NEXT: .LBB0_4:
-# CHECK-NEXT: catch_all
-# CHECK-NEXT: .LBB0_5:
+# CHECK-NEXT: end_block
# CHECK-NEXT: end_try
+# CHECK-NEXT: i32.const 0
+# CHECK-NEXT: throw 0
+# CHECK-NEXT: .LBB0_5:
# CHECK-NEXT: global.get __stack_pointer at GLOBAL
# CHECK-NEXT: end_function
Modified: llvm/trunk/unittests/Target/WebAssembly/WebAssemblyExceptionInfoTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Target/WebAssembly/WebAssemblyExceptionInfoTest.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/unittests/Target/WebAssembly/WebAssemblyExceptionInfoTest.cpp (original)
+++ llvm/trunk/unittests/Target/WebAssembly/WebAssemblyExceptionInfoTest.cpp Tue Jan 29 19:21:57 2019
@@ -74,7 +74,7 @@ TEST(WebAssemblyExceptionInfoTest, TEST0
declare i32 @__gxx_wasm_personality_v0(...)
- define hidden void @test0() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
+ define void @test0() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
unreachable
}
@@ -100,14 +100,14 @@ body: |
; predecessors: %bb.0
successors: %bb.3, %bb.9
liveins: $value_stack
- CATCH_ALL implicit-def $arguments
+ %0:except_ref = CATCH implicit-def $arguments
CLEANUPRET implicit-def dead $arguments
bb.3 (landing-pad):
; predecessors: %bb.2
successors: %bb.4, %bb.6
liveins: $value_stack
- CATCH_ALL implicit-def $arguments
+ %1:except_ref = CATCH implicit-def $arguments
BR_IF %bb.4, %58:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack
BR %bb.6, implicit-def $arguments
@@ -138,13 +138,13 @@ body: |
; predecessors: %bb.4
successors: %bb.9
liveins: $value_stack
- CATCH_ALL implicit-def $arguments
+ %2:except_ref = CATCH implicit-def $arguments
CLEANUPRET implicit-def dead $arguments
bb.9 (landing-pad):
; predecessors: %bb.2, %bb.6, %bb.8
liveins: $value_stack
- CATCH_ALL implicit-def $arguments
+ %3:except_ref = CATCH implicit-def $arguments
CLEANUPRET implicit-def dead $arguments
bb.10:
@@ -237,7 +237,7 @@ TEST(WebAssemblyExceptionInfoTest, TEST1
declare i32 @__gxx_wasm_personality_v0(...)
- define hidden void @test1() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
+ define void @test1() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
unreachable
}
@@ -257,7 +257,7 @@ body: |
; predecessors: %bb.0
successors: %bb.2, %bb.8
liveins: $value_stack
- %52:i32 = CATCH_I32 0, implicit-def dead $arguments
+ %0:except_ref = CATCH implicit-def $arguments
BR_IF %bb.2, %32:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack
BR %bb.8, implicit-def $arguments
@@ -271,7 +271,7 @@ body: |
; predecessors: %bb.2
successors: %bb.4, %bb.6
liveins: $value_stack
- CATCH_ALL implicit-def $arguments
+ %1:except_ref = CATCH implicit-def $arguments
BR_IF %bb.4, %43:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack
BR %bb.6, implicit-def $arguments
@@ -313,13 +313,13 @@ body: |
; predecessors: %bb.4
successors: %bb.11
liveins: $value_stack
- CATCH_ALL implicit-def $arguments
+ %2:except_ref = CATCH implicit-def $arguments
CLEANUPRET implicit-def dead $arguments
bb.11 (landing-pad):
; predecessors: %bb.2, %bb.6, %bb.10
liveins: $value_stack
- CATCH_ALL implicit-def $arguments
+ %3:except_ref = CATCH implicit-def $arguments
CLEANUPRET implicit-def dead $arguments
bb.12:
@@ -415,135 +415,3 @@ body: |
EXPECT_EQ(WE0_1->getParentException(), WE0);
EXPECT_EQ(WE0_1->getExceptionDepth(), (unsigned)2);
}
-
-// Terminate pad test
-TEST(WebAssemblyExceptionInfoTest, TEST2) {
- std::unique_ptr<LLVMTargetMachine> TM = createTargetMachine();
- ASSERT_TRUE(TM);
-
- StringRef MIRString = R"MIR(
---- |
- target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
- target triple = "wasm32-unknown-unknown"
-
- declare i32 @__gxx_wasm_personality_v0(...)
- declare void @_ZSt9terminatev()
- declare void @__clang_call_terminate(i8*)
-
- define hidden void @test2() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
- unreachable
- }
-
-...
----
-name: test2
-liveins:
- - { reg: '$arguments' }
- - { reg: '$value_stack' }
-body: |
- bb.0:
- successors: %bb.3, %bb.1
- BR %bb.3, implicit-def dead $arguments
-
- bb.1 (landing-pad):
- ; predecessors: %bb.0
- successors: %bb.2, %bb.4
- %3:i32 = CATCH_I32 0, implicit-def dead $arguments
- BR %bb.2, implicit-def dead $arguments
-
- bb.2:
- ; predecessors: %bb.1
- successors: %bb.3(0x80000000); %bb.3(200.00%)
- CATCHRET %bb.3, %bb.0, implicit-def dead $arguments
-
- bb.3:
- ; predecessors: %bb.0, %bb.2
- RETURN_VOID implicit-def $arguments
-
- bb.4 (landing-pad):
- ; predecessors: %bb.1
- successors: %bb.5, %bb.6
- CATCH_ALL implicit-def $arguments
- BR %bb.5, implicit-def dead $arguments
-
- bb.5:
- ; predecessors: %bb.4
- CLEANUPRET implicit-def dead $arguments
-
- bb.6 (landing-pad):
- ; predecessors: %bb.4
- successors: %bb.7(0x80000000); %bb.7(200.00%)
- %6:i32 = CATCH_I32 0, implicit-def dead $arguments
- CALL_VOID @__clang_call_terminate, %7:i32, implicit-def $arguments
- UNREACHABLE implicit-def $arguments
-
- bb.7 (landing-pad):
- ; predecessors: %bb.6
- CATCH_ALL implicit-def $arguments
- CALL_VOID @_ZSt9terminatev, implicit-def $arguments
- UNREACHABLE implicit-def $arguments
-)MIR";
-
- LLVMContext Context;
- std::unique_ptr<MIRParser> MIR;
- MachineModuleInfo MMI(TM.get());
- std::unique_ptr<Module> M =
- parseMIR(Context, MIR, *TM, MIRString, "test2", MMI);
- ASSERT_TRUE(M);
-
- Function *F = M->getFunction("test2");
- auto *MF = MMI.getMachineFunction(*F);
- ASSERT_TRUE(MF);
-
- WebAssemblyExceptionInfo WEI;
- MachineDominatorTree MDT;
- MachineDominanceFrontier MDF;
- MDT.runOnMachineFunction(*MF);
- MDF.getBase().analyze(MDT.getBase());
- WEI.recalculate(MDT, MDF);
-
- // Exception info structure:
- // |- bb1 (ehpad), bb2, bb4, bb5, bb6, bb7
- // |- bb4 (ehpad), bb5, bb6, bb7
- // |- bb6 (ehpad), bb7
- //
- // Here, bb6 is a terminate pad with a 'catch' instruction, and bb7 is a
- // terminate pad with a 'catch_all' instruction, In this case we put bb6 and
- // bb7 into one exception.
-
- auto *MBB1 = MF->getBlockNumbered(1);
- auto *WE0 = WEI.getExceptionFor(MBB1);
- ASSERT_TRUE(WE0);
- EXPECT_EQ(WE0->getEHPad(), MBB1);
- EXPECT_EQ(WE0->getParentException(), nullptr);
- EXPECT_EQ(WE0->getExceptionDepth(), (unsigned)1);
-
- auto *MBB2 = MF->getBlockNumbered(2);
- WE0 = WEI.getExceptionFor(MBB2);
- ASSERT_TRUE(WE0);
- EXPECT_EQ(WE0->getEHPad(), MBB1);
-
- auto *MBB4 = MF->getBlockNumbered(4);
- auto *WE0_0 = WEI.getExceptionFor(MBB4);
- ASSERT_TRUE(WE0_0);
- EXPECT_EQ(WE0_0->getEHPad(), MBB4);
- EXPECT_EQ(WE0_0->getParentException(), WE0);
- EXPECT_EQ(WE0_0->getExceptionDepth(), (unsigned)2);
-
- auto *MBB5 = MF->getBlockNumbered(5);
- WE0_0 = WEI.getExceptionFor(MBB5);
- ASSERT_TRUE(WE0_0);
- EXPECT_EQ(WE0_0->getEHPad(), MBB4);
-
- auto *MBB6 = MF->getBlockNumbered(6);
- auto *WE0_0_0 = WEI.getExceptionFor(MBB6);
- ASSERT_TRUE(WE0_0_0);
- EXPECT_EQ(WE0_0_0->getEHPad(), MBB6);
- EXPECT_EQ(WE0_0_0->getParentException(), WE0_0);
- EXPECT_EQ(WE0_0_0->getExceptionDepth(), (unsigned)3);
-
- auto *MBB7 = MF->getBlockNumbered(7);
- WE0_0_0 = WEI.getExceptionFor(MBB7);
- ASSERT_TRUE(WE0_0_0);
- EXPECT_EQ(WE0_0_0->getEHPad(), MBB6);
-}
More information about the llvm-commits
mailing list