Skip to content

Commit 56fd846

Browse files
committed
[AArch64][GlobalISel] Lower formal arguments of AAPCS & ms_abi variadic functions.
Reimplemented SelectionDAG code for GlobalISel. Fixes llvm/llvm-project#54079 Differential Revision: https://reviews.llvm.org/D130903
1 parent f32f293 commit 56fd846

File tree

7 files changed

+204
-18
lines changed

7 files changed

+204
-18
lines changed

llvm/lib/Target/AArch64/AArch64ISelLowering.cpp

+15-8
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,17 @@ static cl::opt<unsigned> MaxXors("aarch64-max-xors", cl::init(16), cl::Hidden,
139139
/// Value type used for condition codes.
140140
static const MVT MVT_CC = MVT::i32;
141141

142+
static const MCPhysReg GPRArgRegs[] = {AArch64::X0, AArch64::X1, AArch64::X2,
143+
AArch64::X3, AArch64::X4, AArch64::X5,
144+
AArch64::X6, AArch64::X7};
145+
static const MCPhysReg FPRArgRegs[] = {AArch64::Q0, AArch64::Q1, AArch64::Q2,
146+
AArch64::Q3, AArch64::Q4, AArch64::Q5,
147+
AArch64::Q6, AArch64::Q7};
148+
149+
const ArrayRef<MCPhysReg> llvm::AArch64::getGPRArgRegs() { return GPRArgRegs; }
150+
151+
const ArrayRef<MCPhysReg> llvm::AArch64::getFPRArgRegs() { return FPRArgRegs; }
152+
142153
static inline EVT getPackedSVEVectorVT(EVT VT) {
143154
switch (VT.getSimpleVT().SimpleTy) {
144155
default:
@@ -6562,10 +6573,8 @@ void AArch64TargetLowering::saveVarArgRegisters(CCState &CCInfo,
65626573

65636574
SmallVector<SDValue, 8> MemOps;
65646575

6565-
static const MCPhysReg GPRArgRegs[] = { AArch64::X0, AArch64::X1, AArch64::X2,
6566-
AArch64::X3, AArch64::X4, AArch64::X5,
6567-
AArch64::X6, AArch64::X7 };
6568-
unsigned NumGPRArgRegs = std::size(GPRArgRegs);
6576+
auto GPRArgRegs = AArch64::getGPRArgRegs();
6577+
unsigned NumGPRArgRegs = GPRArgRegs.size();
65696578
if (Subtarget->isWindowsArm64EC()) {
65706579
// In the ARM64EC ABI, only x0-x3 are used to pass arguments to varargs
65716580
// functions.
@@ -6615,10 +6624,8 @@ void AArch64TargetLowering::saveVarArgRegisters(CCState &CCInfo,
66156624
FuncInfo->setVarArgsGPRSize(GPRSaveSize);
66166625

66176626
if (Subtarget->hasFPARMv8() && !IsWin64) {
6618-
static const MCPhysReg FPRArgRegs[] = {
6619-
AArch64::Q0, AArch64::Q1, AArch64::Q2, AArch64::Q3,
6620-
AArch64::Q4, AArch64::Q5, AArch64::Q6, AArch64::Q7};
6621-
static const unsigned NumFPRArgRegs = std::size(FPRArgRegs);
6627+
auto FPRArgRegs = AArch64::getFPRArgRegs();
6628+
const unsigned NumFPRArgRegs = FPRArgRegs.size();
66226629
unsigned FirstVariadicFPR = CCInfo.getFirstUnallocated(FPRArgRegs);
66236630

66246631
unsigned FPRSaveSize = 16 * (NumFPRArgRegs - FirstVariadicFPR);

llvm/lib/Target/AArch64/AArch64ISelLowering.h

+5
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,11 @@ enum Rounding {
497497

498498
// Bit position of rounding mode bits in FPCR.
499499
const unsigned RoundingBitsPos = 22;
500+
501+
// Registers used to pass function arguments.
502+
const ArrayRef<MCPhysReg> getGPRArgRegs();
503+
const ArrayRef<MCPhysReg> getFPRArgRegs();
504+
500505
} // namespace AArch64
501506

502507
class AArch64Subtarget;

llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp

+99-9
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "AArch64CallLowering.h"
1616
#include "AArch64ISelLowering.h"
1717
#include "AArch64MachineFunctionInfo.h"
18+
#include "AArch64RegisterInfo.h"
1819
#include "AArch64Subtarget.h"
1920
#include "llvm/ADT/ArrayRef.h"
2021
#include "llvm/ADT/SmallVector.h"
@@ -546,13 +547,98 @@ bool AArch64CallLowering::fallBackToDAGISel(const MachineFunction &MF) const {
546547
return false;
547548
}
548549

550+
void AArch64CallLowering::saveVarArgRegisters(
551+
MachineIRBuilder &MIRBuilder, CallLowering::IncomingValueHandler &Handler,
552+
CCState &CCInfo) const {
553+
auto GPRArgRegs = AArch64::getGPRArgRegs();
554+
auto FPRArgRegs = AArch64::getFPRArgRegs();
555+
556+
MachineFunction &MF = MIRBuilder.getMF();
557+
MachineRegisterInfo &MRI = MF.getRegInfo();
558+
MachineFrameInfo &MFI = MF.getFrameInfo();
559+
AArch64FunctionInfo *FuncInfo = MF.getInfo<AArch64FunctionInfo>();
560+
auto &Subtarget = MF.getSubtarget<AArch64Subtarget>();
561+
bool IsWin64CC =
562+
Subtarget.isCallingConvWin64(CCInfo.getCallingConv());
563+
const LLT p0 = LLT::pointer(0, 64);
564+
const LLT s64 = LLT::scalar(64);
565+
566+
unsigned FirstVariadicGPR = CCInfo.getFirstUnallocated(GPRArgRegs);
567+
unsigned NumVariadicGPRArgRegs = GPRArgRegs.size() - FirstVariadicGPR + 1;
568+
569+
unsigned GPRSaveSize = 8 * (GPRArgRegs.size() - FirstVariadicGPR);
570+
int GPRIdx = 0;
571+
if (GPRSaveSize != 0) {
572+
if (IsWin64CC) {
573+
GPRIdx = MFI.CreateFixedObject(GPRSaveSize,
574+
-static_cast<int>(GPRSaveSize), false);
575+
} else
576+
GPRIdx = MFI.CreateStackObject(GPRSaveSize, Align(8), false);
577+
578+
auto FIN = MIRBuilder.buildFrameIndex(p0, GPRIdx);
579+
auto Offset =
580+
MIRBuilder.buildConstant(MRI.createGenericVirtualRegister(s64), 8);
581+
582+
for (unsigned i = FirstVariadicGPR; i < GPRArgRegs.size(); ++i) {
583+
Register Val = MRI.createGenericVirtualRegister(s64);
584+
Handler.assignValueToReg(
585+
Val, GPRArgRegs[i],
586+
CCValAssign::getReg(i + MF.getFunction().getNumOperands(), MVT::i64,
587+
GPRArgRegs[i], MVT::i64, CCValAssign::Full));
588+
auto MPO = IsWin64CC ? MachinePointerInfo::getFixedStack(
589+
MF, GPRIdx, (i - FirstVariadicGPR) * 8)
590+
: MachinePointerInfo::getStack(MF, i * 8);
591+
MIRBuilder.buildStore(Val, FIN, MPO, inferAlignFromPtrInfo(MF, MPO));
592+
593+
FIN = MIRBuilder.buildPtrAdd(MRI.createGenericVirtualRegister(p0),
594+
FIN.getReg(0), Offset);
595+
}
596+
}
597+
FuncInfo->setVarArgsGPRIndex(GPRIdx);
598+
FuncInfo->setVarArgsGPRSize(GPRSaveSize);
599+
600+
if (Subtarget.hasFPARMv8() && !IsWin64CC) {
601+
unsigned FirstVariadicFPR = CCInfo.getFirstUnallocated(FPRArgRegs);
602+
603+
unsigned FPRSaveSize = 16 * (FPRArgRegs.size() - FirstVariadicFPR);
604+
int FPRIdx = 0;
605+
if (FPRSaveSize != 0) {
606+
FPRIdx = MFI.CreateStackObject(FPRSaveSize, Align(16), false);
607+
608+
auto FIN = MIRBuilder.buildFrameIndex(p0, FPRIdx);
609+
auto Offset =
610+
MIRBuilder.buildConstant(MRI.createGenericVirtualRegister(s64), 16);
611+
612+
for (unsigned i = FirstVariadicFPR; i < FPRArgRegs.size(); ++i) {
613+
Register Val = MRI.createGenericVirtualRegister(LLT::scalar(128));
614+
Handler.assignValueToReg(
615+
Val, FPRArgRegs[i],
616+
CCValAssign::getReg(
617+
i + MF.getFunction().getNumOperands() + NumVariadicGPRArgRegs,
618+
MVT::f128, FPRArgRegs[i], MVT::f128, CCValAssign::Full));
619+
620+
auto MPO = MachinePointerInfo::getStack(MF, i * 16);
621+
MIRBuilder.buildStore(Val, FIN, MPO, inferAlignFromPtrInfo(MF, MPO));
622+
623+
FIN = MIRBuilder.buildPtrAdd(MRI.createGenericVirtualRegister(p0),
624+
FIN.getReg(0), Offset);
625+
}
626+
}
627+
FuncInfo->setVarArgsFPRIndex(FPRIdx);
628+
FuncInfo->setVarArgsFPRSize(FPRSaveSize);
629+
}
630+
}
631+
549632
bool AArch64CallLowering::lowerFormalArguments(
550633
MachineIRBuilder &MIRBuilder, const Function &F,
551634
ArrayRef<ArrayRef<Register>> VRegs, FunctionLoweringInfo &FLI) const {
552635
MachineFunction &MF = MIRBuilder.getMF();
553636
MachineBasicBlock &MBB = MIRBuilder.getMBB();
554637
MachineRegisterInfo &MRI = MF.getRegInfo();
555638
auto &DL = F.getParent()->getDataLayout();
639+
auto &Subtarget = MF.getSubtarget<AArch64Subtarget>();
640+
// TODO: Support Arm64EC
641+
bool IsWin64 = Subtarget.isCallingConvWin64(F.getCallingConv()) && !Subtarget.isWindowsArm64EC();
556642

557643
SmallVector<ArgInfo, 8> SplitArgs;
558644
SmallVector<std::pair<Register, Register>> BoolArgs;
@@ -598,13 +684,14 @@ bool AArch64CallLowering::lowerFormalArguments(
598684
MIRBuilder.setInstr(*MBB.begin());
599685

600686
const AArch64TargetLowering &TLI = *getTLI<AArch64TargetLowering>();
601-
CCAssignFn *AssignFn =
602-
TLI.CCAssignFnForCall(F.getCallingConv(), /*IsVarArg=*/false);
687+
CCAssignFn *AssignFn = TLI.CCAssignFnForCall(F.getCallingConv(), IsWin64);
603688

604689
AArch64IncomingValueAssigner Assigner(AssignFn, AssignFn);
605690
FormalArgHandler Handler(MIRBuilder, MRI);
606-
if (!determineAndHandleAssignments(Handler, Assigner, SplitArgs, MIRBuilder,
607-
F.getCallingConv(), F.isVarArg()))
691+
SmallVector<CCValAssign, 16> ArgLocs;
692+
CCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs, F.getContext());
693+
if (!determineAssignments(Assigner, SplitArgs, CCInfo) ||
694+
!handleAssignments(Handler, SplitArgs, CCInfo, ArgLocs, MIRBuilder))
608695
return false;
609696

610697
if (!BoolArgs.empty()) {
@@ -622,10 +709,14 @@ bool AArch64CallLowering::lowerFormalArguments(
622709
AArch64FunctionInfo *FuncInfo = MF.getInfo<AArch64FunctionInfo>();
623710
uint64_t StackOffset = Assigner.StackOffset;
624711
if (F.isVarArg()) {
625-
auto &Subtarget = MF.getSubtarget<AArch64Subtarget>();
626-
if (!Subtarget.isTargetDarwin()) {
627-
// FIXME: we need to reimplement saveVarArgsRegisters from
628-
// AArch64ISelLowering.
712+
if ((!Subtarget.isTargetDarwin() && !Subtarget.isWindowsArm64EC()) || IsWin64) {
713+
// The AAPCS variadic function ABI is identical to the non-variadic
714+
// one. As a result there may be more arguments in registers and we should
715+
// save them for future reference.
716+
// Win64 variadic functions also pass arguments in registers, but all
717+
// float arguments are passed in integer registers.
718+
saveVarArgRegisters(MIRBuilder, Handler, CCInfo);
719+
} else if (Subtarget.isWindowsArm64EC()) {
629720
return false;
630721
}
631722

@@ -657,7 +748,6 @@ bool AArch64CallLowering::lowerFormalArguments(
657748
// in this function later.
658749
FuncInfo->setBytesInStackArgArea(StackOffset);
659750

660-
auto &Subtarget = MF.getSubtarget<AArch64Subtarget>();
661751
if (Subtarget.hasCustomCallingConv())
662752
Subtarget.getRegisterInfo()->UpdateCustomCalleeSavedRegs(MF);
663753

llvm/lib/Target/AArch64/GISel/AArch64CallLowering.h

+4
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ class AArch64CallLowering: public CallLowering {
6666
using MemHandler =
6767
std::function<void(MachineIRBuilder &, int, CCValAssign &)>;
6868

69+
void saveVarArgRegisters(MachineIRBuilder &MIRBuilder,
70+
CallLowering::IncomingValueHandler &Handler,
71+
CCState &CCInfo) const;
72+
6973
bool lowerTailCall(MachineIRBuilder &MIRBuilder, CallLoweringInfo &Info,
7074
SmallVectorImpl<ArgInfo> &OutArgs) const;
7175

llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp

+9-1
Original file line numberDiff line numberDiff line change
@@ -1939,10 +1939,18 @@ bool AArch64InstructionSelector::selectVaStartDarwin(
19391939

19401940
Register ArgsAddrReg = MRI.createVirtualRegister(&AArch64::GPR64RegClass);
19411941

1942+
int FrameIdx = FuncInfo->getVarArgsStackIndex();
1943+
if (MF.getSubtarget<AArch64Subtarget>().isCallingConvWin64(
1944+
MF.getFunction().getCallingConv())) {
1945+
FrameIdx = FuncInfo->getVarArgsGPRSize() > 0
1946+
? FuncInfo->getVarArgsGPRIndex()
1947+
: FuncInfo->getVarArgsStackIndex();
1948+
}
1949+
19421950
auto MIB =
19431951
BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(AArch64::ADDXri))
19441952
.addDef(ArgsAddrReg)
1945-
.addFrameIndex(FuncInfo->getVarArgsStackIndex())
1953+
.addFrameIndex(FrameIdx)
19461954
.addImm(0)
19471955
.addImm(0);
19481956

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
; RUN: llc < %s --global-isel=0 -mtriple=aarch64-linux-gnu -mattr=+fp-armv8 | FileCheck %s
2+
; RUN: llc < %s --global-isel=1 -mtriple=aarch64-linux-gnu -mattr=+fp-armv8 | FileCheck %s --check-prefix=GISEL
3+
4+
define void @va(i32 %count, half %f, ...) nounwind {
5+
; CHECK-LABEL: va:
6+
; CHECK: // %bb.0: // %entry
7+
; CHECK-NEXT: sub sp, sp, #176
8+
; CHECK-NEXT: stp x4, x5, [sp, #144]
9+
; CHECK-NEXT: stp x2, x3, [sp, #128]
10+
; CHECK-NEXT: str x1, [sp, #120]
11+
; CHECK-NEXT: stp x6, x7, [sp, #160]
12+
; CHECK-NEXT: stp q1, q2, [sp]
13+
; CHECK-NEXT: stp q3, q4, [sp, #32]
14+
; CHECK-NEXT: stp q5, q6, [sp, #64]
15+
; CHECK-NEXT: str q7, [sp, #96]
16+
; CHECK-NEXT: add sp, sp, #176
17+
; CHECK-NEXT: ret
18+
;
19+
; GISEL-LABEL: va:
20+
; GISEL: // %bb.0: // %entry
21+
; GISEL-NEXT: sub sp, sp, #176
22+
; GISEL-NEXT: stp x1, x2, [sp, #120]
23+
; GISEL-NEXT: stp x3, x4, [sp, #136]
24+
; GISEL-NEXT: stp x5, x6, [sp, #152]
25+
; GISEL-NEXT: str x7, [sp, #168]
26+
; GISEL-NEXT: stp q1, q2, [sp]
27+
; GISEL-NEXT: stp q3, q4, [sp, #32]
28+
; GISEL-NEXT: stp q5, q6, [sp, #64]
29+
; GISEL-NEXT: str q7, [sp, #96]
30+
; GISEL-NEXT: add sp, sp, #176
31+
; GISEL-NEXT: ret
32+
entry:
33+
ret void
34+
}

llvm/test/CodeGen/AArch64/aarch64_win64cc_vararg.ll

+38
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
22
; RUN: llc < %s -mtriple=aarch64-linux-gnu | FileCheck %s
3+
; RUN: llc < %s --global-isel=1 -mtriple=aarch64-apple-darwin | FileCheck %s --check-prefix=DARWIN
34

45
define win64cc void @pass_va(i32 %count, ...) nounwind {
56
; CHECK-LABEL: pass_va:
@@ -17,6 +18,12 @@ define win64cc void @pass_va(i32 %count, ...) nounwind {
1718
; CHECK-NEXT: ldp x30, x18, [sp, #16] // 16-byte Folded Reload
1819
; CHECK-NEXT: add sp, sp, #96
1920
; CHECK-NEXT: ret
21+
;
22+
; DARWIN: ; %bb.0: ; %entry
23+
; DARWIN-DAG: stp x3, x4, [sp, #56]
24+
; DARWIN-DAG: stp x1, x2, [sp, #40]
25+
; DARWIN-DAG: stp x5, x6, [sp, #72]
26+
; DARWIN-DAG: str x7, [sp, #88]
2027
entry:
2128
%ap = alloca i8*, align 8
2229
%ap1 = bitcast i8** %ap to i8*
@@ -40,6 +47,16 @@ define win64cc i8* @f9(i64 %a0, i64 %a1, i64 %a2, i64 %a3, i64 %a4, i64 %a5, i64
4047
; CHECK-NEXT: str x8, [sp, #8]
4148
; CHECK-NEXT: ldr x18, [sp], #16 // 8-byte Folded Reload
4249
; CHECK-NEXT: ret
50+
;
51+
; DARWIN-LABEL: _f9:
52+
; DARWIN: ; %bb.0: ; %entry
53+
; DARWIN-NEXT: str x18, [sp, #-16]! ; 8-byte Folded Spill
54+
; DARWIN-NEXT: add x8, sp, #8
55+
; DARWIN-NEXT: add x9, sp, #24
56+
; DARWIN-NEXT: str x9, [x8]
57+
; DARWIN-NEXT: ldr x0, [sp, #8]
58+
; DARWIN-NEXT: ldr x18, [sp], #16 ; 8-byte Folded Reload
59+
; DARWIN-NEXT: ret
4360
entry:
4461
%ap = alloca i8*, align 8
4562
%ap1 = bitcast i8** %ap to i8*
@@ -57,6 +74,16 @@ define win64cc i8* @f8(i64 %a0, i64 %a1, i64 %a2, i64 %a3, i64 %a4, i64 %a5, i64
5774
; CHECK-NEXT: str x8, [sp, #8]
5875
; CHECK-NEXT: ldr x18, [sp], #16 // 8-byte Folded Reload
5976
; CHECK-NEXT: ret
77+
;
78+
; DARWIN-LABEL: _f8:
79+
; DARWIN: ; %bb.0: ; %entry
80+
; DARWIN-NEXT: str x18, [sp, #-16]! ; 8-byte Folded Spill
81+
; DARWIN-NEXT: add x8, sp, #8
82+
; DARWIN-NEXT: add x9, sp, #16
83+
; DARWIN-NEXT: str x9, [x8]
84+
; DARWIN-NEXT: ldr x0, [sp, #8]
85+
; DARWIN-NEXT: ldr x18, [sp], #16 ; 8-byte Folded Reload
86+
; DARWIN-NEXT: ret
6087
entry:
6188
%ap = alloca i8*, align 8
6289
%ap1 = bitcast i8** %ap to i8*
@@ -75,6 +102,17 @@ define win64cc i8* @f7(i64 %a0, i64 %a1, i64 %a2, i64 %a3, i64 %a4, i64 %a5, i64
75102
; CHECK-NEXT: str x8, [sp, #8]
76103
; CHECK-NEXT: ldr x18, [sp], #32 // 8-byte Folded Reload
77104
; CHECK-NEXT: ret
105+
;
106+
; DARWIN-LABEL: _f7:
107+
; DARWIN: ; %bb.0: ; %entry
108+
; DARWIN-NEXT: str x18, [sp, #-32]! ; 8-byte Folded Spill
109+
; DARWIN-NEXT: add x8, sp, #8
110+
; DARWIN-NEXT: add x9, sp, #24
111+
; DARWIN-NEXT: str x7, [sp, #24]
112+
; DARWIN-NEXT: str x9, [x8]
113+
; DARWIN-NEXT: ldr x0, [sp, #8]
114+
; DARWIN-NEXT: ldr x18, [sp], #32 ; 8-byte Folded Reload
115+
; DARWIN-NEXT: ret
78116
entry:
79117
%ap = alloca i8*, align 8
80118
%ap1 = bitcast i8** %ap to i8*

0 commit comments

Comments
 (0)