[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 18:05:07 PST 2025


================
@@ -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)
----------------
svs-quic wrote:

This has to do with the code in `findMatchingInsn` where they set `MergeForward` based on the following checks

```
         // If the Rt of the second instruction was not modified or used between
        // the two instructions and none of the instructions between the second
        // and first alias with the second, we can combine the second into the
        // first.
        if (ModifiedRegUnits.available(MI.getOperand(0).getReg()) &&
            !(MI.mayLoad() &&
              !UsedRegUnits.available(MI.getOperand(0).getReg())) &&
            !mayAlias(MI, MemInsns, AA)) {

          MergeForward = false;
          return MBBI;
        }

        // Likewise, if the Rt of the first instruction is not modified or used
        // between the two instructions and none of the instructions between the
        // first and the second alias with the first, we can combine the first
        // into the second.
        if (!(MayLoad &&
              !UsedRegUnits.available(FirstMI.getOperand(0).getReg())) &&
            !mayAlias(FirstMI, MemInsns, AA)) {

          if (ModifiedRegUnits.available(FirstMI.getOperand(0).getReg())) {
            MergeForward = true;
            return MBBI;
          }
```
And then clear the kill flags in `mergePairedInsns`

```
if (!MergeForward)
    Paired->getOperand(1).setIsKill(false);
```

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


More information about the llvm-commits mailing list