diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp --- a/clang/lib/CodeGen/CGException.cpp +++ b/clang/lib/CodeGen/CGException.cpp @@ -1552,17 +1552,8 @@ CurrentFuncletPad = Builder.CreateCleanupPad(ParentPad); // Emit the __std_terminate call. - llvm::Value *Exn = nullptr; - // In case of wasm personality, we need to pass the exception value to - // __clang_call_terminate function. - if (getLangOpts().CPlusPlus && - EHPersonality::get(*this).isWasmPersonality()) { - llvm::Function *GetExnFn = - CGM.getIntrinsic(llvm::Intrinsic::wasm_get_exception); - Exn = Builder.CreateCall(GetExnFn, CurrentFuncletPad); - } llvm::CallInst *terminateCall = - CGM.getCXXABI().emitTerminateForUnexpectedException(*this, Exn); + CGM.getCXXABI().emitTerminateForUnexpectedException(*this, nullptr); terminateCall->setDoesNotReturn(); Builder.CreateUnreachable(); diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -515,6 +515,9 @@ : ItaniumCXXABI(CGM, /*UseARMMethodPtrABI=*/true, /*UseARMGuardVarABI=*/true) {} void emitBeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *C) override; + llvm::CallInst * + emitTerminateForUnexpectedException(CodeGenFunction &CGF, + llvm::Value *Exn) override; private: bool HasThisReturn(GlobalDecl GD) const override { @@ -4640,6 +4643,18 @@ ItaniumCXXABI::emitBeginCatch(CGF, C); } +llvm::CallInst * +WebAssemblyCXXABI::emitTerminateForUnexpectedException(CodeGenFunction &CGF, + llvm::Value *Exn) { + // Itanium ABI calls __clang_call_terminate(), which __cxa_begin_catch() on + // the violating exception to mark it handled, but it is currently hard to do + // with wasm EH instruction structure with catch/catch_all, we just call + // std::terminate and ignore the violating exception as in CGCXXABI. + // TODO Consider code transformation that makes calling __clang_call_terminate + // possible. + return CGCXXABI::emitTerminateForUnexpectedException(CGF, Exn); +} + /// Register a global destructor as best as we know how. void XLCXXABI::registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D, llvm::FunctionCallee dtor, diff --git a/clang/test/CodeGenCXX/wasm-eh.cpp b/clang/test/CodeGenCXX/wasm-eh.cpp --- a/clang/test/CodeGenCXX/wasm-eh.cpp +++ b/clang/test/CodeGenCXX/wasm-eh.cpp @@ -188,13 +188,7 @@ // CHECK: [[TERMINATE_BB]]: // CHECK-NEXT: %[[CLEANUPPAD1:.*]] = cleanuppad within %[[CLEANUPPAD0]] [] -// CHECK-NEXT: %[[EXN:.*]] = call i8* @llvm.wasm.get.exception(token %[[CLEANUPPAD1]]) -// CHECK-NEXT: call void @__clang_call_terminate(i8* %[[EXN]]) {{.*}} [ "funclet"(token %[[CLEANUPPAD1]]) ] -// CHECK-NEXT: unreachable - -// CHECK-LABEL: define {{.*}} void @__clang_call_terminate(i8* %0) -// CHECK-NEXT: call i8* @__cxa_begin_catch(i8* %{{.*}}) -// CHECK-NEXT: call void @_ZSt9terminatev() +// CHECK-NEXT: call void @_ZSt9terminatev() {{.*}} [ "funclet"(token %[[CLEANUPPAD1]]) ] // CHECK-NEXT: unreachable // Try-catch with cleanups @@ -336,7 +330,7 @@ // CHECK: unreachable // CHECK: %[[CLEANUPPAD7:.*]] = cleanuppad within %[[CLEANUPPAD4]] [] -// CHECK: call void @__clang_call_terminate(i8* %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD7]]) ] +// CHECK: call void @_ZSt9terminatev() {{.*}} [ "funclet"(token %[[CLEANUPPAD7]]) ] // CHECK: unreachable // Nested try-catches within a catch diff --git a/llvm/lib/CodeGen/WasmEHPrepare.cpp b/llvm/lib/CodeGen/WasmEHPrepare.cpp --- a/llvm/lib/CodeGen/WasmEHPrepare.cpp +++ b/llvm/lib/CodeGen/WasmEHPrepare.cpp @@ -297,8 +297,8 @@ } } - // 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. + // Cleanup pads 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()"); diff --git a/llvm/lib/Target/WebAssembly/CMakeLists.txt b/llvm/lib/Target/WebAssembly/CMakeLists.txt --- a/llvm/lib/Target/WebAssembly/CMakeLists.txt +++ b/llvm/lib/Target/WebAssembly/CMakeLists.txt @@ -22,7 +22,6 @@ WebAssemblyCFGSort.cpp WebAssemblyDebugFixup.cpp WebAssemblyDebugValueManager.cpp - WebAssemblyHandleEHTerminatePads.cpp WebAssemblyLateEHPrepare.cpp WebAssemblyExceptionInfo.cpp WebAssemblyExplicitLocals.cpp diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.h b/llvm/lib/Target/WebAssembly/WebAssembly.h --- a/llvm/lib/Target/WebAssembly/WebAssembly.h +++ b/llvm/lib/Target/WebAssembly/WebAssembly.h @@ -49,7 +49,6 @@ FunctionPass *createWebAssemblyLateEHPrepare(); FunctionPass *createWebAssemblyCFGSort(); FunctionPass *createWebAssemblyCFGStackify(); -FunctionPass *createWebAssemblyHandleEHTerminatePads(); FunctionPass *createWebAssemblyExplicitLocals(); FunctionPass *createWebAssemblyLowerBrUnless(); FunctionPass *createWebAssemblyRegNumbering(); @@ -76,7 +75,6 @@ void initializeWebAssemblyExceptionInfoPass(PassRegistry &); void initializeWebAssemblyCFGSortPass(PassRegistry &); void initializeWebAssemblyCFGStackifyPass(PassRegistry &); -void initializeWebAssemblyHandleEHTerminatePadsPass(PassRegistry &); void initializeWebAssemblyExplicitLocalsPass(PassRegistry &); void initializeWebAssemblyLowerBrUnlessPass(PassRegistry &); void initializeWebAssemblyRegNumberingPass(PassRegistry &); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyHandleEHTerminatePads.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyHandleEHTerminatePads.cpp deleted file mode 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyHandleEHTerminatePads.cpp +++ /dev/null @@ -1,152 +0,0 @@ -// WebAssemblyHandleEHTerminatePads.cpp - WebAssembly Handle EH TerminatePads // -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief Add catch_all blocks to terminate pads. -/// -/// Terminate pads are cleanup pads with a __clang_call_terminate call. These -/// are reached when an exception is thrown again in the middle of processing a -/// thrown exception, to terminate the program. These are cleanup pads that -/// should run regardless whether the thrown exception is a C++ exception or -/// not. -/// -/// Because __clang_call_terminate takes an exception pointer, and -/// llvm.get.exception intrinsic is selected to 'catch' instruction in -/// instruction selection, terminate pads have a catch instruction and are in -/// this form after LateEHPrepare, even though they are cleanup pads: -/// termpad: -/// %exn = catch $__cpp_exception -/// call @__clang_call_terminate(%exn) -/// unreachable -/// -/// This pass assumes LateEHPrepare ensured every terminate pad is a single -/// BB. -/// -/// __clang_call_terminate is a function generated by clang, in the form of -/// void __clang_call_terminate(i8* %arg) { -/// call @__cxa_begin_catch(%arg) -/// call void @std::terminate() -/// unreachable -/// } -/// -/// To make the terminate pads reachable when a foreign exception is thrown, -/// this pass attaches an additional catch_all BB after this catch terminate pad -/// BB, with a call to std::terminate, because foreign exceptions don't have a -/// valid exception pointer to call __cxa_begin_catch with. So the code example -/// becomes: -/// termpad: -/// %exn = catch $__cpp_exception -/// call @__clang_call_terminate(%exn) -/// unreachable -/// termpad-catchall: -/// catch_all -/// call @std::terminate() -/// unreachable -/// -/// We do this at the very end of compilation pipeline, even after CFGStackify, -/// because even though wasm spec allows multiple catch/catch_all blocks per a -/// try instruction, it has been convenient to maintain the invariant so far -/// that there has been only a single catch or catch_all attached to a try. This -/// assumption makes ExceptionInfo generation and CFGStackify simpler, because -/// we have been always able to assume an EH pad is an end of try block and a -/// start of catch/catch_all block. -//===----------------------------------------------------------------------===// - -#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" -#include "WebAssembly.h" -#include "WebAssemblySubtarget.h" -#include "WebAssemblyUtilities.h" -#include "llvm/CodeGen/MachineModuleInfo.h" -#include "llvm/MC/MCAsmInfo.h" -#include "llvm/Target/TargetMachine.h" -using namespace llvm; - -#define DEBUG_TYPE "wasm-handle-termpads" - -namespace { -class WebAssemblyHandleEHTerminatePads final : public MachineFunctionPass { - StringRef getPassName() const override { - return "WebAssembly Handle EH Terminate Pads"; - } - - bool runOnMachineFunction(MachineFunction &MF) override; - -public: - static char ID; // Pass identification, replacement for typeid - WebAssemblyHandleEHTerminatePads() : MachineFunctionPass(ID) {} -}; -} // end anonymous namespace - -char WebAssemblyHandleEHTerminatePads::ID = 0; -INITIALIZE_PASS(WebAssemblyHandleEHTerminatePads, DEBUG_TYPE, - "WebAssembly Handle EH Terminate Pads", false, false) - -FunctionPass *llvm::createWebAssemblyHandleEHTerminatePads() { - return new WebAssemblyHandleEHTerminatePads(); -} - -bool WebAssemblyHandleEHTerminatePads::runOnMachineFunction( - MachineFunction &MF) { - LLVM_DEBUG(dbgs() << "********** Handle EH Terminate Pads **********\n" - "********** Function: " - << MF.getName() << '\n'); - - if (MF.getTarget().getMCAsmInfo()->getExceptionHandlingType() != - ExceptionHandling::Wasm || - !MF.getFunction().hasPersonalityFn()) - return false; - - const auto &TII = *MF.getSubtarget().getInstrInfo(); - - // Find calls to __clang_call_terminate() - SmallVector ClangCallTerminateCalls; - 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); - } - } - } - - if (ClangCallTerminateCalls.empty()) - return false; - - for (auto *Call : ClangCallTerminateCalls) { - // This should be an EH pad because LateEHPrepare ensures terminate pads are - // a single BB. - MachineBasicBlock *CatchBB = Call->getParent(); - assert(CatchBB->isEHPad()); - - auto *CatchAllBB = MF.CreateMachineBasicBlock(); - MF.insert(std::next(CatchBB->getIterator()), CatchAllBB); - CatchAllBB->setIsEHPad(true); - for (auto *Pred : CatchBB->predecessors()) - Pred->addSuccessor(CatchAllBB); - - // If the definition of __clang_call_terminate exists in the module, there - // should be a declaration of std::terminate within the same module, because - // __clang_call_terminate calls it. - const auto *StdTerminateFn = - MF.getMMI().getModule()->getNamedValue(WebAssembly::StdTerminateFn); - assert(StdTerminateFn && "std::terminate() does not exist in the module"); - - // Generate a BB in the form of: - // catch_all - // call @std::terminate - // unreachable - BuildMI(CatchAllBB, Call->getDebugLoc(), TII.get(WebAssembly::CATCH_ALL)); - BuildMI(CatchAllBB, Call->getDebugLoc(), TII.get(WebAssembly::CALL)) - .addGlobalAddress(StdTerminateFn); - BuildMI(CatchAllBB, Call->getDebugLoc(), TII.get(WebAssembly::UNREACHABLE)); - } - - return true; -} diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp @@ -38,7 +38,6 @@ bool addCatchAlls(MachineFunction &MF); bool replaceFuncletReturns(MachineFunction &MF); bool removeUnnecessaryUnreachables(MachineFunction &MF); - bool ensureSingleBBTermPads(MachineFunction &MF); bool restoreStackPointer(MachineFunction &MF); MachineBasicBlock *getMatchingEHPad(MachineInstr *MI); @@ -128,7 +127,6 @@ Changed |= hoistCatches(MF); Changed |= addCatchAlls(MF); Changed |= replaceFuncletReturns(MF); - Changed |= ensureSingleBBTermPads(MF); } Changed |= removeUnnecessaryUnreachables(MF); if (MF.getFunction().hasPersonalityFn()) @@ -288,80 +286,6 @@ return Changed; } -// Clang-generated terminate pads are an single-BB EH pad in the form of -// termpad: -// %exn = catch $__cpp_exception -// 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. -// -// This is preparation work for the HandleEHTerminatePads pass later, which -// duplicates terminate pads both for 'catch' and 'catch_all'. Refer to -// WebAssemblyHandleEHTerminatePads.cpp for details. -bool WebAssemblyLateEHPrepare::ensureSingleBBTermPads(MachineFunction &MF) { - const auto &TII = *MF.getSubtarget().getInstrInfo(); - - // Find calls to __clang_call_terminate() - SmallVector ClangCallTerminateCalls; - SmallPtrSet TermPads; - 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) { - MachineBasicBlock *EHPad = getMatchingEHPad(&MI); - assert(EHPad && "No matching EH pad for __clang_call_terminate"); - // In case a __clang_call_terminate call is duplicated during code - // transformation so one terminate pad contains multiple - // __clang_call_terminate calls, we only count one of them - if (TermPads.insert(EHPad).second) - ClangCallTerminateCalls.push_back(&MI); - } - } - } - } - - bool Changed = false; - for (auto *Call : ClangCallTerminateCalls) { - MachineBasicBlock *EHPad = getMatchingEHPad(Call); - assert(EHPad && "No matching EH pad for __clang_call_terminate"); - - // 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; - // This runs after hoistCatches(), so catch instruction should be at the top - MachineInstr *Catch = WebAssembly::findCatch(EHPad); - assert(Catch && "EH pad does not have a catch instruction"); - // 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 Succs(EHPad->successors()); - for (auto *Succ : Succs) - EHPad->removeSuccessor(Succ); - eraseDeadBBsAndChildren(Succs); - } - return Changed; -} - // After the stack is unwound due to a thrown exception, the __stack_pointer // global can point to an invalid address. This inserts instructions that // restore __stack_pointer global. diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -82,7 +82,6 @@ initializeWebAssemblyExceptionInfoPass(PR); initializeWebAssemblyCFGSortPass(PR); initializeWebAssemblyCFGStackifyPass(PR); - initializeWebAssemblyHandleEHTerminatePadsPass(PR); initializeWebAssemblyExplicitLocalsPass(PR); initializeWebAssemblyLowerBrUnlessPass(PR); initializeWebAssemblyRegNumberingPass(PR); @@ -486,10 +485,6 @@ // Insert BLOCK and LOOP markers. addPass(createWebAssemblyCFGStackify()); - // Handle terminate pads for cleanups - if (TM->Options.ExceptionModel == ExceptionHandling::Wasm) - addPass(createWebAssemblyHandleEHTerminatePads()); - // Insert explicit local.get and local.set operators. if (!WasmDisableExplicitLocals) addPass(createWebAssemblyExplicitLocals()); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp @@ -18,7 +18,6 @@ #include "llvm/MC/MCContext.h" using namespace llvm; -const char *const WebAssembly::ClangCallTerminateFn = "__clang_call_terminate"; const char *const WebAssembly::CxaBeginCatchFn = "__cxa_begin_catch"; const char *const WebAssembly::CxaRethrowFn = "__cxa_rethrow"; const char *const WebAssembly::StdTerminateFn = "_ZSt9terminatev"; @@ -73,7 +72,7 @@ return false; // These functions never throw if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn || - F->getName() == ClangCallTerminateFn || F->getName() == StdTerminateFn) + F->getName() == StdTerminateFn) return false; // TODO Can we exclude call instructions that are marked as 'nounwind' in the diff --git a/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll b/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll --- a/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll +++ b/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll @@ -233,8 +233,8 @@ ; CHECK: catch ; CHECK: try ; CHECK: call __cxa_end_catch -; CHECK: catch -; CHECK: call __clang_call_terminate +; CHECK: catch_all +; CHECK: call _ZSt9terminatev ; CHECK: unreachable ; CHECK: end_try ; CHECK: rethrow 0 # to caller @@ -291,8 +291,7 @@ 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) ] + call void @_ZSt9terminatev() [ "funclet"(token %6) ] unreachable } @@ -806,8 +805,7 @@ terminate: ; preds = %entry %0 = cleanuppad within none [] - %1 = tail call i8* @llvm.wasm.get.exception(token %0) - call void @__clang_call_terminate(i8* %1) [ "funclet"(token %0) ] + call void @_ZSt9terminatev() [ "funclet"(token %0) ] unreachable } @@ -876,8 +874,7 @@ terminate7: ; preds = %ehcleanup %10 = cleanuppad within %9 [] - %11 = call i8* @llvm.wasm.get.exception(token %10) - call void @__clang_call_terminate(i8* %11) [ "funclet"(token %10) ] + call void @_ZSt9terminatev() [ "funclet"(token %10) ] unreachable } @@ -1046,8 +1043,7 @@ ehcleanup: ; preds = %catch.start %5 = cleanuppad within %1 [] - %6 = call i8* @llvm.wasm.get.exception(token %5) - call void @__clang_call_terminate(i8* %6) [ "funclet"(token %5) ] + call void @_ZSt9terminatev() [ "funclet"(token %5) ] unreachable while.end: ; preds = %while.body, %while.cond @@ -1570,8 +1566,7 @@ ; Function Attrs: nounwind declare i32 @llvm.wasm.get.ehselector(token) #0 declare i8* @__cxa_allocate_exception(i32) #0 -; Function Attrs: noreturn -declare void @__cxa_throw(i8*, i8*, i8*) #1 +declare void @__cxa_throw(i8*, i8*, i8*) ; Function Attrs: noreturn declare void @llvm.wasm.rethrow() #1 ; Function Attrs: nounwind @@ -1580,7 +1575,6 @@ declare i8* @__cxa_begin_catch(i8*) declare void @__cxa_end_catch() declare i8* @__cxa_get_exception_ptr(i8*) -declare void @__clang_call_terminate(i8*) declare void @_ZSt9terminatev() ; Function Attrs: nounwind declare void @llvm.memcpy.p0i8.p0i8.i32(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i32, i1 immarg) #0 diff --git a/llvm/test/CodeGen/WebAssembly/eh-lsda.ll b/llvm/test/CodeGen/WebAssembly/eh-lsda.ll --- a/llvm/test/CodeGen/WebAssembly/eh-lsda.ll +++ b/llvm/test/CodeGen/WebAssembly/eh-lsda.ll @@ -231,10 +231,15 @@ } declare void @may_throw() -declare i32 @llvm.eh.typeid.for(i8*) -declare i8* @llvm.wasm.get.exception(token) -declare i32 @llvm.wasm.get.ehselector(token) +; Function Attrs: nounwind +declare i32 @llvm.eh.typeid.for(i8*) #0 +; Function Attrs: nounwind +declare i8* @llvm.wasm.get.exception(token) #0 +; Function Attrs: nounwind +declare i32 @llvm.wasm.get.ehselector(token) #0 declare void @__cxa_rethrow() declare i8* @__cxa_begin_catch(i8*) declare void @__cxa_end_catch() declare i32 @__gxx_wasm_personality_v0(...) + +attributes #0 = { nounwind } diff --git a/llvm/test/CodeGen/WebAssembly/exception.ll b/llvm/test/CodeGen/WebAssembly/exception.ll --- a/llvm/test/CodeGen/WebAssembly/exception.ll +++ b/llvm/test/CodeGen/WebAssembly/exception.ll @@ -1,5 +1,5 @@ ; 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 --implicit-check-not=ehgcr -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 -O0 | FileCheck -allow-deprecated-dag-overlap --check-prefix=NOOPT %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 -O0 ; 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" @@ -129,9 +129,6 @@ ; CHECK: catch_all ; CHECK: try ; CHECK: call __cxa_end_catch -; CHECK: catch $[[EXN:[0-9]+]]=, __cpp_exception -; CHECK: call __clang_call_terminate, $[[EXN]] -; CHECK: unreachable ; CHECK: catch_all ; CHECK: call _ZSt9terminatev ; CHECK: unreachable @@ -173,75 +170,7 @@ 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 -} - -; Tests a case when there are multiple BBs within a terminate pad. This kind of -; structure is not generated by clang, but can generated by code -; transformations. After LateEHPrepare, there should be a single 'terminate' BB -; with these instructions: - -; %exn = catch $__cpp_exception -; call @__clang_call_terminate(%exn) -; unreachable - -; NOOPT-LABEL: test_split_terminatepad -define void @test_split_terminatepad(i1 %arg) personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { -entry: - invoke void @foo() - to label %try.cont unwind label %catch.dispatch - -catch.dispatch: ; preds = %entry - %0 = catchswitch within none [label %catch.start] unwind to caller - -; NOOPT: catch -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 - -invoke.cont1: ; preds = %catch.start - call void @__cxa_end_catch() [ "funclet"(token %1) ] - catchret from %1 to label %try.cont - -try.cont: ; preds = %invoke.cont1, %entry - ret void - -; NOOPT: catch_all -ehcleanup: ; preds = %catch.start - %5 = cleanuppad within %1 [] - invoke void @__cxa_end_catch() [ "funclet"(token %5) ] - to label %invoke.cont2 unwind label %terminate - -invoke.cont2: ; preds = %ehcleanup - cleanupret from %5 unwind to caller - -; This weird structure of split terminate pads are not generated by clang, but -; we cannot guarantee this kind of multi-BB terminate pads cannot be generated -; by code transformations. This structure is manually created for this test. -; NOOPT: catch $[[EXN:[0-9]+]]=, __cpp_exception -; NOOPT-NEXT: global.set __stack_pointer -; NOOPT-NEXT: call __clang_call_terminate, $[[EXN]] -; NOOPT-NEXT: unreachable - -terminate: ; preds = %ehcleanup - %6 = cleanuppad within %5 [] - %7 = call i8* @llvm.wasm.get.exception(token %6) - br i1 %arg, label %terminate.split1, label %terminate.split2 - -terminate.split1: - call void @__clang_call_terminate(i8* %7) [ "funclet"(token %6) ] - unreachable - -terminate.split2: - ; This is to test a hypothetical case that a call to __clang_call_terminate is - ; duplicated within a terminate pad - call void @__clang_call_terminate(i8* %7) [ "funclet"(token %6) ] + call void @_ZSt9terminatev() [ "funclet"(token %6) ] unreachable } @@ -424,16 +353,23 @@ declare void @foo() declare void @bar(i32*) declare i32 @__gxx_wasm_personality_v0(...) -declare void @llvm.wasm.throw(i32, i8*) -declare i8* @llvm.wasm.get.exception(token) -declare i32 @llvm.wasm.get.ehselector(token) -declare void @llvm.wasm.rethrow() -declare i32 @llvm.eh.typeid.for(i8*) +; Function Attrs: noreturn +declare void @llvm.wasm.throw(i32, i8*) #1 +; Function Attrs: nounwind +declare i8* @llvm.wasm.get.exception(token) #0 +; Function Attrs: nounwind +declare i32 @llvm.wasm.get.ehselector(token) #0 +; Function Attrs: noreturn +declare void @llvm.wasm.rethrow() #1 +; Function Attrs: nounwind +declare i32 @llvm.eh.typeid.for(i8*) #0 declare i8* @__cxa_begin_catch(i8*) declare void @__cxa_end_catch() -declare void @__clang_call_terminate(i8*) declare void @_ZSt9terminatev() declare %struct.Temp* @_ZN4TempD2Ev(%struct.Temp* returned) +attributes #0 = { nounwind } +attributes #1 = { noreturn } + ; CHECK: __cpp_exception: ; CHECK: .eventtype __cpp_exception i32 diff --git a/llvm/test/CodeGen/WebAssembly/wasmehprepare.ll b/llvm/test/CodeGen/WebAssembly/wasmehprepare.ll --- a/llvm/test/CodeGen/WebAssembly/wasmehprepare.ll +++ b/llvm/test/CodeGen/WebAssembly/wasmehprepare.ll @@ -132,59 +132,6 @@ ret void } -; A cleanuppad with a call to __clang_call_terminate(). -; -; void foo(); -; void test2() { -; try { -; foo(); -; } catch (...) { -; foo(); -; } -; } -define void @test2() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { -; CHECK-LABEL: @test2 -entry: - invoke void @foo() - to label %try.cont unwind label %catch.dispatch - -catch.dispatch: ; preds = %entry - %0 = catchswitch within none [label %catch.start] unwind to caller - -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 - -invoke.cont1: ; preds = %catch.start - call void @__cxa_end_catch() [ "funclet"(token %1) ] - catchret from %1 to label %try.cont - -try.cont: ; preds = %entry, %invoke.cont1 - ret void - -ehcleanup: ; preds = %catch.start - %5 = cleanuppad within %1 [] - invoke void @__cxa_end_catch() [ "funclet"(token %5) ] - to label %invoke.cont2 unwind label %terminate - -invoke.cont2: ; preds = %ehcleanup - cleanupret from %5 unwind to caller - -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 -; CHECK: terminate: -; CHECK-NEXT: cleanuppad -; CHECK-NEXT: %[[EXN:.*]] = call i8* @llvm.wasm.catch -; 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. ; @@ -194,7 +141,7 @@ ; ~Temp() {} ; }; ; -; void test3() { +; void test2() { ; int num; ; try { ; Temp t; @@ -214,8 +161,8 @@ ; bar(num); ; } ; } -define void @test3() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { -; CHECK-LABEL: @test3 +define void @test2() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { +; CHECK-LABEL: @test2 entry: %t = alloca %struct.Temp, align 1 invoke void @foo() @@ -279,8 +226,8 @@ ; Tests if instructions after a call to @llvm.wasm.throw are deleted and the ; BB's dead children are deleted. -; CHECK-LABEL: @test4 -define i32 @test4(i1 %b, i8* %p) { +; CHECK-LABEL: @test3 +define i32 @test3(i1 %b, i8* %p) { entry: br i1 %b, label %bb.true, label %bb.false @@ -308,14 +255,22 @@ declare void @bar(i32) declare %struct.Temp* @_ZN4TempD2Ev(%struct.Temp* returned) declare i32 @__gxx_wasm_personality_v0(...) -declare i8* @llvm.wasm.get.exception(token) -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() +; Function Attrs: nounwind +declare i8* @llvm.wasm.get.exception(token) #0 +; Function Attrs: nounwind +declare i32 @llvm.wasm.get.ehselector(token) #0 +; Function Attrs: nounwind +declare i32 @llvm.eh.typeid.for(i8*) #0 +; Function Attrs: noreturn +declare void @llvm.wasm.throw(i32, i8*) #1 +; Function Attrs: noreturn +declare void @llvm.wasm.rethrow() #1 declare i8* @__cxa_begin_catch(i8*) declare void @__cxa_end_catch() -declare void @__clang_call_terminate(i8*) +declare void @_ZSt9terminatev() + +attributes #0 = { nounwind } +attributes #1 = { noreturn } ; CHECK-DAG: declare void @llvm.wasm.landingpad.index(token, i32 immarg) ; CHECK-DAG: declare i8* @llvm.wasm.lsda()