Skip to content

[RISCV][GISEL] Legalize G_VAARG through expansion. #73065

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Dec 8, 2023
1 change: 1 addition & 0 deletions llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ class LegalizerHelper {
LegalizeResult lowerVectorReduction(MachineInstr &MI);
LegalizeResult lowerMemcpyInline(MachineInstr &MI);
LegalizeResult lowerMemCpyFamily(MachineInstr &MI, unsigned MaxLen = 0);
LegalizeResult lowerVAArg(MachineInstr &MI);
};

/// Helper function that creates a libcall to the given \p Name using the given
Expand Down
52 changes: 52 additions & 0 deletions llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3783,6 +3783,8 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
return lowerTRUNC(MI);
GISEL_VECREDUCE_CASES_NONSEQ
return lowerVectorReduction(MI);
case G_VAARG:
return lowerVAArg(MI);
}
}

Expand Down Expand Up @@ -7868,6 +7870,56 @@ LegalizerHelper::lowerVectorReduction(MachineInstr &MI) {
return UnableToLegalize;
}

static Type *getTypeForLLT(LLT Ty, LLVMContext &C);

LegalizerHelper::LegalizeResult LegalizerHelper::lowerVAArg(MachineInstr &MI) {
MachineFunction &MF = *MI.getMF();
const DataLayout &DL = MIRBuilder.getDataLayout();
LLVMContext &Ctx = MF.getFunction().getContext();
Register ListPtr = MI.getOperand(1).getReg();
LLT PtrTy = MRI.getType(ListPtr);

// LstPtr is a pointer to the head of the list. Get the address
// of the head of the list.
Align PtrAlignment = DL.getABITypeAlign(getTypeForLLT(PtrTy, Ctx));
MachineMemOperand *PtrLoadMMO = MF.getMachineMemOperand(
MachinePointerInfo(), MachineMemOperand::MOLoad, PtrTy, PtrAlignment);
auto VAList = MIRBuilder.buildLoad(PtrTy, ListPtr, *PtrLoadMMO).getReg(0);

const Align A(MI.getOperand(2).getImm());
LLT PtrTyAsScalarTy = LLT::scalar(PtrTy.getSizeInBits());
if (A > TLI.getMinStackArgumentAlignment()) {
Register AlignAmt =
MIRBuilder.buildConstant(PtrTyAsScalarTy, A.value() - 1).getReg(0);
auto AddDst = MIRBuilder.buildPtrAdd(PtrTy, VAList, AlignAmt);
auto AndDst = MIRBuilder.buildMaskLowPtrBits(PtrTy, AddDst, Log2(A));
VAList = AndDst.getReg(0);
}

// Increment the pointer, VAList, to the next vaarg
// The list should be bumped by the size of element in the current head of
// list.
Register Dst = MI.getOperand(0).getReg();
LLT LLTTy = MRI.getType(Dst);
Type *Ty = getTypeForLLT(LLTTy, Ctx);
auto IncAmt =
MIRBuilder.buildConstant(PtrTyAsScalarTy, DL.getTypeAllocSize(Ty));
auto Succ = MIRBuilder.buildPtrAdd(PtrTy, VAList, IncAmt);

// Store the increment VAList to the legalized pointer
MachineMemOperand *StoreMMO = MF.getMachineMemOperand(
MachinePointerInfo(), MachineMemOperand::MOStore, PtrTy, PtrAlignment);
MIRBuilder.buildStore(Succ, ListPtr, *StoreMMO);
// Load the actual argument out of the pointer VAList
Align EltAlignment = DL.getABITypeAlign(Ty);
MachineMemOperand *EltLoadMMO = MF.getMachineMemOperand(
MachinePointerInfo(), MachineMemOperand::MOLoad, LLTTy, EltAlignment);
MIRBuilder.buildLoad(Dst, VAList, *EltLoadMMO);

MI.eraseFromParent();
return Legalized;
}

static bool shouldLowerMemFuncForSize(const MachineFunction &MF) {
// On Darwin, -Os means optimize for size without hurting performance, so
// only really optimize for size when -Oz (MinSize) is used.
Expand Down
8 changes: 8 additions & 0 deletions llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,14 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST)

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

// va_list must be a pointer, but most sized types are pretty easy to handle
// as the destination.
getActionDefinitionsBuilder(G_VAARG)
// TODO: Implement narrowScalar and widenScalar for G_VAARG for types
// outside the [s32, sXLen] range.
.clampScalar(0, s32, sXLen)
.lowerForCartesianProduct({s32, sXLen, p0}, {p0});

getLegacyLegalizerInfo().computeTables();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
# RUN: llc -mtriple=riscv32 -run-pass=legalizer %s -o - | FileCheck %s

# On RISC-V, the MinStackArgumentAlignment is 1 and the ABI Alignment for p0 is
# greater than 1, so we will always generate code to adjust for this alignment.

---
name: va_arg_i32
legalized: false
tracksRegLiveness: true
fixedStack:
- { id: 0, type: default, offset: 0, size: 4, alignment: 16,
isImmutable: true, isAliased: false }
stack:
- { id: 0, type: default, offset: 0, size: 4, alignment: 4 }
machineFunctionInfo:
varArgsFrameIndex: -1
varArgsSaveSize: 0
body: |
bb.1:
liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17
; CHECK-LABEL: name: va_arg_i32
; CHECK: liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0
; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(p0) = G_LOAD [[FRAME_INDEX]](p0) :: (load (p0))
; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 3
; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[LOAD]], [[C]](s32)
; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 -4
; CHECK-NEXT: [[PTRMASK:%[0-9]+]]:_(p0) = G_PTRMASK [[PTR_ADD]], [[C1]](s32)
; CHECK-NEXT: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
; CHECK-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = G_PTR_ADD [[PTRMASK]], [[C2]](s32)
; CHECK-NEXT: G_STORE [[PTR_ADD1]](p0), [[FRAME_INDEX]](p0) :: (store (p0))
; CHECK-NEXT: PseudoRET
%0:_(p0) = G_FRAME_INDEX %stack.0
%1:_(s32) = G_VAARG %0(p0), 4
PseudoRET
...
---
name: va_arg_ptr
legalized: false
tracksRegLiveness: true
fixedStack:
- { id: 0, type: default, offset: 0, size: 4, alignment: 16,
isImmutable: true, isAliased: false }
stack:
- { id: 0, type: default, offset: 0, size: 4, alignment: 4 }
machineFunctionInfo:
varArgsFrameIndex: -1
varArgsSaveSize: 0
body: |
bb.1:
liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17
; CHECK-LABEL: name: va_arg_ptr
; CHECK: liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0
; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(p0) = G_LOAD [[FRAME_INDEX]](p0) :: (load (p0))
; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 3
; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[LOAD]], [[C]](s32)
; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 -4
; CHECK-NEXT: [[PTRMASK:%[0-9]+]]:_(p0) = G_PTRMASK [[PTR_ADD]], [[C1]](s32)
; CHECK-NEXT: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
; CHECK-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = G_PTR_ADD [[PTRMASK]], [[C2]](s32)
; CHECK-NEXT: G_STORE [[PTR_ADD1]](p0), [[FRAME_INDEX]](p0) :: (store (p0))
; CHECK-NEXT: PseudoRET
%0:_(p0) = G_FRAME_INDEX %stack.0
%1:_(p0) = G_VAARG %0(p0), 4
PseudoRET
...
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
# RUN: llc -mtriple=riscv64 -run-pass=legalizer %s -o - | FileCheck %s

# On RISC-V, the MinStackArgumentAlignment is 1 and the ABI Alignment for p0 is
# greater than 1, so we will always generate code to adjust for this alignment.

---
name: va_arg_i32
legalized: false
tracksRegLiveness: true
fixedStack:
- { id: 0, type: default, offset: 0, size: 8, alignment: 16,
isImmutable: true, isAliased: false }
stack:
- { id: 0, type: default, offset: 0, size: 8, alignment: 8 }
machineFunctionInfo:
varArgsFrameIndex: -1
varArgsSaveSize: 0
body: |
bb.1:
; CHECK-LABEL: name: va_arg_i32
; CHECK: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0
; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(p0) = G_LOAD [[FRAME_INDEX]](p0) :: (load (p0))
; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 3
; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[LOAD]], [[C]](s64)
; CHECK-NEXT: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 -4
; CHECK-NEXT: [[PTRMASK:%[0-9]+]]:_(p0) = G_PTRMASK [[PTR_ADD]], [[C1]](s64)
; CHECK-NEXT: [[C2:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
; CHECK-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = G_PTR_ADD [[PTRMASK]], [[C2]](s64)
; CHECK-NEXT: G_STORE [[PTR_ADD1]](p0), [[FRAME_INDEX]](p0) :: (store (p0))
; CHECK-NEXT: PseudoRET
%0:_(p0) = G_FRAME_INDEX %stack.0
%1:_(s32) = G_VAARG %0(p0), 4
PseudoRET
...
---
name: va_arg_i64
legalized: false
tracksRegLiveness: true
fixedStack:
- { id: 0, type: default, offset: 0, size: 8, alignment: 16,
isImmutable: true, isAliased: false }
stack:
- { id: 0, type: default, offset: 0, size: 8, alignment: 8 }
machineFunctionInfo:
varArgsFrameIndex: -1
varArgsSaveSize: 0
body: |
bb.1:
; CHECK-LABEL: name: va_arg_i64
; CHECK: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0
; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(p0) = G_LOAD [[FRAME_INDEX]](p0) :: (load (p0))
; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 3
; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[LOAD]], [[C]](s64)
; CHECK-NEXT: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 -4
; CHECK-NEXT: [[PTRMASK:%[0-9]+]]:_(p0) = G_PTRMASK [[PTR_ADD]], [[C1]](s64)
; CHECK-NEXT: [[C2:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
; CHECK-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = G_PTR_ADD [[PTRMASK]], [[C2]](s64)
; CHECK-NEXT: G_STORE [[PTR_ADD1]](p0), [[FRAME_INDEX]](p0) :: (store (p0))
; CHECK-NEXT: PseudoRET
%0:_(p0) = G_FRAME_INDEX %stack.0
%1:_(s64) = G_VAARG %0(p0), 4
PseudoRET
...
---
name: va_arg_ptr
legalized: false
tracksRegLiveness: true
fixedStack:
- { id: 0, type: default, offset: 0, size: 8, alignment: 16,
isImmutable: true, isAliased: false }
stack:
- { id: 0, type: default, offset: 0, size: 8, alignment: 8 }
machineFunctionInfo:
varArgsFrameIndex: -1
varArgsSaveSize: 0
body: |
bb.1:
; CHECK-LABEL: name: va_arg_ptr
; CHECK: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0
; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(p0) = G_LOAD [[FRAME_INDEX]](p0) :: (load (p0))
; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 3
; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[LOAD]], [[C]](s64)
; CHECK-NEXT: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 -4
; CHECK-NEXT: [[PTRMASK:%[0-9]+]]:_(p0) = G_PTRMASK [[PTR_ADD]], [[C1]](s64)
; CHECK-NEXT: [[C2:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
; CHECK-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = G_PTR_ADD [[PTRMASK]], [[C2]](s64)
; CHECK-NEXT: G_STORE [[PTR_ADD1]](p0), [[FRAME_INDEX]](p0) :: (store (p0))
; CHECK-NEXT: PseudoRET
%0:_(p0) = G_FRAME_INDEX %stack.0
%1:_(s64) = G_VAARG %0(p0), 4
PseudoRET
...