[llvm-branch-commits] [RISC-V][RVY] Add support for compressed stack-pointer addition (PR #203598)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Jun 12 11:02:57 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-risc-v

Author: Alexander Richardson (arichardson)

<details>
<summary>Changes</summary>

In RVY mode, the c.addi4spn/c.addi16sp instructions expand to YADDI to
perform arithmetic on the YLEN stack pointer instead.
Ideally, we would reuse C_ADDI4SPN/C_ADDI16SP with SP:$rs1, but since the
CompressPat uses instructions with different register classes (ADDI vs YADDI)
we can't do this until tablegen resolves predicates in CompressPat.


---
Full diff: https://github.com/llvm/llvm-project/pull/203598.diff


6 Files Affected:

- (modified) llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp (+1) 
- (modified) llvm/lib/Target/RISCV/RISCVFeatures.td (+2-2) 
- (modified) llvm/lib/Target/RISCV/RISCVInstrInfoC.td (+6) 
- (modified) llvm/lib/Target/RISCV/RISCVInstrInfoY.td (+34) 
- (modified) llvm/lib/Target/RISCV/RISCVSubtarget.h (+2) 
- (added) llvm/test/MC/RISCV/rvy/rvyc-valid-addi.s (+73) 


``````````diff
diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
index 93cb83027af3f..c7dbdcd5fab78 100644
--- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
+++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
@@ -641,6 +641,7 @@ static constexpr DecoderListEntry DecoderList16[]{
     {DecoderTableRVY64Only16,
      {RISCV::FeatureStdExtY, RISCV::Feature64Bit},
      "RVY64-only 16-bit instructions"},
+    {DecoderTableRVY16, {RISCV::FeatureStdExtY}, "RVY 16-bit instructions"},
     {DecoderTable16, {}, "standard 16-bit instructions"},
     {DecoderTableRV32Only16, {}, "RV32-only 16-bit instructions"},
     // Zc* instructions incompatible with Zcf or Zcd
diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td
index 3b1013fb15c3e..804b7c133b804 100644
--- a/llvm/lib/Target/RISCV/RISCVFeatures.td
+++ b/llvm/lib/Target/RISCV/RISCVFeatures.td
@@ -1894,11 +1894,11 @@ def IsRV32 : Predicate<"!Subtarget->is64Bit()">,
              AssemblerPredicate<(all_of (not Feature64Bit)),
                                 "RV32I Base Instruction Set">;
 def IsStdExtYCapMode
-    : Predicate<"Subtarget->hasStdExtY() && !Subtarget->isRVYIntMode()">,
+    : Predicate<"Subtarget->isStdExtYCapMode()">,
       AssemblerPredicate<(all_of FeatureStdExtY, (not FeatureVendorXLLVMRVYIPM)),
                          "Using RVY Capability pointer mode">;
 def NotStdExtYCapMode
-    : Predicate<"!Subtarget->hasStdExtY() || Subtarget->isRVYIntMode()">,
+    : Predicate<"!Subtarget->isStdExtYCapMode()">,
       AssemblerPredicate<(any_of (not FeatureStdExtY), FeatureVendorXLLVMRVYIPM),
                          "Not using RVY Capability Pointer Mode">;
 defvar RV32I = DefaultMode;
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoC.td b/llvm/lib/Target/RISCV/RISCVInstrInfoC.td
index bf58d4b72d47f..b3b28cfc17813 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoC.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoC.td
@@ -266,6 +266,9 @@ class CA_ALU<bits<6> funct6, bits<2> funct2, string OpcodeStr>
 
 let Predicates = [HasStdExtZca] in {
 
+// Ideally we would reuse C_ADDI16SP for StdExtY, but since the CompressPat
+// uses instructions with different register classes (ADDI vs YADDI) we can't
+// do this yet. Instead, add a variant of the instruction in RISCVInstrInfoY.td.
 let hasSideEffects = 0, mayLoad = 0, mayStore = 0,
     append Predicates = [NotStdExtYCapMode] in
 def C_ADDI4SPN : RVInst16CIW<0b000, OPC_C0, (outs GPRC:$rd),
@@ -371,6 +374,9 @@ def C_LI : RVInst16CI<0b010, OPC_C1, (outs GPR:$rd), (ins simm6:$imm),
                       "c.li", "$rd, $imm">,
            Sched<[WriteIALU]>;
 
+// Ideally we would reuse C_ADDI16SP for StdExtY, but since the CompressPat
+// uses instructions with different register classes (ADDI vs YADDI) we can't
+// do this yet. Instead, add a variant of the instruction in RISCVInstrInfoY.td.
 let hasSideEffects = 0, mayLoad = 0, mayStore = 0,
     append Predicates = [NotStdExtYCapMode] in
 def C_ADDI16SP : RVInst16CI<0b011, OPC_C1, (outs SP_X:$rd_wb),
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoY.td b/llvm/lib/Target/RISCV/RISCVInstrInfoY.td
index e7f3e08c77522..4f588a4a7c695 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoY.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoY.td
@@ -219,6 +219,40 @@ def : CompressPat<(SY YGPR:$rs2, SPMem:$rs1, uimm9_lsb000:$imm),
                   (C_SYSP_RV32 YGPR:$rs2, SPMem:$rs1, uimm9_lsb000:$imm)>;
 } // Predicates = [HasStdExtZca, IsStdExtYCapMode, IsRV32]
 
+let Predicates = [HasStdExtZca, IsStdExtYCapMode] in {
+// Ideally, we would reuse C_ADDI4SPN/C_ADDI16SP with SP:$rs1, but since the
+// CompressPat uses instructions with different register classes (ADDI vs YADDI)
+// we can't do this until tablegen resolves predicates in CompressPat.
+let hasSideEffects = 0, mayLoad = 0, mayStore = 0, DecoderNamespace = "RVY" in {
+def C_YADDI4SPN : RVInst16CIW<0b000, OPC_C0, (outs YGPRC:$rd),
+                              (ins SP_Y:$rs1, uimm10_lsb00nonzero:$imm),
+                              "c.addi4spn", "$rd, $rs1, $imm">,
+                              Sched<[WriteIALU, ReadIALU]> {
+  bits<0> rs1;
+  let Inst{12-11} = imm{5-4};
+  let Inst{10-7} = imm{9-6};
+  let Inst{6} = imm{2};
+  let Inst{5} = imm{3};
+}
+def C_YADDI16SP : RVInst16CI<0b011, OPC_C1, (outs SP_Y:$rd_wb),
+                             (ins SP_Y:$rd, simm10_lsb0000nonzero:$imm),
+                             "c.addi16sp", "$rd, $imm">,
+                  Sched<[WriteIALU, ReadIALU]> {
+  let Constraints = "$rd = $rd_wb";
+  let rd = 2;
+  let Inst{12} = imm{9};
+  let Inst{6} = imm{4};
+  let Inst{5} = imm{6};
+  let Inst{4-3} = imm{8-7};
+  let Inst{2} = imm{5};
+}
+} // hasSideEffects = 0, mayLoad = 0, mayStore = 0, DecoderNamespace = "RVY"
+def : CompressPat<(YADDI YGPRC:$rd, SP_Y:$rs1, uimm10_lsb00nonzero:$imm),
+                  (C_YADDI4SPN YGPRC:$rd, SP_Y:$rs1, uimm10_lsb00nonzero:$imm)>;
+def : CompressPat<(YADDI X2_Y, X2_Y, simm10_lsb0000nonzero:$imm),
+                  (C_YADDI16SP X2_Y, simm10_lsb0000nonzero:$imm)>;
+} // Predicates = [HasStdExtZca, IsStdExtYCapMode]
+
 let Predicates = [HasStdExtZca, IsStdExtYCapMode, IsRV64] in {
 // DecoderNamespace needed since RVY64 reuses Zcd/Zcm* encodings
 let DecoderNamespace = "RVY64Only" in {
diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.h b/llvm/lib/Target/RISCV/RISCVSubtarget.h
index 4cf2c80323532..5bc8a1fe9ad69 100644
--- a/llvm/lib/Target/RISCV/RISCVSubtarget.h
+++ b/llvm/lib/Target/RISCV/RISCVSubtarget.h
@@ -176,6 +176,8 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo {
   bool GETTER() const { return ATTRIBUTE; }
 #include "RISCVGenSubtargetInfo.inc"
 
+  bool isStdExtYCapMode() const { return hasStdExtY() && !isRVYIntMode(); }
+
   LLVM_DEPRECATED("Now Equivalent to hasStdExtZcd", "hasStdExtZcd")
   bool hasStdExtCOrZcd() const { return HasStdExtZcd; }
   LLVM_DEPRECATED("Now Equivalent to hasStdExtZcf", "hasStdExtZcf")
diff --git a/llvm/test/MC/RISCV/rvy/rvyc-valid-addi.s b/llvm/test/MC/RISCV/rvy/rvyc-valid-addi.s
new file mode 100644
index 0000000000000..88cf60884c966
--- /dev/null
+++ b/llvm/test/MC/RISCV/rvy/rvyc-valid-addi.s
@@ -0,0 +1,73 @@
+/// Check that addi/yaddi uses compressed instructions correctly depending on the mode.
+// RUN: llvm-mc --triple=riscv32 --mattr=+zca,+zcb,+zcf,+zcd,+f,+d,+zfh,+xllvmrvyipm --riscv-no-aliases --show-encoding --show-inst < %s \
+// RUN:   | FileCheck --check-prefixes=CHECK-ASM-AND-OBJ,CHECK-ASM,CHECK-INT,CHECK-INT-ASM-AND-OBJ %s
+// RUN: llvm-mc --triple=riscv32 --mattr=+zca,+zcb,+zcd,+f,+d,+zfh,+experimental-y --defsym=RVY=1 --riscv-no-aliases --show-encoding --show-inst < %s \
+// RUN:   | FileCheck --check-prefixes=CHECK-ASM-AND-OBJ,CHECK-ASM,CHECK-CAP,CHECK-CAP-ASM-AND-OBJ %s
+// RUN: llvm-mc --filetype=obj --triple=riscv32 --mattr=+zca,+zcb,+zcf,+zcd,+f,+d,+zfh,+xllvmrvyipm --riscv-add-build-attributes < %s \
+// RUN:   | llvm-objdump --mattr=+xllvmrvyipm -M no-aliases -d --no-print-imm-hex - | FileCheck %s --check-prefixes=CHECK-ASM-AND-OBJ,CHECK-INT-ASM-AND-OBJ
+// RUN: llvm-mc --filetype=obj --triple=riscv32 --mattr=+zca,+zcb,+zcd,+f,+d,+zfh,+experimental-y --defsym=RVY=1 --riscv-add-build-attributes < %s \
+// RUN:   | llvm-objdump -M no-aliases -d --no-print-imm-hex - | FileCheck %s --check-prefixes=CHECK-ASM-AND-OBJ,CHECK-CAP-ASM-AND-OBJ
+//
+// RUN: llvm-mc --triple=riscv64 --mattr=+zca,+zcb,+zcd,+f,+d,+zfh,+xllvmrvyipm --defsym=RV64=1 --riscv-no-aliases --show-encoding --show-inst < %s \
+// RUN:   | FileCheck --check-prefixes=CHECK-ASM-AND-OBJ,CHECK-ASM,CHECK-INT,CHECK-INT-ASM-AND-OBJ %s
+// RUN: llvm-mc --triple=riscv64 --mattr=+zca,+zcb,+f,+d,+zfh,+experimental-y --defsym=RVY=1 --defsym=RV64=1 --defsym=RV64_CAP=1 --riscv-no-aliases --show-encoding --show-inst < %s \
+// RUN:   | FileCheck --check-prefixes=CHECK-ASM-AND-OBJ,CHECK-ASM,CHECK-CAP,CHECK-CAP-ASM-AND-OBJ %s
+// RUN: llvm-mc --filetype=obj --triple=riscv64 --mattr=+zca,+zcb,+zcd,+f,+d,+zfh,+xllvmrvyipm --defsym=RV64=1 --riscv-add-build-attributes < %s \
+// RUN:   | llvm-objdump --mattr=+xllvmrvyipm -M no-aliases -d --no-print-imm-hex - | FileCheck %s --check-prefixes=CHECK-ASM-AND-OBJ,CHECK-INT-ASM-AND-OBJ
+// RUN: llvm-mc --filetype=obj --triple=riscv64 --mattr=+zca,+zcb,+f,+d,+zfh,+experimental-y --defsym=RVY=1 --defsym=RV64=1 --defsym=RV64_CAP=1 --riscv-add-build-attributes < %s \
+// RUN:   | llvm-objdump -M no-aliases -d --no-print-imm-hex - | FileCheck %s --check-prefixes=CHECK-ASM-AND-OBJ,CHECK-CAP-ASM-AND-OBJ
+
+c.addi4spn a0, sp, 12
+// CHECK-ASM-AND-OBJ: c.addi4spn	a0, sp, 12
+// CHECK-ASM-SAME: # encoding: [0x68,0x00]
+// CHECK-INT-NEXT: # <MCInst #[[#]] C_ADDI4SPN{{$}}
+// CHECK-CAP-NEXT: # <MCInst #[[#]] C_YADDI4SPN{{$}}
+// CHECK-INT-NEXT: #  <MCOperand Reg:X10>
+// CHECK-CAP-NEXT: #  <MCOperand Reg:X10_Y>
+// CHECK-INT-NEXT: #  <MCOperand Reg:X2>
+// CHECK-CAP-NEXT: #  <MCOperand Reg:X2_Y>
+// CHECK-ASM-NEXT: #  <MCOperand Imm:12>>
+
+c.addi16sp sp, 16
+// CHECK-ASM-AND-OBJ: c.addi16sp	sp, 16
+// CHECK-ASM-SAME: # encoding: [0x41,0x61]
+// CHECK-INT-NEXT: # <MCInst #[[#]] C_ADDI16SP{{$}}
+// CHECK-CAP-NEXT: # <MCInst #[[#]] C_YADDI16SP{{$}}
+// CHECK-INT-NEXT: #  <MCOperand Reg:X2>
+// CHECK-CAP-NEXT: #  <MCOperand Reg:X2_Y>
+// CHECK-INT-NEXT: #  <MCOperand Reg:X2>
+// CHECK-CAP-NEXT: #  <MCOperand Reg:X2_Y>
+// CHECK-ASM-NEXT: #  <MCOperand Imm:16>>
+
+addi a0, sp, 12
+// CHECK-INT-ASM-AND-OBJ: c.addi4spn	a0, sp, 12
+// CHECK-INT-SAME: # encoding: [0x68,0x00]
+// CHECK-CAP-ASM-AND-OBJ: addi	a0, sp, 12
+// CHECK-CAP-SAME: # encoding: [0x13,0x05,0xc1,0x00]
+// CHECK-INT-NEXT: # <MCInst #[[#]] C_ADDI4SPN{{$}}
+// CHECK-CAP-NEXT: # <MCInst #[[#]] ADDI{{$}}
+// CHECK-ASM-NEXT: #  <MCOperand Reg:X10>
+// CHECK-ASM-NEXT: #  <MCOperand Reg:X2>
+// CHECK-ASM-NEXT: #  <MCOperand Imm:12>>
+
+yaddi a0, sp, 12
+// CHECK-INT-ASM-AND-OBJ: yaddi	a0, sp, 12
+// CHECK-INT-SAME: # encoding: [0x7b,0x45,0xc1,0x00]
+// CHECK-CAP-ASM-AND-OBJ: c.addi4spn	a0, sp, 12
+// CHECK-CAP-SAME: # encoding: [0x68,0x00]
+// CHECK-INT-NEXT: # <MCInst #[[#]] YADDI{{$}}
+// CHECK-CAP-NEXT: # <MCInst #[[#]] C_YADDI4SPN{{$}}
+// CHECK-ASM-NEXT: #  <MCOperand Reg:X10_Y>
+// CHECK-ASM-NEXT: #  <MCOperand Reg:X2_Y>
+// CHECK-ASM-NEXT: #  <MCOperand Imm:12>>
+
+yaddi sp, sp, 16
+// CHECK-INT-ASM-AND-OBJ: yaddi	sp, sp, 16
+// CHECK-INT-SAME: # encoding: [0x7b,0x41,0x01,0x01]
+// CHECK-CAP-ASM-AND-OBJ: c.addi16sp	sp, 16
+// CHECK-CAP-SAME: # encoding: [0x41,0x61]
+// CHECK-INT-NEXT: # <MCInst #[[#]] YADDI{{$}}
+// CHECK-CAP-NEXT: # <MCInst #[[#]] C_YADDI16SP{{$}}
+// CHECK-ASM-NEXT: #  <MCOperand Reg:X2_Y>
+// CHECK-ASM-NEXT: #  <MCOperand Reg:X2_Y>
+// CHECK-ASM-NEXT: #  <MCOperand Imm:16>>

``````````

</details>


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


More information about the llvm-branch-commits mailing list