[llvm] [RISCV] Generate Xqcilsm LWMI/SWMI load/store multiple instructions (PR #171079)

Sudharsan Veeravalli via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 9 00:23:04 PST 2025


https://github.com/svs-quic updated https://github.com/llvm/llvm-project/pull/171079

>From 4d5643a4e88257c3d6c835a178a80fb7d6095876 Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <quic_svs at quicinc.com>
Date: Mon, 8 Dec 2025 11:28:48 +0530
Subject: [PATCH 1/2] [RISCV] Generate LWMI/SWMI

---
 .../Target/RISCV/RISCVLoadStoreOptimizer.cpp  |  89 ++++-
 llvm/test/CodeGen/RISCV/xqcilsm-lwmi-swmi.mir | 311 ++++++++++++++++++
 2 files changed, 389 insertions(+), 11 deletions(-)
 create mode 100644 llvm/test/CodeGen/RISCV/xqcilsm-lwmi-swmi.mir

diff --git a/llvm/lib/Target/RISCV/RISCVLoadStoreOptimizer.cpp b/llvm/lib/Target/RISCV/RISCVLoadStoreOptimizer.cpp
index a22ab6bfc04b8..11fa0febcff1d 100644
--- a/llvm/lib/Target/RISCV/RISCVLoadStoreOptimizer.cpp
+++ b/llvm/lib/Target/RISCV/RISCVLoadStoreOptimizer.cpp
@@ -114,7 +114,7 @@ bool RISCVLoadStoreOpt::runOnMachineFunction(MachineFunction &Fn) {
   ModifiedRegUnits.init(*TRI);
   UsedRegUnits.init(*TRI);
 
-  if (Subtarget.useMIPSLoadStorePairs()) {
+  if (Subtarget.useMIPSLoadStorePairs() || Subtarget.hasVendorXqcilsm()) {
     for (MachineBasicBlock &MBB : Fn) {
       LLVM_DEBUG(dbgs() << "MBB: " << MBB.getName() << "\n");
 
@@ -168,14 +168,85 @@ bool RISCVLoadStoreOpt::tryToPairLdStInst(MachineBasicBlock::iterator &MBBI) {
   return false;
 }
 
-// Merge two adjacent load/store instructions into a paired instruction
-// (LDP/SDP/SWP/LWP) if the effective address is 8-byte aligned in case of
-// SWP/LWP 16-byte aligned in case of LDP/SDP. This function selects the
-// appropriate paired opcode, verifies that the memory operand is properly
-// aligned, and checks that the offset is valid. If all conditions are met, it
-// builds and inserts the paired instruction.
+// Merge two adjacent load/store instructions into a paired instruction.
+// This function selects the appropriate paired opcode, verifies that the
+// memory operand is properly aligned, and checks that the offset is valid. If
+// all conditions are met, it builds and inserts the paired instruction.
 bool RISCVLoadStoreOpt::tryConvertToLdStPair(
     MachineBasicBlock::iterator First, MachineBasicBlock::iterator Second) {
+  MachineFunction *MF = First->getMF();
+  const RISCVSubtarget &STI = MF->getSubtarget<RISCVSubtarget>();
+  const MachineMemOperand *MMO = *First->memoperands_begin();
+  Align MMOAlign = MMO->getAlign();
+
+  // Try converting to QC_LWMI/QC_SWMI if the XQCILSM extension is enabled.
+  if (!STI.is64Bit() && STI.hasVendorXqcilsm()) {
+    unsigned Opc = First->getOpcode();
+    if ((Opc != RISCV::LW && Opc != RISCV::SW) || Second->getOpcode() != Opc)
+      return false;
+
+    // Require simple reg+imm addressing for both.
+    if (!First->getOperand(1).isReg() || !Second->getOperand(1).isReg() ||
+        !First->getOperand(2).isImm() || !Second->getOperand(2).isImm())
+      return false;
+
+    Register Base1 = First->getOperand(1).getReg();
+    Register Base2 = Second->getOperand(1).getReg();
+
+    if (Base1 != Base2)
+      return false;
+
+    if (MMOAlign < Align(4))
+      return false;
+
+    int64_t Off1 = First->getOperand(2).getImm();
+    int64_t Off2 = Second->getOperand(2).getImm();
+    int64_t BaseOff = std::min(Off1, Off2);
+
+    if (!isShiftedUInt<5, 2>(BaseOff) || std::abs(Off1 - Off2) != 4)
+      return false;
+
+    Register StartReg = First->getOperand(0).getReg();
+    Register NextReg = Second->getOperand(0).getReg();
+
+    if (StartReg == RISCV::X0 || NextReg == RISCV::X0)
+      return false;
+
+    // If the base reg gets overwritten by one of the loads then bail out.
+    if (Opc == RISCV::LW && (StartReg == Base1 || NextReg == Base1))
+      return false;
+
+    if (Off2 < Off1)
+      std::swap(StartReg, NextReg);
+
+    if (NextReg != StartReg + 1)
+      return false;
+
+    unsigned XqciOpc = (Opc == RISCV::LW) ? RISCV::QC_LWMI : RISCV::QC_SWMI;
+
+    auto StartRegState = (Opc == RISCV::LW) ? RegState::Define : 0;
+    auto NextRegState =
+        (Opc == RISCV::LW) ? RegState::ImplicitDefine : RegState::Implicit;
+
+    DebugLoc DL =
+        First->getDebugLoc() ? First->getDebugLoc() : Second->getDebugLoc();
+    MachineInstrBuilder MIB = BuildMI(*MF, DL, TII->get(XqciOpc));
+    MIB.addReg(StartReg, StartRegState)
+        .addReg(Base1)
+        .addImm(2)
+        .addImm(BaseOff)
+        .cloneMergedMemRefs({&*First, &*Second})
+        .addReg(NextReg, NextRegState);
+
+    First->getParent()->insert(First, MIB);
+    First->removeFromParent();
+    Second->removeFromParent();
+
+    return true;
+  }
+
+  // Try converting to SWP/LWP/LDP/SDP.
+  // SWP/LWP requires 8-byte alignment whereas LDP/SDP needs 16-byte alignment.
   unsigned PairOpc;
   Align RequiredAlignment;
   switch (First->getOpcode()) {
@@ -199,10 +270,6 @@ bool RISCVLoadStoreOpt::tryConvertToLdStPair(
     break;
   }
 
-  MachineFunction *MF = First->getMF();
-  const MachineMemOperand *MMO = *First->memoperands_begin();
-  Align MMOAlign = MMO->getAlign();
-
   if (MMOAlign < RequiredAlignment)
     return false;
 
diff --git a/llvm/test/CodeGen/RISCV/xqcilsm-lwmi-swmi.mir b/llvm/test/CodeGen/RISCV/xqcilsm-lwmi-swmi.mir
new file mode 100644
index 0000000000000..155a1564c392d
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/xqcilsm-lwmi-swmi.mir
@@ -0,0 +1,311 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=riscv32 -mattr=+experimental-xqcilsm -run-pass=riscv-load-store-opt %s -o - | FileCheck %s
+
+--- |
+
+  define void @pair_two_lw_into_qc_lwmi() nounwind { ret void }
+  define void @pair_two_lw_into_qc_lwmi_reversed() nounwind { ret void }
+  define void @pair_two_sw_into_qc_swmi_reversed() nounwind { ret void }
+  define void @no_pair_if_different_base_regs() nounwind { ret void }
+  define void @no_pair_if_alignment_lt_4() nounwind { ret void }
+  define void @pair_two_sw_into_qc_swmi() nounwind { ret void }
+  define void @no_pair_if_misaligned() nounwind { ret void }
+  define void @pair_at_upper_boundary_lw() nounwind { ret void }
+  define void @pair_at_upper_boundary_sw() nounwind { ret void }
+  define void @no_pair_if_offset_out_of_range_lw() nounwind { ret void }
+  define void @no_pair_if_offset_out_of_range_sw() nounwind { ret void }
+  define void @no_pair_if_non_consecutive_regs() nounwind { ret void }
+  define void @no_pair_if_rd_is_x0() nounwind { ret void }
+  define void @no_pair_if_lw_rd_equals_base() nounwind { ret void }
+  define void @pair_if_not_adjacent() nounwind { ret void }
+  define void @pair_if_not_adjacent_use() nounwind { ret void }
+  define void @no_pair_if_not_adjacent_use() nounwind { ret void }
+---
+name: pair_two_lw_into_qc_lwmi
+tracksRegLiveness: false
+body: |
+  bb.0:
+    liveins: $x10
+    ; CHECK-LABEL: name: pair_two_lw_into_qc_lwmi
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: $x12 = QC_LWMI $x10, 2, 0, implicit-def $x13 :: (load (s32))
+    ; CHECK-NEXT: PseudoRET
+    $x12 = LW $x10, 0 :: (load (s32), align 4)
+    $x13 = LW $x10, 4 :: (load (s32), align 4)
+    PseudoRET
+
+...
+---
+name: pair_two_lw_into_qc_lwmi_reversed
+tracksRegLiveness: false
+body: |
+  bb.0:
+    liveins: $x10
+    ; CHECK-LABEL: name: pair_two_lw_into_qc_lwmi_reversed
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: $x12 = QC_LWMI $x10, 2, 0, implicit-def $x13 :: (load (s32))
+    ; CHECK-NEXT: PseudoRET
+    $x13 = LW $x10, 4 :: (load (s32))
+    $x12 = LW $x10, 0 :: (load (s32))
+    PseudoRET
+
+...
+---
+name: pair_two_sw_into_qc_swmi_reversed
+tracksRegLiveness: false
+body: |
+  bb.0:
+    liveins: $x10, $x12, $x13
+    ; CHECK-LABEL: name: pair_two_sw_into_qc_swmi_reversed
+    ; CHECK: liveins: $x10, $x12, $x13
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: QC_SWMI $x12, $x10, 2, 0, implicit $x13 :: (store (s32))
+    ; CHECK-NEXT: PseudoRET
+    SW killed $x13, $x10, 4 :: (store (s32))
+    SW killed $x12, $x10, 0 :: (store (s32))
+    PseudoRET
+
+...
+---
+name: no_pair_if_different_base_regs
+tracksRegLiveness: false
+body: |
+  bb.0:
+    liveins: $x10, $x11
+    ; CHECK-LABEL: name: no_pair_if_different_base_regs
+    ; CHECK: liveins: $x10, $x11
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: $x12 = LW $x10, 0 :: (load (s32))
+    ; CHECK-NEXT: $x13 = LW $x11, 4 :: (load (s32))
+    ; CHECK-NEXT: PseudoRET
+    $x12 = LW $x10, 0 :: (load (s32))
+    $x13 = LW $x11, 4 :: (load (s32))
+    PseudoRET
+
+...
+---
+name: no_pair_if_alignment_lt_4
+tracksRegLiveness: false
+body: |
+  bb.0:
+    liveins: $x10
+    ; CHECK-LABEL: name: no_pair_if_alignment_lt_4
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: $x12 = LW $x10, 0 :: (load (s32))
+    ; CHECK-NEXT: $x13 = LW $x10, 3 :: (load (s32))
+    ; CHECK-NEXT: PseudoRET
+    $x12 = LW $x10, 0 :: (load (s32))
+    $x13 = LW $x10, 3 :: (load (s32))
+    PseudoRET
+
+...
+---
+name: pair_two_sw_into_qc_swmi
+tracksRegLiveness: false
+body: |
+  bb.0:
+    liveins: $x10, $x12, $x13
+    ; CHECK-LABEL: name: pair_two_sw_into_qc_swmi
+    ; CHECK: liveins: $x10, $x12, $x13
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: QC_SWMI $x12, $x10, 2, 0, implicit $x13 :: (store (s32))
+    ; CHECK-NEXT: PseudoRET
+    SW killed $x12, $x10, 0 :: (store (s32), align 4)
+    SW killed $x13, $x10, 4 :: (store (s32), align 4)
+    PseudoRET
+
+...
+---
+name: no_pair_if_misaligned
+tracksRegLiveness: false
+body: |
+  bb.0:
+    liveins: $x10
+    ; CHECK-LABEL: name: no_pair_if_misaligned
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: $x12 = LW $x10, 2 :: (load (s32))
+    ; CHECK-NEXT: $x13 = LW $x10, 6 :: (load (s32))
+    ; CHECK-NEXT: PseudoRET
+    $x12 = LW $x10, 2 :: (load (s32), align 4)
+    $x13 = LW $x10, 6 :: (load (s32), align 4)
+    PseudoRET
+
+...
+---
+name: pair_at_upper_boundary_lw
+tracksRegLiveness: false
+body: |
+  bb.0:
+    liveins: $x10
+    ; CHECK-LABEL: name: pair_at_upper_boundary_lw
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: $x12 = QC_LWMI $x10, 2, 124, implicit-def $x13 :: (load (s32))
+    ; CHECK-NEXT: PseudoRET
+    $x12 = LW $x10, 124 :: (load (s32), align 4)
+    $x13 = LW $x10, 128 :: (load (s32), align 4)
+    PseudoRET
+
+...
+---
+name: pair_at_upper_boundary_sw
+tracksRegLiveness: false
+body: |
+  bb.0:
+    liveins: $x10, $x12, $x13
+    ; CHECK-LABEL: name: pair_at_upper_boundary_sw
+    ; CHECK: liveins: $x10, $x12, $x13
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: QC_SWMI $x12, $x10, 2, 124, implicit $x13 :: (store (s32))
+    ; CHECK-NEXT: PseudoRET
+    SW $x12, $x10, 124 :: (store (s32), align 4)
+    SW $x13, $x10, 128 :: (store (s32), align 4)
+    PseudoRET
+
+...
+---
+name: no_pair_if_offset_out_of_range_lw
+tracksRegLiveness: false
+body: |
+  bb.0:
+    liveins: $x10
+    ; CHECK-LABEL: name: no_pair_if_offset_out_of_range_lw
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: $x12 = LW $x10, 128 :: (load (s32))
+    ; CHECK-NEXT: $x13 = LW $x10, 132 :: (load (s32))
+    ; CHECK-NEXT: PseudoRET
+    $x12 = LW $x10, 128 :: (load (s32), align 4)
+    $x13 = LW $x10, 132 :: (load (s32), align 4)
+    PseudoRET
+
+...
+---
+name: no_pair_if_offset_out_of_range_sw
+tracksRegLiveness: false
+body: |
+  bb.0:
+    liveins: $x10, $x12, $x13
+    ; CHECK-LABEL: name: no_pair_if_offset_out_of_range_sw
+    ; CHECK: liveins: $x10, $x12, $x13
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: SW $x12, $x10, 128 :: (store (s32))
+    ; CHECK-NEXT: SW $x13, $x10, 132 :: (store (s32))
+    ; CHECK-NEXT: PseudoRET
+    SW $x12, $x10, 128 :: (store (s32), align 4)
+    SW $x13, $x10, 132 :: (store (s32), align 4)
+    PseudoRET
+
+...
+---
+name: no_pair_if_non_consecutive_regs
+tracksRegLiveness: false
+body: |
+  bb.0:
+    liveins: $x10
+    ; CHECK-LABEL: name: no_pair_if_non_consecutive_regs
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: $x11 = LW $x10, 0 :: (load (s32))
+    ; CHECK-NEXT: $x13 = LW $x10, 4 :: (load (s32))
+    ; CHECK-NEXT: PseudoRET
+    $x11 = LW $x10, 0 :: (load (s32), align 4)
+    $x13 = LW $x10, 4 :: (load (s32), align 4)
+    PseudoRET
+
+...
+---
+name: no_pair_if_rd_is_x0
+tracksRegLiveness: false
+body: |
+  bb.0:
+    liveins: $x10
+    ; CHECK-LABEL: name: no_pair_if_rd_is_x0
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: $x0 = LW $x10, 0 :: (load (s32))
+    ; CHECK-NEXT: $x1 = LW $x10, 4 :: (load (s32))
+    ; CHECK-NEXT: PseudoRET
+    $x0 = LW $x10, 0 :: (load (s32), align 4)
+    $x1 = LW $x10, 4 :: (load (s32), align 4)
+    PseudoRET
+
+...
+---
+name: no_pair_if_lw_rd_equals_base
+tracksRegLiveness: false
+body: |
+  bb.0:
+    liveins: $x10
+    ; CHECK-LABEL: name: no_pair_if_lw_rd_equals_base
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: $x10 = LW $x10, 20 :: (load (s32))
+    ; CHECK-NEXT: $x11 = LW $x10, 24 :: (load (s32))
+    ; CHECK-NEXT: PseudoRET
+    $x10 = LW $x10, 20 :: (load (s32), align 4)
+    $x11 = LW $x10, 24 :: (load (s32), align 4)
+    PseudoRET
+
+...
+---
+name: pair_if_not_adjacent
+tracksRegLiveness: false
+body: |
+  bb.0:
+    liveins: $x10
+    ; CHECK-LABEL: name: pair_if_not_adjacent
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: $x1 = QC_LWMI $x10, 2, 20, implicit-def $x2 :: (load (s32))
+    ; CHECK-NEXT: $x3 = ADDI $x1, 10
+    ; CHECK-NEXT: PseudoRET
+    $x1 = LW $x10, 20 :: (load (s32), align 4)
+    $x3 = ADDI $x1, 10
+    $x2 = LW $x10, 24 :: (load (s32), align 4)
+    PseudoRET
+
+...
+---
+name: pair_if_not_adjacent_use
+tracksRegLiveness: false
+body: |
+  bb.0:
+    liveins: $x10, $x1, $x2
+    ; CHECK-LABEL: name: pair_if_not_adjacent_use
+    ; CHECK: liveins: $x10, $x1, $x2
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: $x2 = ADDI $x2, 10
+    ; CHECK-NEXT: QC_SWMI $x1, $x10, 2, 20, implicit $x2 :: (store (s32))
+    ; CHECK-NEXT: PseudoRET
+    SW $x1, $x10, 20 :: (store (s32), align 4)
+    $x2 = ADDI $x2, 10
+    SW $x2, $x10, 24 :: (store (s32), align 4)
+    PseudoRET
+
+...
+---
+name: no_pair_if_not_adjacent_use
+tracksRegLiveness: false
+body: |
+  bb.0:
+    liveins: $x10, $x2
+    ; CHECK-LABEL: name: no_pair_if_not_adjacent_use
+    ; CHECK: liveins: $x10, $x2
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: $x1 = LW $x10, 20 :: (load (s32))
+    ; CHECK-NEXT: $x1 = ADDI $x1, 10
+    ; CHECK-NEXT: SW $x2, $x10, 40 :: (store (s32))
+    ; CHECK-NEXT: $x2 = LW $x10, 24 :: (load (s32))
+    ; CHECK-NEXT: PseudoRET
+    $x1 = LW $x10, 20 :: (load (s32), align 4)
+    $x1 = ADDI $x1, 10
+    SW $x2, $x10, 40 :: (store (s32), align 4)
+    $x2 = LW $x10, 24 :: (load (s32), align 4)
+    PseudoRET
+
+...

>From 051c771fdeb73358f4d306169326047e05f7e129 Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <quic_svs at quicinc.com>
Date: Tue, 9 Dec 2025 13:52:05 +0530
Subject: [PATCH 2/2] Preserve kill flags and do all swaps together

---
 .../Target/RISCV/RISCVLoadStoreOptimizer.cpp  | 47 ++++++++++++-------
 llvm/test/CodeGen/RISCV/xqcilsm-lwmi-swmi.mir | 16 ++++---
 2 files changed, 40 insertions(+), 23 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVLoadStoreOptimizer.cpp b/llvm/lib/Target/RISCV/RISCVLoadStoreOptimizer.cpp
index 11fa0febcff1d..c29a1947165c1 100644
--- a/llvm/lib/Target/RISCV/RISCVLoadStoreOptimizer.cpp
+++ b/llvm/lib/Target/RISCV/RISCVLoadStoreOptimizer.cpp
@@ -185,13 +185,18 @@ bool RISCVLoadStoreOpt::tryConvertToLdStPair(
     if ((Opc != RISCV::LW && Opc != RISCV::SW) || Second->getOpcode() != Opc)
       return false;
 
+    auto FirstOp1 = First->getOperand(1);
+    auto SecondOp1 = Second->getOperand(1);
+    auto FirstOp2 = First->getOperand(2);
+    auto SecondOp2 = Second->getOperand(2);
+
     // Require simple reg+imm addressing for both.
-    if (!First->getOperand(1).isReg() || !Second->getOperand(1).isReg() ||
-        !First->getOperand(2).isImm() || !Second->getOperand(2).isImm())
+    if (!FirstOp1.isReg() || !SecondOp1.isReg() || !FirstOp2.isImm() ||
+        !SecondOp2.isImm())
       return false;
 
-    Register Base1 = First->getOperand(1).getReg();
-    Register Base2 = Second->getOperand(1).getReg();
+    Register Base1 = FirstOp1.getReg();
+    Register Base2 = SecondOp1.getReg();
 
     if (Base1 != Base2)
       return false;
@@ -199,15 +204,19 @@ bool RISCVLoadStoreOpt::tryConvertToLdStPair(
     if (MMOAlign < Align(4))
       return false;
 
-    int64_t Off1 = First->getOperand(2).getImm();
-    int64_t Off2 = Second->getOperand(2).getImm();
-    int64_t BaseOff = std::min(Off1, Off2);
+    auto FirstOp0 = First->getOperand(0);
+    auto SecondOp0 = Second->getOperand(0);
 
-    if (!isShiftedUInt<5, 2>(BaseOff) || std::abs(Off1 - Off2) != 4)
-      return false;
+    int64_t Off1 = FirstOp2.getImm();
+    int64_t Off2 = SecondOp2.getImm();
 
-    Register StartReg = First->getOperand(0).getReg();
-    Register NextReg = Second->getOperand(0).getReg();
+    if (Off2 < Off1) {
+      std::swap(FirstOp0, SecondOp0);
+      std::swap(Off1, Off2);
+    }
+
+    Register StartReg = FirstOp0.getReg();
+    Register NextReg = SecondOp0.getReg();
 
     if (StartReg == RISCV::X0 || NextReg == RISCV::X0)
       return false;
@@ -216,25 +225,29 @@ bool RISCVLoadStoreOpt::tryConvertToLdStPair(
     if (Opc == RISCV::LW && (StartReg == Base1 || NextReg == Base1))
       return false;
 
-    if (Off2 < Off1)
-      std::swap(StartReg, NextReg);
+    if (!isShiftedUInt<5, 2>(Off1) || (Off2 - Off1 != 4))
+      return false;
 
     if (NextReg != StartReg + 1)
       return false;
 
     unsigned XqciOpc = (Opc == RISCV::LW) ? RISCV::QC_LWMI : RISCV::QC_SWMI;
 
-    auto StartRegState = (Opc == RISCV::LW) ? RegState::Define : 0;
+    auto StartRegState = (Opc == RISCV::LW)
+                             ? RegState::Define
+                             : getKillRegState(FirstOp0.isKill());
     auto NextRegState =
-        (Opc == RISCV::LW) ? RegState::ImplicitDefine : RegState::Implicit;
+        (Opc == RISCV::LW)
+            ? RegState::ImplicitDefine
+            : (RegState::Implicit | getKillRegState(SecondOp0.isKill()));
 
     DebugLoc DL =
         First->getDebugLoc() ? First->getDebugLoc() : Second->getDebugLoc();
     MachineInstrBuilder MIB = BuildMI(*MF, DL, TII->get(XqciOpc));
     MIB.addReg(StartReg, StartRegState)
-        .addReg(Base1)
+        .addReg(Base1, getKillRegState(FirstOp1.isKill() || SecondOp1.isKill()))
         .addImm(2)
-        .addImm(BaseOff)
+        .addImm(Off1)
         .cloneMergedMemRefs({&*First, &*Second})
         .addReg(NextReg, NextRegState);
 
diff --git a/llvm/test/CodeGen/RISCV/xqcilsm-lwmi-swmi.mir b/llvm/test/CodeGen/RISCV/xqcilsm-lwmi-swmi.mir
index 155a1564c392d..396f67326a7ca 100644
--- a/llvm/test/CodeGen/RISCV/xqcilsm-lwmi-swmi.mir
+++ b/llvm/test/CodeGen/RISCV/xqcilsm-lwmi-swmi.mir
@@ -37,6 +37,7 @@ body: |
 
 ...
 ---
+# FIXME: Kill flags are not propagated correctly for the base register
 name: pair_two_lw_into_qc_lwmi_reversed
 tracksRegLiveness: false
 body: |
@@ -48,7 +49,7 @@ body: |
     ; CHECK-NEXT: $x12 = QC_LWMI $x10, 2, 0, implicit-def $x13 :: (load (s32))
     ; CHECK-NEXT: PseudoRET
     $x13 = LW $x10, 4 :: (load (s32))
-    $x12 = LW $x10, 0 :: (load (s32))
+    $x12 = LW killed $x10, 0 :: (load (s32))
     PseudoRET
 
 ...
@@ -61,7 +62,7 @@ body: |
     ; CHECK-LABEL: name: pair_two_sw_into_qc_swmi_reversed
     ; CHECK: liveins: $x10, $x12, $x13
     ; CHECK-NEXT: {{  $}}
-    ; CHECK-NEXT: QC_SWMI $x12, $x10, 2, 0, implicit $x13 :: (store (s32))
+    ; CHECK-NEXT: QC_SWMI killed $x12, $x10, 2, 0, implicit killed $x13 :: (store (s32))
     ; CHECK-NEXT: PseudoRET
     SW killed $x13, $x10, 4 :: (store (s32))
     SW killed $x12, $x10, 0 :: (store (s32))
@@ -111,7 +112,7 @@ body: |
     ; CHECK-LABEL: name: pair_two_sw_into_qc_swmi
     ; CHECK: liveins: $x10, $x12, $x13
     ; CHECK-NEXT: {{  $}}
-    ; CHECK-NEXT: QC_SWMI $x12, $x10, 2, 0, implicit $x13 :: (store (s32))
+    ; CHECK-NEXT: QC_SWMI killed $x12, $x10, 2, 0, implicit killed $x13 :: (store (s32))
     ; CHECK-NEXT: PseudoRET
     SW killed $x12, $x10, 0 :: (store (s32), align 4)
     SW killed $x13, $x10, 4 :: (store (s32), align 4)
@@ -136,6 +137,7 @@ body: |
 
 ...
 ---
+# FIXME: Kill flags are not propagated correctly for the base register
 name: pair_at_upper_boundary_lw
 tracksRegLiveness: false
 body: |
@@ -147,11 +149,12 @@ body: |
     ; CHECK-NEXT: $x12 = QC_LWMI $x10, 2, 124, implicit-def $x13 :: (load (s32))
     ; CHECK-NEXT: PseudoRET
     $x12 = LW $x10, 124 :: (load (s32), align 4)
-    $x13 = LW $x10, 128 :: (load (s32), align 4)
+    $x13 = LW killed $x10, 128 :: (load (s32), align 4)
     PseudoRET
 
 ...
 ---
+# FIXME: Kill flags are not propagated correctly for the base register
 name: pair_at_upper_boundary_sw
 tracksRegLiveness: false
 body: |
@@ -163,7 +166,7 @@ body: |
     ; CHECK-NEXT: QC_SWMI $x12, $x10, 2, 124, implicit $x13 :: (store (s32))
     ; CHECK-NEXT: PseudoRET
     SW $x12, $x10, 124 :: (store (s32), align 4)
-    SW $x13, $x10, 128 :: (store (s32), align 4)
+    SW $x13, killed $x10, 128 :: (store (s32), align 4)
     PseudoRET
 
 ...
@@ -253,6 +256,7 @@ body: |
 
 ...
 ---
+# FIXME: Kill flags are not propagated correctly for the base register
 name: pair_if_not_adjacent
 tracksRegLiveness: false
 body: |
@@ -266,7 +270,7 @@ body: |
     ; CHECK-NEXT: PseudoRET
     $x1 = LW $x10, 20 :: (load (s32), align 4)
     $x3 = ADDI $x1, 10
-    $x2 = LW $x10, 24 :: (load (s32), align 4)
+    $x2 = LW killed $x10, 24 :: (load (s32), align 4)
     PseudoRET
 
 ...



More information about the llvm-commits mailing list