[llvm] [RISCV][GISEL] Legalize G_VAARG through expansion. (PR #73065)

Michael Maitland via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 21 18:13:37 PST 2023


https://github.com/michaelmaitland updated https://github.com/llvm/llvm-project/pull/73065

>From 1138caa354beb5f57225e148adaca22ef7d83129 Mon Sep 17 00:00:00 2001
From: Michael Maitland <michaeltmaitland at gmail.com>
Date: Fri, 17 Nov 2023 07:37:47 -0800
Subject: [PATCH 1/2] [RISCV][GISEL] Legalize G_PTRMASK

G_PTRMASK is custom legalized by using G_PTRTOINT on the pointer, using a
G_AND to calculate the mask, and converted back to pointer using G_PTRTOINT.
---
 .../Target/RISCV/GISel/RISCVLegalizerInfo.cpp | 23 ++++++++++++++++++
 .../Target/RISCV/GISel/RISCVLegalizerInfo.h   |  3 +++
 .../legalizer/legalize-ptrmask-rv32.mir       | 24 +++++++++++++++++++
 .../legalizer/legalize-ptrmask-rv64.mir       | 24 +++++++++++++++++++
 4 files changed, 74 insertions(+)
 create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-ptrmask-rv32.mir
 create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-ptrmask-rv64.mir

diff --git a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
index 9eb5812e024b915..1c1c4ee6a9aed3a 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
@@ -147,6 +147,8 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST) {
 
   getActionDefinitionsBuilder(G_PTR_ADD).legalFor({{p0, sXLen}});
 
+  getActionDefinitionsBuilder(G_PTRMASK).customFor({{p0, sXLen}});
+
   getActionDefinitionsBuilder(G_PTRTOINT)
       .legalFor({{sXLen, p0}})
       .clampScalar(0, sXLen, sXLen);
@@ -288,6 +290,25 @@ bool RISCVLegalizerInfo::legalizeShlAshrLshr(
   return true;
 }
 
+bool RISCVLegalizerInfo::legalizePtrMask(MachineInstr &MI,
+                                         MachineIRBuilder &MIRBuilder,
+                                         GISelChangeObserver &Observer) const {
+  assert(MI.getOpcode() == TargetOpcode::G_PTRMASK);
+
+  MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
+  Register Tmp1 =
+      MRI.createGenericVirtualRegister(MRI.getType(MI.getOperand(2).getReg()));
+  Register Tmp2 =
+      MRI.createGenericVirtualRegister(MRI.getType(MI.getOperand(2).getReg()));
+  MIRBuilder.buildPtrToInt(Tmp1, MI.getOperand(1).getReg());
+  MIRBuilder.buildAnd(Tmp2, Tmp1, MI.getOperand(2).getReg());
+  MIRBuilder.buildIntToPtr(MI.getOperand(0).getReg(), Tmp2);
+
+  Observer.erasingInstr(MI);
+  MI.eraseFromParent();
+  return true;
+}
+
 bool RISCVLegalizerInfo::legalizeCustom(LegalizerHelper &Helper,
                                         MachineInstr &MI) const {
   MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
@@ -309,6 +330,8 @@ bool RISCVLegalizerInfo::legalizeCustom(LegalizerHelper &Helper,
     return Helper.lower(MI, 0, /* Unused hint type */ LLT()) ==
            LegalizerHelper::Legalized;
   }
+  case TargetOpcode::G_PTRMASK:
+    return legalizePtrMask(MI, MIRBuilder, Observer);
   }
 
   llvm_unreachable("expected switch to return");
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.h b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.h
index f39d3a130d85063..ff2be0622023795 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.h
+++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.h
@@ -31,6 +31,9 @@ class RISCVLegalizerInfo : public LegalizerInfo {
 private:
   bool legalizeShlAshrLshr(MachineInstr &MI, MachineIRBuilder &MIRBuilder,
                            GISelChangeObserver &Observer) const;
+
+  bool legalizePtrMask(MachineInstr &MI, MachineIRBuilder &MIRBuilder,
+                       GISelChangeObserver &Observer) const;
 };
 } // end namespace llvm
 #endif
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-ptrmask-rv32.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-ptrmask-rv32.mir
new file mode 100644
index 000000000000000..af91461040047f8
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-ptrmask-rv32.mir
@@ -0,0 +1,24 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=riscv32 -run-pass=legalizer -verify-machineinstrs %s -o - | FileCheck %s
+
+---
+name:            ptrmask_p0_s32
+body:             |
+  bb.0:
+    liveins: $x10, $x11
+    ; CHECK-LABEL: name: ptrmask_p0_s32
+    ; CHECK: liveins: $x10, $x11
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x10
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $x11
+    ; CHECK-NEXT: [[PTRTOINT:%[0-9]+]]:_(s32) = G_PTRTOINT [[COPY]](p0)
+    ; CHECK-NEXT: [[AND:%[0-9]+]]:_(s32) = G_AND [[PTRTOINT]], [[COPY1]]
+    ; CHECK-NEXT: [[INTTOPTR:%[0-9]+]]:_(p0) = G_INTTOPTR [[AND]](s32)
+    ; CHECK-NEXT: $x10 = COPY [[INTTOPTR]](p0)
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:_(p0) = COPY $x10
+    %1:_(s32) = COPY $x11
+    %2:_(p0) = G_PTRMASK %0(p0), %1(s32)
+    $x10 = COPY %2(p0)
+    PseudoRET implicit $x10
+...
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-ptrmask-rv64.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-ptrmask-rv64.mir
new file mode 100644
index 000000000000000..b7223c1e2ca2ea6
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-ptrmask-rv64.mir
@@ -0,0 +1,24 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=riscv64 -run-pass=legalizer -verify-machineinstrs %s -o - | FileCheck %s
+
+---
+name:            ptrmask_p0_s64
+body:             |
+  bb.0:
+    liveins: $x10, $x11
+    ; CHECK-LABEL: name: ptrmask_p0_s64
+    ; CHECK: liveins: $x10, $x11
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x10
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x11
+    ; CHECK-NEXT: [[PTRTOINT:%[0-9]+]]:_(s64) = G_PTRTOINT [[COPY]](p0)
+    ; CHECK-NEXT: [[AND:%[0-9]+]]:_(s64) = G_AND [[PTRTOINT]], [[COPY1]]
+    ; CHECK-NEXT: [[INTTOPTR:%[0-9]+]]:_(p0) = G_INTTOPTR [[AND]](s64)
+    ; CHECK-NEXT: $x10 = COPY [[INTTOPTR]](p0)
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:_(p0) = COPY $x10
+    %1:_(s64) = COPY $x11
+    %2:_(p0) = G_PTRMASK %0(p0), %1(s64)
+    $x10 = COPY %2(p0)
+    PseudoRET implicit $x10
+...

>From 8e46f0fd5757955ee1286fb39fc96f334f9c0bb1 Mon Sep 17 00:00:00 2001
From: Michael Maitland <michaeltmaitland at gmail.com>
Date: Fri, 17 Nov 2023 07:27:37 -0800
Subject: [PATCH 2/2] [RISCV][GISEL] Legalize G_VAARG through expansion.

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.
---
 .../llvm/CodeGen/GlobalISel/LegalizerHelper.h |  1 +
 .../CodeGen/GlobalISel/LegalizerHelper.cpp    | 67 +++++++++++++++++++
 .../Target/RISCV/GISel/RISCVLegalizerInfo.cpp |  5 ++
 .../legalizer/legalize-vaarg-rv32.mir         | 40 +++++++++++
 .../legalizer/legalize-vaarg-rv64.mir         | 40 +++++++++++
 5 files changed, 153 insertions(+)
 create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-vaarg-rv32.mir
 create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-vaarg-rv64.mir

diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
index 86d3cb2bedb95b6..350c91ad6fa4f61 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
@@ -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
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index dd5577d47f97764..310b71dca37bf3c 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -3780,6 +3780,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);
   }
 }
 
@@ -7865,6 +7867,71 @@ LegalizerHelper::lowerVectorReduction(MachineInstr &MI) {
   return UnableToLegalize;
 }
 
+static Type *getTypeForLLT(LLT Ty, LLVMContext &C);
+
+LegalizerHelper::LegalizeResult LegalizerHelper::lowerVAArg(MachineInstr &MI) {
+  Observer.changingInstr(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 = Align(DL.getABITypeAlign(getTypeForLLT(PtrTy, Ctx)));
+  MachineMemOperand *PtrLoadMMO =
+      MF.getMachineMemOperand(MachinePointerInfo::getUnknownStack(MF),
+                              MachineMemOperand::MOLoad, PtrTy, PtrAlignment);
+  Register HeadOfList = MRI.createGenericVirtualRegister(PtrTy);
+  Register VAList =
+      MIRBuilder.buildLoad(HeadOfList, ListPtr, *PtrLoadMMO).getReg(0);
+
+  const MaybeAlign MA(MI.getOperand(2).getImm());
+  LLT PtrTyAsScalarTy = LLT::scalar(PtrTy.getSizeInBits());
+  if (MA && *MA > TLI.getMinStackArgumentAlignment()) {
+    Register AlignAmt =
+        MIRBuilder.buildConstant(PtrTyAsScalarTy, MA->value() - 1).getReg(0);
+    Register AddDst = MRI.createGenericVirtualRegister(PtrTy);
+    MIRBuilder.buildPtrAdd(AddDst, HeadOfList, AlignAmt);
+    Register Mask =
+        MIRBuilder.buildConstant(PtrTyAsScalarTy, -(int64_t)MA->value())
+            .getReg(0);
+    Register AndDst = MRI.createGenericVirtualRegister(PtrTy);
+    VAList = MIRBuilder.buildPtrMask(AndDst, AddDst, Mask).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 Ty = MRI.getType(Dst);
+  Register IncAmt =
+      MIRBuilder
+          .buildConstant(PtrTyAsScalarTy,
+                         DL.getTypeAllocSize(getTypeForLLT(Ty, Ctx)))
+          .getReg(0);
+  Register Succ = MRI.createGenericVirtualRegister(PtrTy);
+  MIRBuilder.buildPtrAdd(Succ, VAList, IncAmt);
+
+  // Store the increment VAList to the legalized pointer
+  MachineMemOperand *StoreMMO =
+      MF.getMachineMemOperand(MachinePointerInfo::getUnknownStack(MF),
+                              MachineMemOperand::MOStore, PtrTy, PtrAlignment);
+  MIRBuilder.buildStore(Succ, ListPtr, *StoreMMO);
+  // Load the actual argument out of the pointer VAList
+  Align EltAlignment = Align(DL.getABITypeAlign(getTypeForLLT(Ty, Ctx)));
+  MachineMemOperand *EltLoadMMO =
+      MF.getMachineMemOperand(MachinePointerInfo::getUnknownStack(MF),
+                              MachineMemOperand::MOLoad, Ty, EltAlignment);
+  MIRBuilder.buildLoad(Dst, VAList, *EltLoadMMO);
+
+  Observer.changedInstr(MI);
+  Observer.erasingInstr(MI);
+  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 1c1c4ee6a9aed3a..e19231777eb335d 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
@@ -263,6 +263,11 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST) {
   getActionDefinitionsBuilder({G_FCEIL, G_FFLOOR})
       .libcallFor({s32, s64});
 
+  // va_list must be a pointer, but most sized types are pretty easy to handle
+  // as the destination.
+  getActionDefinitionsBuilder(G_VAARG).lowerForCartesianProduct(
+      {s8, s16, s32, s64, 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 000000000000000..4876e0d5ee96b2f
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-vaarg-rv32.mir
@@ -0,0 +1,40 @@
+# 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.
+
+--- |
+  define void @va_arg() {
+    %va = alloca ptr, align 4
+    %1 = va_arg ptr %va, i32
+    ret void
+  }
+...
+---
+name:            va_arg
+legalized:       false
+tracksRegLiveness: true
+stack:
+  - { id: 0, name: va, type: default, offset: 0, size: 4, alignment: 4,
+      stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+body:             |
+  bb.1 (%ir-block.0):
+    ; CHECK-LABEL: name: va_arg
+    ; CHECK: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0.va
+    ; 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: [[PTRTOINT:%[0-9]+]]:_(s32) = G_PTRTOINT [[PTR_ADD]](p0)
+    ; CHECK-NEXT: [[AND:%[0-9]+]]:_(s32) = G_AND [[PTRTOINT]], [[C1]]
+    ; CHECK-NEXT: [[INTTOPTR:%[0-9]+]]:_(p0) = G_INTTOPTR [[AND]](s32)
+    ; CHECK-NEXT: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
+    ; CHECK-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = G_PTR_ADD [[INTTOPTR]], [[C2]](s32)
+    ; CHECK-NEXT: G_STORE [[PTR_ADD1]](p0), [[FRAME_INDEX]](p0) :: (store (p0))
+    ; CHECK-NEXT: PseudoRET
+    %0:_(p0) = G_FRAME_INDEX %stack.0.va
+    %1:_(s32) = 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 000000000000000..c32f590479c7aa3
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-vaarg-rv64.mir
@@ -0,0 +1,40 @@
+# 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.
+
+--- |
+  define void @va_arg() {
+    %va = alloca ptr, align 8
+    %1 = va_arg ptr %va, i32
+    ret void
+  }
+...
+---
+name:            va_arg
+legalized:       false
+tracksRegLiveness: true
+stack:
+  - { id: 0, name: va, type: default, offset: 0, size: 8, alignment: 4,
+      stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+body:             |
+  bb.1 (%ir-block.0):
+    ; CHECK-LABEL: name: va_arg
+    ; CHECK: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0.va
+    ; 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: [[PTRTOINT:%[0-9]+]]:_(s64) = G_PTRTOINT [[PTR_ADD]](p0)
+    ; CHECK-NEXT: [[AND:%[0-9]+]]:_(s64) = G_AND [[PTRTOINT]], [[C1]]
+    ; CHECK-NEXT: [[INTTOPTR:%[0-9]+]]:_(p0) = G_INTTOPTR [[AND]](s64)
+    ; CHECK-NEXT: [[C2:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
+    ; CHECK-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = G_PTR_ADD [[INTTOPTR]], [[C2]](s64)
+    ; CHECK-NEXT: G_STORE [[PTR_ADD1]](p0), [[FRAME_INDEX]](p0) :: (store (p0))
+    ; CHECK-NEXT: PseudoRET
+    %0:_(p0) = G_FRAME_INDEX %stack.0.va
+    %1:_(s32) = G_VAARG %0(p0), 4
+    PseudoRET
+...



More information about the llvm-commits mailing list