[llvm] [RISCV][llvm] Support frame index in zilsd optimizer (PR #174073)

via llvm-commits llvm-commits at lists.llvm.org
Wed Dec 31 00:51:01 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-risc-v

Author: Brandon Wu (4vtomat)

<details>
<summary>Changes</summary>

Current zilsd optimizer only support base op that is in a register,
however many use cases are essentially stack load/store.


---
Full diff: https://github.com/llvm/llvm-project/pull/174073.diff


4 Files Affected:

- (modified) llvm/lib/Target/RISCV/RISCVLoadStoreOptimizer.cpp (+48-19) 
- (modified) llvm/lib/Target/RISCV/RISCVZilsdOptimizer.cpp (+39-18) 
- (modified) llvm/test/CodeGen/RISCV/zilsd-ldst-opt-postra.mir (+99) 
- (modified) llvm/test/CodeGen/RISCV/zilsd-ldst-opt-prera.mir (+95) 


``````````diff
diff --git a/llvm/lib/Target/RISCV/RISCVLoadStoreOptimizer.cpp b/llvm/lib/Target/RISCV/RISCVLoadStoreOptimizer.cpp
index ff5894e1a657d..c4b83adef5ee3 100644
--- a/llvm/lib/Target/RISCV/RISCVLoadStoreOptimizer.cpp
+++ b/llvm/lib/Target/RISCV/RISCVLoadStoreOptimizer.cpp
@@ -576,7 +576,12 @@ void RISCVLoadStoreOpt::splitLdSdIntoTwo(MachineBasicBlock &MBB,
   const MachineOperand &BaseOp = MI->getOperand(2);
   Register FirstReg = FirstOp.getReg();
   Register SecondReg = SecondOp.getReg();
-  Register BaseReg = BaseOp.getReg();
+  unsigned BaseReg;
+  bool BaseIsReg = BaseOp.isReg();
+  if (BaseIsReg)
+    BaseReg = BaseOp.getReg().id();
+  else
+    BaseReg = BaseOp.getIndex();
 
   // Handle both immediate and symbolic operands for offset
   const MachineOperand &OffsetOp = MI->getOperand(3);
@@ -601,26 +606,37 @@ void RISCVLoadStoreOpt::splitLdSdIntoTwo(MachineBasicBlock &MBB,
     // we can just switch the order to resolve that:
     // X13 = LW X10, 4
     // X10 = LW killed X10, 0
-    if (FirstReg == BaseReg) {
+    if (BaseIsReg && FirstReg == BaseReg) {
       MIB2 = BuildMI(MBB, MBBI, DL, TII->get(Opc))
                  .addReg(SecondReg,
-                         RegState::Define | getDeadRegState(SecondOp.isDead()))
-                 .addReg(BaseReg);
+                         RegState::Define | getDeadRegState(SecondOp.isDead()));
       MIB1 = BuildMI(MBB, MBBI, DL, TII->get(Opc))
                  .addReg(FirstReg,
-                         RegState::Define | getDeadRegState(FirstOp.isDead()))
-                 .addReg(BaseReg, getKillRegState(BaseOp.isKill()));
+                         RegState::Define | getDeadRegState(FirstOp.isDead()));
+
+      if (BaseIsReg) {
+        MIB2 = MIB2.addReg(BaseReg);
+        MIB1 = MIB1.addReg(BaseReg, getKillRegState(BaseOp.isKill()));
+      } else {
+        MIB2 = MIB2.addFrameIndex(BaseReg);
+        MIB1 = MIB1.addFrameIndex(BaseReg);
+      }
 
     } else {
       MIB1 = BuildMI(MBB, MBBI, DL, TII->get(Opc))
                  .addReg(FirstReg,
-                         RegState::Define | getDeadRegState(FirstOp.isDead()))
-                 .addReg(BaseReg);
-
+                         RegState::Define | getDeadRegState(FirstOp.isDead()));
       MIB2 = BuildMI(MBB, MBBI, DL, TII->get(Opc))
                  .addReg(SecondReg,
-                         RegState::Define | getDeadRegState(SecondOp.isDead()))
-                 .addReg(BaseReg, getKillRegState(BaseOp.isKill()));
+                         RegState::Define | getDeadRegState(SecondOp.isDead()));
+
+      if (BaseIsReg) {
+        MIB1 = MIB1.addReg(BaseReg);
+        MIB2 = MIB2.addReg(BaseReg, getKillRegState(BaseOp.isKill()));
+      } else {
+        MIB1 = MIB1.addFrameIndex(BaseReg);
+        MIB2 = MIB2.addFrameIndex(BaseReg);
+      }
     }
 
     ++NumLD2LW;
@@ -630,12 +646,18 @@ void RISCVLoadStoreOpt::splitLdSdIntoTwo(MachineBasicBlock &MBB,
         FirstReg != SecondReg &&
         "First register and second register is impossible to be same register");
     MIB1 = BuildMI(MBB, MBBI, DL, TII->get(Opc))
-               .addReg(FirstReg, getKillRegState(FirstOp.isKill()))
-               .addReg(BaseReg);
+               .addReg(FirstReg, getKillRegState(FirstOp.isKill()));
 
     MIB2 = BuildMI(MBB, MBBI, DL, TII->get(Opc))
-               .addReg(SecondReg, getKillRegState(SecondOp.isKill()))
-               .addReg(BaseReg, getKillRegState(BaseOp.isKill()));
+               .addReg(SecondReg, getKillRegState(SecondOp.isKill()));
+
+    if (BaseIsReg) {
+      MIB1 = MIB1.addReg(BaseReg);
+      MIB2 = MIB2.addReg(BaseReg, getKillRegState(BaseOp.isKill()));
+    } else {
+      MIB1 = MIB1.addFrameIndex(BaseReg);
+      MIB2 = MIB2.addFrameIndex(BaseReg);
+    }
 
     ++NumSD2SW;
     LLVM_DEBUG(dbgs() << "Split SD back to two SW instructions\n");
@@ -689,7 +711,12 @@ bool RISCVLoadStoreOpt::fixInvalidRegPairOp(MachineBasicBlock &MBB,
 
   // Registers are valid, convert to real LD/SD instruction
   const MachineOperand &BaseOp = MI->getOperand(2);
-  Register BaseReg = BaseOp.getReg();
+  unsigned BaseReg;
+  bool BaseIsReg = BaseOp.isReg();
+  if (BaseIsReg)
+    BaseReg = BaseOp.getReg().id();
+  else
+    BaseReg = BaseOp.getIndex();
   DebugLoc DL = MI->getDebugLoc();
   // Handle both immediate and symbolic operands for offset
   const MachineOperand &OffsetOp = MI->getOperand(3);
@@ -711,9 +738,11 @@ bool RISCVLoadStoreOpt::fixInvalidRegPairOp(MachineBasicBlock &MBB,
     MIB.addReg(RegPair, getKillRegState(FirstOp.isKill() && SecondOp.isKill()));
   }
 
-  MIB.addReg(BaseReg, getKillRegState(BaseOp.isKill()))
-      .add(OffsetOp)
-      .cloneMemRefs(*MI);
+  if (BaseIsReg)
+    MIB = MIB.addReg(BaseReg, getKillRegState(BaseOp.isKill()));
+  else
+    MIB = MIB.addFrameIndex(BaseReg);
+  MIB.add(OffsetOp).cloneMemRefs(*MI);
 
   LLVM_DEBUG(dbgs() << "Converted pseudo to real instruction: " << *MIB
                     << "\n");
diff --git a/llvm/lib/Target/RISCV/RISCVZilsdOptimizer.cpp b/llvm/lib/Target/RISCV/RISCVZilsdOptimizer.cpp
index 3b47903c351bf..2de73e6267dd0 100644
--- a/llvm/lib/Target/RISCV/RISCVZilsdOptimizer.cpp
+++ b/llvm/lib/Target/RISCV/RISCVZilsdOptimizer.cpp
@@ -87,7 +87,8 @@ class RISCVPreAllocZilsdOpt : public MachineFunctionPass {
     Global = 1,
     CPI = 2,
     BlockAddr = 3,
-    Unknown = 4,
+    FrameIdx = 4,
+    Unknown = 5,
   };
   using MemOffset = std::pair<MemoryOffsetKind, int>;
   using BaseRegInfo = std::pair<unsigned, MemoryOffsetKind>;
@@ -160,12 +161,16 @@ RISCVPreAllocZilsdOpt::getMemoryOpOffset(const MachineInstr &MI) {
   switch (MI.getOpcode()) {
   case RISCV::LW:
   case RISCV::SW: {
-    // For LW/SW, the offset is in operand 2
+    // For LW/SW, the base is in operand 1 and offset is in operand 2
+    const MachineOperand &BaseOp = MI.getOperand(1);
     const MachineOperand &OffsetOp = MI.getOperand(2);
 
     // Handle immediate offset
-    if (OffsetOp.isImm())
+    if (OffsetOp.isImm()) {
+      if (BaseOp.isFI())
+        return std::make_pair(MemoryOffsetKind::FrameIdx, OffsetOp.getImm());
       return std::make_pair(MemoryOffsetKind::Imm, OffsetOp.getImm());
+    }
 
     // Handle symbolic operands with MO_LO flag (from MergeBaseOffset)
     if (OffsetOp.getTargetFlags() & RISCVII::MO_LO) {
@@ -229,7 +234,7 @@ bool RISCVPreAllocZilsdOpt::isSafeToMove(MachineInstr *MI, MachineInstr *Target,
     ++Start;
 
   Register DefReg = MI->getOperand(0).getReg();
-  Register BaseReg = MI->getOperand(1).getReg();
+  const MachineOperand &BaseOp = MI->getOperand(1);
 
   unsigned ScanCount = 0;
   for (auto It = Start; It != End; ++It, ++ScanCount) {
@@ -247,8 +252,8 @@ bool RISCVPreAllocZilsdOpt::isSafeToMove(MachineInstr *MI, MachineInstr *Target,
     }
 
     // Check if the base register is modified
-    if (It->modifiesRegister(BaseReg, TRI)) {
-      LLVM_DEBUG(dbgs() << "Base register " << BaseReg
+    if (BaseOp.isReg() && It->modifiesRegister(BaseOp.getReg(), TRI)) {
+      LLVM_DEBUG(dbgs() << "Base register " << BaseOp.getReg()
                         << " modified by: " << *It);
       return false;
     }
@@ -297,8 +302,16 @@ bool RISCVPreAllocZilsdOpt::rescheduleOps(
 
     Register FirstReg = MI0->getOperand(0).getReg();
     Register SecondReg = MI1->getOperand(0).getReg();
-    Register BaseReg = MI0->getOperand(1).getReg();
+    const MachineOperand &BaseOp = MI0->getOperand(1);
     const MachineOperand &OffsetOp = MI0->getOperand(2);
+    assert((BaseOp.isReg() || BaseOp.isFI()) &&
+           "Base register should be register or frame index");
+    unsigned BaseReg;
+    bool BaseIsReg = BaseOp.isReg();
+    if (BaseIsReg)
+      BaseReg = BaseOp.getReg().id();
+    else
+      BaseReg = BaseOp.getIndex();
 
     // At this point, MI0 and MI1 are:
     //    1. both either LW or SW.
@@ -347,21 +360,23 @@ bool RISCVPreAllocZilsdOpt::rescheduleOps(
     if (IsLoad) {
       MIB = BuildMI(*MBB, InsertPos, DL, TII->get(RISCV::PseudoLD_RV32_OPT))
                 .addReg(FirstReg, RegState::Define)
-                .addReg(SecondReg, RegState::Define)
-                .addReg(BaseReg)
-                .add(OffsetOp);
+                .addReg(SecondReg, RegState::Define);
       ++NumLDFormed;
       LLVM_DEBUG(dbgs() << "Formed LD: " << *MIB << "\n");
     } else {
       MIB = BuildMI(*MBB, InsertPos, DL, TII->get(RISCV::PseudoSD_RV32_OPT))
                 .addReg(FirstReg)
-                .addReg(SecondReg)
-                .addReg(BaseReg)
-                .add(OffsetOp);
+                .addReg(SecondReg);
       ++NumSDFormed;
       LLVM_DEBUG(dbgs() << "Formed SD: " << *MIB << "\n");
     }
 
+    if (BaseIsReg)
+      MIB = MIB.addReg(BaseReg);
+    else
+      MIB = MIB.addFrameIndex(BaseReg);
+    MIB = MIB.add(OffsetOp);
+
     // Copy memory operands
     MIB.cloneMergedMemRefs({MI0, MI1});
 
@@ -394,7 +409,7 @@ bool RISCVPreAllocZilsdOpt::isMemoryOp(const MachineInstr &MI) {
   if (Opcode != RISCV::LW && Opcode != RISCV::SW)
     return false;
 
-  if (!MI.getOperand(1).isReg())
+  if (!MI.getOperand(1).isReg() && !MI.getOperand(1).isFI())
     return false;
 
   // When no memory operands are present, conservatively assume unaligned,
@@ -413,7 +428,7 @@ bool RISCVPreAllocZilsdOpt::isMemoryOp(const MachineInstr &MI) {
     return false;
 
   // Likewise don't mess with references to undefined addresses.
-  if (MI.getOperand(1).isUndef())
+  if (MI.getOperand(1).isReg() && MI.getOperand(1).isUndef())
     return false;
 
   return true;
@@ -462,16 +477,22 @@ bool RISCVPreAllocZilsdOpt::rescheduleLoadStoreInstrs(MachineBasicBlock *MBB) {
         continue;
 
       bool IsLd = (MI.getOpcode() == RISCV::LW);
-      Register Base = MI.getOperand(1).getReg();
+      const MachineOperand &BaseOp = MI.getOperand(1);
+      unsigned BaseReg;
+      bool BaseIsReg = BaseOp.isReg();
+      if (BaseIsReg)
+        BaseReg = BaseOp.getReg().id();
+      else
+        BaseReg = BaseOp.getIndex();
       bool StopHere = false;
 
       // Lambda to find or add base register entries
       auto FindBases = [&](Base2InstMap &Base2Ops, BaseVec &Bases) {
-        auto [BI, Inserted] = Base2Ops.try_emplace({Base.id(), Offset.first});
+        auto [BI, Inserted] = Base2Ops.try_emplace({BaseReg, Offset.first});
         if (Inserted) {
           // First time seeing this base register
           BI->second.push_back(&MI);
-          Bases.push_back({Base.id(), Offset.first});
+          Bases.push_back({BaseReg, Offset.first});
           return;
         }
         // Check if we've seen this exact base+offset before
diff --git a/llvm/test/CodeGen/RISCV/zilsd-ldst-opt-postra.mir b/llvm/test/CodeGen/RISCV/zilsd-ldst-opt-postra.mir
index c27cb25366f27..ec7ecf5a534ef 100644
--- a/llvm/test/CodeGen/RISCV/zilsd-ldst-opt-postra.mir
+++ b/llvm/test/CodeGen/RISCV/zilsd-ldst-opt-postra.mir
@@ -10,6 +10,10 @@
     ret i32 %5
   }
 
+  define void @expand_pseudold_frame_index_valid(ptr %0) {
+    ret void
+  }
+
   define void @expand_pseudosd_valid(ptr %0, i32 %1, i32 %2) {
     store i32 %1, ptr %0, align 4
     %4 = getelementptr inbounds i32, ptr %0, i32 1
@@ -17,6 +21,10 @@
     ret void
   }
 
+  define void @expand_pseudosd_frame_index_valid(ptr %0, i32 %1, i32 %2) {
+    ret void
+  }
+
   define i32 @expand_pseudold_invalid_pair(ptr %0) {
     %2 = load i32, ptr %0, align 4
     %3 = getelementptr inbounds i32, ptr %0, i32 1
@@ -25,6 +33,10 @@
     ret i32 %5
   }
 
+  define void @expand_pseudold_frame_index_invalid_pair(ptr %0) {
+    ret void
+  }
+
   define void @expand_pseudosd_invalid_pair(ptr %0, i32 %1, i32 %2) {
     store i32 %1, ptr %0, align 4
     %4 = getelementptr inbounds i32, ptr %0, i32 1
@@ -32,6 +44,10 @@
     ret void
   }
 
+  define void @expand_pseudosd_frame_index_invalid_pair(ptr %0, i32 %1, i32 %2) {
+    ret void
+  }
+
   define void @store_zero_combine_valid(ptr %0) {
     store i32 0, ptr %0, align 8
     %2 = getelementptr inbounds i32, ptr %0, i32 1
@@ -75,6 +91,27 @@ body: |
     $x10 = ADD killed $x12, killed $x13
     PseudoRET implicit $x10
 
+...
+---
+# Valid consecutive even/odd register pair - should expand to LD_RV32
+name: expand_pseudold_frame_index_valid
+tracksRegLiveness: false
+stack:
+  - { id: 0, offset: 0, size: 8, alignment: 4 }
+body: |
+  bb.0:
+    liveins: $x10
+
+    ; CHECK-LABEL: name: expand_pseudold_frame_index_valid
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: $x12_x13 = LD_RV32 %stack.0, 0
+    ; CHECK-NEXT: $x10 = ADD killed $x12, killed $x13
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    $x12, $x13 = PseudoLD_RV32_OPT %stack.0, 0
+    $x10 = ADD killed $x12, killed $x13
+    PseudoRET implicit $x10
+
 ...
 ---
 # Valid consecutive even/odd register pair - should expand to SD_RV32
@@ -93,6 +130,26 @@ body: |
     PseudoSD_RV32_OPT killed $x12, killed $x13, killed $x10, 0
     PseudoRET
 
+...
+---
+# Valid consecutive even/odd register pair - should expand to SD_RV32
+name: expand_pseudosd_frame_index_valid
+tracksRegLiveness: false
+stack:
+  - { id: 0, offset: 0, size: 8, alignment: 4 }
+body: |
+  bb.0:
+    liveins: $x12, $x13
+
+    ; PseudoSD_RV32_OPT with consecutive even/odd registers (x12, x13)
+    ; CHECK-LABEL: name: expand_pseudosd_frame_index_valid
+    ; CHECK: liveins: $x12, $x13
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: SD_RV32 killed $x12_x13, %stack.0, 0
+    ; CHECK-NEXT: PseudoRET
+    PseudoSD_RV32_OPT killed $x12, killed $x13, %stack.0, 0
+    PseudoRET
+
 ...
 ---
 # Invalid register pair (not consecutive) - should decompose back to LW
@@ -115,6 +172,26 @@ body: |
     $x10 = ADD killed $x11, killed $x13
     PseudoRET implicit $x10
 
+...
+---
+# Invalid register pair (not consecutive) - should decompose back to LW
+name: expand_pseudold_frame_index_invalid_pair
+tracksRegLiveness: false
+stack:
+  - { id: 0, offset: 0, size: 8, alignment: 4 }
+body: |
+  bb.0:
+    ; PseudoLD_RV32_OPT with non-consecutive registers (x11, x13)
+    ; Should decompose back to two LW instructions
+    ; CHECK-LABEL: name: expand_pseudold_frame_index_invalid_pair
+    ; CHECK: $x11 = LW %stack.0, 0
+    ; CHECK-NEXT: $x13 = LW %stack.0, 4
+    ; CHECK-NEXT: $x10 = ADD killed $x11, killed $x13
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    $x11, $x13 = PseudoLD_RV32_OPT %stack.0, 0
+    $x10 = ADD killed $x11, killed $x13
+    PseudoRET implicit $x10
+
 ...
 ---
 # Invalid register pair (not even/odd) - should decompose back to SW
@@ -135,6 +212,28 @@ body: |
     PseudoSD_RV32_OPT killed $x11, killed $x14, killed $x10, 0
     PseudoRET
 
+...
+---
+# Invalid register pair (not even/odd) - should decompose back to SW
+name: expand_pseudosd_frame_index_invalid_pair
+tracksRegLiveness: false
+stack:
+  - { id: 0, offset: 0, size: 8, alignment: 4 }
+body: |
+  bb.0:
+    liveins: $x11, $x14
+
+    ; PseudoSD_RV32_OPT with non-consecutive registers (x11, x14)
+    ; Should decompose back to two SW instructions
+    ; CHECK-LABEL: name: expand_pseudosd_frame_index_invalid_pair
+    ; CHECK: liveins: $x11, $x14
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: SW killed $x11, %stack.0, 0
+    ; CHECK-NEXT: SW killed $x14, %stack.0, 4
+    ; CHECK-NEXT: PseudoRET
+    PseudoSD_RV32_OPT killed $x11, killed $x14, %stack.0, 0
+    PseudoRET
+
 ...
 ---
 # Test store zero combinations - zeros don't need consecutive pairs
diff --git a/llvm/test/CodeGen/RISCV/zilsd-ldst-opt-prera.mir b/llvm/test/CodeGen/RISCV/zilsd-ldst-opt-prera.mir
index dab394d4bc8c4..dcb9c44f8030b 100644
--- a/llvm/test/CodeGen/RISCV/zilsd-ldst-opt-prera.mir
+++ b/llvm/test/CodeGen/RISCV/zilsd-ldst-opt-prera.mir
@@ -238,6 +238,19 @@
   define i32 @symbolic_operands_interleave() {
     ret i32 0
   }
+
+  declare void @external(ptr)
+  define i32 @frame_index() {
+    %arr = alloca [2 x i32], align 4
+    %arrayidx1 = getelementptr inbounds nuw i8, ptr %arr, i32 4
+    ret i32 0
+  }
+
+  define i32 @frame_index_operands_interleave() {
+    %arr = alloca [2 x i32], align 4
+    %arrayidx1 = getelementptr inbounds nuw i8, ptr %arr, i32 4
+    ret i32 0
+  }
 ---
 # Basic case: two consecutive 32-bit loads that can be combined into LD
 name: basic_load_combine
@@ -1240,3 +1253,85 @@ body: |
     PseudoRET
 
 ...
+---
+name: frame_index
+alignment: 4
+tracksRegLiveness: true
+stack:
+  - { id: 0, offset: 0, size: 8, alignment: 4 }
+liveins:
+  - { reg: '$x10', virtual-reg: '%0' }
+  - { reg: '$x11', virtual-reg: '%1' }
+body: |
+  bb.0:
+    liveins: $x10, $x11
+
+    ; CHECK-LABEL: name: frame_index
+    ; CHECK: liveins: $x10, $x11
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
+    ; CHECK-NEXT: SW [[COPY]], %stack.0, 0 :: (store (s32) into %ir.arr)
+    ; CHECK-NEXT: SW [[COPY1]], %stack.0, 4 :: (store (s32) into %ir.arrayidx1)
+    ; CHECK-NEXT: PseudoRET
+    ;
+    ; CHECK-4BYTE-LABEL: name: frame_index
+    ; CHECK-4BYTE: liveins: $x10, $x11
+    ; CHECK-4BYTE-NEXT: {{  $}}
+    ; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+    ; CHECK-4BYTE-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
+    ; CHECK-4BYTE-NEXT: PseudoSD_RV32_OPT [[COPY]], [[COPY1]], %stack.0, 0 :: (store (s32) into %ir.arr), (store (s32) into %ir.arrayidx1)
+    ; CHECK-4BYTE-NEXT: PseudoRET
+    %0:gpr = COPY $x10
+    %1:gpr = COPY $x11
+    SW %0:gpr, %stack.0, 0 :: (store (s32) into %ir.arr)
+    SW %1:gpr, %stack.0, 4 :: (store (s32) into %ir.arrayidx1)
+    PseudoRET
+...
+---
+name: frame_index_operands_interleave
+alignment: 4
+tracksRegLiveness: true
+stack:
+  - { id: 0, offset: 0, size: 8, alignment: 4 }
+liveins:
+  - { reg: '$x10', virtual-reg: '%0' }
+  - { reg: '$x11', virtual-reg: '%1' }
+body: |
+  bb.0:
+    liveins: $x10, $x11
+
+    ; CHECK-LABEL: name: frame_index_operands_interleave
+    ; CHECK: liveins: $x10, $x11
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
+    ; CHECK-NEXT: [[LW:%[0-9]+]]:gpr = LW %stack.0, 0 :: (load (s32) from %ir.arr)
+    ; CHECK-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], 4 :: (load (s32))
+    ; CHECK-NEXT: [[LW2:%[0-9]+]]:gpr = LW [[COPY]], 0 :: (load (s32))
+    ; CHECK-NEXT: [[LW3:%[0-9]+]]:gpr = LW %stack.0, 4 :: (load (s32) from %ir.arrayidx1)
+    ; CHECK-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW2]]
+    ; CHECK-NEXT: [[ADD1:%[0-9]+]]:gpr = ADD [[LW1]], [[LW3]]
+    ; CHECK-NEXT: PseudoRET
+    ;
+    ; CHECK-4BYTE-LABEL: name: frame_index_operands_interleave
+    ; CHECK-4BYTE: liveins: $x10, $x11
+    ; CHECK-4BYTE-NEXT: {{  $}}
+    ; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+    ; CHECK-4BYTE-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
+    ; CHECK-4BYTE-NEXT: [[PseudoLD_RV32_OPT:%[0-9]+]]:gpr, [[PseudoLD_RV32_OPT1:%[0-9]+]]:gpr = PseudoLD_RV32_OPT %stack.0, 0 :: (load (s32) from %ir.arr), (load (s32) from %ir.arrayidx1)
+    ; CHECK-4BYTE-NEXT: [[PseudoLD_RV32_OPT2:%[0-9]+]]:gpr, [[PseudoLD_RV32_OPT3:%[0-9]+]]:gpr = PseudoLD_RV32_OPT [[COPY]], 0 :: (load (s32))
+    ; CHECK-4BYTE-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[PseudoLD_RV32_OPT]], [[PseudoLD_RV32_OPT2]]
+    ; CHECK-4BYTE-NEXT: [[ADD1:%[0-9]+]]:gpr = ADD [[PseudoLD_RV32_OPT3]], [[PseudoLD_RV32_OPT1]]
+    ; CHECK-4BYTE-NEXT: PseudoRET
+    %0:gpr = COPY $x10
+    %1:gpr = COPY $x11
+    %2:gpr = LW %stack.0, 0 :: (load (s32) from %ir.arr)
+    %3:gpr = LW %0, 4 :: (load (s32))
+    %4:gpr = LW %0, 0 :: (load (s32))
+    %5:gpr = LW %stack.0, 4 :: (load (s32) from %ir.arrayidx1)
+    %6:gpr = ADD %2, %4
+    %7:gpr = ADD %3, %5
+    PseudoRET
+
+...

``````````

</details>


https://github.com/llvm/llvm-project/pull/174073


More information about the llvm-commits mailing list