Skip to content

Commit 4350ae4

Browse files
committed
[AArch64] Skip over shadow space for ARM64EC entry thunk variadic calls
When in an entry thunk the x64 SP is passed in x4 but this cannot be directly passed through since x64 varargs calls have a 32 byte shadow store at SP followed by the in-stack parameters. ARM64EC varargs calls on the other hand expect x4 to point to the first in-stack parameter.
1 parent 7318585 commit 4350ae4

File tree

2 files changed

+29
-9
lines changed

2 files changed

+29
-9
lines changed

llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,8 @@ void AArch64Arm64ECCallLowering::getThunkType(FunctionType *FT,
119119
getThunkArgTypes(FT, AttrList, TT, Out, Arm64ArgTypes, X64ArgTypes,
120120
HasSretPtr);
121121

122-
Arm64Ty = FunctionType::get(Arm64RetTy, Arm64ArgTypes,
123-
TT == ThunkType::Entry && FT->isVarArg());
122+
Arm64Ty = FunctionType::get(Arm64RetTy, Arm64ArgTypes, false);
123+
124124
X64Ty = FunctionType::get(X64RetTy, X64ArgTypes, false);
125125
}
126126

@@ -158,13 +158,13 @@ void AArch64Arm64ECCallLowering::getThunkArgTypes(
158158
X64ArgTypes.push_back(I64Ty);
159159
}
160160

161+
// x4
162+
Arm64ArgTypes.push_back(PtrTy);
163+
X64ArgTypes.push_back(PtrTy);
164+
// x5
165+
Arm64ArgTypes.push_back(I64Ty);
161166
if (TT != ThunkType::Entry) {
162-
// x4
163-
Arm64ArgTypes.push_back(PtrTy);
164-
X64ArgTypes.push_back(PtrTy);
165-
// x5
166-
Arm64ArgTypes.push_back(I64Ty);
167-
// FIXME: x5 isn't actually passed/used by the x64 side; revisit once we
167+
// FIXME: x5 isn't actually used by the x64 side; revisit once we
168168
// have proper isel for varargs
169169
X64ArgTypes.push_back(I64Ty);
170170
}
@@ -473,10 +473,11 @@ Function *AArch64Arm64ECCallLowering::buildEntryThunk(Function *F) {
473473

474474
bool TransformDirectToSRet = X64RetType->isVoidTy() && !RetTy->isVoidTy();
475475
unsigned ThunkArgOffset = TransformDirectToSRet ? 2 : 1;
476+
unsigned PassthroughArgSize = F->isVarArg() ? 5 : Thunk->arg_size();
476477

477478
// Translate arguments to call.
478479
SmallVector<Value *> Args;
479-
for (unsigned i = ThunkArgOffset, e = Thunk->arg_size(); i != e; ++i) {
480+
for (unsigned i = ThunkArgOffset, e = PassthroughArgSize; i != e; ++i) {
480481
Value *Arg = Thunk->getArg(i);
481482
Type *ArgTy = Arm64Ty->getParamType(i - ThunkArgOffset);
482483
if (ArgTy->isArrayTy() || ArgTy->isStructTy() ||
@@ -493,6 +494,22 @@ Function *AArch64Arm64ECCallLowering::buildEntryThunk(Function *F) {
493494
Args.push_back(Arg);
494495
}
495496

497+
if (F->isVarArg()) {
498+
// The 5th argument to variadic entry thunks is used to model the x64 sp
499+
// which is passed to the thunk in x4, this can be passed to the callee as
500+
// the variadic argument start address after skipping over the 32 byte
501+
// shadow store.
502+
503+
// The EC thunk CC will assign any argument marked as InReg to x4.
504+
Thunk->addParamAttr(5, Attribute::InReg);
505+
Value *Arg = Thunk->getArg(5);
506+
Arg = IRB.CreatePtrAdd(Arg, IRB.getInt64(0x20));
507+
Args.push_back(Arg);
508+
509+
// Pass in a zero variadic argument size (in x5).
510+
Args.push_back(IRB.getInt64(0));
511+
}
512+
496513
// Call the function passed to the thunk.
497514
Value *Callee = Thunk->getArg(0);
498515
Callee = IRB.CreateBitCast(Callee, PtrTy);

llvm/lib/Target/AArch64/AArch64CallingConvention.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,9 @@ def CC_AArch64_Arm64EC_VarArg : CallingConv<[
213213
// address is passed in X9.
214214
let Entry = 1 in
215215
def CC_AArch64_Arm64EC_Thunk : CallingConv<[
216+
// ARM64EC-specific: the InReg attribute can be used to access the x64 sp passed into entry thunks in x4 from the IR.
217+
CCIfInReg<CCIfType<[i64], CCAssignToReg<[X4]>>>,
218+
216219
// Byval aggregates are passed by pointer
217220
CCIfByVal<CCPassIndirect<i64>>,
218221

0 commit comments

Comments
 (0)