diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -103,7 +103,7 @@ if (F.isDeclarationForLinker()) { SmallVector Results; SmallVector Params; - computeSignatureVTs(F.getFunctionType(), F, TM, Params, Results); + computeSignatureVTs(F.getFunctionType(), &F, F, TM, Params, Results); auto *Sym = cast(getSymbol(&F)); Sym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); if (!Sym->getSignature()) { @@ -290,7 +290,8 @@ const Function &F = MF->getFunction(); SmallVector ResultVTs; SmallVector ParamVTs; - computeSignatureVTs(F.getFunctionType(), F, TM, ParamVTs, ResultVTs); + computeSignatureVTs(F.getFunctionType(), &F, F, TM, ParamVTs, ResultVTs); + auto Signature = signatureFromMVTs(ResultVTs, ParamVTs); auto *WasmSym = cast(CurrentFnSym); WasmSym->setSignature(Signature.get()); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp @@ -640,6 +640,9 @@ if (F->isVarArg()) return false; + if (FuncInfo.Fn->getCallingConv() == CallingConv::Swift) + return false; + unsigned I = 0; for (auto const &Arg : F->args()) { const AttributeList &Attrs = F->getAttributes(); @@ -754,6 +757,9 @@ if (Func && Func->isIntrinsic()) return false; + if (Call->getCallingConv() == CallingConv::Swift) + return false; + bool IsDirect = Func != nullptr; if (!IsDirect && isa(Call->getCalledValue())) return false; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp @@ -244,6 +244,10 @@ // Collect all the places that need wrappers. for (Function &F : M) { + // Skip to fix when the function is swiftcc because swiftcc allows + // bitcast type difference for swiftself and swifterror. + if (F.getCallingConv() == CallingConv::Swift) + continue; findUses(&F, F, Uses, ConstantBCs); // If we have a "main" function, and its type isn't 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 @@ -765,10 +765,14 @@ std::swap(OutVals[0], OutVals[1]); } + bool HasSwiftSelfArg = false; + bool HasSwiftErrorArg = false; unsigned NumFixedArgs = 0; for (unsigned I = 0; I < Outs.size(); ++I) { const ISD::OutputArg &Out = Outs[I]; SDValue &OutVal = OutVals[I]; + HasSwiftSelfArg |= Out.Flags.isSwiftSelf(); + HasSwiftErrorArg |= Out.Flags.isSwiftError(); if (Out.Flags.isNest()) fail(DL, DAG, "WebAssembly hasn't implemented nest arguments"); if (Out.Flags.isInAlloca()) @@ -798,6 +802,29 @@ bool IsVarArg = CLI.IsVarArg; auto PtrVT = getPointerTy(Layout); + // For swiftcc, emit additional swiftself and swifterror arguments + // if there aren't. These additional arguments are also added for callee + // signature They are necessary to match callee and caller signature for + // indirect call. + if (CallConv == CallingConv::Swift) { + if (!HasSwiftSelfArg) { + NumFixedArgs++; + ISD::OutputArg Arg; + Arg.Flags.setSwiftSelf(); + CLI.Outs.push_back(Arg); + SDValue ArgVal = DAG.getUNDEF(PtrVT); + CLI.OutVals.push_back(ArgVal); + } + if (!HasSwiftErrorArg) { + NumFixedArgs++; + ISD::OutputArg Arg; + Arg.Flags.setSwiftError(); + CLI.Outs.push_back(Arg); + SDValue ArgVal = DAG.getUNDEF(PtrVT); + CLI.OutVals.push_back(ArgVal); + } + } + // Analyze operands of the call, assigning locations to each operand. SmallVector ArgLocs; CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); @@ -960,7 +987,11 @@ // of the incoming values before they're represented by virtual registers. MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS); + bool HasSwiftErrorArg = false; + bool HasSwiftSelfArg = false; for (const ISD::InputArg &In : Ins) { + HasSwiftSelfArg |= In.Flags.isSwiftSelf(); + HasSwiftErrorArg |= In.Flags.isSwiftError(); if (In.Flags.isInAlloca()) fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments"); if (In.Flags.isNest()) @@ -980,6 +1011,19 @@ MFI->addParam(In.VT); } + // For swiftcc, emit additional swiftself and swifterror arguments + // if there aren't. These additional arguments are also added for callee + // signature They are necessary to match callee and caller signature for + // indirect call. + auto PtrVT = getPointerTy(MF.getDataLayout()); + if (CallConv == CallingConv::Swift) { + if (!HasSwiftSelfArg) { + MFI->addParam(PtrVT); + } + if (!HasSwiftErrorArg) { + MFI->addParam(PtrVT); + } + } // Varargs are copied into a buffer allocated by the caller, and a pointer to // the buffer is passed as an argument. if (IsVarArg) { @@ -997,8 +1041,8 @@ // Record the number and types of arguments and results. SmallVector Params; SmallVector Results; - computeSignatureVTs(MF.getFunction().getFunctionType(), MF.getFunction(), - DAG.getTarget(), Params, Results); + computeSignatureVTs(MF.getFunction().getFunctionType(), &MF.getFunction(), + MF.getFunction(), DAG.getTarget(), Params, Results); for (MVT VT : Results) MFI->addResult(VT); // TODO: Use signatures in WebAssemblyMachineFunctionInfo too and unify diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp @@ -56,7 +56,8 @@ SmallVector ResultMVTs; SmallVector ParamMVTs; - computeSignatureVTs(FuncTy, CurrentFunc, TM, ParamMVTs, ResultMVTs); + const auto *const F = dyn_cast(Global); + computeSignatureVTs(FuncTy, F, CurrentFunc, TM, ParamMVTs, ResultMVTs); auto Signature = signatureFromMVTs(ResultMVTs, ParamMVTs); WasmSym->setSignature(Signature.get()); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h b/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h --- a/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h @@ -159,9 +159,10 @@ SmallVectorImpl &ValueVTs); // Compute the signature for a given FunctionType (Ty). Note that it's not the -// signature for F (F is just used to get varous context) -void computeSignatureVTs(const FunctionType *Ty, const Function &F, - const TargetMachine &TM, SmallVectorImpl &Params, +// signature for ContextFunc (ContextFunc is just used to get varous context) +void computeSignatureVTs(const FunctionType *Ty, const Function *TargetFunc, + const Function &ContextFunc, const TargetMachine &TM, + SmallVectorImpl &Params, SmallVectorImpl &Results); void valTypesFromMVTs(const ArrayRef &In, diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp @@ -42,15 +42,17 @@ } } -void llvm::computeSignatureVTs(const FunctionType *Ty, const Function &F, +void llvm::computeSignatureVTs(const FunctionType *Ty, + const Function *TargetFunc, + const Function &ContextFunc, const TargetMachine &TM, SmallVectorImpl &Params, SmallVectorImpl &Results) { - computeLegalValueVTs(F, TM, Ty->getReturnType(), Results); + computeLegalValueVTs(ContextFunc, TM, Ty->getReturnType(), Results); MVT PtrVT = MVT::getIntegerVT(TM.createDataLayout().getPointerSizeInBits()); if (Results.size() > 1 && - !TM.getSubtarget(F).hasMultivalue()) { + !TM.getSubtarget(ContextFunc).hasMultivalue()) { // WebAssembly can't lower returns of multiple values without demoting to // sret unless multivalue is enabled (see // WebAssemblyTargetLowering::CanLowerReturn). So replace multiple return @@ -60,9 +62,28 @@ } for (auto *Param : Ty->params()) - computeLegalValueVTs(F, TM, Param, Params); + computeLegalValueVTs(ContextFunc, TM, Param, Params); if (Ty->isVarArg()) Params.push_back(PtrVT); + + // For swiftcc, emit additional swiftself and swifterror parameters + // if there aren't. These additional parameters are also passed for caller. + // They are necessary to match callee and caller signature for indirect + // call. + + if (TargetFunc && TargetFunc->getCallingConv() == CallingConv::Swift) { + MVT PtrVT = MVT::getIntegerVT(TM.createDataLayout().getPointerSizeInBits()); + bool HasSwiftErrorArg = false; + bool HasSwiftSelfArg = false; + for (const auto &Arg : TargetFunc->args()) { + HasSwiftErrorArg |= Arg.hasAttribute(Attribute::SwiftError); + HasSwiftSelfArg |= Arg.hasAttribute(Attribute::SwiftSelf); + } + if (!HasSwiftErrorArg) + Params.push_back(PtrVT); + if (!HasSwiftSelfArg) + Params.push_back(PtrVT); + } } void llvm::valTypesFromMVTs(const ArrayRef &In, diff --git a/llvm/test/CodeGen/WebAssembly/swiftcc.ll b/llvm/test/CodeGen/WebAssembly/swiftcc.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/swiftcc.ll @@ -0,0 +1,46 @@ +; RUN: llc < %s -asm-verbose=false -wasm-keep-registers | FileCheck %s --check-prefix=REG +; RUN: llc < %s -asm-verbose=false | FileCheck %s + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +; Test direct and indirect function call between mismatched signatures +; CHECK-LABEL: foo: +; CHECK-NEXT: .functype foo (i32, i32, i32, i32) -> () +define swiftcc void @foo(i32, i32) { + ret void +} +@data = global i8* bitcast (void (i32, i32)* @foo to i8*) + +; CHECK-LABEL: bar: +; CHECK-NEXT: .functype bar (i32, i32) -> () +define swiftcc void @bar() { + %1 = load i8*, i8** @data +; REG: call foo, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}} + call swiftcc void @foo(i32 1, i32 2) + + %2 = bitcast i8* %1 to void (i32, i32)* +; REG: call_indirect $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}} +; CHECK: call_indirect (i32, i32, i32, i32) -> () + call swiftcc void %2(i32 1, i32 2) + + %3 = bitcast i8* %1 to void (i32, i32, i32)* +; REG: call_indirect $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}} +; CHECK: call_indirect (i32, i32, i32, i32) -> () + call swiftcc void %3(i32 1, i32 2, i32 swiftself 3) + + %err = alloca swifterror i32*, align 4 + + %4 = bitcast i8* %1 to void (i32, i32, i32**)* +; REG: call_indirect $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}} +; CHECK: call_indirect (i32, i32, i32, i32) -> () + call swiftcc void %4(i32 1, i32 2, i32** swifterror %err) + + %5 = bitcast i8* %1 to void (i32, i32, i32, i32**)* +; REG: call_indirect $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}} +; CHECK: call_indirect (i32, i32, i32, i32) -> () + call swiftcc void %5(i32 1, i32 2, i32 swiftself 3, i32** swifterror %err) + + ret void +} +