[llvm] 561abd8 - [WebAssembly] Disable uses of __clang_call_terminate

Heejin Ahn via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 4 14:58:10 PST 2021


Author: Heejin Ahn
Date: 2021-03-04T14:26:35-08:00
New Revision: 561abd83ffecc8d4ba8fcbbbcadb31efc55985c2

URL: https://github.com/llvm/llvm-project/commit/561abd83ffecc8d4ba8fcbbbcadb31efc55985c2
DIFF: https://github.com/llvm/llvm-project/commit/561abd83ffecc8d4ba8fcbbbcadb31efc55985c2.diff

LOG: [WebAssembly] Disable uses of __clang_call_terminate

Background:

Wasm EH, while using Windows EH (catchpad/cleanuppad based) IR, uses
Itanium-based libraries and ABIs with some modifications.

`__clang_call_terminate` is a wrapper generated in Clang's Itanium C++
ABI implementation. It contains this code, in C-style pseudocode:
```
void __clang_call_terminate(void *exn) {
  __cxa_begin_catch(exn);
  std::terminate();
}
```
So this function is a wrapper to call `__cxa_begin_catch` on the
exception pointer before termination.

In Itanium ABI, this function is called when another exception is thrown
while processing an exception. The pointer for this second, violating
exception is passed as the argument of this `__clang_call_terminate`,
which calls `__cxa_begin_catch` with that pointer and calls
`std::terminate` to terminate the program.

The spec (https://libcxxabi.llvm.org/spec.html) for `__cxa_begin_catch`
says,
```
When the personality routine encounters a termination condition, it
will call __cxa_begin_catch() to mark the exception as handled and then
call terminate(), which shall not return to its caller.
```

In wasm EH's Clang implementation, this function is called from
cleanuppads that terminates the program, which we also call terminate
pads. Cleanuppads normally don't access the thrown exception and the
wasm backend converts them to `catch_all` blocks. But because we need
the exception pointer in this cleanuppad, we generate
`wasm.get.exception` intrinsic (which will eventually be lowered to
`catch` instruction) as we do in the catchpads. But because terminate
pads are cleanup pads and should run even when a foreign exception is
thrown, so what we have been doing is:
1. In `WebAssemblyLateEHPrepare::ensureSingleBBTermPads()`, we make sure
terminate pads are in this simple shape:
```
%exn = catch
call @__clang_call_terminate(%exn)
unreachable
```
2. In `WebAssemblyHandleEHTerminatePads` pass at the end of the
pipeline, we attach a `catch_all` to terminate pads, so they will be in
this form:
```
%exn = catch
call @__clang_call_terminate(%exn)
unreachable
catch_all
call @std::terminate()
unreachable
```
In `catch_all` part, we don't have the exception pointer, so we call
`std::terminate()` directly. The reason we ran HandleEHTerminatePads at
the end of the pipeline, separate from LateEHPrepare, was it was
convenient to assume there was only a single `catch` part per `try`
during CFGSort and CFGStackify.

---

Problem:

While it thinks terminate pads could have been possibly split or calls
to `__clang_call_terminate` could have been duplicated,
`WebAssemblyLateEHPrepare::ensureSingleBBTermPads()` assumes terminate
pads contain no more than calls to `__clang_call_terminate` and
`unreachable` instruction. I assumed that because in LLVM very limited
forms of transformations are done to catchpads and cleanuppads to
maintain the scoping structure. But it turned out to be incorrect;
passes can merge cleanuppads into one, including terminate pads, as long
as the new code has a correct scoping structure. One pass that does this
I observed was `SimplifyCFG`, but there can be more. After this
transformation, a single cleanuppad can contain any number of other
instructions with the call to `__clang_call_terminate` and can span many
BBs. It wouldn't be practical to duplicate all these BBs within the
cleanuppad to generate the equivalent `catch_all` blocks, only with
calls to `__clang_call_terminate` replaced by calls to `std::terminate`.

Unless we do more complicated transformation to split those calls to
`__clang_call_terminate` into a separate cleanuppad, it is tricky to
solve.

---

Solution (?):

This CL just disables the generation and use of `__clang_call_terminate`
and calls `std::terminate()` directly in its place.

The possible downside of this approach can be, because the Itanium ABI
intended to "mark" the violating exception handled, we don't do that
anymore. What `__cxa_begin_catch` actually does is increment the
exception's handler count and decrement the uncaught exception count,
which in my opinion do not matter much given that we are about to
terminate the program anyway. Also it does not affect info like stack
traces that can be possibly shown to developers.

And while we use a variant of Itanium EH ABI, we can make some
deviations if we choose to; we are already different in that in the
current version of the EH spec we don't support two-phase unwinding. We
can possibly consider a more complicated transformation later to
reenable this, but I don't think that has high priority.

Changes in this CL contains:
- In Clang, we don't generate a call to `wasm.get.exception()` intrinsic
  and `__clang_call_terminate` function in terminate pads anymore; we
  simply generate calls to `std::terminate()`, which is the default
  implementation of `CGCXXABI::emitTerminateForUnexpectedException`.
- Remove `WebAssembly::ensureSingleBBTermPads() function and
  `WebAssemblyHandleEHTerminatePads` pass, because terminate pads are
  already `catch_all` now (because they don't need the exception
  pointer) and we don't need these transformations anymore.
- Change tests to use `std::terminate` directly. Also removes tests that
  tested `LateEHPrepare::ensureSingleBBTermPads` and
  `HandleEHTerminatePads` pass.
- Drive-by fix: Add some function attributes to EH intrinsic
  declarations

Fixes https://github.com/emscripten-core/emscripten/issues/13582.

Reviewed By: dschuff, tlively

Differential Revision: https://reviews.llvm.org/D97834

Added: 
    

Modified: 
    clang/lib/CodeGen/CGException.cpp
    clang/lib/CodeGen/ItaniumCXXABI.cpp
    clang/test/CodeGenCXX/wasm-eh.cpp
    llvm/lib/CodeGen/WasmEHPrepare.cpp
    llvm/lib/Target/WebAssembly/CMakeLists.txt
    llvm/lib/Target/WebAssembly/WebAssembly.h
    llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp
    llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
    llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
    llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll
    llvm/test/CodeGen/WebAssembly/eh-lsda.ll
    llvm/test/CodeGen/WebAssembly/exception.ll
    llvm/test/CodeGen/WebAssembly/wasmehprepare.ll

Removed: 
    llvm/lib/Target/WebAssembly/WebAssemblyHandleEHTerminatePads.cpp


################################################################################
diff  --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp
index ce8b42a8c63f..97e2a3a4b69a 100644
--- a/clang/lib/CodeGen/CGException.cpp
+++ b/clang/lib/CodeGen/CGException.cpp
@@ -1552,17 +1552,8 @@ llvm::BasicBlock *CodeGenFunction::getTerminateFunclet() {
   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
index 2d202414e98e..6ece8566ac08 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -515,6 +515,9 @@ class WebAssemblyCXXABI final : public ItaniumCXXABI {
       : 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 @@ void WebAssemblyCXXABI::emitBeginCatch(CodeGenFunction &CGF,
   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
index dcacd9220588..a5ff609737eb 100644
--- a/clang/test/CodeGenCXX/wasm-eh.cpp
+++ b/clang/test/CodeGenCXX/wasm-eh.cpp
@@ -188,13 +188,7 @@ void test5() {
 
 // 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 @@ void test7() {
 // 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
index 50102744781d..19ebbe3a1c80 100644
--- a/llvm/lib/CodeGen/WasmEHPrepare.cpp
+++ b/llvm/lib/CodeGen/WasmEHPrepare.cpp
@@ -297,8 +297,8 @@ void WasmEHPrepare::prepareEHPad(BasicBlock *BB, bool NeedPersonality,
     }
   }
 
-  // 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
index 40fc85d0df24..87920e7a950b 100644
--- a/llvm/lib/Target/WebAssembly/CMakeLists.txt
+++ b/llvm/lib/Target/WebAssembly/CMakeLists.txt
@@ -22,7 +22,6 @@ add_llvm_target(WebAssemblyCodeGen
   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
index 7838e57d82d3..e812d0047961 100644
--- a/llvm/lib/Target/WebAssembly/WebAssembly.h
+++ b/llvm/lib/Target/WebAssembly/WebAssembly.h
@@ -49,7 +49,6 @@ FunctionPass *createWebAssemblyFixIrreducibleControlFlow();
 FunctionPass *createWebAssemblyLateEHPrepare();
 FunctionPass *createWebAssemblyCFGSort();
 FunctionPass *createWebAssemblyCFGStackify();
-FunctionPass *createWebAssemblyHandleEHTerminatePads();
 FunctionPass *createWebAssemblyExplicitLocals();
 FunctionPass *createWebAssemblyLowerBrUnless();
 FunctionPass *createWebAssemblyRegNumbering();
@@ -76,7 +75,6 @@ void initializeWebAssemblyLateEHPreparePass(PassRegistry &);
 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
index d41947a036dd..000000000000
--- 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<WebAssemblySubtarget>().getInstrInfo();
-
-  // Find calls to __clang_call_terminate()
-  SmallVector<MachineInstr *, 8> 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
index 8cd2b38d8e00..1dcf84a26af0 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp
@@ -38,7 +38,6 @@ class WebAssemblyLateEHPrepare final : public MachineFunctionPass {
   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 @@ bool WebAssemblyLateEHPrepare::runOnMachineFunction(MachineFunction &MF) {
     Changed |= hoistCatches(MF);
     Changed |= addCatchAlls(MF);
     Changed |= replaceFuncletReturns(MF);
-    Changed |= ensureSingleBBTermPads(MF);
   }
   Changed |= removeUnnecessaryUnreachables(MF);
   if (MF.getFunction().hasPersonalityFn())
@@ -288,80 +286,6 @@ bool WebAssemblyLateEHPrepare::removeUnnecessaryUnreachables(
   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<WebAssemblySubtarget>().getInstrInfo();
-
-  // Find calls to __clang_call_terminate()
-  SmallVector<MachineInstr *, 8> ClangCallTerminateCalls;
-  SmallPtrSet<MachineBasicBlock *, 8> 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<MachineBasicBlock *, 8> 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
index 0b078504ec7b..135055a43afc 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
@@ -82,7 +82,6 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeWebAssemblyTarget() {
   initializeWebAssemblyExceptionInfoPass(PR);
   initializeWebAssemblyCFGSortPass(PR);
   initializeWebAssemblyCFGStackifyPass(PR);
-  initializeWebAssemblyHandleEHTerminatePadsPass(PR);
   initializeWebAssemblyExplicitLocalsPass(PR);
   initializeWebAssemblyLowerBrUnlessPass(PR);
   initializeWebAssemblyRegNumberingPass(PR);
@@ -486,10 +485,6 @@ void WebAssemblyPassConfig::addPreEmitPass() {
   // 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
index 332605fef981..b9344bba8dc9 100644
--- 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 @@ bool WebAssembly::mayThrow(const MachineInstr &MI) {
     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
index a07f7a25927d..c18e2389e808 100644
--- a/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll
+++ b/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll
@@ -233,8 +233,8 @@ unreachable:                                      ; preds = %rethrow5
 ; 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 @@ invoke.cont2:                                     ; preds = %ehcleanup
 
 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 @@ invoke.cont:                                      ; preds = %entry
 
 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 @@ for.end:                                          ; preds = %for.cond
 
 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 @@ invoke.cont:                                      ; preds = %catch.start
 
 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 @@ declare i8* @llvm.wasm.get.exception(token) #0
 ; 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 i32 @llvm.eh.typeid.for(i8*) #0
 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
index c34c76b4d644..7d1f8bed107f 100644
--- a/llvm/test/CodeGen/WebAssembly/eh-lsda.ll
+++ b/llvm/test/CodeGen/WebAssembly/eh-lsda.ll
@@ -231,10 +231,15 @@ catch:                                            ; preds = %catch.fallthrough2
 }
 
 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
index 2fdd76f9c514..a6308205b21a 100644
--- 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 @@ ehcleanup:                                        ; preds = %entry
 ; 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 @@ invoke.cont2:                                     ; preds = %ehcleanup
 
 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 @@ ehcleanupret:                                     ; preds = %catch.start, %ehcle
 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
index 4c53a322954d..63bdf2c6bea0 100644
--- a/llvm/test/CodeGen/WebAssembly/wasmehprepare.ll
+++ b/llvm/test/CodeGen/WebAssembly/wasmehprepare.ll
@@ -132,59 +132,6 @@ try.cont7:                                        ; preds = %try.cont, %catch4
   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 @@ terminate:                                        ; preds = %ehcleanup
 ;   ~Temp() {}
 ; };
 ;
-; void test3() {
+; void test2() {
 ;   int num;
 ;   try {
 ;     Temp t;
@@ -214,8 +161,8 @@ terminate:                                        ; preds = %ehcleanup
 ;     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 @@ try.cont10:                                       ; preds = %invoke.cont3, %catc
 ; 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 @foo()
 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()


        


More information about the llvm-commits mailing list