summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
diff options
context:
space:
mode:
authorHeejin Ahn <aheejin@gmail.com>2019-01-30 03:21:57 +0000
committerHeejin Ahn <aheejin@gmail.com>2019-01-30 03:21:57 +0000
commitd6f487863dc951d467b545b86b9ea62980569b5a (patch)
treef0e3f8ee6a6f6060ed36e9b63320fbd2499f93df /llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
parent6d8e1b456a23d6c75be160fc67b0889e2bfe2170 (diff)
downloadbcm5719-llvm-d6f487863dc951d467b545b86b9ea62980569b5a.tar.gz
bcm5719-llvm-d6f487863dc951d467b545b86b9ea62980569b5a.zip
[WebAssembly] Exception handling: Switch to the new proposal
Summary: This switches the EH implementation to the new proposal: https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md (The previous proposal was https://github.com/WebAssembly/exception-handling/blob/master/proposals/old/Exceptions.md) - Instruction changes - Now we have one single `catch` instruction that returns a except_ref value - `throw` now can take variable number of operations - `rethrow` does not have 'depth' argument anymore - `br_on_exn` queries an except_ref to see if it matches the tag and branches to the given label if true. - `extract_exception` is a pseudo instruction that simulates popping values from wasm stack. This is to make `br_on_exn`, a very special instruction, work: `br_on_exn` puts values onto the stack only if it is taken, and the # of values can vay depending on the tag. - Now there's only one `catch` per `try`, this patch removes all special handling for terminate pad with a call to `__clang_call_terminate`. Before it was the only case there are two catch clauses (a normal `catch` and `catch_all` per `try`). - Make `rethrow` act as a terminator like `throw`. This splits BB after `rethrow` in WasmEHPrepare, and deletes an unnecessary `unreachable` after `rethrow` in LateEHPrepare. - Now we stop at all catchpads (because we add wasm `catch` instruction that catches all exceptions), this creates new `findWasmUnwindDestinations` function in SelectionDAGBuilder. - Now we use `br_on_exn` instrution to figure out if an except_ref matches the current tag or not, LateEHPrepare generates this sequence for catch pads: ``` catch block i32 br_on_exn $__cpp_exception end_block extract_exception ``` - Branch analysis for `br_on_exn` in WebAssemblyInstrInfo - Other various misc. changes to switch to the new proposal. Reviewers: dschuff Subscribers: sbc100, jgravelle-google, sunfish, llvm-commits Differential Revision: https://reviews.llvm.org/D57134 llvm-svn: 352598
Diffstat (limited to 'llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp')
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp88
1 files changed, 33 insertions, 55 deletions
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
index 6b30f31ab1d..566b9a5e460 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
@@ -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::createWebAssemblyCFGStackify() {
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::placeBlockMarker(MachineBasicBlock &MBB) {
// 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::placeBlockMarker(MachineBasicBlock &MBB) {
}
// 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::placeTryMarker(MachineBasicBlock &MBB) {
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::placeTryMarker(MachineBasicBlock &MBB) {
// 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(MachineFunction &MF,
/// 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::placeMarkers(MachineFunction &MF) {
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::placeMarkers(MachineFunction &MF) {
}
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::rewriteDepthImmediates(MachineFunction &MF) {
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::rewriteDepthImmediates(MachineFunction &MF) {
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.
OpenPOWER on IntegriCloud