diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp index 03897b551ecaee9..c6c7bf1cacda40d 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -151,19 +151,14 @@ static std::string getEmscriptenInvokeSymbolName(wasm::WasmSignature *Sig) { //===----------------------------------------------------------------------===// MCSymbolWasm *WebAssemblyAsmPrinter::getMCSymbolForFunction( - const Function *F, bool EnableEmEH, wasm::WasmSignature *Sig, + const Function *F, bool EnableEmEHSjLj, wasm::WasmSignature *Sig, bool &InvokeDetected) { MCSymbolWasm *WasmSym = nullptr; - if (EnableEmEH && isEmscriptenInvokeName(F->getName())) { + if (EnableEmEHSjLj && isEmscriptenInvokeName(F->getName())) { assert(Sig); InvokeDetected = true; - if (Sig->Returns.size() > 1) { - std::string Msg = - "Emscripten EH/SjLj does not support multivalue returns: " + - std::string(F->getName()) + ": " + - WebAssembly::signatureToString(Sig); - report_fatal_error(Twine(Msg)); - } + // When Emscripten EH/SjLj is enabled, we don't enable multivalue returns + assert(Sig->Returns.size() <= 1); WasmSym = cast( GetExternalSymbolSymbol(getEmscriptenInvokeSymbolName(Sig))); } else { diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h index c30e0155c81e720..4892df1f22485d8 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h @@ -81,7 +81,7 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyAsmPrinter final : public AsmPrinter { MVT getRegType(unsigned RegNo) const; std::string regToString(const MachineOperand &MO); WebAssemblyTargetStreamer *getTargetStreamer(); - MCSymbolWasm *getMCSymbolForFunction(const Function *F, bool EnableEmEH, + MCSymbolWasm *getMCSymbolForFunction(const Function *F, bool EnableEmEHSjLj, wasm::WasmSignature *Sig, bool &InvokeDetected); MCSymbol *getOrCreateWasmSymbol(StringRef Name); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp index 905ff3b9018428b..64bcadf3f5677cc 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -1288,7 +1288,7 @@ bool WebAssemblyTargetLowering::CanLowerReturn( const SmallVectorImpl &Outs, LLVMContext & /*Context*/) const { // WebAssembly can only handle returning tuples with multivalue enabled - return Subtarget->hasMultivalue() || Outs.size() <= 1; + return WebAssembly::canLowerReturn(Outs.size(), Subtarget); } SDValue WebAssemblyTargetLowering::LowerReturn( @@ -1296,7 +1296,7 @@ SDValue WebAssemblyTargetLowering::LowerReturn( const SmallVectorImpl &Outs, const SmallVectorImpl &OutVals, const SDLoc &DL, SelectionDAG &DAG) const { - assert((Subtarget->hasMultivalue() || Outs.size() <= 1) && + assert(WebAssembly::canLowerReturn(Outs.size(), Subtarget) && "MVP WebAssembly can only return up to one value"); if (!callingConvSupported(CallConv)) fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions"); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp index 1e959111a4dbcb5..4da7fc9e7bb4a1e 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp @@ -17,6 +17,7 @@ #include "Utils/WebAssemblyTypeUtilities.h" #include "WebAssemblyISelLowering.h" #include "WebAssemblySubtarget.h" +#include "WebAssemblyUtilities.h" #include "llvm/CodeGen/Analysis.h" #include "llvm/CodeGen/WasmEHFuncInfo.h" #include "llvm/Target/TargetMachine.h" @@ -70,12 +71,12 @@ void llvm::computeSignatureVTs(const FunctionType *Ty, computeLegalValueVTs(ContextFunc, TM, Ty->getReturnType(), Results); MVT PtrVT = MVT::getIntegerVT(TM.createDataLayout().getPointerSizeInBits()); - if (Results.size() > 1 && - !TM.getSubtarget(ContextFunc).hasMultivalue()) { + if (!WebAssembly::canLowerReturn( + Results.size(), + &TM.getSubtarget(ContextFunc))) { // WebAssembly can't lower returns of multiple values without demoting to - // sret unless multivalue is enabled (see - // WebAssemblyTargetLowering::CanLowerReturn). So replace multiple return - // values with a poitner parameter. + // sret unless multivalue is enabled (see WebAssembly::canLowerReturn). So + // replace multiple return values with a pointer parameter. Results.clear(); Params.push_back(PtrVT); } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp index ac7cf5b37fcaa49..f09700ec7c05277 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp @@ -179,3 +179,17 @@ unsigned WebAssembly::getCopyOpcodeForRegClass(const TargetRegisterClass *RC) { llvm_unreachable("Unexpected register class"); } } + +bool WebAssembly::canLowerReturn(size_t ResultSize, + const WebAssemblySubtarget *Subtarget) { + // We don't return multivalues when either of Emscripten EH or Emscripten SjLj + // is used. JS invoke wrapper functions, which are used in Emscripten EH/SjLj, + // don't support multiple return values, and the functions indirectly called + // from those JS invoke wrapper functions can't be lowered using multivalue + // results because they have to match the signature of the JS invoke wrappers. + // We can come up with a precise set of functions that are called from the JS + // wrappers if we do some bookeeping, but given that Emscripten EH/SjLj is an + // old feature whose use is expected to decline, we don't think it's worth it. + return ResultSize <= 1 || (Subtarget->hasMultivalue() && + !WebAssembly::WasmEnableEmEH && !WasmEnableEmSjLj); +} diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h index 7f28fb1858a6908..b430edba4627aeb 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h @@ -63,6 +63,11 @@ MachineInstr *findCatch(MachineBasicBlock *EHPad); /// Returns the appropriate copy opcode for the given register class. unsigned getCopyOpcodeForRegClass(const TargetRegisterClass *RC); +/// Returns true if the function's return value(s) can be lowered directly, +/// i.e., not indirectly via a pointer parameter that points to the value in +/// memory. +bool canLowerReturn(size_t ResultSize, const WebAssemblySubtarget *Subtarget); + } // end namespace WebAssembly } // end namespace llvm diff --git a/llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj-multi-return.ll b/llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj-multi-return.ll index 4f33439db770dc0..714da63c3c026dd 100644 --- a/llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj-multi-return.ll +++ b/llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj-multi-return.ll @@ -1,8 +1,8 @@ -; RUN: not --crash llc < %s -enable-emscripten-cxx-exceptions -mattr=+multivalue 2>&1 | FileCheck %s --check-prefix=EH -; RUN: not --crash llc < %s -enable-emscripten-sjlj -mattr=+multivalue 2>&1 | FileCheck %s --check-prefix=SJLJ +; RUN: llc < %s -enable-emscripten-cxx-exceptions -enable-emscripten-sjlj -mattr=+multivalue | FileCheck %s -; Currently multivalue returning functions are not supported in Emscripten EH / -; SjLj. Make sure they error out. +; Even with multivalue feature enabled, we don't enable multivalue returns when +; Emscripten EH/SjLj is used. Also the invoke wrappers' (e.g. invoke_vi) +; signature should not change. target triple = "wasm32-unknown-unknown" @@ -35,7 +35,32 @@ entry: unreachable } +define void @invoke_i128() personality ptr @__gxx_personality_v0 { +entry: + invoke i128 @get_i128() + to label %try.cont unwind label %lpad + +lpad: ; preds = %entry + %1 = landingpad { ptr, i32 } + catch ptr null + %2 = extractvalue { ptr, i32 } %1, 0 + %3 = extractvalue { ptr, i32 } %1, 1 + %4 = call ptr @__cxa_begin_catch(ptr %2) + call void @__cxa_end_catch() + br label %try.cont + +try.cont: ; preds = %entry, %lpad + ret void +} + declare {i32, i32} @foo(i32) +; CHECK-DAG: .functype foo (i32, i32) -> () +; CHECK-DAG: .functype invoke_vi (i32, i32) -> () + +declare i128 @get_i128() +; CHECK-DAG: .functype get_i128 (i32) -> () +; CHECK-DAG: .functype invoke_vii (i32, i32, i32) -> () + declare i32 @__gxx_personality_v0(...) declare ptr @__cxa_begin_catch(ptr) declare void @__cxa_end_catch() @@ -49,6 +74,3 @@ declare void @free(ptr) attributes #0 = { returns_twice } attributes #1 = { noreturn } attributes #2 = { nounwind } - -; EH: LLVM ERROR: Emscripten EH/SjLj does not support multivalue returns -; SJLJ: LLVM ERROR: Emscripten EH/SjLj does not support multivalue returns