diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp --- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp +++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp @@ -213,7 +213,7 @@ if (popType(ErrorLoc, {})) return true; } else if (Name == "end_block" || Name == "end_loop" || Name == "end_if" || - Name == "else") { + Name == "else" || Name == "end_try") { if (checkEnd(ErrorLoc)) return true; } else if (Name == "call_indirect" || Name == "return_call_indirect") { @@ -230,6 +230,18 @@ return typeError(ErrorLoc, StringRef("symbol ") + WasmSym->getName() + " missing .functype"); if (checkSig(ErrorLoc, *Sig)) return true; + } else if (Name == "catch") { + const MCSymbolRefExpr *SymRef; + if (getSymRef(ErrorLoc, Inst, SymRef)) + return true; + auto WasmSym = cast(&SymRef->getSymbol()); + auto Sig = WasmSym->getSignature(); + if (!Sig || WasmSym->getType() != wasm::WASM_SYMBOL_TYPE_TAG) + return typeError(ErrorLoc, StringRef("symbol ") + WasmSym->getName() + + " missing .tagtype"); + // catch instruction pushes values whose types are specified in the tag's + // "params" part + Stack.insert(Stack.end(), Sig->Params.begin(), Sig->Params.end()); } else if (Name == "ref.null") { auto VT = static_cast(Inst.getOperand(0).getImm()); Stack.push_back(VT); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISD.def b/llvm/lib/Target/WebAssembly/WebAssemblyISD.def --- a/llvm/lib/Target/WebAssembly/WebAssemblyISD.def +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISD.def @@ -41,8 +41,6 @@ HANDLE_NODETYPE(TRUNC_SAT_ZERO_S) HANDLE_NODETYPE(TRUNC_SAT_ZERO_U) HANDLE_NODETYPE(DEMOTE_ZERO) -HANDLE_NODETYPE(THROW) -HANDLE_NODETYPE(CATCH) HANDLE_NODETYPE(MEMORY_COPY) HANDLE_NODETYPE(MEMORY_FILL) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp @@ -17,6 +17,7 @@ #include "WebAssemblyTargetMachine.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/CodeGen/WasmEHFuncInfo.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/Function.h" // To access function attributes. #include "llvm/IR/IntrinsicsWebAssembly.h" @@ -87,6 +88,19 @@ SelectionDAGISel::PreprocessISelDAG(); } +static SDValue getTagSymNode(SDValue Op, unsigned TagIndex, SelectionDAG *DAG) { + int Tag = + cast(Op.getOperand(TagIndex).getNode())->getZExtValue(); + assert(Tag == WebAssembly::CPP_EXCEPTION || Tag == WebAssembly::C_LONGJMP); + auto &MF = DAG->getMachineFunction(); + const auto &TLI = DAG->getTargetLoweringInfo(); + MVT PtrVT = TLI.getPointerTy(DAG->getDataLayout()); + const char *SymName = Tag == WebAssembly::CPP_EXCEPTION + ? MF.createExternalSymbolName("__cpp_exception") + : MF.createExternalSymbolName("__c_longjmp"); + return DAG->getTargetExternalSymbol(SymName, PtrVT); +} + void WebAssemblyDAGToDAGISel::Select(SDNode *Node) { // If we have a custom node, we already have selected! if (Node->isMachineOpcode()) { @@ -151,6 +165,7 @@ ReplaceNode(Node, TLSSize); return; } + case Intrinsic::wasm_tls_align: { MachineSDNode *TLSAlign = CurDAG->getMachineNode( GlobalGetIns, DL, PtrVT, @@ -161,8 +176,11 @@ } break; } + case ISD::INTRINSIC_W_CHAIN: { unsigned IntNo = cast(Node->getOperand(1))->getZExtValue(); + const auto &TLI = CurDAG->getTargetLoweringInfo(); + MVT PtrVT = TLI.getPointerTy(CurDAG->getDataLayout()); switch (IntNo) { case Intrinsic::wasm_tls_base: { MachineSDNode *TLSBase = CurDAG->getMachineNode( @@ -172,9 +190,46 @@ ReplaceNode(Node, TLSBase); return; } + + case Intrinsic::wasm_catch_exn: { + SDValue SymNode = getTagSymNode(SDValue(Node, 0), 2, CurDAG); + MachineSDNode *Catch = + CurDAG->getMachineNode(WebAssembly::CATCH, DL, + { + PtrVT, // exception pointer + MVT::Other // outchain type + }, + { + SymNode, // exception symbol + Node->getOperand(0) // inchain + }); + ReplaceNode(Node, Catch); + return; + } } break; } + + case ISD::INTRINSIC_VOID: { + unsigned IntNo = cast(Node->getOperand(1))->getZExtValue(); + switch (IntNo) { + case Intrinsic::wasm_throw: { + SDValue SymNode = getTagSymNode(SDValue(Node, 0), 2, CurDAG); + MachineSDNode *Throw = + CurDAG->getMachineNode(WebAssembly::THROW, DL, + MVT::Other, // outchain type + { + SymNode, // exception symbol + Node->getOperand(3), // thrown value + Node->getOperand(0) // inchain + }); + ReplaceNode(Node, Throw); + return; + } + } + break; + } + case WebAssemblyISD::CALL: case WebAssemblyISD::RET_CALL: { // CALL has both variable operands and variable results, but ISel only diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -25,7 +25,6 @@ #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/CodeGen/SelectionDAGNodes.h" -#include "llvm/CodeGen/WasmEHFuncInfo.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/Function.h" @@ -1665,21 +1664,6 @@ MachinePointerInfo(SV)); } -static SDValue getCppExceptionSymNode(SDValue Op, unsigned TagIndex, - SelectionDAG &DAG) { - // We only support C++ exceptions for now - int Tag = - cast(Op.getOperand(TagIndex).getNode())->getZExtValue(); - if (Tag != WebAssembly::CPP_EXCEPTION) - llvm_unreachable("Invalid tag: We only support C++ exceptions for now"); - auto &MF = DAG.getMachineFunction(); - const auto &TLI = DAG.getTargetLoweringInfo(); - MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout()); - const char *SymName = MF.createExternalSymbolName("__cpp_exception"); - return DAG.getNode(WebAssemblyISD::Wrapper, SDLoc(Op), PtrVT, - DAG.getTargetExternalSymbol(SymName, PtrVT)); -} - SDValue WebAssemblyTargetLowering::LowerIntrinsic(SDValue Op, SelectionDAG &DAG) const { MachineFunction &MF = DAG.getMachineFunction(); @@ -1712,30 +1696,6 @@ DAG.getMCSymbol(S, PtrVT)); } - case Intrinsic::wasm_throw: { - SDValue SymNode = getCppExceptionSymNode(Op, 2, DAG); - return DAG.getNode(WebAssemblyISD::THROW, DL, - MVT::Other, // outchain type - { - Op.getOperand(0), // inchain - SymNode, // exception symbol - Op.getOperand(3) // thrown value - }); - } - - case Intrinsic::wasm_catch_exn: { - SDValue SymNode = getCppExceptionSymNode(Op, 2, DAG); - return DAG.getNode(WebAssemblyISD::CATCH, DL, - { - MVT::i32, // outchain type - MVT::Other // return value - }, - { - Op.getOperand(0), // inchain - SymNode // exception symbol - }); - } - case Intrinsic::wasm_shuffle: { // Drop in-chain and replace undefs, but otherwise pass through unchanged SDValue Ops[18]; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td @@ -130,8 +130,7 @@ // Throwing an exception: throw / rethrow let isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in { defm THROW : I<(outs), (ins tag_op:$tag, variable_ops), - (outs), (ins tag_op:$tag), - [(WebAssemblythrow (WebAssemblywrapper texternalsym:$tag))], + (outs), (ins tag_op:$tag), [], "throw \t$tag", "throw \t$tag", 0x08>; defm RETHROW : NRI<(outs), (ins i32imm:$depth), [], "rethrow \t$depth", 0x09>; } // isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 @@ -147,14 +146,10 @@ // Catching an exception: catch / catch_all let hasCtrlDep = 1, hasSideEffects = 1 in { -// Currently 'catch' can only extract an i32, which is sufficient for C++ -// support, but according to the spec 'catch' can extract any number of values -// based on the tag type. -defm CATCH : I<(outs I32:$dst), (ins tag_op:$tag), - (outs), (ins tag_op:$tag), - [(set I32:$dst, - (WebAssemblycatch (WebAssemblywrapper texternalsym:$tag)))], - "catch \t$dst, $tag", "catch \t$tag", 0x07>; +let variadicOpsAreDefs = 1 in +defm CATCH : I<(outs), (ins tag_op:$tag, variable_ops), + (outs), (ins tag_op:$tag), [], + "catch", "catch \t$tag", 0x07>; defm CATCH_ALL : NRI<(outs), (ins), [], "catch_all", 0x19>; } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td @@ -79,8 +79,6 @@ SDTCisPtrTy<0>]>; def SDT_WebAssemblyWrapperPIC : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, SDTCisPtrTy<0>]>; -def SDT_WebAssemblyThrow : SDTypeProfile<0, -1, []>; -def SDT_WebAssemblyCatch : SDTypeProfile<1, 1, [SDTCisPtrTy<0>]>; def SDT_WebAssemblyGlobalGet : SDTypeProfile<1, 1, [SDTCisPtrTy<1>]>; def SDT_WebAssemblyGlobalSet : SDTypeProfile<0, 2, [SDTCisPtrTy<1>]>; @@ -106,10 +104,6 @@ SDT_WebAssemblyWrapper>; def WebAssemblywrapperPIC : SDNode<"WebAssemblyISD::WrapperPIC", SDT_WebAssemblyWrapperPIC>; -def WebAssemblythrow : SDNode<"WebAssemblyISD::THROW", SDT_WebAssemblyThrow, - [SDNPHasChain, SDNPVariadic]>; -def WebAssemblycatch : SDNode<"WebAssemblyISD::CATCH", SDT_WebAssemblyCatch, - [SDNPHasChain, SDNPSideEffect]>; def WebAssemblyglobal_get : SDNode<"WebAssemblyISD::GLOBAL_GET", SDT_WebAssemblyGlobalGet, [SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>;