Skip to content

Commit 08670d4

Browse files
kateinoigakukundschuff
authored andcommitted
[WebAssembly] Support swiftself and swifterror for WebAssembly target
Summary: Swift ABI is based on basic C ABI described here https://github.com/WebAssembly/tool-conventions/blob/master/BasicCABI.md Swift Calling Convention on WebAssembly is a little deffer from swiftcc on another architectures. On non WebAssembly arch, swiftcc accepts extra parameters that are attributed with swifterror or swiftself by caller. Even if callee doesn't have these parameters, the invocation succeed ignoring extra parameters. But WebAssembly strictly checks that callee and caller signatures are same. https://github.com/WebAssembly/design/blob/master/Semantics.md#calls So at WebAssembly level, all swiftcc functions end up extra arguments and all function definitions and invocations explicitly have additional parameters to fill swifterror and swiftself. This patch support signature difference for swiftself and swifterror cc is swiftcc. e.g. ``` 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 direct and indirect function call. Differential Revision: https://reviews.llvm.org/D76049
1 parent 34db3c3 commit 08670d4

File tree

8 files changed

+136
-12
lines changed

8 files changed

+136
-12
lines changed

llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ void WebAssemblyAsmPrinter::emitEndOfAsmFile(Module &M) {
103103
if (F.isDeclarationForLinker()) {
104104
SmallVector<MVT, 4> Results;
105105
SmallVector<MVT, 4> Params;
106-
computeSignatureVTs(F.getFunctionType(), F, TM, Params, Results);
106+
computeSignatureVTs(F.getFunctionType(), &F, F, TM, Params, Results);
107107
auto *Sym = cast<MCSymbolWasm>(getSymbol(&F));
108108
Sym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
109109
if (!Sym->getSignature()) {
@@ -290,7 +290,8 @@ void WebAssemblyAsmPrinter::emitFunctionBodyStart() {
290290
const Function &F = MF->getFunction();
291291
SmallVector<MVT, 1> ResultVTs;
292292
SmallVector<MVT, 4> ParamVTs;
293-
computeSignatureVTs(F.getFunctionType(), F, TM, ParamVTs, ResultVTs);
293+
computeSignatureVTs(F.getFunctionType(), &F, F, TM, ParamVTs, ResultVTs);
294+
294295
auto Signature = signatureFromMVTs(ResultVTs, ParamVTs);
295296
auto *WasmSym = cast<MCSymbolWasm>(CurrentFnSym);
296297
WasmSym->setSignature(Signature.get());

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: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -769,10 +769,14 @@ WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
769769
std::swap(OutVals[0], OutVals[1]);
770770
}
771771

772+
bool HasSwiftSelfArg = false;
773+
bool HasSwiftErrorArg = false;
772774
unsigned NumFixedArgs = 0;
773775
for (unsigned I = 0; I < Outs.size(); ++I) {
774776
const ISD::OutputArg &Out = Outs[I];
775777
SDValue &OutVal = OutVals[I];
778+
HasSwiftSelfArg |= Out.Flags.isSwiftSelf();
779+
HasSwiftErrorArg |= Out.Flags.isSwiftError();
776780
if (Out.Flags.isNest())
777781
fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
778782
if (Out.Flags.isInAlloca())
@@ -802,6 +806,29 @@ WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
802806
bool IsVarArg = CLI.IsVarArg;
803807
auto PtrVT = getPointerTy(Layout);
804808

809+
// For swiftcc, emit additional swiftself and swifterror arguments
810+
// if there aren't. These additional arguments are also added for callee
811+
// signature They are necessary to match callee and caller signature for
812+
// indirect call.
813+
if (CallConv == CallingConv::Swift) {
814+
if (!HasSwiftSelfArg) {
815+
NumFixedArgs++;
816+
ISD::OutputArg Arg;
817+
Arg.Flags.setSwiftSelf();
818+
CLI.Outs.push_back(Arg);
819+
SDValue ArgVal = DAG.getUNDEF(PtrVT);
820+
CLI.OutVals.push_back(ArgVal);
821+
}
822+
if (!HasSwiftErrorArg) {
823+
NumFixedArgs++;
824+
ISD::OutputArg Arg;
825+
Arg.Flags.setSwiftError();
826+
CLI.Outs.push_back(Arg);
827+
SDValue ArgVal = DAG.getUNDEF(PtrVT);
828+
CLI.OutVals.push_back(ArgVal);
829+
}
830+
}
831+
805832
// Analyze operands of the call, assigning locations to each operand.
806833
SmallVector<CCValAssign, 16> ArgLocs;
807834
CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
@@ -964,7 +991,11 @@ SDValue WebAssemblyTargetLowering::LowerFormalArguments(
964991
// of the incoming values before they're represented by virtual registers.
965992
MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS);
966993

994+
bool HasSwiftErrorArg = false;
995+
bool HasSwiftSelfArg = false;
967996
for (const ISD::InputArg &In : Ins) {
997+
HasSwiftSelfArg |= In.Flags.isSwiftSelf();
998+
HasSwiftErrorArg |= In.Flags.isSwiftError();
968999
if (In.Flags.isInAlloca())
9691000
fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
9701001
if (In.Flags.isNest())
@@ -984,6 +1015,19 @@ SDValue WebAssemblyTargetLowering::LowerFormalArguments(
9841015
MFI->addParam(In.VT);
9851016
}
9861017

1018+
// For swiftcc, emit additional swiftself and swifterror arguments
1019+
// if there aren't. These additional arguments are also added for callee
1020+
// signature They are necessary to match callee and caller signature for
1021+
// indirect call.
1022+
auto PtrVT = getPointerTy(MF.getDataLayout());
1023+
if (CallConv == CallingConv::Swift) {
1024+
if (!HasSwiftSelfArg) {
1025+
MFI->addParam(PtrVT);
1026+
}
1027+
if (!HasSwiftErrorArg) {
1028+
MFI->addParam(PtrVT);
1029+
}
1030+
}
9871031
// Varargs are copied into a buffer allocated by the caller, and a pointer to
9881032
// the buffer is passed as an argument.
9891033
if (IsVarArg) {
@@ -1001,8 +1045,8 @@ SDValue WebAssemblyTargetLowering::LowerFormalArguments(
10011045
// Record the number and types of arguments and results.
10021046
SmallVector<MVT, 4> Params;
10031047
SmallVector<MVT, 4> Results;
1004-
computeSignatureVTs(MF.getFunction().getFunctionType(), MF.getFunction(),
1005-
DAG.getTarget(), Params, Results);
1048+
computeSignatureVTs(MF.getFunction().getFunctionType(), &MF.getFunction(),
1049+
MF.getFunction(), DAG.getTarget(), Params, Results);
10061050
for (MVT VT : Results)
10071051
MFI->addResult(VT);
10081052
// TODO: Use signatures in WebAssemblyMachineFunctionInfo too and unify

llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
5656

5757
SmallVector<MVT, 1> ResultMVTs;
5858
SmallVector<MVT, 4> ParamMVTs;
59-
computeSignatureVTs(FuncTy, CurrentFunc, TM, ParamMVTs, ResultMVTs);
59+
const auto *const F = dyn_cast<Function>(Global);
60+
computeSignatureVTs(FuncTy, F, CurrentFunc, TM, ParamMVTs, ResultMVTs);
6061

6162
auto Signature = signatureFromMVTs(ResultMVTs, ParamMVTs);
6263
WasmSym->setSignature(Signature.get());

llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,17 @@ void llvm::computeLegalValueVTs(const Function &F, const TargetMachine &TM,
4242
}
4343
}
4444

45-
void llvm::computeSignatureVTs(const FunctionType *Ty, const Function &F,
45+
void llvm::computeSignatureVTs(const FunctionType *Ty,
46+
const Function *TargetFunc,
47+
const Function &ContextFunc,
4648
const TargetMachine &TM,
4749
SmallVectorImpl<MVT> &Params,
4850
SmallVectorImpl<MVT> &Results) {
49-
computeLegalValueVTs(F, TM, Ty->getReturnType(), Results);
51+
computeLegalValueVTs(ContextFunc, TM, Ty->getReturnType(), Results);
5052

5153
MVT PtrVT = MVT::getIntegerVT(TM.createDataLayout().getPointerSizeInBits());
5254
if (Results.size() > 1 &&
53-
!TM.getSubtarget<WebAssemblySubtarget>(F).hasMultivalue()) {
55+
!TM.getSubtarget<WebAssemblySubtarget>(ContextFunc).hasMultivalue()) {
5456
// WebAssembly can't lower returns of multiple values without demoting to
5557
// sret unless multivalue is enabled (see
5658
// WebAssemblyTargetLowering::CanLowerReturn). So replace multiple return
@@ -60,9 +62,28 @@ void llvm::computeSignatureVTs(const FunctionType *Ty, const Function &F,
6062
}
6163

6264
for (auto *Param : Ty->params())
63-
computeLegalValueVTs(F, TM, Param, Params);
65+
computeLegalValueVTs(ContextFunc, TM, Param, Params);
6466
if (Ty->isVarArg())
6567
Params.push_back(PtrVT);
68+
69+
// For swiftcc, emit additional swiftself and swifterror parameters
70+
// if there aren't. These additional parameters are also passed for caller.
71+
// They are necessary to match callee and caller signature for indirect
72+
// call.
73+
74+
if (TargetFunc && TargetFunc->getCallingConv() == CallingConv::Swift) {
75+
MVT PtrVT = MVT::getIntegerVT(TM.createDataLayout().getPointerSizeInBits());
76+
bool HasSwiftErrorArg = false;
77+
bool HasSwiftSelfArg = false;
78+
for (const auto &Arg : TargetFunc->args()) {
79+
HasSwiftErrorArg |= Arg.hasAttribute(Attribute::SwiftError);
80+
HasSwiftSelfArg |= Arg.hasAttribute(Attribute::SwiftSelf);
81+
}
82+
if (!HasSwiftErrorArg)
83+
Params.push_back(PtrVT);
84+
if (!HasSwiftSelfArg)
85+
Params.push_back(PtrVT);
86+
}
6687
}
6788

6889
void llvm::valTypesFromMVTs(const ArrayRef<MVT> &In,

llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,9 +159,10 @@ void computeLegalValueVTs(const Function &F, const TargetMachine &TM, Type *Ty,
159159
SmallVectorImpl<MVT> &ValueVTs);
160160

161161
// Compute the signature for a given FunctionType (Ty). Note that it's not the
162-
// signature for F (F is just used to get varous context)
163-
void computeSignatureVTs(const FunctionType *Ty, const Function &F,
164-
const TargetMachine &TM, SmallVectorImpl<MVT> &Params,
162+
// signature for ContextFunc (ContextFunc is just used to get varous context)
163+
void computeSignatureVTs(const FunctionType *Ty, const Function *TargetFunc,
164+
const Function &ContextFunc, const TargetMachine &TM,
165+
SmallVectorImpl<MVT> &Params,
165166
SmallVectorImpl<MVT> &Results);
166167

167168
void valTypesFromMVTs(const ArrayRef<MVT> &In,
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
; RUN: llc < %s -asm-verbose=false -wasm-keep-registers | FileCheck %s --check-prefix=REG
2+
; RUN: llc < %s -asm-verbose=false | FileCheck %s
3+
4+
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
5+
target triple = "wasm32-unknown-unknown"
6+
7+
; Test direct and indirect function call between mismatched signatures
8+
; CHECK-LABEL: foo:
9+
; CHECK-NEXT: .functype foo (i32, i32, i32, i32) -> ()
10+
define swiftcc void @foo(i32, i32) {
11+
ret void
12+
}
13+
@data = global i8* bitcast (void (i32, i32)* @foo to i8*)
14+
15+
; CHECK-LABEL: bar:
16+
; CHECK-NEXT: .functype bar (i32, i32) -> ()
17+
define swiftcc void @bar() {
18+
%1 = load i8*, i8** @data
19+
; REG: call foo, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}
20+
call swiftcc void @foo(i32 1, i32 2)
21+
22+
%2 = bitcast i8* %1 to void (i32, i32)*
23+
; REG: call_indirect $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}
24+
; CHECK: call_indirect (i32, i32, i32, i32) -> ()
25+
call swiftcc void %2(i32 1, i32 2)
26+
27+
%3 = bitcast i8* %1 to void (i32, i32, i32)*
28+
; REG: call_indirect $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}
29+
; CHECK: call_indirect (i32, i32, i32, i32) -> ()
30+
call swiftcc void %3(i32 1, i32 2, i32 swiftself 3)
31+
32+
%err = alloca swifterror i32*, align 4
33+
34+
%4 = bitcast i8* %1 to void (i32, i32, i32**)*
35+
; REG: call_indirect $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}
36+
; CHECK: call_indirect (i32, i32, i32, i32) -> ()
37+
call swiftcc void %4(i32 1, i32 2, i32** swifterror %err)
38+
39+
%5 = bitcast i8* %1 to void (i32, i32, i32, i32**)*
40+
; REG: call_indirect $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}
41+
; CHECK: call_indirect (i32, i32, i32, i32) -> ()
42+
call swiftcc void %5(i32 1, i32 2, i32 swiftself 3, i32** swifterror %err)
43+
44+
ret void
45+
}
46+

0 commit comments

Comments
 (0)