Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WebAssembly] Don't return multivalue when Emscripten EH/SjLj is used #86048

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 4 additions & 9 deletions llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<MCSymbolWasm>(
GetExternalSymbolSymbol(getEmscriptenInvokeSymbolName(Sig)));
} else {
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1288,15 +1288,15 @@ bool WebAssemblyTargetLowering::CanLowerReturn(
const SmallVectorImpl<ISD::OutputArg> &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(
SDValue Chain, CallingConv::ID CallConv, bool /*IsVarArg*/,
const SmallVectorImpl<ISD::OutputArg> &Outs,
const SmallVectorImpl<SDValue> &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");
Expand Down
11 changes: 6 additions & 5 deletions llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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<WebAssemblySubtarget>(ContextFunc).hasMultivalue()) {
if (!WebAssembly::canLowerReturn(
Results.size(),
&TM.getSubtarget<WebAssemblySubtarget>(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);
}
Expand Down
14 changes: 14 additions & 0 deletions llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
5 changes: 5 additions & 0 deletions llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
36 changes: 29 additions & 7 deletions llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj-multi-return.ll
Original file line number Diff line number Diff line change
@@ -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

tlively marked this conversation as resolved.
Show resolved Hide resolved
; 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"

Expand Down Expand Up @@ -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()
Expand All @@ -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
Loading