diff options
author | Michael Maitland <michaeltmaitland@gmail.com> | 2023-12-08 13:24:27 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-08 13:24:27 -0500 |
commit | 6f9cb9a75ce20db2ee85cd22ddadc3bed2c450c0 (patch) | |
tree | 3722935a4612a476c319462d331fc236f0ae54e5 | |
parent | 94c837345c27e173284a85471d4efda19eded08e (diff) | |
download | llvm-6f9cb9a75ce20db2ee85cd22ddadc3bed2c450c0.zip llvm-6f9cb9a75ce20db2ee85cd22ddadc3bed2c450c0.tar.gz llvm-6f9cb9a75ce20db2ee85cd22ddadc3bed2c450c0.tar.bz2 |
[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.
5 files changed, 224 insertions, 0 deletions
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h index 365d222..711ba10 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h @@ -432,6 +432,7 @@ public: 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 diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp index 045fc78..37e7153 100644 --- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -3793,6 +3793,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); } } @@ -7887,6 +7889,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. diff --git a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp index 570b980..d71a6cf 100644 --- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp +++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp @@ -317,6 +317,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(); } diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-vaarg-rv32.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-vaarg-rv32.mir new file mode 100644 index 0000000..b67691d --- /dev/null +++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-vaarg-rv32.mir @@ -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 +... diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-vaarg-rv64.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-vaarg-rv64.mir new file mode 100644 index 0000000..537c0fb --- /dev/null +++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-vaarg-rv64.mir @@ -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 +... |