[llvm] 0ac8fed - [RISCV] Use signed target constants for XCVmem post-inc loads (#189276)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Apr 7 14:19:17 PDT 2026
Author: Moritz Scherer
Date: 2026-04-07T14:19:13-07:00
New Revision: 0ac8fed21e5bf71e65275a3dbb0be1272571519a
URL: https://github.com/llvm/llvm-project/commit/0ac8fed21e5bf71e65275a3dbb0be1272571519a
DIFF: https://github.com/llvm/llvm-project/commit/0ac8fed21e5bf71e65275a3dbb0be1272571519a.diff
LOG: [RISCV] Use signed target constants for XCVmem post-inc loads (#189276)
First time opening a PR against LLVM, so please let me know if anything
is missing / wrong.
This fixes an assertion in RISC-V DAG isel for CORE-V xcvmem
post-increment loads with negative immediate offsets.
`RISCVDAGToDAGISel::Select` recognizes `xcvmem POST_INC` loads and
checks whether the offset fits the signed 12-bit immediate form used by
`cv.lb/cv.lbu/cv.lh/cv.lhu/cv.lw ... , (rs1), imm12`. That path was
extracting the offset with `getSExtValue()`, but then rebuilding it with
`getTargetConstant(...)`, which takes the unsigned constant path.
For negative offsets, that could trip the APInt assertion:
```
Assertion failed: (llvm::isUIntN(BitWidth, val) && "Value is not an N-bit unsigned value")
```
during `RISC-V DAG->DAG Pattern Instruction Selection`.
The fix is to use `getSignedTargetConstant(...)` for the xcvmem
immediate case.
A regression test is added to llvm/test/CodeGen/RISCV/xcvmem.ll that
covers a reduced negative post-increment load case and checks the
expected codegen:
```asm
lw a2, 0(a0)
cv.lw a1, (a2), -4
sw a2, 0(a0)
mv a0, a1
ret
```
Reproducer before the fix:
```c
int f(int **pp) {
int *p = *pp;
int x = *p;
*pp = p - 1;
return x;
}
```
Example failing invocation:
```bash
clang --target=riscv32-unknown-elf \
-march=rv32imf_zicsr_zifencei_xcvmem \
-mabi=ilp32f -O2 -ffreestanding -c repro.c
```
Validation:
```bash
llc -O3 -mtriple=riscv32 -mattr=+xcvmem -verify-machineinstrs llvm/test/CodeGen/RISCV/xcvmem.ll
```
Confirmed the reduced repro no longer crashes
Added:
Modified:
llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
llvm/test/CodeGen/RISCV/xcvmem.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index cd3dcfd0aaaf1..bca51053efda1 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -1960,8 +1960,8 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
int ConstantVal = ConstantOffset->getSExtValue();
Simm12 = isInt<12>(ConstantVal);
if (Simm12)
- Offset = CurDAG->getTargetConstant(ConstantVal, SDLoc(Offset),
- Offset.getValueType());
+ Offset = CurDAG->getSignedTargetConstant(ConstantVal, SDLoc(Offset),
+ Offset.getValueType());
}
unsigned Opcode = 0;
diff --git a/llvm/test/CodeGen/RISCV/xcvmem.ll b/llvm/test/CodeGen/RISCV/xcvmem.ll
index 265177ed6ded7..52d0b6d51323a 100644
--- a/llvm/test/CodeGen/RISCV/xcvmem.ll
+++ b/llvm/test/CodeGen/RISCV/xcvmem.ll
@@ -189,6 +189,21 @@ define <2 x i32> @lw_rr_inc(ptr %a, i32 %b) {
ret <2 x i32> %5
}
+define i32 @lw_ri_inc_neg(ptr %pp) {
+; CHECK-LABEL: lw_ri_inc_neg:
+; CHECK: # %bb.0:
+; CHECK-NEXT: lw a2, 0(a0)
+; CHECK-NEXT: cv.lw a1, (a2), -4
+; CHECK-NEXT: sw a2, 0(a0)
+; CHECK-NEXT: mv a0, a1
+; CHECK-NEXT: ret
+ %p = load ptr, ptr %pp, align 4
+ %x = load i32, ptr %p, align 4
+ %next = getelementptr inbounds i8, ptr %p, i32 -4
+ store ptr %next, ptr %pp, align 4
+ ret i32 %x
+}
+
define i32 @lw_rr(ptr %a, i32 %b) {
; CHECK-LABEL: lw_rr:
; CHECK: # %bb.0:
More information about the llvm-commits
mailing list