Skip to content

[RISCV] Make MOP/HINT-based instruction mnemonics always available#178609

Merged
kito-cheng merged 6 commits intollvm:mainfrom
kito-cheng:kitoc/mop-hint
Feb 3, 2026
Merged

[RISCV] Make MOP/HINT-based instruction mnemonics always available#178609
kito-cheng merged 6 commits intollvm:mainfrom
kito-cheng:kitoc/mop-hint

Conversation

@kito-cheng
Copy link
Copy Markdown
Member

Per the psABI discussion in riscv-non-isa/riscv-elf-psabi-doc#474, the conclusion was to NOT introduce a new build attribute for MOP/HINT encoding reinterpretation. Instead, the toolchain should recognize these mnemonics unconditionally in the assembler and disassembler.

The rationale is that these encodings occupy reserved hint/MOP space that is architecturally guaranteed not to trap on any compliant implementation. Requiring explicit extension flags creates unnecessary friction for users who simply want to write or read these instructions, while providing no real safety benefit since the encodings are always valid.

Note: Ideally, the ISA specification would explicitly guarantee that these MOP/HINT encodings will never be reassigned to conflicting instructions. However, the ISA architects prefer to preserve flexibility in this area rather than making such guarantees in the spec. Given the practical reality that reassignment is highly unlikely, the toolchain takes the pragmatic approach of always recognizing these mnemonics.

This change makes the following mnemonics always available:

  • lpad (Zicfilp): AUIPC hint encoding, always valid
  • pause (Zihintpause): FENCE hint encoding, always valid
  • ntl.* (Zihintntl): ADD hint encoding, always valid
  • c.ntl.* (Zihintntl+C): requires C extension only
  • sspush/sspopchk/ssrdp (Zicfiss): requires Zimop only (MOP encoding)
  • c.sspush/c.sspopchk (Zicfiss+Zcmop): requires Zcmop only

Note: ssamoswap.w/d still requires Zicfiss as they use AMO encoding space rather than MOP encoding.

Codegen patterns remain unchanged in this patch - generating these instructions in the compiler backend still requires the full extension to be enabled. A follow-up patch will relax this restriction as well, since these instructions are fundamentally MOP/HINT encodings that should be safe to generate regardless of extension availability.

Link: riscv-non-isa/riscv-elf-psabi-doc#474

Per the psABI discussion in riscv-non-isa/riscv-elf-psabi-doc#474,
the conclusion was to NOT introduce a new build attribute for MOP/HINT
encoding reinterpretation. Instead, the toolchain should recognize
these mnemonics unconditionally in the assembler and disassembler.

The rationale is that these encodings occupy reserved hint/MOP space
that is architecturally guaranteed not to trap on any compliant
implementation. Requiring explicit extension flags creates unnecessary
friction for users who simply want to write or read these instructions,
while providing no real safety benefit since the encodings are always
valid.

Note: Ideally, the ISA specification would explicitly guarantee that
these MOP/HINT encodings will never be reassigned to conflicting
instructions. However, the ISA architects prefer to preserve flexibility
in this area rather than making such guarantees in the spec. Given the
practical reality that reassignment is highly unlikely, the toolchain
takes the pragmatic approach of always recognizing these mnemonics.

This change makes the following mnemonics always available:
- lpad (Zicfilp): AUIPC hint encoding, always valid
- pause (Zihintpause): FENCE hint encoding, always valid
- ntl.* (Zihintntl): ADD hint encoding, always valid
- c.ntl.* (Zihintntl+C): requires C extension only
- sspush/sspopchk/ssrdp (Zicfiss): requires Zimop only (MOP encoding)
- c.sspush/c.sspopchk (Zicfiss+Zcmop): requires Zcmop only

Note: ssamoswap.w/d still requires Zicfiss as they use AMO encoding
space rather than MOP encoding.

Codegen patterns remain unchanged in this patch - generating these
instructions in the compiler backend still requires the full extension
to be enabled. A follow-up patch will relax this restriction as well,
since these instructions are fundamentally MOP/HINT encodings that
should be safe to generate regardless of extension availability.

Link: riscv-non-isa/riscv-elf-psabi-doc#474
@llvmbot
Copy link
Copy Markdown
Member

llvmbot commented Jan 29, 2026

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

Author: Kito Cheng (kito-cheng)

Changes

Per the psABI discussion in riscv-non-isa/riscv-elf-psabi-doc#474, the conclusion was to NOT introduce a new build attribute for MOP/HINT encoding reinterpretation. Instead, the toolchain should recognize these mnemonics unconditionally in the assembler and disassembler.

The rationale is that these encodings occupy reserved hint/MOP space that is architecturally guaranteed not to trap on any compliant implementation. Requiring explicit extension flags creates unnecessary friction for users who simply want to write or read these instructions, while providing no real safety benefit since the encodings are always valid.

Note: Ideally, the ISA specification would explicitly guarantee that these MOP/HINT encodings will never be reassigned to conflicting instructions. However, the ISA architects prefer to preserve flexibility in this area rather than making such guarantees in the spec. Given the practical reality that reassignment is highly unlikely, the toolchain takes the pragmatic approach of always recognizing these mnemonics.

This change makes the following mnemonics always available:

  • lpad (Zicfilp): AUIPC hint encoding, always valid
  • pause (Zihintpause): FENCE hint encoding, always valid
  • ntl.* (Zihintntl): ADD hint encoding, always valid
  • c.ntl.* (Zihintntl+C): requires C extension only
  • sspush/sspopchk/ssrdp (Zicfiss): requires Zimop only (MOP encoding)
  • c.sspush/c.sspopchk (Zicfiss+Zcmop): requires Zcmop only

Note: ssamoswap.w/d still requires Zicfiss as they use AMO encoding space rather than MOP encoding.

Codegen patterns remain unchanged in this patch - generating these instructions in the compiler backend still requires the full extension to be enabled. A follow-up patch will relax this restriction as well, since these instructions are fundamentally MOP/HINT encodings that should be safe to generate regardless of extension availability.

Link: riscv-non-isa/riscv-elf-psabi-doc#474


Patch is 24.14 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/178609.diff

15 Files Affected:

  • (modified) llvm/lib/Target/RISCV/RISCVInstrInfo.td (+11-9)
  • (modified) llvm/lib/Target/RISCV/RISCVInstrInfoC.td (+4-2)
  • (modified) llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td (+12-6)
  • (modified) llvm/test/MC/Disassembler/RISCV/c_lui_disasm.txt (+2-2)
  • (modified) llvm/test/MC/RISCV/compressed-zicfiss.s (+22-8)
  • (modified) llvm/test/MC/RISCV/invalid-instruction-spellcheck.s (+2-2)
  • (modified) llvm/test/MC/RISCV/rv32i-invalid.s (-1)
  • (modified) llvm/test/MC/RISCV/rvzcmop-valid.s (+24-12)
  • (modified) llvm/test/MC/RISCV/rvzihintntl-invalid.s (+6-1)
  • (modified) llvm/test/MC/RISCV/rvzihintntl-valid.s (+14)
  • (modified) llvm/test/MC/RISCV/rvzihintntlc-valid.s (+19-2)
  • (modified) llvm/test/MC/RISCV/rvzihintpause-aliases-valid.s (+14)
  • (modified) llvm/test/MC/RISCV/zicfilp-invalid.s (+7)
  • (modified) llvm/test/MC/RISCV/zicfilp-valid.s (+13-5)
  • (modified) llvm/test/MC/RISCV/zicfiss-valid.s (+13-9)
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index c7be5b07c33cc..aa76b4d5a9926 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -1115,7 +1115,8 @@ def : InstAlias<"jalr $rd, (${rs})",      (JALR GPR:$rd, GPR:$rs, 0), 0>;
 
 def : InstAlias<"fence", (FENCE 0xF, 0xF)>; // 0xF == iorw
 
-let Predicates = [HasStdExtZihintpause] in
+// pause is always available in the assembler and disassembler, even without
+// enabling Zihintpause, per psABI decision (riscv-non-isa/riscv-elf-psabi-doc#474).
 def : InstAlias<"pause", (FENCE 0x1, 0x0)>; // 0x1 == w
 
 def : InstAlias<"rdinstret $rd", (CSRRS GPR:$rd, INSTRET.Encoding, X0), 2>;
@@ -1156,12 +1157,13 @@ def : InstAlias<"hfence.gvma $rs", (HFENCE_GVMA GPR:$rs, X0)>;
 def : InstAlias<"hfence.vvma",     (HFENCE_VVMA      X0, X0), 2>;
 def : InstAlias<"hfence.vvma $rs", (HFENCE_VVMA GPR:$rs, X0)>;
 
-let Predicates = [HasStdExtZihintntl] in {
-  def : InstAlias<"ntl.p1",     (ADD   X0, X0, X2)>;
-  def : InstAlias<"ntl.pall",   (ADD   X0, X0, X3)>;
-  def : InstAlias<"ntl.s1",     (ADD   X0, X0, X4)>;
-  def : InstAlias<"ntl.all",    (ADD   X0, X0, X5)>;
-} // Predicates = [HasStdExtZihintntl]
+// ntl.* hints are always available in the assembler and disassembler, even
+// without enabling Zihintntl, per psABI decision
+// (riscv-non-isa/riscv-elf-psabi-doc#474).
+def : InstAlias<"ntl.p1",     (ADD   X0, X0, X2)>;
+def : InstAlias<"ntl.pall",   (ADD   X0, X0, X3)>;
+def : InstAlias<"ntl.s1",     (ADD   X0, X0, X4)>;
+def : InstAlias<"ntl.all",    (ADD   X0, X0, X5)>;
 
 let EmitPriority = 0 in {
 def : InstAlias<"lb $rd, (${rs1})",
@@ -1229,9 +1231,9 @@ def : MnemonicAlias<"sbreak", "ebreak">;
 
 def : InstAlias<"zext.b $rd, $rs", (ANDI GPR:$rd, GPR:$rs, 0xFF)>;
 
-let Predicates = [HasStdExtZicfilp] in {
+// lpad is always available in the assembler and disassembler, even without
+// enabling Zicfilp, per psABI decision (riscv-non-isa/riscv-elf-psabi-doc#474).
 def : InstAlias<"lpad $imm20", (AUIPC X0, uimm20:$imm20)>;
-}
 
 //===----------------------------------------------------------------------===//
 // .insn directive instructions
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoC.td b/llvm/lib/Target/RISCV/RISCVInstrInfoC.td
index 47046cd3cca72..27d995c9c869b 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoC.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoC.td
@@ -596,12 +596,14 @@ def : InstAlias<"c.srli64 $rs1", (C_SRLI GPRC:$rs1, 0), 0>;
 def : InstAlias<"c.srai64 $rs1", (C_SRAI GPRC:$rs1, 0), 0>;
 }
 
-let Predicates = [HasStdExtC, HasStdExtZihintntl] in {
+// c.ntl.* hints are always available when C extension is present, even without
+// enabling Zihintntl, per psABI decision (riscv-non-isa/riscv-elf-psabi-doc#474).
+let Predicates = [HasStdExtC] in {
 def : InstAlias<"c.ntl.p1", (C_ADD X0, X2)>;
 def : InstAlias<"c.ntl.pall", (C_ADD X0, X3)>;
 def : InstAlias<"c.ntl.s1", (C_ADD X0, X4)>;
 def : InstAlias<"c.ntl.all", (C_ADD X0, X5)>;
-} // Predicates = [HasStdExtC, HasStdExtZihintntl]
+} // Predicates = [HasStdExtC]
 
 let EmitPriority = 0 in {
 let Predicates = [HasStdExtZca] in {
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td
index efd06c29dc99f..d293851cfad6f 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td
@@ -24,7 +24,10 @@ class RVC_SSInst<bits<5> rs1val, RegisterClass reg_class, string opcodestr> :
 // Instructions
 //===----------------------------------------------------------------------===//
 
-let Predicates = [HasStdExtZicfiss] in {
+// Zicfiss instructions that use Zimop encoding space are available when Zimop
+// is enabled, without requiring Zicfiss explicitly. Per psABI decision
+// (riscv-non-isa/riscv-elf-psabi-doc#474).
+let Predicates = [HasStdExtZimop] in {
 let Uses = [SSP], Defs = [SSP], hasSideEffects = 0, mayLoad = 1, mayStore = 0 in
 def SSPOPCHK : RVInstI<0b100, OPC_SYSTEM, (outs), (ins GPRX1X5:$rs1), "sspopchk",
                        "$rs1"> {
@@ -45,16 +48,19 @@ def SSPUSH : RVInstR<0b1100111, 0b100, OPC_SYSTEM, (outs), (ins GPRX1X5:$rs2),
   let rd = 0b00000;
   let rs1 = 0b00000;
 }
-} // Predicates = [HasStdExtZicfiss]
+} // Predicates = [HasStdExtZimop]
 
-let Predicates = [HasStdExtZicfiss, HasStdExtZcmop],
+// Compressed Zicfiss instructions use Zcmop encoding space and are available
+// when Zcmop is enabled, without requiring Zicfiss explicitly. Per psABI
+// decision (riscv-non-isa/riscv-elf-psabi-doc#474).
+let Predicates = [HasStdExtZcmop],
     DecoderNamespace = "Zicfiss" in {
 let Uses = [SSP], Defs = [SSP], hasSideEffects = 0, mayLoad = 0, mayStore = 1 in
 def C_SSPUSH : RVC_SSInst<0b00001, GPRX1, "c.sspush">;
 
 let Uses = [SSP], Defs = [SSP], hasSideEffects = 0, mayLoad = 1, mayStore = 0 in
 def C_SSPOPCHK : RVC_SSInst<0b00101, GPRX5, "c.sspopchk">;
-} // Predicates = [HasStdExtZicfiss, HasStdExtZcmop]
+} // Predicates = [HasStdExtZcmop]
 
 let Predicates = [HasStdExtZicfiss] in
 defm SSAMOSWAP_W  : AMO_rr_aq_rl<0b01001, 0b010, "ssamoswap.w">;
@@ -81,7 +87,7 @@ def PseudoMOP_C_SSPUSH : Pseudo<(outs), (ins), []>,
 // Compress Instruction tablegen backend.
 //===----------------------------------------------------------------------===//
 
-let Predicates = [HasStdExtZicfiss, HasStdExtZcmop] in {
+let Predicates = [HasStdExtZcmop] in {
 def : CompressPat<(SSPUSH X1), (C_SSPUSH X1)>;
 def : CompressPat<(SSPOPCHK X5), (C_SSPOPCHK X5)>;
-} // Predicates = [HasStdExtZicfiss, HasStdExtZcmop]
+} // Predicates = [HasStdExtZcmop]
diff --git a/llvm/test/MC/Disassembler/RISCV/c_lui_disasm.txt b/llvm/test/MC/Disassembler/RISCV/c_lui_disasm.txt
index 0a83a200c9317..beaaad8bf9adf 100644
--- a/llvm/test/MC/Disassembler/RISCV/c_lui_disasm.txt
+++ b/llvm/test/MC/Disassembler/RISCV/c_lui_disasm.txt
@@ -204,7 +204,7 @@
 0x7D 0x70
 
 # BAD: invalid instruction encoding
-# MOP: c.mop.1
+# MOP: c.sspush ra
 0x81 0x60
 
 # GOOD: c.lui ra, 1
@@ -782,7 +782,7 @@
 0x7D 0x72
 
 # BAD: invalid instruction encoding
-# MOP: c.mop.5
+# MOP: c.sspopchk t0
 0x81 0x62
 
 # GOOD: c.lui t0, 1
diff --git a/llvm/test/MC/RISCV/compressed-zicfiss.s b/llvm/test/MC/RISCV/compressed-zicfiss.s
index 7d387b257b7b4..bd4bf1858b6dc 100644
--- a/llvm/test/MC/RISCV/compressed-zicfiss.s
+++ b/llvm/test/MC/RISCV/compressed-zicfiss.s
@@ -9,45 +9,59 @@
 # RUN:     | llvm-objdump --mattr=+experimental-zicfiss,+zcmop -M no-aliases -d -r - \
 # RUN:     | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s
 #
+# Compressed Zicfiss instructions only require Zcmop (and Zimop for
+# uncompressed forms), not Zicfiss (riscv-non-isa/riscv-elf-psabi-doc#474).
+#
+# RUN: llvm-mc %s -triple=riscv32 -mattr=+zcmop,+zimop -M no-aliases -show-encoding \
+# RUN:     | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s
+# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+zcmop,+zimop < %s \
+# RUN:     | llvm-objdump --mattr=+zcmop,+zimop -M no-aliases -d -r - \
+# RUN:     | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s
+# RUN: llvm-mc %s -triple=riscv64 -mattr=+zcmop,+zimop -M no-aliases -show-encoding \
+# RUN:     | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s
+# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+zcmop,+zimop < %s \
+# RUN:     | llvm-objdump --mattr=+zcmop,+zimop -M no-aliases -d -r - \
+# RUN:     | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s
+#
 # RUN: not llvm-mc -triple riscv32 -M no-aliases -show-encoding < %s 2>&1 \
 # RUN:     | FileCheck -check-prefixes=CHECK-NO-EXT %s
 
 # CHECK-ASM-AND-OBJ: c.sspopchk t0
 # CHECK-ASM: encoding: [0x81,0x62]
-# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+# CHECK-NO-EXT: error: instruction requires the following: 'Zimop' (May-Be-Operations)
 sspopchk x5
 
 # CHECK-ASM-AND-OBJ: c.sspopchk t0
 # CHECK-ASM: encoding: [0x81,0x62]
-# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+# CHECK-NO-EXT: error: instruction requires the following: 'Zimop' (May-Be-Operations)
 sspopchk t0
 
 # CHECK-ASM-AND-OBJ: c.sspush ra
 # CHECK-ASM: encoding: [0x81,0x60]
-# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+# CHECK-NO-EXT: error: instruction requires the following: 'Zimop' (May-Be-Operations)
 sspush x1
 
 # CHECK-ASM-AND-OBJ: c.sspush ra
 # CHECK-ASM: encoding: [0x81,0x60]
-# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+# CHECK-NO-EXT: error: instruction requires the following: 'Zimop' (May-Be-Operations)
 sspush ra
 
 # CHECK-ASM-AND-OBJ: c.sspush ra
 # CHECK-ASM: encoding: [0x81,0x60]
-# CHECK-NO-EXT: error: instruction requires the following: 'Zcmop' (Compressed May-Be-Operations), 'Zicfiss' (Shadow stack)
+# CHECK-NO-EXT: error: instruction requires the following: 'Zcmop' (Compressed May-Be-Operations)
 c.sspush x1
 
 # CHECK-ASM-AND-OBJ: c.sspush ra
 # CHECK-ASM: encoding: [0x81,0x60]
-# CHECK-NO-EXT: error: instruction requires the following: 'Zcmop' (Compressed May-Be-Operations), 'Zicfiss' (Shadow stack)
+# CHECK-NO-EXT: error: instruction requires the following: 'Zcmop' (Compressed May-Be-Operations)
 c.sspush ra
 
 # CHECK-ASM-AND-OBJ: c.sspopchk t0
 # CHECK-ASM: encoding: [0x81,0x62]
-# CHECK-NO-EXT: error: instruction requires the following: 'Zcmop' (Compressed May-Be-Operations), 'Zicfiss' (Shadow stack)
+# CHECK-NO-EXT: error: instruction requires the following: 'Zcmop' (Compressed May-Be-Operations)
 c.sspopchk x5
 
 # CHECK-ASM-AND-OBJ: c.sspopchk t0
 # CHECK-ASM: encoding: [0x81,0x62]
-# CHECK-NO-EXT: error: instruction requires the following: 'Zcmop' (Compressed May-Be-Operations), 'Zicfiss' (Shadow stack)
+# CHECK-NO-EXT: error: instruction requires the following: 'Zcmop' (Compressed May-Be-Operations)
 c.sspopchk t0
diff --git a/llvm/test/MC/RISCV/invalid-instruction-spellcheck.s b/llvm/test/MC/RISCV/invalid-instruction-spellcheck.s
index 8e8c42e033b8a..477ccdf6a28de 100644
--- a/llvm/test/MC/RISCV/invalid-instruction-spellcheck.s
+++ b/llvm/test/MC/RISCV/invalid-instruction-spellcheck.s
@@ -11,8 +11,8 @@
 # which are valid for the current set of features
 
 ad x1, x1, x1
-# CHECK-RV32: did you mean: add, addi, and, andi, la
-# CHECK-RV64: did you mean: add, addi, addw, and, andi, la, ld, sd
+# CHECK-RV32: did you mean: add, addi, and, andi, la, lpad
+# CHECK-RV64: did you mean: add, addi, addw, and, andi, la, ld, lpad, sd
 # CHECK-NEXT: ad x1, x1, x1
 
 fl ft0, 0(sp)
diff --git a/llvm/test/MC/RISCV/rv32i-invalid.s b/llvm/test/MC/RISCV/rv32i-invalid.s
index 7f57345c3223c..29daf365d3f1f 100644
--- a/llvm/test/MC/RISCV/rv32i-invalid.s
+++ b/llvm/test/MC/RISCV/rv32i-invalid.s
@@ -196,7 +196,6 @@ sh1add a0, a1, a2 # CHECK: :[[@LINE]]:1: error: instruction requires the followi
 clz a0, a1 # CHECK: :[[@LINE]]:1: error: instruction requires the following: 'Zbb' (Basic Bit-Manipulation){{$}}
 clmul a0, a1, a2 # CHECK: :[[@LINE]]:1: error: instruction requires the following: 'Zbc' (Carry-Less Multiplication) or 'Zbkc' (Carry-less multiply instructions for Cryptography){{$}}
 bset a0, a1, a2 # CHECK: :[[@LINE]]:1: error: instruction requires the following: 'Zbs' (Single-Bit Instructions){{$}}
-pause # CHECK: :[[@LINE]]:1: error: instruction requires the following: 'Zihintpause' (Pause Hint){{$}}
 
 # Using floating point registers when integer registers are expected
 addi a2, ft0, 24 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
diff --git a/llvm/test/MC/RISCV/rvzcmop-valid.s b/llvm/test/MC/RISCV/rvzcmop-valid.s
index dd5d26ac5dd0c..ba6a4ec4ec903 100644
--- a/llvm/test/MC/RISCV/rvzcmop-valid.s
+++ b/llvm/test/MC/RISCV/rvzcmop-valid.s
@@ -1,42 +1,54 @@
 # RUN: llvm-mc %s -triple=riscv32 -mattr=+zcmop -show-encoding \
-# RUN:     | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s
+# RUN:     | FileCheck -check-prefixes=CHECK-ASM %s
 # RUN: llvm-mc %s -triple=riscv64 -mattr=+zcmop -show-encoding \
-# RUN:     | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s
+# RUN:     | FileCheck -check-prefixes=CHECK-ASM %s
 # RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+zcmop < %s \
 # RUN:     | llvm-objdump --mattr=+zcmop -d -r - \
-# RUN:     | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s
+# RUN:     | FileCheck --check-prefix=CHECK-OBJ %s
 # RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+zcmop < %s \
 # RUN:     | llvm-objdump --mattr=+zcmop -d -r - \
-# RUN:     | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s
+# RUN:     | FileCheck --check-prefix=CHECK-OBJ %s
 
-# CHECK-ASM-AND-OBJ: c.mop.1
+# c.mop.1 disassembles as c.sspush ra when Zcmop is enabled
+# (riscv-non-isa/riscv-elf-psabi-doc#474).
+# CHECK-OBJ: c.sspush ra
+# CHECK-ASM: c.mop.1
 # CHECK-ASM: encoding: [0x81,0x60]
 c.mop.1
 
-# CHECK-ASM-AND-OBJ: c.mop.3
+# CHECK-OBJ: c.mop.3
+# CHECK-ASM: c.mop.3
 # CHECK-ASM: encoding: [0x81,0x61]
 c.mop.3
 
-# CHECK-ASM-AND-OBJ: c.mop.5
+# c.mop.5 disassembles as c.sspopchk t0 when Zcmop is enabled
+# (riscv-non-isa/riscv-elf-psabi-doc#474).
+# CHECK-OBJ: c.sspopchk t0
+# CHECK-ASM: c.mop.5
 # CHECK-ASM: encoding: [0x81,0x62]
 c.mop.5
 
-# CHECK-ASM-AND-OBJ: c.mop.7
+# CHECK-OBJ: c.mop.7
+# CHECK-ASM: c.mop.7
 # CHECK-ASM: encoding: [0x81,0x63]
 c.mop.7
 
-# CHECK-ASM-AND-OBJ: c.mop.9
+# CHECK-OBJ: c.mop.9
+# CHECK-ASM: c.mop.9
 # CHECK-ASM: encoding: [0x81,0x64]
 c.mop.9
 
-# CHECK-ASM-AND-OBJ: c.mop.11
+# CHECK-OBJ: c.mop.11
+# CHECK-ASM: c.mop.11
 # CHECK-ASM: encoding: [0x81,0x65]
 c.mop.11
 
-# CHECK-ASM-AND-OBJ: c.mop.13
+# CHECK-OBJ: c.mop.13
+# CHECK-ASM: c.mop.13
 # CHECK-ASM: encoding: [0x81,0x66]
 c.mop.13
 
-# CHECK-ASM-AND-OBJ: c.mop.15
+# CHECK-OBJ: c.mop.15
+# CHECK-ASM: c.mop.15
 # CHECK-ASM: encoding: [0x81,0x67]
 c.mop.15
diff --git a/llvm/test/MC/RISCV/rvzihintntl-invalid.s b/llvm/test/MC/RISCV/rvzihintntl-invalid.s
index af8c4075c3552..9fc647100fcf4 100644
--- a/llvm/test/MC/RISCV/rvzihintntl-invalid.s
+++ b/llvm/test/MC/RISCV/rvzihintntl-invalid.s
@@ -1,5 +1,11 @@
 # RUN: not llvm-mc -triple riscv32 -mattr=+zihintntl < %s 2>&1 | FileCheck %s
 # RUN: not llvm-mc -triple riscv64 -mattr=+zihintntl < %s 2>&1 | FileCheck %s
+#
+# ntl.* hints are always available even without Zihintntl
+# (riscv-non-isa/riscv-elf-psabi-doc#474).
+#
+# RUN: not llvm-mc -triple riscv32 < %s 2>&1 | FileCheck %s
+# RUN: not llvm-mc -triple riscv64 < %s 2>&1 | FileCheck %s
 
 ntl.p1 1 # CHECK: :[[@LINE]]:8: error: invalid operand for instruction
 ntl.pall 2 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
@@ -10,4 +16,3 @@ ntl.p1 t0, t1 # CHECK: :[[@LINE]]:8: error: invalid operand for instruction
 ntl.pall t0, t1 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
 ntl.s1 t0, t1 # CHECK: :[[@LINE]]:8: error: invalid operand for instruction
 ntl.all t0, t1 # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
-
diff --git a/llvm/test/MC/RISCV/rvzihintntl-valid.s b/llvm/test/MC/RISCV/rvzihintntl-valid.s
index 415070a3eee29..1971b0b7a18d8 100644
--- a/llvm/test/MC/RISCV/rvzihintntl-valid.s
+++ b/llvm/test/MC/RISCV/rvzihintntl-valid.s
@@ -8,6 +8,20 @@
 # RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+zihintntl < %s \
 # RUN:     | llvm-objdump --mattr=+zihintntl -M no-aliases -d -r - \
 # RUN:     | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s
+#
+# ntl.* hints are always available even without Zihintntl
+# (riscv-non-isa/riscv-elf-psabi-doc#474).
+#
+# RUN: llvm-mc %s -triple=riscv32 -M no-aliases -show-encoding \
+# RUN:     | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s
+# RUN: llvm-mc %s -triple=riscv64 -M no-aliases -show-encoding \
+# RUN:     | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s
+# RUN: llvm-mc -filetype=obj -triple=riscv32 < %s \
+# RUN:     | llvm-objdump -M no-aliases -d -r - \
+# RUN:     | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s
+# RUN: llvm-mc -filetype=obj -triple=riscv64 < %s \
+# RUN:     | llvm-objdump -M no-aliases -d -r - \
+# RUN:     | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s
 
 # CHECK-ASM-AND-OBJ: add zero, zero, sp
 # CHECK-ASM: encoding: [0x33,0x00,0x20,0x00]
diff --git a/llvm/test/MC/RISCV/rvzihintntlc-valid.s b/llvm/test/MC/RISCV/rvzihintntlc-valid.s
index 53ffd7fbc879c..c8fb3c27cde18 100644
--- a/llvm/test/MC/RISCV/rvzihintntlc-valid.s
+++ b/llvm/test/MC/RISCV/rvzihintntlc-valid.s
@@ -8,8 +8,25 @@
 # RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+zihintntl,+c < %s \
 # RUN:     | llvm-objdump --mattr=+zihintntl,+c -d -r - \
 # RUN:     | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s
-# RUN: not llvm-mc %s -triple=riscv32 -mattr=+zihintntl 2>&1 | FileCheck -check-prefix=CHECK-NO-C %s
-# RUN: not llvm-mc %s -triple=riscv64 -mattr=+zihintntl 2>&1 | FileCheck -check-prefix=CHECK-NO-C %s
+#
+# c.ntl.* hints are available when C extension is present, even without
+# enabling Zihintntl (riscv-non-isa/riscv-elf-psabi-doc#474).
+#
+# RUN: llvm-mc %s -triple=riscv32 -mattr=+c -show-encoding \
+# RUN:     | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s
+# RUN: llvm-mc %s -triple=riscv64 -mattr=+c -show-encoding \
+# RUN:     | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s
+# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+c < %s \
+# RUN:     | llvm-objdump --mattr=+c -d -r - \
+# RUN:     | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s
+# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c < %s \
+# RUN:     | llvm-objdump --mattr=+c -d -r - \
+# RUN:     | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s
+#
+# c.ntl.* still require the C extension.
+#
+# RUN: not llvm-mc %s -triple=riscv32 2>&1 | FileCheck -check-prefix=CHECK-NO-C %s
+# RUN: not llvm-mc %s -triple=riscv64 2>&1 | FileCheck -check-prefix=CHECK-NO-C %s
 
 # CHECK-ASM-AND-OBJ: ntl.p1
 # CHECK-ASM: encoding: [0x33,0x00,0x20,0x00]
diff --git a/llvm/test/MC/RISCV/rvzihintpause-aliases-valid.s b/llvm/test/MC/RISCV/rvzihintpause-aliases-valid.s
index d505029ae4637..0c57a12dff18f 100644
--- a/llvm/test/MC/RISCV/rvzihintpause-aliases-valid.s
+++ b/llvm/test/MC/RISCV/rvzihintpause-aliases-valid.s
@@ -18,6 +18,20 @@
 # RUN: llvm-mc -filetype=obj -triple riscv64 -mattr=+zihintpause < %s \
 # RUN:     | llvm-objdump --mattr=+zihintpause -d -r - \
 # RUN:     | FileCheck -check-prefixes=CHECK-S-OBJ %s
+#
+# pause is always available even without Zihintpause
+# (riscv-non-isa/riscv-elf-psabi-doc#474).
+#
+# RUN: llvm-mc %s -triple=riscv32 -M no-aliases \
+# RUN:     | FileCheck -check-prefixes=CHECK-S-OBJ-NOALIAS %s
+# RUN: llvm-mc %s -triple=riscv32 \
+# RUN:     | FileCheck -check-prefixes=CHECK-S-OBJ %s
+# RUN: llvm-mc -filetype=obj -triple riscv32 < %s \
+# RUN:     | llvm-objdump -d -r -M no-aliases - \
+# RUN:     | FileCheck -check-prefixes=CHECK-S-OBJ-NOALIAS %s
+# RUN: llvm-mc -filetype=obj -triple riscv32 < %s \
+# RUN:     | llvm-objdump -d -r - \
+# RUN:     | FileCheck -check-prefixes=CHECK-S-OBJ %s
 
 # CHECK-S-OBJ-NOALIAS: fence w, 0
 # CHECK-S-OBJ: pause
diff --git a/llvm/test/MC/RISCV/zicfilp-invalid.s b/llvm/test/MC/RISCV/zicfilp-invalid.s
index bff989fa204a3..30d8be2f534a3 100644
--- a/llvm/test/MC/RISCV/zicfilp-invalid.s
+++ b/llvm/test/MC/RISCV/zicfilp-invalid.s
@@ -2,6 +2,13 @@
 # RUN:     | FileCheck -check-prefixes=CHECK-NO-EXT %s
 # RUN: not llvm-mc -triple riscv64 -mattr=+experimental-zicfilp -M no-aliases -show-encoding < %s 2>&1 \
 # RUN:     | FileCheck -check-prefixes=CHECK-NO-EXT %s
+#
+# lpad is always available even without Zicfilp (riscv-non-isa/riscv-elf-psabi-doc#474).
+#
+# RUN: not llvm-mc -triple riscv32 -M no-aliases -show-encoding < %s 2>&1 \
+# RUN:     | FileCheck -check-prefixes=CHECK-NO-EXT %s
+# RUN: not llvm-mc -triple riscv64 -M no-aliases -show-encoding < %s 2>&1 \
+# RUN:     | FileCheck -check-prefixes=CHECK-NO-EXT %s
 
 # CHECK-NO-EXT: immediate must be an integer in the range [0, 1048575]
 lpad 1048576
diff --git a/llvm/test/MC/RISCV/zicfilp-valid.s b/llvm/test/MC/RISCV/zicfilp-valid.s
index f61cad8d85d53..c2ccefa544ba9 100644
--- a/llvm/test/MC/RISCV/zicfilp-valid.s
+++ b/llvm/test/MC/RISCV/zicfilp-valid.s
@@ -9,13 +9,21 @@
 # RUN:     | llvm-objdump --mattr=+experimental-zicfilp --no-print-imm-hex -d -r - \
 # RUN:     | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s
 #
-# RUN: not llvm-mc -triple riscv32 -M no-aliases -show-encoding < %s 2>&1 \
-# RUN:     | FileCheck -check-prefixes=CHECK-NO-EXT %s
-# RUN: not llvm-mc -triple riscv64 -M no-aliases -show-encodi...
[truncated]

Copy link
Copy Markdown
Collaborator

@topperc topperc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update Release Notes?

Copy link
Copy Markdown
Member

@lenary lenary left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems neater than Arm's much more complex scheme that involves two InstAlias and choosing whether to print a numbered nop or the named hint depending on which extensions are enabled.

If we run into problems with -fno-integrated-as, we can always implement that more complex scheme.

- Add release notes entry
- Change c.ntl.* hints predicate from HasStdExtC to HasStdExtZca
Per topperc's review comment, c.mop.1 and c.mop.5 are now InstAlias
for c.sspush ra and c.sspopchk t0 respectively, with EmitPriority=0
so the assembler and disassembler both print c.sspush/c.sspopchk.
# Conflicts:
#	llvm/docs/ReleaseNotes.md
@kito-cheng
Copy link
Copy Markdown
Member Author

Changes:

  • Fix Predicates for c.ntl.*
  • Add release note
  • Declare c.mop.1/c.mop.5 as InstAlias for c.sspush/c.sspopchk
  • Merge trunk

Copy link
Copy Markdown
Member

@lenary lenary left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks Kito!

@kito-cheng
Copy link
Copy Markdown
Member Author

Changes:

  • Address Craig's comment, mostly for test case tweaking

Copy link
Copy Markdown
Collaborator

@topperc topperc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@kito-cheng kito-cheng enabled auto-merge (squash) February 3, 2026 03:09
@kito-cheng kito-cheng disabled auto-merge February 3, 2026 03:14
@kito-cheng kito-cheng merged commit 466c22b into llvm:main Feb 3, 2026
11 checks passed
moar55 pushed a commit to moar55/llvm-project that referenced this pull request Feb 3, 2026
…lvm#178609)

Per the psABI discussion in riscv-non-isa/riscv-elf-psabi-doc#474, the
conclusion was to NOT introduce a new build attribute for MOP/HINT
encoding reinterpretation. Instead, the toolchain should recognize these
mnemonics unconditionally in the assembler and disassembler.

The rationale is that these encodings occupy reserved hint/MOP space
that is architecturally guaranteed not to trap on any compliant
implementation. Requiring explicit extension flags creates unnecessary
friction for users who simply want to write or read these instructions,
while providing no real safety benefit since the encodings are always
valid.

Note: Ideally, the ISA specification would explicitly guarantee that
these MOP/HINT encodings will never be reassigned to conflicting
instructions. However, the ISA architects prefer to preserve flexibility
in this area rather than making such guarantees in the spec. Given the
practical reality that reassignment is highly unlikely, the toolchain
takes the pragmatic approach of always recognizing these mnemonics.

This change makes the following mnemonics always available:
- lpad (Zicfilp): AUIPC hint encoding, always valid
- pause (Zihintpause): FENCE hint encoding, always valid
- ntl.* (Zihintntl): ADD hint encoding, always valid
- c.ntl.* (Zihintntl+C): requires C extension only
- sspush/sspopchk/ssrdp (Zicfiss): requires Zimop only (MOP encoding)
- c.sspush/c.sspopchk (Zicfiss+Zcmop): requires Zcmop only

Note: ssamoswap.w/d still requires Zicfiss as they use AMO encoding
space rather than MOP encoding.

Codegen patterns remain unchanged in this patch - generating these
instructions in the compiler backend still requires the full extension
to be enabled. A follow-up patch will relax this restriction as well,
since these instructions are fundamentally MOP/HINT encodings that
should be safe to generate regardless of extension availability.

Link: riscv-non-isa/riscv-elf-psabi-doc#474
@kito-cheng kito-cheng deleted the kitoc/mop-hint branch February 4, 2026 01:50
rishabhmadan19 pushed a commit to rishabhmadan19/llvm-project that referenced this pull request Feb 9, 2026
…lvm#178609)

Per the psABI discussion in riscv-non-isa/riscv-elf-psabi-doc#474, the
conclusion was to NOT introduce a new build attribute for MOP/HINT
encoding reinterpretation. Instead, the toolchain should recognize these
mnemonics unconditionally in the assembler and disassembler.

The rationale is that these encodings occupy reserved hint/MOP space
that is architecturally guaranteed not to trap on any compliant
implementation. Requiring explicit extension flags creates unnecessary
friction for users who simply want to write or read these instructions,
while providing no real safety benefit since the encodings are always
valid.

Note: Ideally, the ISA specification would explicitly guarantee that
these MOP/HINT encodings will never be reassigned to conflicting
instructions. However, the ISA architects prefer to preserve flexibility
in this area rather than making such guarantees in the spec. Given the
practical reality that reassignment is highly unlikely, the toolchain
takes the pragmatic approach of always recognizing these mnemonics.

This change makes the following mnemonics always available:
- lpad (Zicfilp): AUIPC hint encoding, always valid
- pause (Zihintpause): FENCE hint encoding, always valid
- ntl.* (Zihintntl): ADD hint encoding, always valid
- c.ntl.* (Zihintntl+C): requires C extension only
- sspush/sspopchk/ssrdp (Zicfiss): requires Zimop only (MOP encoding)
- c.sspush/c.sspopchk (Zicfiss+Zcmop): requires Zcmop only

Note: ssamoswap.w/d still requires Zicfiss as they use AMO encoding
space rather than MOP encoding.

Codegen patterns remain unchanged in this patch - generating these
instructions in the compiler backend still requires the full extension
to be enabled. A follow-up patch will relax this restriction as well,
since these instructions are fundamentally MOP/HINT encodings that
should be safe to generate regardless of extension availability.

Link: riscv-non-isa/riscv-elf-psabi-doc#474
kito-cheng added a commit that referenced this pull request Mar 2, 2026
Following the assembler/disassembler changes in #178609, this patch also
relaxes the codegen predicates for HINT-based instructions. Since these
instructions use encodings that are architecturally guaranteed not to
trap, the compiler can safely generate them regardless of extension
availability.

Changes:
- int_riscv_pause: Remove HasStdExtZihintpause predicate. The pause
intrinsic now generates the FENCE hint encoding unconditionally.
- NTL hints: Remove hasStdExtZihintntl() check in emitNTLHint().
Non-temporal locality hints are now emitted for all nontemporal memory
operations.
sahas3 pushed a commit to sahas3/llvm-project that referenced this pull request Mar 4, 2026
…9872)

Following the assembler/disassembler changes in llvm#178609, this patch also
relaxes the codegen predicates for HINT-based instructions. Since these
instructions use encodings that are architecturally guaranteed not to
trap, the compiler can safely generate them regardless of extension
availability.

Changes:
- int_riscv_pause: Remove HasStdExtZihintpause predicate. The pause
intrinsic now generates the FENCE hint encoding unconditionally.
- NTL hints: Remove hasStdExtZihintntl() check in emitNTLHint().
Non-temporal locality hints are now emitted for all nontemporal memory
operations.
sujianIBM pushed a commit to sujianIBM/llvm-project that referenced this pull request Mar 5, 2026
…9872)

Following the assembler/disassembler changes in llvm#178609, this patch also
relaxes the codegen predicates for HINT-based instructions. Since these
instructions use encodings that are architecturally guaranteed not to
trap, the compiler can safely generate them regardless of extension
availability.

Changes:
- int_riscv_pause: Remove HasStdExtZihintpause predicate. The pause
intrinsic now generates the FENCE hint encoding unconditionally.
- NTL hints: Remove hasStdExtZihintntl() check in emitNTLHint().
Non-temporal locality hints are now emitted for all nontemporal memory
operations.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants