[llvm] [RISCV] Generate Xqcilsm multi-word load/store instructions for three or more words (PR #174789)
Sudharsan Veeravalli via llvm-commits
llvm-commits at lists.llvm.org
Wed Jan 7 08:24:41 PST 2026
https://github.com/svs-quic updated https://github.com/llvm/llvm-project/pull/174789
>From b5238c514f4c5fe9c33464c0c46d9330731ed6a8 Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <quic_svs at quicinc.com>
Date: Wed, 7 Jan 2026 20:43:19 +0530
Subject: [PATCH 1/2] Generate Xqcilsm instructions for 3 or more loads/stores
---
.../Target/RISCV/RISCVLoadStoreOptimizer.cpp | 200 ++++++++++++++++++
.../RISCV/xqcilsm-lwmi-swmi-multiple.mir | 159 ++++++++++++++
llvm/test/CodeGen/RISCV/xqcilsm-memset.ll | 12 +-
3 files changed, 363 insertions(+), 8 deletions(-)
create mode 100644 llvm/test/CodeGen/RISCV/xqcilsm-lwmi-swmi-multiple.mir
diff --git a/llvm/lib/Target/RISCV/RISCVLoadStoreOptimizer.cpp b/llvm/lib/Target/RISCV/RISCVLoadStoreOptimizer.cpp
index 63b50913ce74b..4358e8b8a30bd 100644
--- a/llvm/lib/Target/RISCV/RISCVLoadStoreOptimizer.cpp
+++ b/llvm/lib/Target/RISCV/RISCVLoadStoreOptimizer.cpp
@@ -26,6 +26,7 @@
#include "RISCV.h"
#include "RISCVTargetMachine.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/CodeGen/Passes.h"
@@ -73,6 +74,7 @@ struct RISCVLoadStoreOpt : public MachineFunctionPass {
bool tryConvertToXqcilsmLdStPair(MachineFunction *MF,
MachineBasicBlock::iterator First,
MachineBasicBlock::iterator Second);
+ bool tryConvertToXqcilsmMultiLdSt(MachineBasicBlock::iterator &First);
bool tryConvertToMIPSLdStPair(MachineFunction *MF,
MachineBasicBlock::iterator First,
MachineBasicBlock::iterator Second);
@@ -163,6 +165,13 @@ bool RISCVLoadStoreOpt::tryToPairLdStInst(MachineBasicBlock::iterator &MBBI) {
if (!TII->isLdStSafeToPair(MI, TRI))
return false;
+ // If Xqcilsm is available, first try to form a multi-instruction group (>2).
+ const RISCVSubtarget &STI = MI.getMF()->getSubtarget<RISCVSubtarget>();
+ if (!STI.is64Bit() && STI.hasVendorXqcilsm()) {
+ if (tryConvertToXqcilsmMultiLdSt(MBBI))
+ return true;
+ }
+
// Look ahead for a pairable instruction.
MachineBasicBlock::iterator E = MI.getParent()->end();
bool MergeForward;
@@ -174,6 +183,197 @@ bool RISCVLoadStoreOpt::tryToPairLdStInst(MachineBasicBlock::iterator &MBBI) {
return false;
}
+// Convert set of 3 or more LW/SW instructions to QC_LWMI/QC_SWMI/QC_SETWMI.
+// For now this only handles consecutive loads and stores traversing the basic
+// block top-down.
+// TODO: Traverse the basic block bottom-up as well.
+bool RISCVLoadStoreOpt::tryConvertToXqcilsmMultiLdSt(
+ MachineBasicBlock::iterator &FirstIt) {
+ MachineInstr &FirstMI = *FirstIt;
+ MachineFunction *MF = FirstMI.getMF();
+ const RISCVSubtarget &STI = MF->getSubtarget<RISCVSubtarget>();
+
+ if (STI.is64Bit() || !STI.hasVendorXqcilsm())
+ return false;
+
+ unsigned Opc = FirstMI.getOpcode();
+ if (Opc != RISCV::LW && Opc != RISCV::SW)
+ return false;
+
+ // Require simple reg+imm addressing.
+ const MachineOperand &BaseOp = FirstMI.getOperand(1);
+ const MachineOperand &OffOp = FirstMI.getOperand(2);
+ if (!BaseOp.isReg() || !OffOp.isImm())
+ return false;
+
+ Register Base = BaseOp.getReg();
+ int64_t BaseOff = OffOp.getImm();
+
+ const MachineMemOperand *MMO = *FirstMI.memoperands_begin();
+ Align MMOAlign = MMO->getAlign();
+ if (MMOAlign < Align(4))
+ return false;
+
+ if (!isShiftedUInt<5, 2>(BaseOff))
+ return false;
+
+ Register StartReg = FirstMI.getOperand(0).getReg();
+ bool IsLoad = (Opc == RISCV::LW);
+
+ // Load rd cannot be x0 and must not clobber the base register.
+ if (IsLoad) {
+ if (StartReg == RISCV::X0)
+ return false;
+ if (StartReg == Base)
+ return false;
+ }
+
+ // Collect a set of consecutive matching instructions.
+ SmallVector<MachineInstr *, 8> Group;
+ Group.push_back(&FirstMI);
+
+ MachineBasicBlock::iterator E = FirstIt->getParent()->end();
+ MachineBasicBlock::iterator It = next_nodbg(FirstIt, E);
+ int64_t ExpectedOff = BaseOff + 4;
+ unsigned Index = 1;
+ enum class StoreMode { Unknown, Setwmi, Swmi };
+ StoreMode SMode = StoreMode::Unknown;
+
+ while (It != E) {
+ MachineInstr &MI = *It;
+
+ if (!TII->isPairableLdStInstOpc(MI.getOpcode()))
+ break;
+ if (MI.getOpcode() != Opc)
+ break;
+ if (!TII->isLdStSafeToPair(MI, TRI))
+ break;
+
+ const MachineOperand &BaseMIOp = MI.getOperand(1);
+ const MachineOperand &OffsetMIOp = MI.getOperand(2);
+ if (!BaseMIOp.isReg() || !OffsetMIOp.isImm())
+ break;
+ if (BaseMIOp.getReg() != Base)
+ break;
+ int64_t Off = OffsetMIOp.getImm();
+ if (Off != ExpectedOff)
+ break;
+
+ Register Reg = MI.getOperand(0).getReg();
+ if (IsLoad) {
+ // For loads, require consecutive destination registers.
+ if (Reg != StartReg + Index)
+ break;
+ if (Reg == Base)
+ break;
+ } else {
+ // For stores, decide mode based on the second instruction and then
+ // enforce the same for the rest.
+ if (SMode == StoreMode::Unknown) {
+ if (Reg == StartReg)
+ SMode = StoreMode::Setwmi;
+ else if (Reg == StartReg + 1)
+ SMode = StoreMode::Swmi;
+ else
+ break;
+ } else if (SMode == StoreMode::Setwmi) {
+ if (Reg != StartReg)
+ break;
+ } else {
+ if (Reg != StartReg + Index)
+ break;
+ }
+ }
+
+ // Passed checks, extend the group.
+ Group.push_back(&MI);
+ ++Index;
+ ExpectedOff += 4;
+ It = next_nodbg(It, E);
+ }
+
+ // We only handle more than 2 here. Pairs are handled in
+ // tryConvertToXqcilsmLdStPair.
+ unsigned Len = Group.size();
+ if (Len <= 2)
+ return false;
+ if (!isUInt<5>(Len))
+ return false;
+
+ unsigned NewOpc;
+ unsigned StartRegState;
+ bool AddImplicitRegs = false;
+
+ if (IsLoad) {
+ NewOpc = RISCV::QC_LWMI;
+ StartRegState = static_cast<unsigned>(RegState::Define);
+ AddImplicitRegs = true;
+ } else {
+ if (SMode == StoreMode::Setwmi) {
+ NewOpc = RISCV::QC_SETWMI;
+ // Kill if any of the individual stores killed the reg.
+ bool StartKill = false;
+ for (MachineInstr *MI : Group)
+ StartKill |= MI->getOperand(0).isKill();
+ StartRegState = getKillRegState(StartKill);
+ AddImplicitRegs = false;
+ } else {
+ // SWMI requires consecutive source regs and rd != x0.
+ if (StartReg == RISCV::X0)
+ return false;
+ NewOpc = RISCV::QC_SWMI;
+ StartRegState = getKillRegState(Group.front()->getOperand(0).isKill());
+ AddImplicitRegs = true;
+ }
+ }
+
+ // Aggregate kill on base.
+ bool BaseKill = false;
+ for (MachineInstr *MI : Group)
+ BaseKill |= MI->getOperand(1).isKill();
+
+ // Build the new instruction.
+ DebugLoc DL = FirstMI.getDebugLoc();
+ if (!DL)
+ DL = Group.back()->getDebugLoc();
+ MachineInstrBuilder MIB = BuildMI(*MF, DL, TII->get(NewOpc));
+ MIB.addReg(StartReg, StartRegState)
+ .addReg(Base, getKillRegState(BaseKill))
+ .addImm(Len)
+ .addImm(BaseOff);
+
+ // Merge memory references from all merged instructions.
+ SmallVector<const MachineInstr *, 8> ConstGroup;
+ ConstGroup.reserve(Group.size());
+ for (MachineInstr *MI : Group)
+ ConstGroup.push_back(MI);
+ MIB.cloneMergedMemRefs(ConstGroup);
+
+ if (AddImplicitRegs) {
+ // Add implicit operands for the additional registers.
+ for (unsigned i = 1; i < Len; ++i) {
+ Register R = StartReg + i;
+ unsigned State = 0;
+ if (IsLoad)
+ State = static_cast<unsigned>(RegState::ImplicitDefine);
+ else
+ State = RegState::Implicit |
+ getKillRegState(Group[i]->getOperand(0).isKill());
+ MIB.addReg(R, State);
+ }
+ }
+
+ // Insert before the first instruction and remove all in the group.
+ MachineBasicBlock *MBB = FirstIt->getParent();
+ MachineBasicBlock::iterator NewIt = MBB->insert(FirstIt, MIB);
+ for (MachineInstr *MI : Group)
+ MI->removeFromParent();
+
+ // Advance the cursor to the next non-debug instruction after the group.
+ FirstIt = next_nodbg(NewIt, MBB->end());
+ return true;
+}
+
bool RISCVLoadStoreOpt::tryConvertToXqcilsmLdStPair(
MachineFunction *MF, MachineBasicBlock::iterator First,
MachineBasicBlock::iterator Second) {
diff --git a/llvm/test/CodeGen/RISCV/xqcilsm-lwmi-swmi-multiple.mir b/llvm/test/CodeGen/RISCV/xqcilsm-lwmi-swmi-multiple.mir
new file mode 100644
index 0000000000000..0bda7914836f1
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/xqcilsm-lwmi-swmi-multiple.mir
@@ -0,0 +1,159 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=riscv32 -mattr=+xqcilsm -run-pass=riscv-load-store-opt %s -o - | FileCheck %s
+
+--- |
+
+ define void @lwmi() { ret void }
+ define void @lwmi_x0() { ret void }
+ define void @lwmi_nonconsecutive() { ret void }
+ define void @lwmi_misaligned() { ret void }
+ define void @swmi() { ret void }
+ define void @swmi_x0() { ret void }
+ define void @swmi_nonconsecutive() { ret void }
+ define void @setwmi() { ret void }
+...
+---
+name: lwmi
+body: |
+ bb.0:
+ liveins: $x10
+ ; CHECK-LABEL: name: lwmi
+ ; CHECK: liveins: $x10
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: $x28 = QC_LWMI $x10, 4, 0, implicit-def $x29, implicit-def $x30, implicit-def $x31 :: (load (s32))
+ ; CHECK-NEXT: $x10 = ADD $x28, $x29
+ ; CHECK-NEXT: $x10 = ADD $x10, $x30
+ ; CHECK-NEXT: $x10 = ADD $x10, $x31
+ ; CHECK-NEXT: PseudoRET
+ $x28 = LW $x10, 0 :: (load (s32))
+ $x29 = LW $x10, 4 :: (load (s32))
+ $x30 = LW $x10, 8 :: (load (s32))
+ $x31 = LW $x10, 12 :: (load (s32))
+ $x10 = ADD $x28, $x29
+ $x10 = ADD $x10, $x30
+ $x10 = ADD $x10, $x31
+ PseudoRET
+...
+---
+name: lwmi_x0
+body: |
+ bb.0:
+ liveins: $x10
+ ; CHECK-LABEL: name: lwmi_x0
+ ; CHECK: liveins: $x10
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: $x0 = LW $x10, 0 :: (load (s32))
+ ; CHECK-NEXT: $x1 = QC_LWMI killed $x10, 3, 4, implicit-def $x2, implicit-def $x3 :: (load (s32))
+ ; CHECK-NEXT: PseudoRET
+ $x0 = LW $x10, 0 :: (load (s32))
+ $x1 = LW $x10, 4 :: (load (s32))
+ $x2 = LW $x10, 8 :: (load (s32))
+ $x3 = LW killed $x10, 12 :: (load (s32))
+ PseudoRET
+...
+---
+name: lwmi_nonconsecutive
+body: |
+ bb.0:
+ liveins: $x10
+ ; CHECK-LABEL: name: lwmi_nonconsecutive
+ ; CHECK: liveins: $x10
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: $x28 = LW $x10, 0 :: (load (s32))
+ ; CHECK-NEXT: $x30 = LW $x10, 4 :: (load (s32))
+ ; CHECK-NEXT: $x29 = LW $x10, 8 :: (load (s32))
+ ; CHECK-NEXT: $x31 = LW $x10, 12 :: (load (s32))
+ ; CHECK-NEXT: PseudoRET
+ $x28 = LW $x10, 0 :: (load (s32))
+ $x29 = LW $x10, 8 :: (load (s32))
+ $x30 = LW $x10, 4 :: (load (s32))
+ $x31 = LW $x10, 12 :: (load (s32))
+ PseudoRET
+...
+---
+name: lwmi_misaligned
+body: |
+ bb.0:
+ liveins: $x10
+ ; CHECK-LABEL: name: lwmi_misaligned
+ ; CHECK: liveins: $x10
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: $x28 = LW $x10, 2 :: (load (s32))
+ ; CHECK-NEXT: $x29 = LW $x10, 6 :: (load (s32))
+ ; CHECK-NEXT: $x30 = LW $x10, 10 :: (load (s32))
+ ; CHECK-NEXT: PseudoRET
+ $x28 = LW $x10, 2 :: (load (s32))
+ $x29 = LW $x10, 6 :: (load (s32))
+ $x30 = LW $x10, 10 :: (load (s32))
+ PseudoRET
+...
+---
+name: swmi
+body: |
+ bb.0:
+ liveins: $x10
+ ; CHECK-LABEL: name: swmi
+ ; CHECK: liveins: $x10
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: QC_SWMI killed $x28, $x10, 4, 0, implicit killed $x29, implicit $x30, implicit killed $x31 :: (store (s32))
+ ; CHECK-NEXT: PseudoRET
+ SW killed $x28, $x10, 0 :: (store (s32))
+ SW killed $x29, $x10, 4 :: (store (s32))
+ SW $x30, $x10, 8 :: (store (s32))
+ SW killed $x31, $x10, 12 :: (store (s32))
+ PseudoRET
+...
+---
+name: swmi_x0
+body: |
+ bb.0:
+ liveins: $x10
+ ; CHECK-LABEL: name: swmi_x0
+ ; CHECK: liveins: $x10
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: SW $x0, $x10, 0 :: (store (s32))
+ ; CHECK-NEXT: QC_SWMI $x1, $x10, 3, 4, implicit $x2, implicit $x3 :: (store (s32))
+ ; CHECK-NEXT: PseudoRET
+ SW $x0, $x10, 0 :: (store (s32))
+ SW $x1, $x10, 4 :: (store (s32))
+ SW $x2, $x10, 8 :: (store (s32))
+ SW $x3, $x10, 12 :: (store (s32))
+ PseudoRET
+...
+---
+name: swmi_nonconsecutive
+body: |
+ bb.0:
+ liveins: $x10
+ ; CHECK-LABEL: name: swmi_nonconsecutive
+ ; CHECK: liveins: $x10
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: QC_SWMI $x28, $x10, 2, 0, implicit killed $x29 :: (store (s32))
+ ; CHECK-NEXT: $x11 = ADDI $x28, 1
+ ; CHECK-NEXT: QC_SWMI $x30, $x10, 2, 8, implicit killed $x31 :: (store (s32))
+ ; CHECK-NEXT: $x12 = ADDI $x30, 1
+ ; CHECK-NEXT: PseudoRET
+ SW $x28, $x10, 0 :: (store (s32))
+ $x11 = ADDI $x28, 1
+ SW killed $x29, $x10, 4 :: (store (s32))
+ SW $x30, $x10, 8 :: (store (s32))
+ $x12 = ADDI $x30, 1
+ SW killed $x31, $x10, 12 :: (store (s32))
+ PseudoRET
+...
+---
+name: setwmi
+body: |
+ bb.0:
+ liveins: $x10
+ ; CHECK-LABEL: name: setwmi
+ ; CHECK: liveins: $x10
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: QC_SETWMI $x0, $x10, 4, 0 :: (store (s32))
+ ; CHECK-NEXT: PseudoRET
+ SW $x0, $x10, 0 :: (store (s32))
+ SW $x0, $x10, 4 :: (store (s32))
+ SW $x0, $x10, 8 :: (store (s32))
+ SW $x0, $x10, 12 :: (store (s32))
+ PseudoRET
+...
diff --git a/llvm/test/CodeGen/RISCV/xqcilsm-memset.ll b/llvm/test/CodeGen/RISCV/xqcilsm-memset.ll
index 399d6066c3366..e380122cf6efe 100644
--- a/llvm/test/CodeGen/RISCV/xqcilsm-memset.ll
+++ b/llvm/test/CodeGen/RISCV/xqcilsm-memset.ll
@@ -539,8 +539,7 @@ define void @test7a_unalign() nounwind {
; RV32IXQCILSM-NEXT: addi a0, a0, %lo(arr1)
; RV32IXQCILSM-NEXT: li a1, -1
; RV32IXQCILSM-NEXT: sb a1, 16(a0)
-; RV32IXQCILSM-NEXT: qc.setwmi a1, 2, 0(a0)
-; RV32IXQCILSM-NEXT: qc.setwmi a1, 2, 8(a0)
+; RV32IXQCILSM-NEXT: qc.setwmi a1, 4, 0(a0)
; RV32IXQCILSM-NEXT: ret
entry:
tail call void @llvm.memset.p0.i32(ptr align 4 @arr1, i8 -1, i32 17, i1 false)
@@ -654,8 +653,7 @@ define void @test8() nounwind {
; RV32IXQCILSM: # %bb.0: # %entry
; RV32IXQCILSM-NEXT: lui a0, %hi(arr1)
; RV32IXQCILSM-NEXT: addi a0, a0, %lo(arr1)
-; RV32IXQCILSM-NEXT: qc.setwmi zero, 2, 0(a0)
-; RV32IXQCILSM-NEXT: qc.setwmi zero, 2, 8(a0)
+; RV32IXQCILSM-NEXT: qc.setwmi zero, 4, 0(a0)
; RV32IXQCILSM-NEXT: ret
entry:
tail call void @llvm.memset.p0.i32(ptr align 4 @arr1, i8 0, i32 16, i1 false)
@@ -681,10 +679,8 @@ define void @test9() nounwind {
; RV32IXQCILSM: # %bb.0: # %entry
; RV32IXQCILSM-NEXT: lui a0, %hi(arr1)
; RV32IXQCILSM-NEXT: addi a0, a0, %lo(arr1)
-; RV32IXQCILSM-NEXT: qc.setwmi zero, 2, 16(a0)
-; RV32IXQCILSM-NEXT: qc.setwmi zero, 2, 24(a0)
-; RV32IXQCILSM-NEXT: qc.setwmi zero, 2, 0(a0)
-; RV32IXQCILSM-NEXT: qc.setwmi zero, 2, 8(a0)
+; RV32IXQCILSM-NEXT: qc.setwmi zero, 4, 16(a0)
+; RV32IXQCILSM-NEXT: qc.setwmi zero, 4, 0(a0)
; RV32IXQCILSM-NEXT: ret
entry:
tail call void @llvm.memset.p0.i32(ptr align 4 @arr1, i8 0, i32 32, i1 false)
>From cd3c4e162a5410f168b99f90813925866dcbd162 Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <quic_svs at quicinc.com>
Date: Wed, 7 Jan 2026 21:53:09 +0530
Subject: [PATCH 2/2] Split out alignment check.
---
.../Target/RISCV/RISCVLoadStoreOptimizer.cpp | 28 ++++---
.../RISCV/xqcilsm-lwmi-swmi-multiple.mir | 82 ++++++++++++-------
2 files changed, 66 insertions(+), 44 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVLoadStoreOptimizer.cpp b/llvm/lib/Target/RISCV/RISCVLoadStoreOptimizer.cpp
index 4358e8b8a30bd..a57d6ecf1f617 100644
--- a/llvm/lib/Target/RISCV/RISCVLoadStoreOptimizer.cpp
+++ b/llvm/lib/Target/RISCV/RISCVLoadStoreOptimizer.cpp
@@ -183,6 +183,14 @@ bool RISCVLoadStoreOpt::tryToPairLdStInst(MachineBasicBlock::iterator &MBBI) {
return false;
}
+static bool isMemOpAligned(MachineInstr &MI, Align RequiredAlignment) {
+ const MachineMemOperand *MMO = *MI.memoperands_begin();
+ Align MMOAlign = MMO->getAlign();
+ if (MMOAlign < RequiredAlignment)
+ return false;
+ return true;
+}
+
// Convert set of 3 or more LW/SW instructions to QC_LWMI/QC_SWMI/QC_SETWMI.
// For now this only handles consecutive loads and stores traversing the basic
// block top-down.
@@ -200,6 +208,9 @@ bool RISCVLoadStoreOpt::tryConvertToXqcilsmMultiLdSt(
if (Opc != RISCV::LW && Opc != RISCV::SW)
return false;
+ if (!isMemOpAligned(FirstMI, Align(4)))
+ return false;
+
// Require simple reg+imm addressing.
const MachineOperand &BaseOp = FirstMI.getOperand(1);
const MachineOperand &OffOp = FirstMI.getOperand(2);
@@ -209,11 +220,6 @@ bool RISCVLoadStoreOpt::tryConvertToXqcilsmMultiLdSt(
Register Base = BaseOp.getReg();
int64_t BaseOff = OffOp.getImm();
- const MachineMemOperand *MMO = *FirstMI.memoperands_begin();
- Align MMOAlign = MMO->getAlign();
- if (MMOAlign < Align(4))
- return false;
-
if (!isShiftedUInt<5, 2>(BaseOff))
return false;
@@ -248,6 +254,8 @@ bool RISCVLoadStoreOpt::tryConvertToXqcilsmMultiLdSt(
break;
if (!TII->isLdStSafeToPair(MI, TRI))
break;
+ if (!isMemOpAligned(MI, Align(4)))
+ break;
const MachineOperand &BaseMIOp = MI.getOperand(1);
const MachineOperand &OffsetMIOp = MI.getOperand(2);
@@ -397,10 +405,7 @@ bool RISCVLoadStoreOpt::tryConvertToXqcilsmLdStPair(
if (Base1 != Base2)
return false;
- const MachineMemOperand *MMO = *First->memoperands_begin();
- Align MMOAlign = MMO->getAlign();
-
- if (MMOAlign < Align(4))
+ if (!isMemOpAligned(*First, Align(4)) || !isMemOpAligned(*Second, Align(4)))
return false;
auto &FirstOp0 = First->getOperand(0);
@@ -503,10 +508,7 @@ bool RISCVLoadStoreOpt::tryConvertToMIPSLdStPair(
break;
}
- const MachineMemOperand *MMO = *First->memoperands_begin();
- Align MMOAlign = MMO->getAlign();
-
- if (MMOAlign < RequiredAlignment)
+ if (!isMemOpAligned(*First, RequiredAlignment))
return false;
int64_t Offset = First->getOperand(2).getImm();
diff --git a/llvm/test/CodeGen/RISCV/xqcilsm-lwmi-swmi-multiple.mir b/llvm/test/CodeGen/RISCV/xqcilsm-lwmi-swmi-multiple.mir
index 0bda7914836f1..20b7e306cbdcf 100644
--- a/llvm/test/CodeGen/RISCV/xqcilsm-lwmi-swmi-multiple.mir
+++ b/llvm/test/CodeGen/RISCV/xqcilsm-lwmi-swmi-multiple.mir
@@ -10,6 +10,7 @@
define void @swmi() { ret void }
define void @swmi_x0() { ret void }
define void @swmi_nonconsecutive() { ret void }
+ define void @swmi_misaligned() { ret void}
define void @setwmi() { ret void }
...
---
@@ -25,10 +26,10 @@ body: |
; CHECK-NEXT: $x10 = ADD $x10, $x30
; CHECK-NEXT: $x10 = ADD $x10, $x31
; CHECK-NEXT: PseudoRET
- $x28 = LW $x10, 0 :: (load (s32))
- $x29 = LW $x10, 4 :: (load (s32))
- $x30 = LW $x10, 8 :: (load (s32))
- $x31 = LW $x10, 12 :: (load (s32))
+ $x28 = LW $x10, 0 :: (load (s32), align 4)
+ $x29 = LW $x10, 4 :: (load (s32), align 4)
+ $x30 = LW $x10, 8 :: (load (s32), align 4)
+ $x31 = LW $x10, 12 :: (load (s32), align 4)
$x10 = ADD $x28, $x29
$x10 = ADD $x10, $x30
$x10 = ADD $x10, $x31
@@ -45,10 +46,10 @@ body: |
; CHECK-NEXT: $x0 = LW $x10, 0 :: (load (s32))
; CHECK-NEXT: $x1 = QC_LWMI killed $x10, 3, 4, implicit-def $x2, implicit-def $x3 :: (load (s32))
; CHECK-NEXT: PseudoRET
- $x0 = LW $x10, 0 :: (load (s32))
- $x1 = LW $x10, 4 :: (load (s32))
- $x2 = LW $x10, 8 :: (load (s32))
- $x3 = LW killed $x10, 12 :: (load (s32))
+ $x0 = LW $x10, 0 :: (load (s32), align 4)
+ $x1 = LW $x10, 4 :: (load (s32), align 4)
+ $x2 = LW $x10, 8 :: (load (s32), align 4)
+ $x3 = LW killed $x10, 12 :: (load (s32), align 4)
PseudoRET
...
---
@@ -64,10 +65,10 @@ body: |
; CHECK-NEXT: $x29 = LW $x10, 8 :: (load (s32))
; CHECK-NEXT: $x31 = LW $x10, 12 :: (load (s32))
; CHECK-NEXT: PseudoRET
- $x28 = LW $x10, 0 :: (load (s32))
- $x29 = LW $x10, 8 :: (load (s32))
- $x30 = LW $x10, 4 :: (load (s32))
- $x31 = LW $x10, 12 :: (load (s32))
+ $x28 = LW $x10, 0 :: (load (s32), align 4)
+ $x29 = LW $x10, 8 :: (load (s32), align 4)
+ $x30 = LW $x10, 4 :: (load (s32), align 4)
+ $x31 = LW $x10, 12 :: (load (s32), align 4)
PseudoRET
...
---
@@ -82,9 +83,9 @@ body: |
; CHECK-NEXT: $x29 = LW $x10, 6 :: (load (s32))
; CHECK-NEXT: $x30 = LW $x10, 10 :: (load (s32))
; CHECK-NEXT: PseudoRET
- $x28 = LW $x10, 2 :: (load (s32))
- $x29 = LW $x10, 6 :: (load (s32))
- $x30 = LW $x10, 10 :: (load (s32))
+ $x28 = LW $x10, 2 :: (load (s32), align 4)
+ $x29 = LW $x10, 6 :: (load (s32), align 4)
+ $x30 = LW $x10, 10 :: (load (s32), align 4)
PseudoRET
...
---
@@ -97,10 +98,10 @@ body: |
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: QC_SWMI killed $x28, $x10, 4, 0, implicit killed $x29, implicit $x30, implicit killed $x31 :: (store (s32))
; CHECK-NEXT: PseudoRET
- SW killed $x28, $x10, 0 :: (store (s32))
- SW killed $x29, $x10, 4 :: (store (s32))
- SW $x30, $x10, 8 :: (store (s32))
- SW killed $x31, $x10, 12 :: (store (s32))
+ SW killed $x28, $x10, 0 :: (store (s32), align 4)
+ SW killed $x29, $x10, 4 :: (store (s32), align 4)
+ SW $x30, $x10, 8 :: (store (s32), align 4)
+ SW killed $x31, $x10, 12 :: (store (s32), align 4)
PseudoRET
...
---
@@ -114,10 +115,10 @@ body: |
; CHECK-NEXT: SW $x0, $x10, 0 :: (store (s32))
; CHECK-NEXT: QC_SWMI $x1, $x10, 3, 4, implicit $x2, implicit $x3 :: (store (s32))
; CHECK-NEXT: PseudoRET
- SW $x0, $x10, 0 :: (store (s32))
- SW $x1, $x10, 4 :: (store (s32))
- SW $x2, $x10, 8 :: (store (s32))
- SW $x3, $x10, 12 :: (store (s32))
+ SW $x0, $x10, 0 :: (store (s32), align 4)
+ SW $x1, $x10, 4 :: (store (s32), align 4)
+ SW $x2, $x10, 8 :: (store (s32), align 4)
+ SW $x3, $x10, 12 :: (store (s32), align 4)
PseudoRET
...
---
@@ -133,12 +134,31 @@ body: |
; CHECK-NEXT: QC_SWMI $x30, $x10, 2, 8, implicit killed $x31 :: (store (s32))
; CHECK-NEXT: $x12 = ADDI $x30, 1
; CHECK-NEXT: PseudoRET
- SW $x28, $x10, 0 :: (store (s32))
+ SW $x28, $x10, 0 :: (store (s32), align 4)
$x11 = ADDI $x28, 1
- SW killed $x29, $x10, 4 :: (store (s32))
- SW $x30, $x10, 8 :: (store (s32))
+ SW killed $x29, $x10, 4 :: (store (s32), align 4)
+ SW $x30, $x10, 8 :: (store (s32), align 4)
$x12 = ADDI $x30, 1
- SW killed $x31, $x10, 12 :: (store (s32))
+ SW killed $x31, $x10, 12 :: (store (s32), align 4)
+ PseudoRET
+...
+---
+name: swmi_misaligned
+body: |
+ bb.0:
+ liveins: $x10
+ ; CHECK-LABEL: name: swmi_misaligned
+ ; CHECK: liveins: $x10
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: SW $x0, $x10, 0 :: (store (s32))
+ ; CHECK-NEXT: SW $x1, $x10, 4 :: (store (s32))
+ ; CHECK-NEXT: SW $x2, $x10, 8 :: (store (s32), align 2)
+ ; CHECK-NEXT: SW $x3, $x10, 12 :: (store (s32))
+ ; CHECK-NEXT: PseudoRET
+ SW $x0, $x10, 0 :: (store (s32), align 4)
+ SW $x1, $x10, 4 :: (store (s32), align 4)
+ SW $x2, $x10, 8 :: (store (s32), align 2)
+ SW $x3, $x10, 12 :: (store (s32), align 4)
PseudoRET
...
---
@@ -151,9 +171,9 @@ body: |
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: QC_SETWMI $x0, $x10, 4, 0 :: (store (s32))
; CHECK-NEXT: PseudoRET
- SW $x0, $x10, 0 :: (store (s32))
- SW $x0, $x10, 4 :: (store (s32))
- SW $x0, $x10, 8 :: (store (s32))
- SW $x0, $x10, 12 :: (store (s32))
+ SW $x0, $x10, 0 :: (store (s32), align 4)
+ SW $x0, $x10, 4 :: (store (s32), align 4)
+ SW $x0, $x10, 8 :: (store (s32), align 4)
+ SW $x0, $x10, 12 :: (store (s32), align 4)
PseudoRET
...
More information about the llvm-commits
mailing list