[llvm] [RISCV] Reject XTHeadMemIdx load-update with rd == rs1 (PR #225271)
Zeyi Xu via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 21 22:46:38 PDT 2026
https://github.com/zeyi2 updated https://github.com/llvm/llvm-project/pull/225271
>From 9c074652ccee9ebbea11905cc2cecaa47eb92f59 Mon Sep 17 00:00:00 2001
From: Zeyi Xu <mitchell.xu2 at gmail.com>
Date: Tue, 22 Sep 2026 11:04:50 +0800
Subject: [PATCH 1/3] [RISCV] Reject XTHeadMemIdx load-update with rd == rs1
---
.../Target/RISCV/AsmParser/RISCVAsmParser.cpp | 30 +++++++++++++++++--
llvm/test/MC/RISCV/rv64xtheadmemidx-invalid.s | 25 ++++++++++++++--
2 files changed, 50 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index f9c1b8275108f..2c7be2f7b809c 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -4245,16 +4245,40 @@ bool RISCVAsmParser::validateInstruction(MCInst &Inst,
}
}
- if (Opcode == RISCV::TH_LDD || Opcode == RISCV::TH_LWUD ||
- Opcode == RISCV::TH_LWD) {
+ switch (Opcode) {
+ default:
+ break;
+ case RISCV::TH_LBIA:
+ case RISCV::TH_LBIB:
+ case RISCV::TH_LBUIA:
+ case RISCV::TH_LBUIB:
+ case RISCV::TH_LHIA:
+ case RISCV::TH_LHIB:
+ case RISCV::TH_LHUIA:
+ case RISCV::TH_LHUIB:
+ case RISCV::TH_LWIA:
+ case RISCV::TH_LWIB:
+ case RISCV::TH_LWUIA:
+ case RISCV::TH_LWUIB:
+ case RISCV::TH_LDIA:
+ case RISCV::TH_LDIB:
+ if (Inst.getOperand(0).getReg() == Inst.getOperand(2).getReg())
+ return Error(Operands[1]->getStartLoc(), "rd and rs1 must be different");
+ break;
+ case RISCV::TH_LDD:
+ case RISCV::TH_LWUD:
+ case RISCV::TH_LWD: {
MCRegister Rd1 = Inst.getOperand(0).getReg();
MCRegister Rd2 = Inst.getOperand(1).getReg();
MCRegister Rs1 = Inst.getOperand(2).getReg();
- // The encoding with rd1 == rd2 == rs1 is reserved for XTHead load pair.
+ // The encoding with overlapping rs1, rd1, and rd2 is reserved for XTHead
+ // load pair.
if (Rs1 == Rd1 || Rs1 == Rd2 || Rd1 == Rd2) {
SMLoc Loc = Operands[1]->getStartLoc();
return Error(Loc, "rs1, rd1, and rd2 cannot overlap");
}
+ break;
+ }
}
if (Opcode == RISCV::CM_MVSA01 || Opcode == RISCV::QC_CM_MVSA01) {
diff --git a/llvm/test/MC/RISCV/rv64xtheadmemidx-invalid.s b/llvm/test/MC/RISCV/rv64xtheadmemidx-invalid.s
index 0b3d8a7040e78..e9792c0336634 100644
--- a/llvm/test/MC/RISCV/rv64xtheadmemidx-invalid.s
+++ b/llvm/test/MC/RISCV/rv64xtheadmemidx-invalid.s
@@ -1,5 +1,5 @@
-# RUN: not llvm-mc -triple riscv32 -mattr=+xtheadmemidx < %s 2>&1 | FileCheck %s
-# RUN: not llvm-mc -triple riscv64 -mattr=+xtheadmemidx < %s 2>&1 | FileCheck %s
+# RUN: not llvm-mc -triple riscv32 -mattr=+xtheadmemidx < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,RV32
+# RUN: not llvm-mc -triple riscv64 -mattr=+xtheadmemidx < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,RV64
th.ldia 0(a0), (a1), 0, 0 # CHECK: :[[@LINE]]:10: error: register must be a GPR
th.ldib a0, 2(a1), 15, 1 # CHECK: :[[@LINE]]:14: error: expected '('
@@ -11,3 +11,24 @@ th.lrw a0, 3(a1), a2, 1 # CHECK: :[[@LINE]]:13: error: register must be a GPR
th.lrw a0, a1, 4(a2), 2 # CHECK: :[[@LINE]]:17: error: register must be a GPR
th.lrh a0, a1, a2, 5 # CHECK: :[[@LINE]]:21: error: immediate must be an integer in the range [0, 3]
th.lrhu a0, a1, a2, -1 # CHECK: :[[@LINE]]:22: error: immediate must be an integer in the range [0, 3]
+
+th.lbia a0, (a0), 0, 0 # CHECK: :[[@LINE]]:10: error: rd and rs1 must be different
+th.lbib a0, (a0), 0, 0 # CHECK: :[[@LINE]]:10: error: rd and rs1 must be different
+th.lbuia a0, (a0), 0, 0 # CHECK: :[[@LINE]]:10: error: rd and rs1 must be different
+th.lbuib a0, (a0), 0, 0 # CHECK: :[[@LINE]]:10: error: rd and rs1 must be different
+th.lhia a0, (a0), 0, 0 # CHECK: :[[@LINE]]:10: error: rd and rs1 must be different
+th.lhib a0, (a0), 0, 0 # CHECK: :[[@LINE]]:10: error: rd and rs1 must be different
+th.lhuia a0, (a0), 0, 0 # CHECK: :[[@LINE]]:10: error: rd and rs1 must be different
+th.lhuib a0, (a0), 0, 0 # CHECK: :[[@LINE]]:10: error: rd and rs1 must be different
+th.lwia a0, (a0), 0, 0 # CHECK: :[[@LINE]]:10: error: rd and rs1 must be different
+th.lwib a0, (a0), 0, 0 # CHECK: :[[@LINE]]:10: error: rd and rs1 must be different
+th.lwuia a0, (a0), 0, 0 # RV32: :[[@LINE]]:1: error: instruction requires the following: RV64I Base Instruction Set{{$}}
+ # RV64: :[[@LINE-1]]:10: error: rd and rs1 must be different
+th.lwuib a0, (a0), 0, 0 # RV32: :[[@LINE]]:1: error: instruction requires the following: RV64I Base Instruction Set{{$}}
+ # RV64: :[[@LINE-1]]:10: error: rd and rs1 must be different
+th.ldia a0, (a0), 0, 0 # RV32: :[[@LINE]]:1: error: instruction requires the following: RV64I Base Instruction Set{{$}}
+ # RV64: :[[@LINE-1]]:10: error: rd and rs1 must be different
+th.ldib a0, (a0), 0, 0 # RV32: :[[@LINE]]:1: error: instruction requires the following: RV64I Base Instruction Set{{$}}
+ # RV64: :[[@LINE-1]]:10: error: rd and rs1 must be different
+th.lbia a0, (x10), 1, 0 # CHECK: :[[@LINE]]:10: error: rd and rs1 must be different
+th.lbia zero, (zero), 0, 0 # CHECK: :[[@LINE]]:10: error: rd and rs1 must be different
>From 383aa6e62dcf38b30d18268e8200ff3bf08a0cb5 Mon Sep 17 00:00:00 2001
From: Zeyi Xu <mitchell.xu2 at gmail.com>
Date: Tue, 22 Sep 2026 13:34:34 +0800
Subject: [PATCH 2/3] address feedback
---
.../RISCV/Disassembler/RISCVDisassembler.cpp | 29 +++++++
llvm/lib/Target/RISCV/RISCVInstrInfoXTHead.td | 12 ++-
.../RISCV/xthead-invalid-overlap.txt | 78 +++++++++++++++++++
3 files changed, 117 insertions(+), 2 deletions(-)
create mode 100644 llvm/test/MC/Disassembler/RISCV/xthead-invalid-overlap.txt
diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
index df0eeca12ddeb..b222fed6906bb 100644
--- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
+++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
@@ -155,6 +155,35 @@ constexpr auto DecodeGPRNoX31RegisterClass =
constexpr auto DecodeGPRX1X5RegisterClass =
DecodeFilteredRegisterClass<DecodeGPRRegisterClass, PredX1OrX5>;
+static DecodeStatus decodeTHMemIdxRs1Operand(MCInst &Inst, uint32_t RegNo,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ const DecodeStatus Result =
+ DecodeGPRRegisterClass(Inst, RegNo, Address, Decoder);
+ if (Result != MCDisassembler::Success)
+ return Result;
+ const MCRegister Rd = Inst.getOperand(0).getReg();
+ const MCRegister Rs1 = Inst.getOperand(Inst.getNumOperands() - 1).getReg();
+ if (Rd == Rs1)
+ return MCDisassembler::Fail;
+ return Result;
+}
+
+static DecodeStatus decodeTHMemPairRs1Operand(MCInst &Inst, uint32_t RegNo,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ const DecodeStatus Result =
+ DecodeGPRRegisterClass(Inst, RegNo, Address, Decoder);
+ if (Result != MCDisassembler::Success)
+ return Result;
+ const MCRegister Rd1 = Inst.getOperand(0).getReg();
+ const MCRegister Rd2 = Inst.getOperand(1).getReg();
+ const MCRegister Rs1 = Inst.getOperand(Inst.getNumOperands() - 1).getReg();
+ if (Rs1 == Rd1 || Rs1 == Rd2 || Rd1 == Rd2)
+ return MCDisassembler::Fail;
+ return Result;
+}
+
static DecodeStatus DecodeGPRPairRegisterClass(MCInst &Inst, uint32_t RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXTHead.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXTHead.td
index bc8fc8915b649..0433a56b032d7 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXTHead.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXTHead.td
@@ -62,6 +62,14 @@ def immfour : RISCVOp {
def tuimm2 : TImmLeaf<XLenVT, [{return isUInt<2>(Imm);}]>;
+def th_memidx_rs1 : RegisterOperand<GPR> {
+ let DecoderMethod = "decodeTHMemIdxRs1Operand";
+}
+
+def th_mempair_rs1 : RegisterOperand<GPR> {
+ let DecoderMethod = "decodeTHMemPairRs1Operand";
+}
+
//===----------------------------------------------------------------------===//
// Instruction class templates
//===----------------------------------------------------------------------===//
@@ -162,7 +170,7 @@ let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in
class THLoadPair<bits<5> funct5, string opcodestr, Operand consttype>
: RVInstRBase<0b100, OPC_CUSTOM_0,
(outs GPR:$rd, GPR:$rs2),
- (ins GPR:$rs1, uimm2:$uimm2, consttype:$const3or4),
+ (ins th_mempair_rs1:$rs1, uimm2:$uimm2, consttype:$const3or4),
opcodestr, "$rd, $rs2, (${rs1}), $uimm2, $const3or4"> {
bits<2> uimm2;
bits<0> const3or4;
@@ -217,7 +225,7 @@ class THLoadIndexed<RegisterClass Ty, bits<5> funct5, string opcodestr>
class THLoadUpdate<bits<5> funct5, string opcodestr>
: RVInstIBase<0b100, OPC_CUSTOM_0, (outs GPR:$rd, GPR:$rs1_wb),
- (ins GPR:$rs1, simm5:$simm5, uimm2:$uimm2),
+ (ins th_memidx_rs1:$rs1, simm5:$simm5, uimm2:$uimm2),
opcodestr, "$rd, (${rs1}), $simm5, $uimm2"> {
bits<5> simm5;
bits<2> uimm2;
diff --git a/llvm/test/MC/Disassembler/RISCV/xthead-invalid-overlap.txt b/llvm/test/MC/Disassembler/RISCV/xthead-invalid-overlap.txt
new file mode 100644
index 0000000000000..1ca353647117f
--- /dev/null
+++ b/llvm/test/MC/Disassembler/RISCV/xthead-invalid-overlap.txt
@@ -0,0 +1,78 @@
+# RUN: not llvm-mc -disassemble -triple=riscv32 -mattr=+xtheadmemidx,+xtheadmempair %s 2>&1 | FileCheck %s --check-prefixes=CHECK,RV32
+# RUN: not llvm-mc -disassemble -triple=riscv64 -mattr=+xtheadmemidx,+xtheadmempair %s 2>&1 | FileCheck %s --check-prefixes=CHECK,RV64
+
+[0x0b,0x45,0x05,0x1c]
+# CHECK: warning: invalid instruction encoding
+# CHECK-NOT: th.lbia a0, (a0), 0, 2
+
+[0x0b,0x45,0x05,0x0f]
+# CHECK: warning: invalid instruction encoding
+# CHECK-NOT: th.lbib a0, (a0), -16, 3
+
+[0x0b,0x45,0x05,0x98]
+# CHECK: warning: invalid instruction encoding
+# CHECK-NOT: th.lbuia a0, (a0), 0, 0
+
+[0x0b,0x45,0xf5,0x8a]
+# CHECK: warning: invalid instruction encoding
+# CHECK-NOT: th.lbuib a0, (a0), 15, 1
+
+[0x0b,0x45,0x05,0x3c]
+# CHECK: warning: invalid instruction encoding
+# CHECK-NOT: th.lhia a0, (a0), 0, 2
+
+[0x0b,0x45,0x05,0x2f]
+# CHECK: warning: invalid instruction encoding
+# CHECK-NOT: th.lhib a0, (a0), -16, 3
+
+[0x0b,0x45,0x05,0xb8]
+# CHECK: warning: invalid instruction encoding
+# CHECK-NOT: th.lhuia a0, (a0), 0, 0
+
+[0x0b,0x45,0xf5,0xaa]
+# CHECK: warning: invalid instruction encoding
+# CHECK-NOT: th.lhuib a0, (a0), 15, 1
+
+[0x0b,0x45,0x05,0x5c]
+# CHECK: warning: invalid instruction encoding
+# CHECK-NOT: th.lwia a0, (a0), 0, 2
+
+[0x0b,0x45,0x05,0x4f]
+# CHECK: warning: invalid instruction encoding
+# CHECK-NOT: th.lwib a0, (a0), -16, 3
+
+[0x0b,0x45,0x05,0xd8]
+# CHECK: warning: invalid instruction encoding
+# CHECK-NOT: th.lwuia a0, (a0), 0, 0
+
+[0x0b,0x45,0xf5,0xca]
+# CHECK: warning: invalid instruction encoding
+# CHECK-NOT: th.lwuib a0, (a0), 15, 1
+
+[0x0b,0x45,0x05,0x78]
+# CHECK: warning: invalid instruction encoding
+# CHECK-NOT: th.ldia a0, (a0), 0, 0
+
+[0x0b,0x45,0xf5,0x6a]
+# CHECK: warning: invalid instruction encoding
+# CHECK-NOT: th.ldib a0, (a0), 15, 1
+
+[0x0b,0x45,0xb5,0xe2]
+# CHECK: warning: invalid instruction encoding
+# CHECK-NOT: th.lwd a0, a1, (a0), 1, 3
+
+[0x0b,0xc5,0xb5,0xf4]
+# CHECK: warning: invalid instruction encoding
+# CHECK-NOT: th.lwud a0, a1, (a1), 2, 3
+
+[0x0b,0x45,0xa6,0xf8]
+# CHECK: warning: invalid instruction encoding
+# CHECK-NOT: th.ldd a0, a0, (a2), 0, 4
+
+[0x0b,0xc5,0x05,0x1c]
+# RV32: th.lbia a0, (a1), 0, 2
+# RV64: th.lbia a0, (a1), 0, 2
+
+[0x0b,0x45,0xb6,0xe2]
+# RV32: th.lwd a0, a1, (a2), 1, 3
+# RV64: th.lwd a0, a1, (a2), 1, 3
>From 6702cf83ec10acc26cd1988cc78fe413d38cda6b Mon Sep 17 00:00:00 2001
From: Zeyi Xu <mitchell.xu2 at gmail.com>
Date: Tue, 22 Sep 2026 13:46:11 +0800
Subject: [PATCH 3/3] better formatting
---
llvm/test/MC/Disassembler/RISCV/xthead-invalid-overlap.txt | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/llvm/test/MC/Disassembler/RISCV/xthead-invalid-overlap.txt b/llvm/test/MC/Disassembler/RISCV/xthead-invalid-overlap.txt
index 1ca353647117f..23d4b90807d91 100644
--- a/llvm/test/MC/Disassembler/RISCV/xthead-invalid-overlap.txt
+++ b/llvm/test/MC/Disassembler/RISCV/xthead-invalid-overlap.txt
@@ -1,5 +1,7 @@
-# RUN: not llvm-mc -disassemble -triple=riscv32 -mattr=+xtheadmemidx,+xtheadmempair %s 2>&1 | FileCheck %s --check-prefixes=CHECK,RV32
-# RUN: not llvm-mc -disassemble -triple=riscv64 -mattr=+xtheadmemidx,+xtheadmempair %s 2>&1 | FileCheck %s --check-prefixes=CHECK,RV64
+# RUN: not llvm-mc -disassemble -triple=riscv32 -mattr=+xtheadmemidx,+xtheadmempair %s 2>&1 \
+# RUN: | FileCheck %s --check-prefixes=CHECK,RV32
+# RUN: not llvm-mc -disassemble -triple=riscv64 -mattr=+xtheadmemidx,+xtheadmempair %s 2>&1 \
+# RUN: | FileCheck %s --check-prefixes=CHECK,RV64
[0x0b,0x45,0x05,0x1c]
# CHECK: warning: invalid instruction encoding
More information about the llvm-commits
mailing list