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 @@ -291,6 +291,24 @@ SmallVector ResultVTs; SmallVector ParamVTs; computeSignatureVTs(F.getFunctionType(), F, TM, ParamVTs, ResultVTs); + + // For swiftcc, emit additional swiftself and swifterror arguments + // if there aren't. These additional arguments are also added for caller + // signature They are necessary to match callee and caller signature for + // indirect call. + if (F.getCallingConv() == CallingConv::Swift) { + MVT PtrVT = MVT::getIntegerVT(TM.createDataLayout().getPointerSizeInBits()); + bool HasSwiftErrorArg = false; + bool HasSwiftSelfArg = false; + for (const auto &Arg : F.args()) { + HasSwiftErrorArg |= Arg.hasAttribute(Attribute::SwiftError); + HasSwiftSelfArg |= Arg.hasAttribute(Attribute::SwiftSelf); + } + if (!HasSwiftErrorArg) + ParamVTs.push_back(PtrVT); + if (!HasSwiftSelfArg) + ParamVTs.push_back(PtrVT); + } auto Signature = signatureFromMVTs(ResultVTs, ParamVTs); auto *WasmSym = cast(CurrentFnSym); WasmSym->setSignature(Signature.get()); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp @@ -242,6 +242,21 @@ // Start assigning local numbers after the last parameter. unsigned CurLocal = static_cast(MFI.getParams().size()); + // For swiftcc, additional swiftself and swifterror paramsters are added + // if there aren't. Forward the cursor for the extra parameters. + if (MF.getFunction().getCallingConv() == CallingConv::Swift) { + bool HasSwiftErrorArg = false; + bool HasSwiftSelfArg = false; + for (const auto &Arg : MF.getFunction().args()) { + HasSwiftErrorArg |= Arg.hasAttribute(Attribute::SwiftError); + HasSwiftSelfArg |= Arg.hasAttribute(Attribute::SwiftSelf); + } + if (!HasSwiftErrorArg) + CurLocal++; + if (!HasSwiftSelfArg) + CurLocal++; + } + // Precompute the set of registers that are unused, so that we can insert // drops to their defs. BitVector UseEmpty(MRI.getNumVirtRegs()); 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) { @@ -999,6 +1043,12 @@ SmallVector Results; computeSignatureVTs(MF.getFunction().getFunctionType(), MF.getFunction(), DAG.getTarget(), Params, Results); + if (CallConv == CallingConv::Swift) { + if (!HasSwiftErrorArg) + Params.push_back(PtrVT); + if (!HasSwiftSelfArg) + Params.push_back(PtrVT); + } 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 @@ -58,6 +58,26 @@ SmallVector ParamMVTs; computeSignatureVTs(FuncTy, CurrentFunc, TM, ParamMVTs, ResultMVTs); + // 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. + const auto *const F = dyn_cast(Global); + if (F && F->getCallingConv() == CallingConv::Swift) { + MVT PtrVT = + MVT::getIntegerVT(TM.createDataLayout().getPointerSizeInBits()); + bool HasSwiftErrorArg = false; + bool HasSwiftSelfArg = false; + for (const auto &Arg : F->args()) { + HasSwiftErrorArg |= Arg.hasAttribute(Attribute::SwiftError); + HasSwiftSelfArg |= Arg.hasAttribute(Attribute::SwiftSelf); + } + if (!HasSwiftErrorArg) + ParamMVTs.push_back(PtrVT); + if (!HasSwiftSelfArg) + ParamMVTs.push_back(PtrVT); + } + auto Signature = signatureFromMVTs(ResultMVTs, ParamMVTs); WasmSym->setSignature(Signature.get()); Printer.addSignature(std::move(Signature)); 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,23 @@ +; 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 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) -> () +; CHECK: call_indirect (i32, i32, i32, i32) -> () +define swiftcc void @bar() { + %1 = load i8*, i8** @data + %2 = bitcast i8* %1 to void (i32, i32, i32)* + call swiftcc void %2(i32 1, i32 2, i32 swiftself 3) + ret void +} +