[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