diff options
Diffstat (limited to 'llvm/lib/Target/WebAssembly')
11 files changed, 142 insertions, 11 deletions
diff --git a/llvm/lib/Target/WebAssembly/CMakeLists.txt b/llvm/lib/Target/WebAssembly/CMakeLists.txt index 41b7694b97f..b22b8696247 100644 --- a/llvm/lib/Target/WebAssembly/CMakeLists.txt +++ b/llvm/lib/Target/WebAssembly/CMakeLists.txt @@ -18,6 +18,7 @@ add_llvm_target(WebAssemblyCodeGen WebAssemblyCallIndirectFixup.cpp WebAssemblyCFGStackify.cpp WebAssemblyCFGSort.cpp + WebAssemblyExceptionPrepare.cpp WebAssemblyExplicitLocals.cpp WebAssemblyFastISel.cpp WebAssemblyFixIrreducibleControlFlow.cpp diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.h b/llvm/lib/Target/WebAssembly/WebAssembly.h index 10a0a606d2b..5e67e8df576 100644 --- a/llvm/lib/Target/WebAssembly/WebAssembly.h +++ b/llvm/lib/Target/WebAssembly/WebAssembly.h @@ -46,6 +46,7 @@ FunctionPass *createWebAssemblyRegStackify(); FunctionPass *createWebAssemblyRegColoring(); FunctionPass *createWebAssemblyExplicitLocals(); FunctionPass *createWebAssemblyFixIrreducibleControlFlow(); +FunctionPass *createWebAssemblyExceptionPrepare(); FunctionPass *createWebAssemblyCFGSort(); FunctionPass *createWebAssemblyCFGStackify(); FunctionPass *createWebAssemblyLowerBrUnless(); @@ -68,6 +69,7 @@ void initializeWebAssemblyRegStackifyPass(PassRegistry &); void initializeWebAssemblyRegColoringPass(PassRegistry &); void initializeWebAssemblyExplicitLocalsPass(PassRegistry &); void initializeWebAssemblyFixIrreducibleControlFlowPass(PassRegistry &); +void initializeWebAssemblyExceptionPreparePass(PassRegistry &); void initializeWebAssemblyCFGSortPass(PassRegistry &); void initializeWebAssemblyCFGStackifyPass(PassRegistry &); void initializeWebAssemblyLowerBrUnlessPass(PassRegistry &); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp index 1245ac03727..a53fe28d264 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp @@ -145,9 +145,6 @@ static void PlaceBlockMarker( std::prev(InsertPos)->getOpcode() != WebAssembly::END_LOOP) --InsertPos; } - // The header block in which a 'block' mark will be inserted should have a - // terminator because it is branching to a non-layout successor. - assert(InsertPos != Header->end()); // Add the BLOCK. MachineInstr *Begin = diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyExceptionPrepare.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyExceptionPrepare.cpp new file mode 100644 index 00000000000..837e9576c85 --- /dev/null +++ b/llvm/lib/Target/WebAssembly/WebAssemblyExceptionPrepare.cpp @@ -0,0 +1,88 @@ +//=== WebAssemblyExceptionPrepare.cpp - WebAssembly Exception Preparation -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Does various transformations for exception handling. +/// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" +#include "WebAssembly.h" +#include "WebAssemblySubtarget.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +using namespace llvm; + +#define DEBUG_TYPE "wasm-exception-prepare" + +namespace { +class WebAssemblyExceptionPrepare final : public MachineFunctionPass { + StringRef getPassName() const override { + return "WebAssembly Prepare Exception"; + } + + bool runOnMachineFunction(MachineFunction &MF) override; + + bool replaceFuncletReturns(MachineFunction &MF); + +public: + static char ID; // Pass identification, replacement for typeid + WebAssemblyExceptionPrepare() : MachineFunctionPass(ID) {} +}; +} // end anonymous namespace + +char WebAssemblyExceptionPrepare::ID = 0; +INITIALIZE_PASS(WebAssemblyExceptionPrepare, DEBUG_TYPE, + "WebAssembly Exception Preparation", false, false) + +FunctionPass *llvm::createWebAssemblyExceptionPrepare() { + return new WebAssemblyExceptionPrepare(); +} + +bool WebAssemblyExceptionPrepare::runOnMachineFunction(MachineFunction &MF) { + bool Changed = false; + if (!MF.getFunction().hasPersonalityFn()) + return false; + Changed |= replaceFuncletReturns(MF); + // TODO More transformations will be added + return Changed; +} + +bool WebAssemblyExceptionPrepare::replaceFuncletReturns(MachineFunction &MF) { + bool Changed = false; + const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); + + for (auto &MBB : MF) { + auto Pos = MBB.getFirstTerminator(); + if (Pos == MBB.end()) + continue; + MachineInstr *TI = &*Pos; + + switch (TI->getOpcode()) { + case WebAssembly::CATCHRET: { + // Replace a catchret with a branch + MachineBasicBlock *TBB = TI->getOperand(0).getMBB(); + if (!MBB.isLayoutSuccessor(TBB)) + BuildMI(MBB, TI, TI->getDebugLoc(), TII.get(WebAssembly::BR)) + .addMBB(TBB); + TI->eraseFromParent(); + Changed = true; + break; + } + case WebAssembly::CLEANUPRET: { + // Replace a cleanupret with a rethrow + BuildMI(MBB, TI, TI->getDebugLoc(), TII.get(WebAssembly::RETHROW)) + .addImm(0); + TI->eraseFromParent(); + Changed = true; + break; + } + } + } + return Changed; +} diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp index d7d49e039c3..52b1e18c8a4 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -151,6 +151,9 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering( // Trap lowers to wasm unreachable setOperationAction(ISD::TRAP, MVT::Other, Legal); + // Exception handling intrinsics + setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); + setMaxAtomicSizeInBitsSupported(64); } @@ -737,6 +740,8 @@ SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op, return LowerFRAMEADDR(Op, DAG); case ISD::CopyToReg: return LowerCopyToReg(Op, DAG); + case ISD::INTRINSIC_WO_CHAIN: + return LowerINTRINSIC_WO_CHAIN(Op, DAG); } } @@ -869,6 +874,21 @@ SDValue WebAssemblyTargetLowering::LowerVASTART(SDValue Op, MachinePointerInfo(SV), 0); } +SDValue +WebAssemblyTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, + SelectionDAG &DAG) const { + unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue(); + SDLoc DL(Op); + switch (IntNo) { + default: + return {}; // Don't custom lower most intrinsics. + + case Intrinsic::wasm_lsda: + // TODO For now, just return 0 not to crash + return DAG.getConstant(0, DL, Op.getValueType()); + } +} + //===----------------------------------------------------------------------===// // WebAssembly Optimization Hooks //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h index 3e9759eece8..ba42d20a2c7 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h @@ -90,6 +90,7 @@ class WebAssemblyTargetLowering final : public TargetLowering { 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; }; namespace WebAssembly { diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td index d59aba40d8d..98e15361048 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td @@ -140,9 +140,25 @@ def TRY : I<(outs), (ins Signature:$sig), [], "try \t$sig", 0x06>; def END_TRY : I<(outs), (ins), [], "end_try", 0x0b>; } // Uses = [VALUE_STACK], Defs = [VALUE_STACK] -} // Defs = [ARGUMENTS] +// Catching an exception: catch / catch_all +let hasCtrlDep = 1 in { +def CATCH_I32 : I<(outs I32:$dst), (ins i32imm:$tag), + [(set I32:$dst, (int_wasm_catch imm:$tag))], + "i32.catch \t$dst, $tag", 0x07>; +def CATCH_I64 : I<(outs I64:$dst), (ins i32imm:$tag), + [(set I64:$dst, (int_wasm_catch imm:$tag))], + "i64.catch \t$dst, $tag", 0x07>; +def CATCH_ALL : I<(outs), (ins), [], "catch_all", 0x05>; +} -// rethrow takes a relative depth as an argument, for which currently only 0 is -// possible for C++. Once other languages need depths other than 0, depths will -// be computed in CFGStackify. -def : Pat<(int_wasm_rethrow), (RETHROW 0)>; +// Pseudo instructions: cleanupret / catchret +// They are not return instructions in wasm, but setting 'isReturn' to true as +// in X86 is necessary for computing funclet membership. +let isTerminator = 1, hasSideEffects = 1, isBarrier = 1, hasCtrlDep = 1, + isCodeGenOnly = 1, isReturn = 1 in { + def CLEANUPRET : I<(outs), (ins), [(cleanupret)], "", 0>; + def CATCHRET : I<(outs), (ins bb_op:$dst, bb_op:$from), + [(catchret bb:$dst, bb:$from)], "", 0>; +} + +} // Defs = [ARGUMENTS] diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp index fbdf4c011a9..cd49bd1682a 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp @@ -30,7 +30,8 @@ using namespace llvm; WebAssemblyInstrInfo::WebAssemblyInstrInfo(const WebAssemblySubtarget &STI) : WebAssemblyGenInstrInfo(WebAssembly::ADJCALLSTACKDOWN, - WebAssembly::ADJCALLSTACKUP), + WebAssembly::ADJCALLSTACKUP, + WebAssembly::CATCHRET), RI(STI.getTargetTriple()) {} bool WebAssemblyInstrInfo::isReallyTriviallyReMaterializable( diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp index 0b71edae3ce..dc51d7aa3df 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp @@ -160,10 +160,9 @@ static void QueryCallee(const MachineInstr &MI, unsigned CalleeOpNo, bool &Read, // and/or uses the stack pointer value. static void Query(const MachineInstr &MI, AliasAnalysis &AA, bool &Read, bool &Write, bool &Effects, bool &StackPointer) { - assert(!MI.isPosition()); assert(!MI.isTerminator()); - if (MI.isDebugInstr()) + if (MI.isDebugInstr() || MI.isPosition()) return; // Check for loads. diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.h b/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.h index 4be8d40593c..2a73dfd4b06 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.h @@ -45,6 +45,8 @@ public: const TargetRegisterClass * getPointerRegClass(const MachineFunction &MF, unsigned Kind = 0) const override; + // This does not apply to wasm. + const uint32_t *getNoPreservedMask() const override { return nullptr; } }; } // end namespace llvm diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp index 3349b6f8cd0..56449a74351 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -65,6 +65,7 @@ extern "C" void LLVMInitializeWebAssemblyTarget() { initializeWebAssemblyRegColoringPass(PR); initializeWebAssemblyExplicitLocalsPass(PR); initializeWebAssemblyFixIrreducibleControlFlowPass(PR); + initializeWebAssemblyExceptionPreparePass(PR); initializeWebAssemblyCFGSortPass(PR); initializeWebAssemblyCFGStackifyPass(PR); initializeWebAssemblyLowerBrUnlessPass(PR); @@ -320,6 +321,9 @@ void WebAssemblyPassConfig::addPreEmitPass() { // Insert explicit get_local and set_local operators. addPass(createWebAssemblyExplicitLocals()); + // Do various transformations for exception handling + addPass(createWebAssemblyExceptionPrepare()); + // Sort the blocks of the CFG into topological order, a prerequisite for // BLOCK and LOOP markers. addPass(createWebAssemblyCFGSort()); |