Skip to content

Commit b15b427

Browse files
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.
1 parent 89c9790 commit b15b427

File tree

7 files changed

+136
-0
lines changed

7 files changed

+136
-0
lines changed

llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,24 @@ void WebAssemblyAsmPrinter::EmitFunctionBodyStart() {
291291
SmallVector<MVT, 1> ResultVTs;
292292
SmallVector<MVT, 4> ParamVTs;
293293
computeSignatureVTs(F.getFunctionType(), F, TM, ParamVTs, ResultVTs);
294+
295+
// For swiftcc, emit additional swiftself and swifterror arguments
296+
// if there aren't any. These additional arguments are also added for caller
297+
// signature. They are necessary to match callee and caller signature for
298+
// indirect call.
299+
if (F.getCallingConv() == CallingConv::Swift) {
300+
MVT PtrVT = MVT::getIntegerVT(TM.createDataLayout().getPointerSizeInBits());
301+
bool HasSwiftErrorArg = false;
302+
bool HasSwiftSelfArg = false;
303+
for (const auto &Arg : F.args()) {
304+
HasSwiftErrorArg |= Arg.hasAttribute(Attribute::SwiftError);
305+
HasSwiftSelfArg |= Arg.hasAttribute(Attribute::SwiftSelf);
306+
}
307+
if (!HasSwiftErrorArg)
308+
ParamVTs.push_back(PtrVT);
309+
if (!HasSwiftSelfArg)
310+
ParamVTs.push_back(PtrVT);
311+
}
294312
auto Signature = signatureFromMVTs(ResultVTs, ParamVTs);
295313
auto *WasmSym = cast<MCSymbolWasm>(CurrentFnSym);
296314
WasmSym->setSignature(Signature.get());

llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,21 @@ bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) {
218218
// Start assigning local numbers after the last parameter.
219219
unsigned CurLocal = static_cast<unsigned>(MFI.getParams().size());
220220

221+
// For swiftcc, additional swiftself and swifterror parameters are added
222+
// if there aren't any. Forward the cursor for the extra parameters.
223+
if (MF.getFunction().getCallingConv() == CallingConv::Swift) {
224+
bool HasSwiftErrorArg = false;
225+
bool HasSwiftSelfArg = false;
226+
for (const auto &Arg : MF.getFunction().args()) {
227+
HasSwiftErrorArg |= Arg.hasAttribute(Attribute::SwiftError);
228+
HasSwiftSelfArg |= Arg.hasAttribute(Attribute::SwiftSelf);
229+
}
230+
if (!HasSwiftErrorArg)
231+
CurLocal++;
232+
if (!HasSwiftSelfArg)
233+
CurLocal++;
234+
}
235+
221236
// Precompute the set of registers that are unused, so that we can insert
222237
// drops to their defs.
223238
BitVector UseEmpty(MRI.getNumVirtRegs());

llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,9 @@ bool WebAssemblyFastISel::fastLowerArguments() {
640640
if (F->isVarArg())
641641
return false;
642642

643+
if (FuncInfo.Fn->getCallingConv() == CallingConv::Swift)
644+
return false;
645+
643646
unsigned I = 0;
644647
for (auto const &Arg : F->args()) {
645648
const AttributeList &Attrs = F->getAttributes();
@@ -754,6 +757,9 @@ bool WebAssemblyFastISel::selectCall(const Instruction *I) {
754757
if (Func && Func->isIntrinsic())
755758
return false;
756759

760+
if (Call->getCallingConv() == CallingConv::Swift)
761+
return false;
762+
757763
bool IsDirect = Func != nullptr;
758764
if (!IsDirect && isa<ConstantExpr>(Call->getCalledValue()))
759765
return false;

llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,10 @@ bool FixFunctionBitcasts::runOnModule(Module &M) {
244244

245245
// Collect all the places that need wrappers.
246246
for (Function &F : M) {
247+
// Skip to fix when the function is swiftcc because swiftcc allows
248+
// bitcast type difference for swiftself and swifterror.
249+
if (F.getCallingConv() == CallingConv::Swift)
250+
continue;
247251
findUses(&F, F, Uses, ConstantBCs);
248252

249253
// If we have a "main" function, and its type isn't

llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,10 +718,14 @@ WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
718718
std::swap(OutVals[0], OutVals[1]);
719719
}
720720

721+
bool HasSwiftSelfArg = false;
722+
bool HasSwiftErrorArg = false;
721723
unsigned NumFixedArgs = 0;
722724
for (unsigned I = 0; I < Outs.size(); ++I) {
723725
const ISD::OutputArg &Out = Outs[I];
724726
SDValue &OutVal = OutVals[I];
727+
HasSwiftSelfArg |= Out.Flags.isSwiftSelf();
728+
HasSwiftErrorArg |= Out.Flags.isSwiftError();
725729
if (Out.Flags.isNest())
726730
fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
727731
if (Out.Flags.isInAlloca())
@@ -751,6 +755,29 @@ WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
751755
bool IsVarArg = CLI.IsVarArg;
752756
auto PtrVT = getPointerTy(Layout);
753757

758+
// For swiftcc, emit additional swiftself and swifterror arguments
759+
// if there aren't any. These additional arguments are also added for callee
760+
// signature. They are necessary to match callee and caller signature for
761+
// indirect call.
762+
if (CallConv == CallingConv::Swift) {
763+
if (!HasSwiftSelfArg) {
764+
NumFixedArgs++;
765+
ISD::OutputArg Arg;
766+
Arg.Flags.setSwiftSelf();
767+
CLI.Outs.push_back(Arg);
768+
SDValue ArgVal = DAG.getUNDEF(PtrVT);
769+
CLI.OutVals.push_back(ArgVal);
770+
}
771+
if (!HasSwiftErrorArg) {
772+
NumFixedArgs++;
773+
ISD::OutputArg Arg;
774+
Arg.Flags.setSwiftError();
775+
CLI.Outs.push_back(Arg);
776+
SDValue ArgVal = DAG.getUNDEF(PtrVT);
777+
CLI.OutVals.push_back(ArgVal);
778+
}
779+
}
780+
754781
// Analyze operands of the call, assigning locations to each operand.
755782
SmallVector<CCValAssign, 16> ArgLocs;
756783
CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
@@ -917,7 +944,11 @@ SDValue WebAssemblyTargetLowering::LowerFormalArguments(
917944
// of the incoming values before they're represented by virtual registers.
918945
MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS);
919946

947+
bool HasSwiftErrorArg = false;
948+
bool HasSwiftSelfArg = false;
920949
for (const ISD::InputArg &In : Ins) {
950+
HasSwiftSelfArg |= In.Flags.isSwiftSelf();
951+
HasSwiftErrorArg |= In.Flags.isSwiftError();
921952
if (In.Flags.isInAlloca())
922953
fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
923954
if (In.Flags.isNest())
@@ -937,6 +968,19 @@ SDValue WebAssemblyTargetLowering::LowerFormalArguments(
937968
MFI->addParam(In.VT);
938969
}
939970

971+
// For swiftcc, emit additional swiftself and swifterror arguments
972+
// if there aren't any. These additional arguments are also added for callee
973+
// signature. They are necessary to match callee and caller signature for
974+
// indirect call.
975+
auto PtrVT = getPointerTy(MF.getDataLayout());
976+
if (CallConv == CallingConv::Swift) {
977+
if (!HasSwiftSelfArg) {
978+
MFI->addParam(PtrVT);
979+
}
980+
if (!HasSwiftErrorArg) {
981+
MFI->addParam(PtrVT);
982+
}
983+
}
940984
// Varargs are copied into a buffer allocated by the caller, and a pointer to
941985
// the buffer is passed as an argument.
942986
if (IsVarArg) {
@@ -956,6 +1000,12 @@ SDValue WebAssemblyTargetLowering::LowerFormalArguments(
9561000
SmallVector<MVT, 4> Results;
9571001
computeSignatureVTs(MF.getFunction().getFunctionType(), MF.getFunction(),
9581002
DAG.getTarget(), Params, Results);
1003+
if (CallConv == CallingConv::Swift) {
1004+
if (!HasSwiftErrorArg)
1005+
Params.push_back(PtrVT);
1006+
if (!HasSwiftSelfArg)
1007+
Params.push_back(PtrVT);
1008+
}
9591009
for (MVT VT : Results)
9601010
MFI->addResult(VT);
9611011
// TODO: Use signatures in WebAssemblyMachineFunctionInfo too and unify

llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,26 @@ WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
5858
SmallVector<MVT, 4> ParamMVTs;
5959
computeSignatureVTs(FuncTy, CurrentFunc, TM, ParamMVTs, ResultMVTs);
6060

61+
// For swiftcc, emit additional swiftself and swifterror parameters
62+
// if there aren't any. These additional parameters are also passed for caller.
63+
// They are necessary to match callee and caller signature for indirect
64+
// call.
65+
const auto *const F = dyn_cast<Function>(Global);
66+
if (F && F->getCallingConv() == CallingConv::Swift) {
67+
MVT PtrVT =
68+
MVT::getIntegerVT(TM.createDataLayout().getPointerSizeInBits());
69+
bool HasSwiftErrorArg = false;
70+
bool HasSwiftSelfArg = false;
71+
for (const auto &Arg : F->args()) {
72+
HasSwiftErrorArg |= Arg.hasAttribute(Attribute::SwiftError);
73+
HasSwiftSelfArg |= Arg.hasAttribute(Attribute::SwiftSelf);
74+
}
75+
if (!HasSwiftErrorArg)
76+
ParamMVTs.push_back(PtrVT);
77+
if (!HasSwiftSelfArg)
78+
ParamMVTs.push_back(PtrVT);
79+
}
80+
6181
auto Signature = signatureFromMVTs(ResultMVTs, ParamMVTs);
6282
WasmSym->setSignature(Signature.get());
6383
Printer.addSignature(std::move(Signature));
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
; RUN: llc < %s -asm-verbose=false | FileCheck %s
2+
3+
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
4+
target triple = "wasm32-unknown-unknown"
5+
6+
; Test indirect function call between mismatched signatures
7+
; CHECK-LABEL: foo:
8+
; CHECK-NEXT: .functype foo (i32, i32, i32, i32) -> ()
9+
define swiftcc void @foo(i32, i32) {
10+
ret void
11+
}
12+
@data = global i8* bitcast (void (i32, i32)* @foo to i8*)
13+
14+
; CHECK-LABEL: bar:
15+
; CHECK-NEXT: .functype bar (i32, i32) -> ()
16+
; CHECK: call_indirect (i32, i32, i32, i32) -> ()
17+
define swiftcc void @bar() {
18+
%1 = load i8*, i8** @data
19+
%2 = bitcast i8* %1 to void (i32, i32, i32)*
20+
call swiftcc void %2(i32 1, i32 2, i32 swiftself 3)
21+
ret void
22+
}
23+

0 commit comments

Comments
 (0)