Skip to content

Commit abc693f

Browse files
authored
[AArch64] Skip over shadow space for ARM64EC entry thunk variadic calls (#80994)
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 0ef66fc commit abc693f

File tree

3 files changed

+30
-10
lines changed

3 files changed

+30
-10
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

llvm/test/CodeGen/AArch64/arm64ec-entry-thunks.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ define void @has_varargs(...) nounwind {
147147
; CHECK-NEXT: add x29, sp, #160
148148
; CHECK-NEXT: .seh_add_fp 160
149149
; CHECK-NEXT: .seh_endprologue
150-
; CHECK-NEXT: mov x4, sp
150+
; CHECK-NEXT: add x4, x4, #32
151151
; CHECK-NEXT: mov x5, xzr
152152
; CHECK-NEXT: blr x9
153153
; CHECK-NEXT: adrp x8, __os_arm64x_dispatch_ret

0 commit comments

Comments
 (0)