[llvm] [RISCV] Fold shxadd into Xqcisls scaled load/store in RISCVMergeBaseOffset (PR #182221)
Sudharsan Veeravalli via llvm-commits
llvm-commits at lists.llvm.org
Thu Feb 19 18:01:15 PST 2026
https://github.com/svs-quic updated https://github.com/llvm/llvm-project/pull/182221
>From de48777a1bdf7ea84f2868d398bc4d02feb4d892 Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <svs at qti.qualcomm.com>
Date: Thu, 19 Feb 2026 10:38:05 +0530
Subject: [PATCH 1/4] Pre-commit test
---
.../xqcisls-merge-base-offset-muliadd.ll | 118 ++++++++++++++++++
1 file changed, 118 insertions(+)
create mode 100644 llvm/test/CodeGen/RISCV/xqcisls-merge-base-offset-muliadd.ll
diff --git a/llvm/test/CodeGen/RISCV/xqcisls-merge-base-offset-muliadd.ll b/llvm/test/CodeGen/RISCV/xqcisls-merge-base-offset-muliadd.ll
new file mode 100644
index 0000000000000..d1e82643c3df0
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/xqcisls-merge-base-offset-muliadd.ll
@@ -0,0 +1,118 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=riscv32 -mattr=+xqcili,+xqcisls,+zba -verify-machineinstrs %s -o - | FileCheck %s
+
+ at sym = external global i8, align 1
+
+define i32 @load_scaled(i32 %idx) nounwind {
+; CHECK-LABEL: load_scaled:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: qc.e.li a1, sym
+; CHECK-NEXT: sh2add a0, a0, a1
+; CHECK-NEXT: lw a0, 16(a0)
+; CHECK-NEXT: ret
+entry:
+ %baseptr = getelementptr i8, i8* @sym, i32 0
+ %baseint = ptrtoint i8* %baseptr to i32
+ %idxsh = shl i32 %idx, 2
+ %sum = add i32 %baseint, %idxsh
+ %sum_ptr = inttoptr i32 %sum to i8*
+ %addr_plus_imm = getelementptr i8, i8* %sum_ptr, i32 16
+ %addr_i32p = bitcast i8* %addr_plus_imm to i32*
+ %val = load i32, i32* %addr_i32p, align 4
+ ret i32 %val
+}
+
+define void @store_scaled(i32 %idx, i32 %val) nounwind {
+; CHECK-LABEL: store_scaled:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: qc.e.li a2, sym
+; CHECK-NEXT: sh3add a0, a0, a2
+; CHECK-NEXT: sw a1, 12(a0)
+; CHECK-NEXT: ret
+entry:
+ %baseptr = getelementptr i8, i8* @sym, i32 0
+ %baseint = ptrtoint i8* %baseptr to i32
+ %idxsh = shl i32 %idx, 3
+ %sum = add i32 %baseint, %idxsh
+ %sum_ptr = inttoptr i32 %sum to i8*
+ %addr_plus_imm = getelementptr i8, i8* %sum_ptr, i32 12
+ %addr_i32p = bitcast i8* %addr_plus_imm to i32*
+ store i32 %val, i32* %addr_i32p, align 4
+ ret void
+}
+
+define i32 @load_scaled_i8(i32 %idx) nounwind {
+; CHECK-LABEL: load_scaled_i8:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: qc.e.li a1, sym
+; CHECK-NEXT: sh2add a0, a0, a1
+; CHECK-NEXT: lb a0, 5(a0)
+; CHECK-NEXT: ret
+entry:
+ %baseptr = getelementptr i8, i8* @sym, i32 0
+ %baseint = ptrtoint i8* %baseptr to i32
+ %idxsh = shl i32 %idx, 2
+ %sum = add i32 %baseint, %idxsh
+ %sum_ptr = inttoptr i32 %sum to i8*
+ %addr_plus_imm = getelementptr i8, i8* %sum_ptr, i32 5
+ %val8 = load i8, i8* %addr_plus_imm, align 1
+ %val = sext i8 %val8 to i32
+ ret i32 %val
+}
+
+define void @store_scaled_i8(i32 %idx, i32 %val) nounwind {
+; CHECK-LABEL: store_scaled_i8:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: qc.e.li a2, sym
+; CHECK-NEXT: sh3add a0, a0, a2
+; CHECK-NEXT: sb a1, 7(a0)
+; CHECK-NEXT: ret
+entry:
+ %baseptr = getelementptr i8, i8* @sym, i32 0
+ %baseint = ptrtoint i8* %baseptr to i32
+ %idxsh = shl i32 %idx, 3
+ %sum = add i32 %baseint, %idxsh
+ %sum_ptr = inttoptr i32 %sum to i8*
+ %addr_plus_imm = getelementptr i8, i8* %sum_ptr, i32 7
+ %val8 = trunc i32 %val to i8
+ store i8 %val8, i8* %addr_plus_imm, align 1
+ ret void
+}
+
+define i32 @load_scaled_i16(i32 %idx) nounwind {
+; CHECK-LABEL: load_scaled_i16:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: qc.e.li a1, sym
+; CHECK-NEXT: sh1add a0, a0, a1
+; CHECK-NEXT: lh a0, 6(a0)
+; CHECK-NEXT: ret
+entry:
+ %baseptr = getelementptr i8, i8* @sym, i32 0
+ %baseint = ptrtoint i8* %baseptr to i32
+ %idxsh = shl i32 %idx, 1
+ %sum = add i32 %baseint, %idxsh
+ %sum_ptr = inttoptr i32 %sum to i16*
+ %addr_plus_imm = getelementptr i16, i16* %sum_ptr, i32 3
+ %val16 = load i16, i16* %addr_plus_imm, align 2
+ %val = sext i16 %val16 to i32
+ ret i32 %val
+}
+
+define void @store_scaled_i16(i32 %idx, i32 %val) nounwind {
+; CHECK-LABEL: store_scaled_i16:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: qc.e.li a2, sym
+; CHECK-NEXT: sh2add a0, a0, a2
+; CHECK-NEXT: sh a1, 10(a0)
+; CHECK-NEXT: ret
+entry:
+ %baseptr = getelementptr i8, i8* @sym, i32 0
+ %baseint = ptrtoint i8* %baseptr to i32
+ %idxsh = shl i32 %idx, 2
+ %sum = add i32 %baseint, %idxsh
+ %sum_ptr = inttoptr i32 %sum to i16*
+ %addr_plus_imm = getelementptr i16, i16* %sum_ptr, i32 5
+ %val16 = trunc i32 %val to i16
+ store i16 %val16, i16* %addr_plus_imm, align 2
+ ret void
+}
>From eb9b174b7bac561f0b95362d25dd3220e77a0cc9 Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <svs at qti.qualcomm.com>
Date: Thu, 19 Feb 2026 10:39:31 +0530
Subject: [PATCH 2/4] Merge shxadd into scaled load/store
---
.../lib/Target/RISCV/RISCVMergeBaseOffset.cpp | 110 ++++++++++++++++++
.../xqcisls-merge-base-offset-muliadd.ll | 30 ++---
2 files changed, 122 insertions(+), 18 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp b/llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp
index be15f17e84298..2ebd14bbe60d3 100644
--- a/llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp
+++ b/llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp
@@ -43,6 +43,7 @@ class RISCVMergeBaseOffsetOpt : public MachineFunctionPass {
MachineInstr &TailShXAdd, Register GSReg);
bool foldIntoMemoryOps(MachineInstr &Hi, MachineInstr &Lo);
+ bool foldShxaddIntoScaledMemory(MachineInstr &Hi, MachineInstr &Lo);
RISCVMergeBaseOffsetOpt() : MachineFunctionPass(ID) {}
@@ -575,6 +576,114 @@ bool RISCVMergeBaseOffsetOpt::foldIntoMemoryOps(MachineInstr &Hi,
return true;
}
+// Try to fold sequences of the form:
+// Hi/lo: qc.e.li vreg1, s -> qc.e.lo vreg1, s+imm
+// TailAdd: shxadd vreg2, vreg3, vreg1 -> deleted
+// Tail: lx vreg4, imm(vreg2) -> qc.lrx vreg4, vreg1, vreg3, (1/2/3)
+bool RISCVMergeBaseOffsetOpt::foldShxaddIntoScaledMemory(MachineInstr &Hi,
+ MachineInstr &Lo) {
+ if (!ST->hasVendorXqcisls())
+ return false;
+
+ if (Hi.getOpcode() != RISCV::QC_E_LI)
+ return false;
+
+ Register BaseReg = Hi.getOperand(0).getReg();
+ if (!BaseReg.isVirtual() || !MRI->hasOneUse(BaseReg))
+ return false;
+
+ MachineInstr &ShxAdd = *MRI->use_instr_begin(BaseReg);
+ unsigned ShxOpc = ShxAdd.getOpcode();
+ if (ShxOpc != RISCV::SH1ADD && ShxOpc != RISCV::SH2ADD &&
+ ShxOpc != RISCV::SH3ADD)
+ return false;
+
+ // shxadd Rd, Rs1, Rs2
+ Register Rd = ShxAdd.getOperand(0).getReg();
+ Register Rs1 = ShxAdd.getOperand(1).getReg();
+ Register Rs2 = ShxAdd.getOperand(2).getReg();
+
+ if (Rs2 != BaseReg)
+ return false;
+
+ if (!Rd.isVirtual() || !MRI->hasOneUse(Rd))
+ return false;
+
+ MachineInstr &TailMem = *MRI->use_instr_begin(Rd);
+ unsigned Opc = TailMem.getOpcode();
+
+ if (!TailMem.getOperand(1).isReg() || TailMem.getOperand(1).getReg() != Rd)
+ return false;
+ if (!TailMem.getOperand(2).isImm())
+ return false;
+ int64_t Imm = TailMem.getOperand(2).getImm();
+
+ // Update QC_E_LI offset.
+ int64_t NewOffset = SignExtend64<32>(Hi.getOperand(1).getOffset() + Imm);
+
+ if (!isInt<32>(NewOffset))
+ return false;
+
+ unsigned NewOpc = 0;
+ switch (Opc) {
+ case RISCV::LB:
+ NewOpc = RISCV::QC_LRB;
+ break;
+ case RISCV::LBU:
+ NewOpc = RISCV::QC_LRBU;
+ break;
+ case RISCV::LH:
+ NewOpc = RISCV::QC_LRH;
+ break;
+ case RISCV::LHU:
+ NewOpc = RISCV::QC_LRHU;
+ break;
+ case RISCV::LW:
+ NewOpc = RISCV::QC_LRW;
+ break;
+ case RISCV::SB:
+ NewOpc = RISCV::QC_SRB;
+ break;
+ case RISCV::SH:
+ NewOpc = RISCV::QC_SRH;
+ break;
+ case RISCV::SW:
+ NewOpc = RISCV::QC_SRW;
+ break;
+ default:
+ return false;
+ }
+
+ Hi.getOperand(1).setOffset(NewOffset);
+ TailMem.getOperand(2).ChangeToImmediate(0);
+
+ // Build scaled load/store.
+ auto *TII = ST->getInstrInfo();
+ auto *MBB = TailMem.getParent();
+ RegState DestRegState;
+ DestRegState = TailMem.mayLoad()
+ ? RegState::Define
+ : getKillRegState(TailMem.getOperand(0).isKill());
+ unsigned ShAmt = (ShxOpc == RISCV::SH1ADD) ? 1
+ : (ShxOpc == RISCV::SH2ADD) ? 2
+ : 3;
+
+ // Ensure index register satisfies GPRNoX0 class required by QC_LR*/QC_SR*.
+ MRI->constrainRegClass(Rs1, &RISCV::GPRNoX0RegClass);
+
+ BuildMI(*MBB, TailMem, TailMem.getDebugLoc(), TII->get(NewOpc))
+ .addReg(TailMem.getOperand(0).getReg(), DestRegState)
+ .addReg(Rs2, getKillRegState(ShxAdd.getOperand(2).isKill()))
+ .addReg(Rs1, getKillRegState(ShxAdd.getOperand(1).isKill()))
+ .addImm(ShAmt)
+ .cloneMemRefs(TailMem);
+
+ MRI->replaceRegWith(Rd, Rs2);
+ TailMem.eraseFromParent();
+ ShxAdd.eraseFromParent();
+ return true;
+}
+
bool RISCVMergeBaseOffsetOpt::runOnMachineFunction(MachineFunction &Fn) {
if (skipFunction(Fn.getFunction()))
return false;
@@ -591,6 +700,7 @@ bool RISCVMergeBaseOffsetOpt::runOnMachineFunction(MachineFunction &Fn) {
continue;
MadeChange |= detectAndFoldOffset(Hi, *Lo);
MadeChange |= foldIntoMemoryOps(Hi, *Lo);
+ MadeChange |= foldShxaddIntoScaledMemory(Hi, *Lo);
}
}
diff --git a/llvm/test/CodeGen/RISCV/xqcisls-merge-base-offset-muliadd.ll b/llvm/test/CodeGen/RISCV/xqcisls-merge-base-offset-muliadd.ll
index d1e82643c3df0..f30961bdb0add 100644
--- a/llvm/test/CodeGen/RISCV/xqcisls-merge-base-offset-muliadd.ll
+++ b/llvm/test/CodeGen/RISCV/xqcisls-merge-base-offset-muliadd.ll
@@ -6,9 +6,8 @@
define i32 @load_scaled(i32 %idx) nounwind {
; CHECK-LABEL: load_scaled:
; CHECK: # %bb.0: # %entry
-; CHECK-NEXT: qc.e.li a1, sym
-; CHECK-NEXT: sh2add a0, a0, a1
-; CHECK-NEXT: lw a0, 16(a0)
+; CHECK-NEXT: qc.e.li a1, sym+16
+; CHECK-NEXT: qc.lrw a0, a1, a0, 2
; CHECK-NEXT: ret
entry:
%baseptr = getelementptr i8, i8* @sym, i32 0
@@ -25,9 +24,8 @@ entry:
define void @store_scaled(i32 %idx, i32 %val) nounwind {
; CHECK-LABEL: store_scaled:
; CHECK: # %bb.0: # %entry
-; CHECK-NEXT: qc.e.li a2, sym
-; CHECK-NEXT: sh3add a0, a0, a2
-; CHECK-NEXT: sw a1, 12(a0)
+; CHECK-NEXT: qc.e.li a2, sym+12
+; CHECK-NEXT: qc.srw a1, a2, a0, 3
; CHECK-NEXT: ret
entry:
%baseptr = getelementptr i8, i8* @sym, i32 0
@@ -44,9 +42,8 @@ entry:
define i32 @load_scaled_i8(i32 %idx) nounwind {
; CHECK-LABEL: load_scaled_i8:
; CHECK: # %bb.0: # %entry
-; CHECK-NEXT: qc.e.li a1, sym
-; CHECK-NEXT: sh2add a0, a0, a1
-; CHECK-NEXT: lb a0, 5(a0)
+; CHECK-NEXT: qc.e.li a1, sym+5
+; CHECK-NEXT: qc.lrb a0, a1, a0, 2
; CHECK-NEXT: ret
entry:
%baseptr = getelementptr i8, i8* @sym, i32 0
@@ -63,9 +60,8 @@ entry:
define void @store_scaled_i8(i32 %idx, i32 %val) nounwind {
; CHECK-LABEL: store_scaled_i8:
; CHECK: # %bb.0: # %entry
-; CHECK-NEXT: qc.e.li a2, sym
-; CHECK-NEXT: sh3add a0, a0, a2
-; CHECK-NEXT: sb a1, 7(a0)
+; CHECK-NEXT: qc.e.li a2, sym+7
+; CHECK-NEXT: qc.srb a1, a2, a0, 3
; CHECK-NEXT: ret
entry:
%baseptr = getelementptr i8, i8* @sym, i32 0
@@ -82,9 +78,8 @@ entry:
define i32 @load_scaled_i16(i32 %idx) nounwind {
; CHECK-LABEL: load_scaled_i16:
; CHECK: # %bb.0: # %entry
-; CHECK-NEXT: qc.e.li a1, sym
-; CHECK-NEXT: sh1add a0, a0, a1
-; CHECK-NEXT: lh a0, 6(a0)
+; CHECK-NEXT: qc.e.li a1, sym+6
+; CHECK-NEXT: qc.lrh a0, a1, a0, 1
; CHECK-NEXT: ret
entry:
%baseptr = getelementptr i8, i8* @sym, i32 0
@@ -101,9 +96,8 @@ entry:
define void @store_scaled_i16(i32 %idx, i32 %val) nounwind {
; CHECK-LABEL: store_scaled_i16:
; CHECK: # %bb.0: # %entry
-; CHECK-NEXT: qc.e.li a2, sym
-; CHECK-NEXT: sh2add a0, a0, a2
-; CHECK-NEXT: sh a1, 10(a0)
+; CHECK-NEXT: qc.e.li a2, sym+10
+; CHECK-NEXT: qc.srh a1, a2, a0, 2
; CHECK-NEXT: ret
entry:
%baseptr = getelementptr i8, i8* @sym, i32 0
>From 545d944e4c5658f56f979e893c5f90afe10f298f Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <svs at qti.qualcomm.com>
Date: Thu, 19 Feb 2026 13:01:42 +0530
Subject: [PATCH 3/4] Fix typo
---
llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp b/llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp
index 2ebd14bbe60d3..903e2e96e863c 100644
--- a/llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp
+++ b/llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp
@@ -577,7 +577,7 @@ bool RISCVMergeBaseOffsetOpt::foldIntoMemoryOps(MachineInstr &Hi,
}
// Try to fold sequences of the form:
-// Hi/lo: qc.e.li vreg1, s -> qc.e.lo vreg1, s+imm
+// Hi/lo: qc.e.li vreg1, s -> qc.e.li vreg1, s+imm
// TailAdd: shxadd vreg2, vreg3, vreg1 -> deleted
// Tail: lx vreg4, imm(vreg2) -> qc.lrx vreg4, vreg1, vreg3, (1/2/3)
bool RISCVMergeBaseOffsetOpt::foldShxaddIntoScaledMemory(MachineInstr &Hi,
>From 58459b5056f43300b5eb1e01b793f01c136dbc73 Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <svs at qti.qualcomm.com>
Date: Fri, 20 Feb 2026 07:30:46 +0530
Subject: [PATCH 4/4] Address comments and also add more tests
---
.../lib/Target/RISCV/RISCVMergeBaseOffset.cpp | 24 ++++---
.../xqcisls-merge-base-offset-muliadd.ll | 65 ++++++++++++++++++-
2 files changed, 75 insertions(+), 14 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp b/llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp
index 903e2e96e863c..95b16d75e38da 100644
--- a/llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp
+++ b/llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp
@@ -594,32 +594,32 @@ bool RISCVMergeBaseOffsetOpt::foldShxaddIntoScaledMemory(MachineInstr &Hi,
MachineInstr &ShxAdd = *MRI->use_instr_begin(BaseReg);
unsigned ShxOpc = ShxAdd.getOpcode();
+ // TODO: Add support for QC.SHLADD
if (ShxOpc != RISCV::SH1ADD && ShxOpc != RISCV::SH2ADD &&
ShxOpc != RISCV::SH3ADD)
return false;
// shxadd Rd, Rs1, Rs2
- Register Rd = ShxAdd.getOperand(0).getReg();
- Register Rs1 = ShxAdd.getOperand(1).getReg();
- Register Rs2 = ShxAdd.getOperand(2).getReg();
+ Register ScaledReg = ShxAdd.getOperand(0).getReg();
+ Register IndexReg = ShxAdd.getOperand(1).getReg();
- if (Rs2 != BaseReg)
+ if (ShxAdd.getOperand(2).getReg() != BaseReg)
return false;
- if (!Rd.isVirtual() || !MRI->hasOneUse(Rd))
+ if (!ScaledReg.isVirtual() || !MRI->hasOneUse(ScaledReg))
return false;
- MachineInstr &TailMem = *MRI->use_instr_begin(Rd);
+ MachineInstr &TailMem = *MRI->use_instr_begin(ScaledReg);
unsigned Opc = TailMem.getOpcode();
- if (!TailMem.getOperand(1).isReg() || TailMem.getOperand(1).getReg() != Rd)
+ if (!TailMem.getOperand(1).isReg() || TailMem.getOperand(1).getReg() != ScaledReg)
return false;
if (!TailMem.getOperand(2).isImm())
return false;
int64_t Imm = TailMem.getOperand(2).getImm();
// Update QC_E_LI offset.
- int64_t NewOffset = SignExtend64<32>(Hi.getOperand(1).getOffset() + Imm);
+ int64_t NewOffset = Hi.getOperand(1).getOffset() + Imm;
if (!isInt<32>(NewOffset))
return false;
@@ -655,7 +655,6 @@ bool RISCVMergeBaseOffsetOpt::foldShxaddIntoScaledMemory(MachineInstr &Hi,
}
Hi.getOperand(1).setOffset(NewOffset);
- TailMem.getOperand(2).ChangeToImmediate(0);
// Build scaled load/store.
auto *TII = ST->getInstrInfo();
@@ -669,16 +668,15 @@ bool RISCVMergeBaseOffsetOpt::foldShxaddIntoScaledMemory(MachineInstr &Hi,
: 3;
// Ensure index register satisfies GPRNoX0 class required by QC_LR*/QC_SR*.
- MRI->constrainRegClass(Rs1, &RISCV::GPRNoX0RegClass);
+ MRI->constrainRegClass(IndexReg, &RISCV::GPRNoX0RegClass);
BuildMI(*MBB, TailMem, TailMem.getDebugLoc(), TII->get(NewOpc))
.addReg(TailMem.getOperand(0).getReg(), DestRegState)
- .addReg(Rs2, getKillRegState(ShxAdd.getOperand(2).isKill()))
- .addReg(Rs1, getKillRegState(ShxAdd.getOperand(1).isKill()))
+ .addReg(BaseReg, getKillRegState(ShxAdd.getOperand(2).isKill()))
+ .addReg(IndexReg, getKillRegState(ShxAdd.getOperand(1).isKill()))
.addImm(ShAmt)
.cloneMemRefs(TailMem);
- MRI->replaceRegWith(Rd, Rs2);
TailMem.eraseFromParent();
ShxAdd.eraseFromParent();
return true;
diff --git a/llvm/test/CodeGen/RISCV/xqcisls-merge-base-offset-muliadd.ll b/llvm/test/CodeGen/RISCV/xqcisls-merge-base-offset-muliadd.ll
index f30961bdb0add..61260494fcfdc 100644
--- a/llvm/test/CodeGen/RISCV/xqcisls-merge-base-offset-muliadd.ll
+++ b/llvm/test/CodeGen/RISCV/xqcisls-merge-base-offset-muliadd.ll
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
-; RUN: llc -mtriple=riscv32 -mattr=+xqcili,+xqcisls,+zba -verify-machineinstrs %s -o - | FileCheck %s
+; RUN: llc -mtriple=riscv32 -mattr=+xqcili,+xqcisls,+zba,+xqciac -verify-machineinstrs %s -o - | FileCheck %s
@sym = external global i8, align 1
@@ -110,3 +110,66 @@ entry:
store i16 %val16, i16* %addr_plus_imm, align 2
ret void
}
+
+define void @no_store_scaled_i16_multiuse_base_reg(i32 %idx, i32 %val) nounwind {
+; CHECK-LABEL: no_store_scaled_i16_multiuse_base_reg:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: qc.e.li a2, sym
+; CHECK-NEXT: sh2add a0, a0, a2
+; CHECK-NEXT: sh a1, 10(a0)
+; CHECK-NEXT: sh a1, 14(a0)
+; CHECK-NEXT: ret
+entry:
+ %baseptr = getelementptr i8, i8* @sym, i32 0
+ %baseint = ptrtoint i8* %baseptr to i32
+ %idxsh = shl i32 %idx, 2
+ %sum = add i32 %baseint, %idxsh
+ %sum_ptr = inttoptr i32 %sum to i16*
+ %addr_plus_imm = getelementptr i16, i16* %sum_ptr, i32 5
+ %addr_plus_imm2 = getelementptr i16, i16* %sum_ptr, i32 7
+ %val16 = trunc i32 %val to i16
+ store i16 %val16, i16* %addr_plus_imm, align 2
+ store i16 %val16, i16* %addr_plus_imm2, align 2
+ ret void
+}
+
+define void @no_store_scaled_i8_multiuse_scaled_reg(i32 %idx, i32 %val) nounwind {
+; CHECK-LABEL: no_store_scaled_i8_multiuse_scaled_reg:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: qc.e.li a2, sym
+; CHECK-NEXT: sh3add a0, a0, a2
+; CHECK-NEXT: add a0, a0, a1
+; CHECK-NEXT: sb a1, 7(a0)
+; CHECK-NEXT: ret
+entry:
+ %baseptr = getelementptr i8, i8* @sym, i32 0
+ %baseint = ptrtoint i8* %baseptr to i32
+ %idxsh = shl i32 %idx, 3
+ %sum = add i32 %baseint, %idxsh
+ %sum2 = add i32 %sum, %val
+ %sum_ptr = inttoptr i32 %sum2 to i8*
+ %addr_plus_imm = getelementptr i8, i8* %sum_ptr, i32 7
+ %val8 = trunc i32 %val to i8
+ store i8 %val8, i8* %addr_plus_imm, align 1
+ ret void
+}
+
+; FIXME: This should be folded once we add support for QC.SHLADD in RISCVMergeBaseOffset
+define i32 @no_load_scaled_i16_shift_gt_3(i32 %idx) nounwind {
+; CHECK-LABEL: no_load_scaled_i16_shift_gt_3:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: qc.e.li a1, sym
+; CHECK-NEXT: qc.shladd a0, a0, a1, 5
+; CHECK-NEXT: lh a0, 6(a0)
+; CHECK-NEXT: ret
+entry:
+ %baseptr = getelementptr i8, i8* @sym, i32 0
+ %baseint = ptrtoint i8* %baseptr to i32
+ %idxsh = shl i32 %idx, 5
+ %sum = add i32 %baseint, %idxsh
+ %sum_ptr = inttoptr i32 %sum to i16*
+ %addr_plus_imm = getelementptr i16, i16* %sum_ptr, i32 3
+ %val16 = load i16, i16* %addr_plus_imm, align 2
+ %val = sext i16 %val16 to i32
+ ret i32 %val
+}
More information about the llvm-commits
mailing list