Skip to content
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
...