Skip to content

Commit 6f9cb9a

Browse files
[RISCV][GISEL] Legalize G_VAARG through expansion. (#73065)
G_VAARG can be expanded similiar to SelectionDAG::expandVAArg through LegalizerHelper::lower. This patch implements the lowering through this style of expansion. The expansion gets the head of the va_list by loading the pointer to va_list. Then, the head of the list is adjusted depending on argument alignment information. This gives a pointer to the element to be read out of the va_list. Next, the head of the va_list is bumped to the next element in the list. The new head of the list is stored back to the original pointer to the head of the va_list so that subsequent G_VAARG instructions get the next element in the list. Lastly, the element is loaded from the alignment adjusted pointer constructed earlier. This change is stacked on #73062.
1 parent 94c8373 commit 6f9cb9a

File tree

5 files changed

+224
-0
lines changed

5 files changed

+224
-0
lines changed

llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,7 @@ class LegalizerHelper {
432432
LegalizeResult lowerVectorReduction(MachineInstr &MI);
433433
LegalizeResult lowerMemcpyInline(MachineInstr &MI);
434434
LegalizeResult lowerMemCpyFamily(MachineInstr &MI, unsigned MaxLen = 0);
435+
LegalizeResult lowerVAArg(MachineInstr &MI);
435436
};
436437

437438
/// Helper function that creates a libcall to the given \p Name using the given

llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3793,6 +3793,8 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
37933793
return lowerTRUNC(MI);
37943794
GISEL_VECREDUCE_CASES_NONSEQ
37953795
return lowerVectorReduction(MI);
3796+
case G_VAARG:
3797+
return lowerVAArg(MI);
37963798
}
37973799
}
37983800

@@ -7887,6 +7889,56 @@ LegalizerHelper::lowerVectorReduction(MachineInstr &MI) {
78877889
return UnableToLegalize;
78887890
}
78897891

7892+
static Type *getTypeForLLT(LLT Ty, LLVMContext &C);
7893+
7894+
LegalizerHelper::LegalizeResult LegalizerHelper::lowerVAArg(MachineInstr &MI) {
7895+
MachineFunction &MF = *MI.getMF();
7896+
const DataLayout &DL = MIRBuilder.getDataLayout();
7897+
LLVMContext &Ctx = MF.getFunction().getContext();
7898+
Register ListPtr = MI.getOperand(1).getReg();
7899+
LLT PtrTy = MRI.getType(ListPtr);
7900+
7901+
// LstPtr is a pointer to the head of the list. Get the address
7902+
// of the head of the list.
7903+
Align PtrAlignment = DL.getABITypeAlign(getTypeForLLT(PtrTy, Ctx));
7904+
MachineMemOperand *PtrLoadMMO = MF.getMachineMemOperand(
7905+
MachinePointerInfo(), MachineMemOperand::MOLoad, PtrTy, PtrAlignment);
7906+
auto VAList = MIRBuilder.buildLoad(PtrTy, ListPtr, *PtrLoadMMO).getReg(0);
7907+
7908+
const Align A(MI.getOperand(2).getImm());
7909+
LLT PtrTyAsScalarTy = LLT::scalar(PtrTy.getSizeInBits());
7910+
if (A > TLI.getMinStackArgumentAlignment()) {
7911+
Register AlignAmt =
7912+
MIRBuilder.buildConstant(PtrTyAsScalarTy, A.value() - 1).getReg(0);
7913+
auto AddDst = MIRBuilder.buildPtrAdd(PtrTy, VAList, AlignAmt);
7914+
auto AndDst = MIRBuilder.buildMaskLowPtrBits(PtrTy, AddDst, Log2(A));
7915+
VAList = AndDst.getReg(0);
7916+
}
7917+
7918+
// Increment the pointer, VAList, to the next vaarg
7919+
// The list should be bumped by the size of element in the current head of
7920+
// list.
7921+
Register Dst = MI.getOperand(0).getReg();
7922+
LLT LLTTy = MRI.getType(Dst);
7923+
Type *Ty = getTypeForLLT(LLTTy, Ctx);
7924+
auto IncAmt =
7925+
MIRBuilder.buildConstant(PtrTyAsScalarTy, DL.getTypeAllocSize(Ty));
7926+
auto Succ = MIRBuilder.buildPtrAdd(PtrTy, VAList, IncAmt);
7927+
7928+
// Store the increment VAList to the legalized pointer
7929+
MachineMemOperand *StoreMMO = MF.getMachineMemOperand(
7930+
MachinePointerInfo(), MachineMemOperand::MOStore, PtrTy, PtrAlignment);
7931+
MIRBuilder.buildStore(Succ, ListPtr, *StoreMMO);
7932+
// Load the actual argument out of the pointer VAList
7933+
Align EltAlignment = DL.getABITypeAlign(Ty);
7934+
MachineMemOperand *EltLoadMMO = MF.getMachineMemOperand(
7935+
MachinePointerInfo(), MachineMemOperand::MOLoad, LLTTy, EltAlignment);
7936+
MIRBuilder.buildLoad(Dst, VAList, *EltLoadMMO);
7937+
7938+
MI.eraseFromParent();
7939+
return Legalized;
7940+
}
7941+
78907942
static bool shouldLowerMemFuncForSize(const MachineFunction &MF) {
78917943
// On Darwin, -Os means optimize for size without hurting performance, so
78927944
// only really optimize for size when -Oz (MinSize) is used.

llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,14 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST)
317317

318318
getActionDefinitionsBuilder(G_VASTART).customFor({p0});
319319

320+
// va_list must be a pointer, but most sized types are pretty easy to handle
321+
// as the destination.
322+
getActionDefinitionsBuilder(G_VAARG)
323+
// TODO: Implement narrowScalar and widenScalar for G_VAARG for types
324+
// outside the [s32, sXLen] range.
325+
.clampScalar(0, s32, sXLen)
326+
.lowerForCartesianProduct({s32, sXLen, p0}, {p0});
327+
320328
getLegacyLegalizerInfo().computeTables();
321329
}
322330

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
2+
# RUN: llc -mtriple=riscv32 -run-pass=legalizer %s -o - | FileCheck %s
3+
4+
# On RISC-V, the MinStackArgumentAlignment is 1 and the ABI Alignment for p0 is
5+
# greater than 1, so we will always generate code to adjust for this alignment.
6+
7+
---
8+
name: va_arg_i32
9+
legalized: false
10+
tracksRegLiveness: true
11+
fixedStack:
12+
- { id: 0, type: default, offset: 0, size: 4, alignment: 16,
13+
isImmutable: true, isAliased: false }
14+
stack:
15+
- { id: 0, type: default, offset: 0, size: 4, alignment: 4 }
16+
machineFunctionInfo:
17+
varArgsFrameIndex: -1
18+
varArgsSaveSize: 0
19+
body: |
20+
bb.1:
21+
liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17
22+
; CHECK-LABEL: name: va_arg_i32
23+
; CHECK: liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17
24+
; CHECK-NEXT: {{ $}}
25+
; CHECK-NEXT: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0
26+
; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(p0) = G_LOAD [[FRAME_INDEX]](p0) :: (load (p0))
27+
; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 3
28+
; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[LOAD]], [[C]](s32)
29+
; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 -4
30+
; CHECK-NEXT: [[PTRMASK:%[0-9]+]]:_(p0) = G_PTRMASK [[PTR_ADD]], [[C1]](s32)
31+
; CHECK-NEXT: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
32+
; CHECK-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = G_PTR_ADD [[PTRMASK]], [[C2]](s32)
33+
; CHECK-NEXT: G_STORE [[PTR_ADD1]](p0), [[FRAME_INDEX]](p0) :: (store (p0))
34+
; CHECK-NEXT: PseudoRET
35+
%0:_(p0) = G_FRAME_INDEX %stack.0
36+
%1:_(s32) = G_VAARG %0(p0), 4
37+
PseudoRET
38+
...
39+
---
40+
name: va_arg_ptr
41+
legalized: false
42+
tracksRegLiveness: true
43+
fixedStack:
44+
- { id: 0, type: default, offset: 0, size: 4, alignment: 16,
45+
isImmutable: true, isAliased: false }
46+
stack:
47+
- { id: 0, type: default, offset: 0, size: 4, alignment: 4 }
48+
machineFunctionInfo:
49+
varArgsFrameIndex: -1
50+
varArgsSaveSize: 0
51+
body: |
52+
bb.1:
53+
liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17
54+
; CHECK-LABEL: name: va_arg_ptr
55+
; CHECK: liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17
56+
; CHECK-NEXT: {{ $}}
57+
; CHECK-NEXT: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0
58+
; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(p0) = G_LOAD [[FRAME_INDEX]](p0) :: (load (p0))
59+
; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 3
60+
; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[LOAD]], [[C]](s32)
61+
; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 -4
62+
; CHECK-NEXT: [[PTRMASK:%[0-9]+]]:_(p0) = G_PTRMASK [[PTR_ADD]], [[C1]](s32)
63+
; CHECK-NEXT: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
64+
; CHECK-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = G_PTR_ADD [[PTRMASK]], [[C2]](s32)
65+
; CHECK-NEXT: G_STORE [[PTR_ADD1]](p0), [[FRAME_INDEX]](p0) :: (store (p0))
66+
; CHECK-NEXT: PseudoRET
67+
%0:_(p0) = G_FRAME_INDEX %stack.0
68+
%1:_(p0) = G_VAARG %0(p0), 4
69+
PseudoRET
70+
...
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
2+
# RUN: llc -mtriple=riscv64 -run-pass=legalizer %s -o - | FileCheck %s
3+
4+
# On RISC-V, the MinStackArgumentAlignment is 1 and the ABI Alignment for p0 is
5+
# greater than 1, so we will always generate code to adjust for this alignment.
6+
7+
---
8+
name: va_arg_i32
9+
legalized: false
10+
tracksRegLiveness: true
11+
fixedStack:
12+
- { id: 0, type: default, offset: 0, size: 8, alignment: 16,
13+
isImmutable: true, isAliased: false }
14+
stack:
15+
- { id: 0, type: default, offset: 0, size: 8, alignment: 8 }
16+
machineFunctionInfo:
17+
varArgsFrameIndex: -1
18+
varArgsSaveSize: 0
19+
body: |
20+
bb.1:
21+
; CHECK-LABEL: name: va_arg_i32
22+
; CHECK: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0
23+
; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(p0) = G_LOAD [[FRAME_INDEX]](p0) :: (load (p0))
24+
; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 3
25+
; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[LOAD]], [[C]](s64)
26+
; CHECK-NEXT: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 -4
27+
; CHECK-NEXT: [[PTRMASK:%[0-9]+]]:_(p0) = G_PTRMASK [[PTR_ADD]], [[C1]](s64)
28+
; CHECK-NEXT: [[C2:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
29+
; CHECK-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = G_PTR_ADD [[PTRMASK]], [[C2]](s64)
30+
; CHECK-NEXT: G_STORE [[PTR_ADD1]](p0), [[FRAME_INDEX]](p0) :: (store (p0))
31+
; CHECK-NEXT: PseudoRET
32+
%0:_(p0) = G_FRAME_INDEX %stack.0
33+
%1:_(s32) = G_VAARG %0(p0), 4
34+
PseudoRET
35+
...
36+
---
37+
name: va_arg_i64
38+
legalized: false
39+
tracksRegLiveness: true
40+
fixedStack:
41+
- { id: 0, type: default, offset: 0, size: 8, alignment: 16,
42+
isImmutable: true, isAliased: false }
43+
stack:
44+
- { id: 0, type: default, offset: 0, size: 8, alignment: 8 }
45+
machineFunctionInfo:
46+
varArgsFrameIndex: -1
47+
varArgsSaveSize: 0
48+
body: |
49+
bb.1:
50+
; CHECK-LABEL: name: va_arg_i64
51+
; CHECK: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0
52+
; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(p0) = G_LOAD [[FRAME_INDEX]](p0) :: (load (p0))
53+
; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 3
54+
; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[LOAD]], [[C]](s64)
55+
; CHECK-NEXT: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 -4
56+
; CHECK-NEXT: [[PTRMASK:%[0-9]+]]:_(p0) = G_PTRMASK [[PTR_ADD]], [[C1]](s64)
57+
; CHECK-NEXT: [[C2:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
58+
; CHECK-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = G_PTR_ADD [[PTRMASK]], [[C2]](s64)
59+
; CHECK-NEXT: G_STORE [[PTR_ADD1]](p0), [[FRAME_INDEX]](p0) :: (store (p0))
60+
; CHECK-NEXT: PseudoRET
61+
%0:_(p0) = G_FRAME_INDEX %stack.0
62+
%1:_(s64) = G_VAARG %0(p0), 4
63+
PseudoRET
64+
...
65+
---
66+
name: va_arg_ptr
67+
legalized: false
68+
tracksRegLiveness: true
69+
fixedStack:
70+
- { id: 0, type: default, offset: 0, size: 8, alignment: 16,
71+
isImmutable: true, isAliased: false }
72+
stack:
73+
- { id: 0, type: default, offset: 0, size: 8, alignment: 8 }
74+
machineFunctionInfo:
75+
varArgsFrameIndex: -1
76+
varArgsSaveSize: 0
77+
body: |
78+
bb.1:
79+
; CHECK-LABEL: name: va_arg_ptr
80+
; CHECK: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0
81+
; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(p0) = G_LOAD [[FRAME_INDEX]](p0) :: (load (p0))
82+
; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 3
83+
; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[LOAD]], [[C]](s64)
84+
; CHECK-NEXT: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 -4
85+
; CHECK-NEXT: [[PTRMASK:%[0-9]+]]:_(p0) = G_PTRMASK [[PTR_ADD]], [[C1]](s64)
86+
; CHECK-NEXT: [[C2:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
87+
; CHECK-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = G_PTR_ADD [[PTRMASK]], [[C2]](s64)
88+
; CHECK-NEXT: G_STORE [[PTR_ADD1]](p0), [[FRAME_INDEX]](p0) :: (store (p0))
89+
; CHECK-NEXT: PseudoRET
90+
%0:_(p0) = G_FRAME_INDEX %stack.0
91+
%1:_(s64) = G_VAARG %0(p0), 4
92+
PseudoRET
93+
...

0 commit comments

Comments
 (0)