From b15b427ffcbbfe4e7ddf409820e7f90b215176b0 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 12 Mar 2020 08:27:54 +0000 Subject: [PATCH] Support swiftself and swifterror for WebAssembly Support signature difference for swiftself and swifterror when cc is swiftcc. e.g. ```llvm declare swiftcc void @foo(i32, i32) @data = global i8* bitcast (void (i32, i32)* @foo to i8*) 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 } ``` For swiftcc, emit additional swiftself and swifterror parameters if there aren't while lowering. These additional parameters are added for both callee and caller. They are necessary to match callee and caller signature for indirect call. --- .../WebAssembly/WebAssemblyAsmPrinter.cpp | 18 +++++++ .../WebAssembly/WebAssemblyExplicitLocals.cpp | 15 ++++++ .../WebAssembly/WebAssemblyFastISel.cpp | 6 +++ .../WebAssemblyFixFunctionBitcasts.cpp | 4 ++ .../WebAssembly/WebAssemblyISelLowering.cpp | 50 +++++++++++++++++++ .../WebAssembly/WebAssemblyMCInstLower.cpp | 20 ++++++++ llvm/test/CodeGen/WebAssembly/swiftcc.ll | 23 +++++++++ 7 files changed, 136 insertions(+) create mode 100644 llvm/test/CodeGen/WebAssembly/swiftcc.ll diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp index cb95d5dbfc063..ac65a52356bdc 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -291,6 +291,24 @@ void WebAssemblyAsmPrinter::EmitFunctionBodyStart() { SmallVector ResultVTs; SmallVector ParamVTs; computeSignatureVTs(F.getFunctionType(), F, TM, ParamVTs, ResultVTs); + + // For swiftcc, emit additional swiftself and swifterror arguments + // if there aren't any. 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 index acbd4c9921b0e..9e73a681f4c9a 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp @@ -218,6 +218,21 @@ bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) { // Start assigning local numbers after the last parameter. unsigned CurLocal = static_cast(MFI.getParams().size()); + // For swiftcc, additional swiftself and swifterror parameters are added + // if there aren't any. 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 index c932f985489ab..81a56fb88c713 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp @@ -640,6 +640,9 @@ bool WebAssemblyFastISel::fastLowerArguments() { 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 @@ bool WebAssemblyFastISel::selectCall(const Instruction *I) { 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 index 6b1bbd7a2b079..8b1bf590c2ea5 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp @@ -244,6 +244,10 @@ bool FixFunctionBitcasts::runOnModule(Module &M) { // 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 index b5aa575da8bd2..e1c7d15874740 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -718,10 +718,14 @@ WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI, 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()) @@ -751,6 +755,29 @@ WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI, bool IsVarArg = CLI.IsVarArg; auto PtrVT = getPointerTy(Layout); + // For swiftcc, emit additional swiftself and swifterror arguments + // if there aren't any. 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()); @@ -917,7 +944,11 @@ SDValue WebAssemblyTargetLowering::LowerFormalArguments( // 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()) @@ -937,6 +968,19 @@ SDValue WebAssemblyTargetLowering::LowerFormalArguments( MFI->addParam(In.VT); } + // For swiftcc, emit additional swiftself and swifterror arguments + // if there aren't any. 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) { @@ -956,6 +1000,12 @@ SDValue WebAssemblyTargetLowering::LowerFormalArguments( 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 index 59c10243c545e..85e4d5a7d22f3 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp @@ -58,6 +58,26 @@ WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const { SmallVector ParamMVTs; computeSignatureVTs(FuncTy, CurrentFunc, TM, ParamMVTs, ResultMVTs); + // For swiftcc, emit additional swiftself and swifterror parameters + // if there aren't any. 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 index 0000000000000..005196c0823a4 --- /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 +} +