[lldb] [llvm] [AArch64][llvm] Tighten SYSP parsing; don't disassemble invalid encodings (PR #182410)
Jonathan Thackray via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 1 14:51:36 PDT 2026
https://github.com/jthackray updated https://github.com/llvm/llvm-project/pull/182410
>From 6fcd1671590c6589f79cc652ba923fb450f01f36 Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Thu, 19 Feb 2026 23:54:20 +0000
Subject: [PATCH 01/17] [AArch64][llvm] Tighten SYSP; don't disassemble invalid
encodings
Tighten SYSP aliases, so that invalid encodings are disassembled
to `<unknown>`. This is because:
```
Cn is a 4-bit unsigned immediate, in the range 8 to 9
Cm is a 4-bit unsigned immediate, in the range 0 to 7
op1 is a 3-bit unsigned immediate, in the range 0 to 6
op2 is a 3-bit unsigned immediate, in the range 0 to 7
```
Ensure we check this when disassembling, and also constrain
tablegen for compile-time errors of invalid encodings.
Also adjust the testcases in `armv9-sysp-diagnostics.s` and
`llvm/test/MC/AArch64/armv9a-sysp.s` as they were invalid,
and added a few invalid (outside of range) SYSP-alikes to
test that `<unknown>` is printed
---
.../command-disassemble-aarch64-color.s | 4 +-
.../command-disassemble-aarch64-extensions.s | 4 +-
.../lib/Target/AArch64/AArch64InstrFormats.td | 26 +-
llvm/lib/Target/AArch64/AArch64InstrInfo.td | 10 +-
.../Disassembler/AArch64Disassembler.cpp | 25 ++
.../MCTargetDesc/AArch64InstPrinter.cpp | 8 +
llvm/test/MC/AArch64/armv9-sysp-diagnostics.s | 15 +-
llvm/test/MC/AArch64/armv9-sysp-invalid.s | 20 ++
llvm/test/MC/AArch64/armv9a-sysp.s | 222 +++++++++---------
9 files changed, 207 insertions(+), 127 deletions(-)
create mode 100644 llvm/test/MC/AArch64/armv9-sysp-invalid.s
diff --git a/lldb/test/Shell/Commands/command-disassemble-aarch64-color.s b/lldb/test/Shell/Commands/command-disassemble-aarch64-color.s
index bb97680a32970..6ddde3d974adc 100644
--- a/lldb/test/Shell/Commands/command-disassemble-aarch64-color.s
+++ b/lldb/test/Shell/Commands/command-disassemble-aarch64-color.s
@@ -17,7 +17,7 @@ fn:
crc32b w0, w0, w0 // AEK_CRC
// AEK_CRYPTO enables a combination of other features
smin x0, x0, #0 // AEK_CSSC
- sysp #0, c2, c0, #0, x0, x1 // AEK_D128
+ sysp #0, c8, c0, #0, x0, x1 // AEK_D128
sdot v0.2s, v1.8b, v2.8b // AEK_DOTPROD
fmmla z0.s, z1.s, z2.s // AEK_F32MM
@@ -28,6 +28,6 @@ fn:
# CHECK-NEXT: [0xc] <+12>: brb iall
# CHECK-NEXT: [0x10] <+16>: crc32b [0;36mw0[0m, [0;36mw0[0m, [0;36mw0[0m
# CHECK-NEXT: [0x14] <+20>: smin [0;36mx0[0m, [0;36mx0[0m, [0;31m#0x0[0m
-# CHECK-NEXT: [0x18] <+24>: sysp [0;31m#0x0[0m, c2, c0, [0;31m#0x0[0m, [0;36mx0[0m, [0;36mx1[0m
+# CHECK-NEXT: [0x18] <+24>: sysp [0;31m#0x0[0m, c8, c0, [0;31m#0x0[0m, [0;36mx0[0m, [0;36mx1[0m
# CHECK-NEXT: [0x1c] <+28>: sdot [0;36mv0[0m.2s, [0;36mv1[0m.8b, [0;36mv2[0m.8b
# CHECK-NEXT: [0x20] <+32>: fmmla [0;36mz0[0m.s, [0;36mz1[0m.s, [0;36mz2[0m.s
diff --git a/lldb/test/Shell/Commands/command-disassemble-aarch64-extensions.s b/lldb/test/Shell/Commands/command-disassemble-aarch64-extensions.s
index 4e281332a33bb..945654e905876 100644
--- a/lldb/test/Shell/Commands/command-disassemble-aarch64-extensions.s
+++ b/lldb/test/Shell/Commands/command-disassemble-aarch64-extensions.s
@@ -17,7 +17,7 @@ fn:
crc32b w0, w0, w0 // AEK_CRC
// AEK_CRYPTO enables a combination of other features
smin x0, x0, #0 // AEK_CSSC
- sysp #0, c2, c0, #0, x0, x1 // AEK_D128
+ sysp #0, c8, c0, #0, x0, x1 // AEK_D128
sdot v0.2s, v1.8b, v2.8b // AEK_DOTPROD
fmmla z0.s, z1.s, z2.s // AEK_F32MM
fmmla z0.d, z1.d, z2.d // AEK_F64MM
@@ -72,7 +72,7 @@ lbl:
# CHECK-NEXT: brb iall
# CHECK-NEXT: crc32b w0, w0, w0
# CHECK-NEXT: smin x0, x0, #0
-# CHECK-NEXT: sysp #0x0, c2, c0, #0x0, x0, x1
+# CHECK-NEXT: sysp #0x0, c8, c0, #0x0, x0, x1
# CHECK-NEXT: sdot v0.2s, v1.8b, v2.8b
# CHECK-NEXT: fmmla z0.s, z1.s, z2.s
# CHECK-NEXT: fmmla z0.d, z1.d, z2.d
diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index daf53c99988b0..82cdc1bd7795b 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -2127,6 +2127,29 @@ def sys_cr_op : Operand<i32>, TImmLeaf<i32, [{
let OperandType = "OPERAND_IMMEDIATE";
}
+def sysp_crn_op : Operand<i32>, ImmLeaf<i32, [{
+ return Imm == 8 || Imm == 9;
+}]> {
+ let PrintMethod = "printSysCROperand";
+ let ParserMatchClass = SysCRAsmOperand;
+ let OperandType = "OPERAND_IMMEDIATE";
+}
+
+def sysp_crm_op : Operand<i32>, ImmLeaf<i32, [{
+ return Imm >= 0 && Imm <= 7;
+}]> {
+ let PrintMethod = "printSysCROperand";
+ let ParserMatchClass = SysCRAsmOperand;
+ let OperandType = "OPERAND_IMMEDIATE";
+}
+
+def sysp_op1 : Operand<i64>, ImmLeaf<i64, [{
+ return Imm >= 0 && Imm <= 6;
+}]> {
+ let ParserMatchClass = Imm0_7Operand;
+ let OperandType = "OPERAND_IMMEDIATE";
+}
+
class SystemXtI<string asm>
: RtSystemI<0, (outs),
(ins imm32_0_7:$op1, sys_cr_op:$Cn, sys_cr_op:$Cm, imm32_0_7:$op2,
@@ -13329,7 +13352,8 @@ class BaseSYSPEncoding<bit L, string asm, string operands, dag outputs, dag inpu
}
class SystemPXtI<bit L, string asm> :
BaseSYSPEncoding<L, asm, "\t$op1, $Cn, $Cm, $op2, $Rt", (outs),
- (ins imm0_7:$op1, sys_cr_op:$Cn, sys_cr_op:$Cm, imm0_7:$op2, XSeqPairClassOperand:$Rt)>;
+ (ins sysp_op1:$op1, sysp_crn_op:$Cn, sysp_crm_op:$Cm, imm0_7:$op2,
+ XSeqPairClassOperand:$Rt)>;
//----------------------------------------------------------------------------
// 2023 Armv9.5 Extensions
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index a898d1e228053..627c3b9627d47 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -11609,11 +11609,14 @@ let Predicates = [HasRCPC3, HasNEON] in {
//===----------------------------------------------------------------------===//
// 128-bit System Instructions (FEAT_SYSINSTR128)
//===----------------------------------------------------------------------===//
-def SYSPxt : SystemPXtI<0, "sysp">;
+def SYSPxt : SystemPXtI<0, "sysp"> {
+ let DecoderMethod = "DecodeSyspInstruction";
+}
def SYSPxt_XZR
: BaseSystemI<0, (outs),
- (ins imm0_7:$op1, sys_cr_op:$Cn, sys_cr_op:$Cm, imm0_7:$op2, SyspXzrPairOperand:$xzr_pair),
+ (ins sysp_op1:$op1, sysp_crn_op:$Cn, sysp_crm_op:$Cm, imm0_7:$op2,
+ SyspXzrPairOperand:$xzr_pair),
"sysp", "\t$op1, $Cn, $Cm, $op2, $xzr_pair">,
Sched<[WriteSys]>
{
@@ -11639,7 +11642,8 @@ def SYSPxt_XZR
}
def : InstAlias<"sysp $op1, $Cn, $Cm, $op2",
- (SYSPxt_XZR imm0_7:$op1, sys_cr_op:$Cn, sys_cr_op:$Cm, imm0_7:$op2, XZR)>;
+ (SYSPxt_XZR sysp_op1:$op1, sysp_crn_op:$Cn, sysp_crm_op:$Cm,
+ imm0_7:$op2, XZR)>;
//---
// 128-bit System Registers (FEAT_SYSREG128)
diff --git a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
index 15f40e2fa9f1b..c80eaad88e434 100644
--- a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
+++ b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
@@ -1395,6 +1395,10 @@ static DecodeStatus DecodeSyspXzrInstruction(MCInst &Inst, uint32_t insn,
unsigned CRm = fieldFromInstruction(insn, 8, 4);
unsigned op2 = fieldFromInstruction(insn, 5, 3);
unsigned Rt = fieldFromInstruction(insn, 0, 5);
+
+ if (op1 > 6 || (CRn != 8 && CRn != 9) || CRm > 7 || op2 > 7)
+ return Fail;
+
if (Rt != 0b11111)
return Fail;
@@ -1408,6 +1412,27 @@ static DecodeStatus DecodeSyspXzrInstruction(MCInst &Inst, uint32_t insn,
return Success;
}
+static DecodeStatus DecodeSyspInstruction(MCInst &Inst, uint32_t insn,
+ uint64_t Addr,
+ const MCDisassembler *Decoder) {
+ unsigned op1 = fieldFromInstruction(insn, 16, 3);
+ unsigned CRn = fieldFromInstruction(insn, 12, 4);
+ unsigned CRm = fieldFromInstruction(insn, 8, 4);
+ unsigned op2 = fieldFromInstruction(insn, 5, 3);
+ unsigned Rt = fieldFromInstruction(insn, 0, 5);
+
+ if (op1 > 6 || (CRn != 8 && CRn != 9) || CRm > 7 || op2 > 7)
+ return Fail;
+
+ Inst.addOperand(MCOperand::createImm(op1));
+ Inst.addOperand(MCOperand::createImm(CRn));
+ Inst.addOperand(MCOperand::createImm(CRm));
+ Inst.addOperand(MCOperand::createImm(op2));
+ DecodeXSeqPairsClassRegisterClass(Inst, Rt, Addr, Decoder);
+
+ return Success;
+}
+
static DecodeStatus
DecodeSVELogicalImmInstruction(MCInst &Inst, uint32_t insn, uint64_t Addr,
const MCDisassembler *Decoder) {
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
index 2783b559c8f5c..f6e483f900de7 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
@@ -1142,6 +1142,14 @@ bool AArch64InstPrinter::printSyspAlias(const MCInst *MI,
unsigned CmVal = Cm.getImm();
unsigned Op2Val = Op2.getImm();
+ // Early checks for invalid SYSP aliases
+ // Op1 == 0..6
+ // Op2 == 0..7
+ // Cm == 0..7
+ // Cn == 8 or 9
+ if (Op1Val > 6 || Op2Val > 7 || CmVal > 7 || (CnVal != 8 && CnVal != 9))
+ return false;
+
uint16_t Encoding = Op2Val;
Encoding |= CmVal << 3;
Encoding |= CnVal << 7;
diff --git a/llvm/test/MC/AArch64/armv9-sysp-diagnostics.s b/llvm/test/MC/AArch64/armv9-sysp-diagnostics.s
index 8b466c10b0aa7..51bb307912fef 100644
--- a/llvm/test/MC/AArch64/armv9-sysp-diagnostics.s
+++ b/llvm/test/MC/AArch64/armv9-sysp-diagnostics.s
@@ -7,22 +7,21 @@
// registers with 128-bit formats (op0, op1, Cn, Cm, op2)
// For sysp, op0 is 0
-sysp #0, c2, c0, #0, x0, x2
+sysp #0, c8, c0, #0, x0, x2
// ERRORS: error: expected second odd register of a consecutive same-size even/odd register pair
-sysp #0, c2, c0, #0, x0
+sysp #0, c8, c0, #0, x0
// ERRORS: error: expected comma
-sysp #0, c2, c0, #0, x1, x2
+sysp #0, c8, c0, #0, x1, x2
// ERRORS: error: expected first even register of a consecutive same-size even/odd register pair
-sysp #0, c2, c0, #0, x31, x0
+sysp #0, c8, c0, #0, x31, x0
// ERRORS: error: xzr must be followed by xzr
-sysp #0, c2, c0, #0, xzr, x30
+sysp #0, c8, c0, #0, xzr, x30
// ERRORS: error: xzr must be followed by xzr
-sysp #0, c2, c0, #0, xzr
+sysp #0, c8, c0, #0, xzr
// ERRORS: error: expected comma
-sysp #0, c2, c0, #0, xzr,
+sysp #0, c8, c0, #0, xzr,
// ERRORS: error: expected register operand
-
tlbip RVAE3IS
// ERRORS: error: expected comma
tlbip RVAE3IS,
diff --git a/llvm/test/MC/AArch64/armv9-sysp-invalid.s b/llvm/test/MC/AArch64/armv9-sysp-invalid.s
new file mode 100644
index 0000000000000..248d5ccc5056a
--- /dev/null
+++ b/llvm/test/MC/AArch64/armv9-sysp-invalid.s
@@ -0,0 +1,20 @@
+// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+d128 < %s \
+// RUN: | llvm-objdump -d --mattr=+d128 --no-print-imm-hex - \
+// RUN: | FileCheck %s --check-prefix=DISASM
+
+// Ensure invalid SYSP encodings are not printed as TLBIP aliases.
+
+// op1 = 7 (outside architecturally valid SYSP range for op1)
+// Cn = 8, Cm = 0, op2 = 0, Rt = 0 (x0, x1)
+.inst 0xd54f8000
+
+// Cn = 0 (outside architecturally valid SYSP range for Cn)
+.inst 0xd5480000
+
+// Cm = 8 (outside architecturally valid SYSP range for Cm)
+.inst 0xd5488800
+
+// DISASM-NOT: tlbip
+// DISASM: <unknown>
+// DISASM: <unknown>
+// DISASM: <unknown>
diff --git a/llvm/test/MC/AArch64/armv9a-sysp.s b/llvm/test/MC/AArch64/armv9a-sysp.s
index f1e039f3e8770..349f75eb95424 100644
--- a/llvm/test/MC/AArch64/armv9a-sysp.s
+++ b/llvm/test/MC/AArch64/armv9a-sysp.s
@@ -13,150 +13,150 @@
// registers with 128-bit formats (op0, op1, Cn, Cm, op2)
// For sysp, op0 is 0
-sysp #0, c2, c0, #0, x0, x1// TTBR0_EL1 3 0 2 0 0
-// CHECK-INST: sysp #0, c2, c0, #0, x0, x1
-// CHECK-ENCODING: encoding: [0x00,0x20,0x48,0xd5]
+sysp #0, c8, c0, #0, x0, x1
+// CHECK-INST: sysp #0, c8, c0, #0, x0, x1
+// CHECK-ENCODING: encoding: [0x00,0x80,0x48,0xd5]
-sysp #0, c2, c0, #1, x0, x1// TTBR1_EL1 3 0 2 0 1
-// CHECK-INST: sysp #0, c2, c0, #1, x0, x1
-// CHECK-ENCODING: encoding: [0x20,0x20,0x48,0xd5]
+sysp #0, c8, c0, #1, x0, x1
+// CHECK-INST: sysp #0, c8, c0, #1, x0, x1
+// CHECK-ENCODING: encoding: [0x20,0x80,0x48,0xd5]
-sysp #0, c7, c4, #0, x0, x1// PAR_EL1 3 0 7 4 0
-// CHECK-INST: sysp #0, c7, c4, #0, x0, x1
-// CHECK-ENCODING: encoding: [0x00,0x74,0x48,0xd5]
+sysp #0, c8, c4, #0, x0, x1
+// CHECK-INST: sysp #0, c8, c4, #0, x0, x1
+// CHECK-ENCODING: encoding: [0x00,0x84,0x48,0xd5]
-sysp #0, c13, c0, #3, x0, x1 // RCWSMASK_EL1 3 0 13 0 3
-// CHECK-INST: sysp #0, c13, c0, #3, x0, x1
-// CHECK-ENCODING: encoding: [0x60,0xd0,0x48,0xd5]
+sysp #0, c8, c0, #3, x0, x1
+// CHECK-INST: sysp #0, c8, c0, #3, x0, x1
+// CHECK-ENCODING: encoding: [0x60,0x80,0x48,0xd5]
-sysp #0, c13, c0, #6, x0, x1 // RCWMASK_EL1 3 0 13 0 6
-// CHECK-INST: sysp #0, c13, c0, #6, x0, x1
-// CHECK-ENCODING: encoding: [0xc0,0xd0,0x48,0xd5]
+sysp #0, c8, c0, #6, x0, x1
+// CHECK-INST: sysp #0, c8, c0, #6, x0, x1
+// CHECK-ENCODING: encoding: [0xc0,0x80,0x48,0xd5]
-sysp #4, c2, c0, #0, x0, x1// TTBR0_EL2 3 4 2 0 0
-// CHECK-INST: sysp #4, c2, c0, #0, x0, x1
-// CHECK-ENCODING: encoding: [0x00,0x20,0x4c,0xd5]
+sysp #4, c8, c0, #0, x0, x1
+// CHECK-INST: sysp #4, c8, c0, #0, x0, x1
+// CHECK-ENCODING: encoding: [0x00,0x80,0x4c,0xd5]
-sysp #4, c2, c0, #1, x0, x1// TTBR1_EL2 3 4 2 0 1
-// CHECK-INST: sysp #4, c2, c0, #1, x0, x1
-// CHECK-ENCODING: encoding: [0x20,0x20,0x4c,0xd5]
+sysp #4, c8, c0, #3, x0, x1
+// CHECK-INST: sysp #4, c8, c0, #3, x0, x1
+// CHECK-ENCODING: encoding: [0x60,0x80,0x4c,0xd5]
-sysp #4, c2, c1, #0, x0, x1// VTTBR_EL2 3 4 2 1 0
-// CHECK-INST: sysp #4, c2, c1, #0, x0, x1
-// CHECK-ENCODING: encoding: [0x00,0x21,0x4c,0xd5]
+sysp #4, c8, c1, #0, x0, x1
+// CHECK-INST: sysp #4, c8, c1, #0, x0, x1
+// CHECK-ENCODING: encoding: [0x00,0x81,0x4c,0xd5]
-sysp #0, c2, c0, #0, x0, x1
-// CHECK-INST: sysp #0, c2, c0, #0, x0, x1
-// CHECK-ENCODING: encoding: [0x00,0x20,0x48,0xd5]
+sysp #0, c8, c0, #0, x0, x1
+// CHECK-INST: sysp #0, c8, c0, #0, x0, x1
+// CHECK-ENCODING: encoding: [0x00,0x80,0x48,0xd5]
-sysp #0, c2, c0, #1, x0, x1
-// CHECK-INST: sysp #0, c2, c0, #1, x0, x1
-// CHECK-ENCODING: encoding: [0x20,0x20,0x48,0xd5]
+sysp #0, c8, c0, #1, x0, x1
+// CHECK-INST: sysp #0, c8, c0, #1, x0, x1
+// CHECK-ENCODING: encoding: [0x20,0x80,0x48,0xd5]
-sysp #0, c7, c4, #0, x0, x1
-// CHECK-INST: sysp #0, c7, c4, #0, x0, x1
-// CHECK-ENCODING: encoding: [0x00,0x74,0x48,0xd5]
+sysp #0, c8, c4, #0, x0, x1
+// CHECK-INST: sysp #0, c8, c4, #0, x0, x1
+// CHECK-ENCODING: encoding: [0x00,0x84,0x48,0xd5]
-sysp #0, c13, c0, #3, x0, x1
-// CHECK-INST: sysp #0, c13, c0, #3, x0, x1
-// CHECK-ENCODING: encoding: [0x60,0xd0,0x48,0xd5]
+sysp #0, c8, c0, #3, x0, x1
+// CHECK-INST: sysp #0, c8, c0, #3, x0, x1
+// CHECK-ENCODING: encoding: [0x60,0x80,0x48,0xd5]
-sysp #0, c13, c0, #6, x0, x1
-// CHECK-INST: sysp #0, c13, c0, #6, x0, x1
-// CHECK-ENCODING: encoding: [0xc0,0xd0,0x48,0xd5]
+sysp #0, c8, c0, #6, x0, x1
+// CHECK-INST: sysp #0, c8, c0, #6, x0, x1
+// CHECK-ENCODING: encoding: [0xc0,0x80,0x48,0xd5]
-sysp #4, c2, c0, #0, x0, x1
-// CHECK-INST: sysp #4, c2, c0, #0, x0, x1
-// CHECK-ENCODING: encoding: [0x00,0x20,0x4c,0xd5]
+sysp #4, c8, c0, #0, x0, x1
+// CHECK-INST: sysp #4, c8, c0, #0, x0, x1
+// CHECK-ENCODING: encoding: [0x00,0x80,0x4c,0xd5]
-sysp #4, c2, c0, #1, x0, x1
-// CHECK-INST: sysp #4, c2, c0, #1, x0, x1
-// CHECK-ENCODING: encoding: [0x20,0x20,0x4c,0xd5]
+sysp #4, c8, c0, #3, x0, x1
+// CHECK-INST: sysp #4, c8, c0, #3, x0, x1
+// CHECK-ENCODING: encoding: [0x60,0x80,0x4c,0xd5]
-sysp #4, c2, c1, #0, x0, x1
-// CHECK-INST: sysp #4, c2, c1, #0, x0, x1
-// CHECK-ENCODING: encoding: [0x00,0x21,0x4c,0xd5]
+sysp #4, c8, c1, #0, x0, x1
+// CHECK-INST: sysp #4, c8, c1, #0, x0, x1
+// CHECK-ENCODING: encoding: [0x00,0x81,0x4c,0xd5]
-sysp #0, c2, c0, #0, x0, x1
-// CHECK-INST: sysp #0, c2, c0, #0, x0, x1
-// CHECK-ENCODING: encoding: [0x00,0x20,0x48,0xd5]
+sysp #0, c8, c0, #0, x0, x1
+// CHECK-INST: sysp #0, c8, c0, #0, x0, x1
+// CHECK-ENCODING: encoding: [0x00,0x80,0x48,0xd5]
-sysp #0, c2, c0, #0, x2, x3
-// CHECK-INST: sysp #0, c2, c0, #0, x2, x3
-// CHECK-ENCODING: encoding: [0x02,0x20,0x48,0xd5]
+sysp #0, c8, c0, #0, x2, x3
+// CHECK-INST: sysp #0, c8, c0, #0, x2, x3
+// CHECK-ENCODING: encoding: [0x02,0x80,0x48,0xd5]
-sysp #0, c2, c0, #0, x4, x5
-// CHECK-INST: sysp #0, c2, c0, #0, x4, x5
-// CHECK-ENCODING: encoding: [0x04,0x20,0x48,0xd5]
+sysp #0, c8, c0, #0, x4, x5
+// CHECK-INST: sysp #0, c8, c0, #0, x4, x5
+// CHECK-ENCODING: encoding: [0x04,0x80,0x48,0xd5]
-sysp #0, c2, c0, #0, x6, x7
-// CHECK-INST: sysp #0, c2, c0, #0, x6, x7
-// CHECK-ENCODING: encoding: [0x06,0x20,0x48,0xd5]
+sysp #0, c8, c0, #0, x6, x7
+// CHECK-INST: sysp #0, c8, c0, #0, x6, x7
+// CHECK-ENCODING: encoding: [0x06,0x80,0x48,0xd5]
-sysp #0, c2, c0, #0, x8, x9
-// CHECK-INST: sysp #0, c2, c0, #0, x8, x9
-// CHECK-ENCODING: encoding: [0x08,0x20,0x48,0xd5]
+sysp #0, c8, c0, #0, x8, x9
+// CHECK-INST: sysp #0, c8, c0, #0, x8, x9
+// CHECK-ENCODING: encoding: [0x08,0x80,0x48,0xd5]
-sysp #0, c2, c0, #0, x10, x11
-// CHECK-INST: sysp #0, c2, c0, #0, x10, x11
-// CHECK-ENCODING: encoding: [0x0a,0x20,0x48,0xd5]
+sysp #0, c8, c0, #0, x10, x11
+// CHECK-INST: sysp #0, c8, c0, #0, x10, x11
+// CHECK-ENCODING: encoding: [0x0a,0x80,0x48,0xd5]
-sysp #0, c2, c0, #0, x12, x13
-// CHECK-INST: sysp #0, c2, c0, #0, x12, x13
-// CHECK-ENCODING: encoding: [0x0c,0x20,0x48,0xd5]
+sysp #0, c8, c0, #0, x12, x13
+// CHECK-INST: sysp #0, c8, c0, #0, x12, x13
+// CHECK-ENCODING: encoding: [0x0c,0x80,0x48,0xd5]
-sysp #0, c2, c0, #0, x14, x15
-// CHECK-INST: sysp #0, c2, c0, #0, x14, x15
-// CHECK-ENCODING: encoding: [0x0e,0x20,0x48,0xd5]
+sysp #0, c8, c0, #0, x14, x15
+// CHECK-INST: sysp #0, c8, c0, #0, x14, x15
+// CHECK-ENCODING: encoding: [0x0e,0x80,0x48,0xd5]
-sysp #0, c2, c0, #0, x16, x17
-// CHECK-INST: sysp #0, c2, c0, #0, x16, x17
-// CHECK-ENCODING: encoding: [0x10,0x20,0x48,0xd5]
+sysp #0, c8, c0, #0, x16, x17
+// CHECK-INST: sysp #0, c8, c0, #0, x16, x17
+// CHECK-ENCODING: encoding: [0x10,0x80,0x48,0xd5]
-sysp #0, c2, c0, #0, x18, x19
-// CHECK-INST: sysp #0, c2, c0, #0, x18, x19
-// CHECK-ENCODING: encoding: [0x12,0x20,0x48,0xd5]
+sysp #0, c8, c0, #0, x18, x19
+// CHECK-INST: sysp #0, c8, c0, #0, x18, x19
+// CHECK-ENCODING: encoding: [0x12,0x80,0x48,0xd5]
-sysp #0, c2, c0, #0, x20, x21
-// CHECK-INST: sysp #0, c2, c0, #0, x20, x21
-// CHECK-ENCODING: encoding: [0x14,0x20,0x48,0xd5]
+sysp #0, c8, c0, #0, x20, x21
+// CHECK-INST: sysp #0, c8, c0, #0, x20, x21
+// CHECK-ENCODING: encoding: [0x14,0x80,0x48,0xd5]
-sysp #0, c2, c0, #0, x22, x23
-// CHECK-INST: sysp #0, c2, c0, #0, x22, x23
-// CHECK-ENCODING: encoding: [0x16,0x20,0x48,0xd5]
+sysp #0, c8, c0, #0, x22, x23
+// CHECK-INST: sysp #0, c8, c0, #0, x22, x23
+// CHECK-ENCODING: encoding: [0x16,0x80,0x48,0xd5]
-sysp #0, c2, c0, #0, x24, x25
-// CHECK-INST: sysp #0, c2, c0, #0, x24, x25
-// CHECK-ENCODING: encoding: [0x18,0x20,0x48,0xd5]
+sysp #0, c8, c0, #0, x24, x25
+// CHECK-INST: sysp #0, c8, c0, #0, x24, x25
+// CHECK-ENCODING: encoding: [0x18,0x80,0x48,0xd5]
-sysp #0, c2, c0, #0, x26, x27
-// CHECK-INST: sysp #0, c2, c0, #0, x26, x27
-// CHECK-ENCODING: encoding: [0x1a,0x20,0x48,0xd5]
+sysp #0, c8, c0, #0, x26, x27
+// CHECK-INST: sysp #0, c8, c0, #0, x26, x27
+// CHECK-ENCODING: encoding: [0x1a,0x80,0x48,0xd5]
-sysp #0, c2, c0, #0, x28, x29
-// CHECK-INST: sysp #0, c2, c0, #0, x28, x29
-// CHECK-ENCODING: encoding: [0x1c,0x20,0x48,0xd5]
+sysp #0, c8, c0, #0, x28, x29
+// CHECK-INST: sysp #0, c8, c0, #0, x28, x29
+// CHECK-ENCODING: encoding: [0x1c,0x80,0x48,0xd5]
-sysp #0, c2, c0, #0, x30, x31
-// CHECK-INST: sysp #0, c2, c0, #0, x30, xzr
-// CHECK-ENCODING: encoding: [0x1e,0x20,0x48,0xd5]
+sysp #0, c8, c0, #0, x30, x31
+// CHECK-INST: sysp #0, c8, c0, #0, x30, xzr
+// CHECK-ENCODING: encoding: [0x1e,0x80,0x48,0xd5]
-sysp #0, c2, c0, #0, x31, x31
-// CHECK-INST: sysp #0, c2, c0, #0
-// CHECK-ENCODING: encoding: [0x1f,0x20,0x48,0xd5]
+sysp #0, c8, c0, #0, x31, x31
+// CHECK-INST: sysp #0, c8, c0, #0
+// CHECK-ENCODING: encoding: [0x1f,0x80,0x48,0xd5]
-sysp #0, c2, c0, #0, xzr, xzr
-// CHECK-INST: sysp #0, c2, c0, #0
-// CHECK-ENCODING: encoding: [0x1f,0x20,0x48,0xd5]
+sysp #0, c8, c0, #0, xzr, xzr
+// CHECK-INST: sysp #0, c8, c0, #0
+// CHECK-ENCODING: encoding: [0x1f,0x80,0x48,0xd5]
-sysp #0, c2, c0, #0, x31, xzr
-// CHECK-INST: sysp #0, c2, c0, #0
-// CHECK-ENCODING: encoding: [0x1f,0x20,0x48,0xd5]
+sysp #0, c8, c0, #0, x31, xzr
+// CHECK-INST: sysp #0, c8, c0, #0
+// CHECK-ENCODING: encoding: [0x1f,0x80,0x48,0xd5]
-sysp #0, c2, c0, #0, xzr, x31
-// CHECK-INST: sysp #0, c2, c0, #0
-// CHECK-ENCODING: encoding: [0x1f,0x20,0x48,0xd5]
+sysp #0, c8, c0, #0, xzr, x31
+// CHECK-INST: sysp #0, c8, c0, #0
+// CHECK-ENCODING: encoding: [0x1f,0x80,0x48,0xd5]
-sysp #0, c2, c0, #0
-// CHECK-INST: sysp #0, c2, c0, #0
-// CHECK-ENCODING: encoding: [0x1f,0x20,0x48,0xd5]
+sysp #0, c8, c0, #0
+// CHECK-INST: sysp #0, c8, c0, #0
+// CHECK-ENCODING: encoding: [0x1f,0x80,0x48,0xd5]
>From be3fee860b26bcec3091736106dc25f8564ab509 Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Thu, 5 Mar 2026 12:32:15 +0000
Subject: [PATCH 02/17] fixup! Address Marian's PR comments: use imm0_6
predicate
---
llvm/lib/Target/AArch64/AArch64InstrFormats.td | 10 +++++++++-
llvm/lib/Target/AArch64/AArch64InstrInfo.td | 4 ++--
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index 82cdc1bd7795b..06a6fbee967bd 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -951,6 +951,7 @@ def Imm0_1Operand : AsmImmRange<0, 1>;
def Imm1_1Operand : AsmImmRange<1, 1>;
def Imm0_3Operand : AsmImmRange<0, 3>;
def Imm1_3Operand : AsmImmRange<1, 3>;
+def Imm0_6Operand : AsmImmRange<0, 6>;
def Imm0_7Operand : AsmImmRange<0, 7>;
def Imm1_7Operand : AsmImmRange<1, 7>;
def Imm0_15Operand : AsmImmRange<0, 15>;
@@ -1184,6 +1185,13 @@ def imm0_15 : Operand<i64>, ImmLeaf<i64, [{
let ParserMatchClass = Imm0_15Operand;
}
+// imm0_6 predicate - True if the immediate is in the range [0,6]
+def imm0_6 : Operand<i64>, ImmLeaf<i64, [{
+ return ((uint64_t)Imm) < 7;
+}]> {
+ let ParserMatchClass = Imm0_6Operand;
+}
+
// imm0_7 predicate - True if the immediate is in the range [0,7]
def imm0_7 : Operand<i64>, ImmLeaf<i64, [{
return ((uint64_t)Imm) < 8;
@@ -13352,7 +13360,7 @@ class BaseSYSPEncoding<bit L, string asm, string operands, dag outputs, dag inpu
}
class SystemPXtI<bit L, string asm> :
BaseSYSPEncoding<L, asm, "\t$op1, $Cn, $Cm, $op2, $Rt", (outs),
- (ins sysp_op1:$op1, sysp_crn_op:$Cn, sysp_crm_op:$Cm, imm0_7:$op2,
+ (ins imm0_6:$op1, sysp_crn_op:$Cn, sysp_crm_op:$Cm, imm0_7:$op2,
XSeqPairClassOperand:$Rt)>;
//----------------------------------------------------------------------------
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 627c3b9627d47..053d4d84a43ce 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -11615,7 +11615,7 @@ def SYSPxt : SystemPXtI<0, "sysp"> {
def SYSPxt_XZR
: BaseSystemI<0, (outs),
- (ins sysp_op1:$op1, sysp_crn_op:$Cn, sysp_crm_op:$Cm, imm0_7:$op2,
+ (ins imm0_6:$op1, sysp_crn_op:$Cn, sysp_crm_op:$Cm, imm0_7:$op2,
SyspXzrPairOperand:$xzr_pair),
"sysp", "\t$op1, $Cn, $Cm, $op2, $xzr_pair">,
Sched<[WriteSys]>
@@ -11642,7 +11642,7 @@ def SYSPxt_XZR
}
def : InstAlias<"sysp $op1, $Cn, $Cm, $op2",
- (SYSPxt_XZR sysp_op1:$op1, sysp_crn_op:$Cn, sysp_crm_op:$Cm,
+ (SYSPxt_XZR imm0_6:$op1, sysp_crn_op:$Cn, sysp_crm_op:$Cm,
imm0_7:$op2, XZR)>;
//---
>From 01eec5977996a4101b96c334e19030b9b3d37e69 Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Thu, 5 Mar 2026 14:41:46 +0000
Subject: [PATCH 03/17] fixup! Templatise bounds checking and improve tests
---
.../lib/Target/AArch64/AArch64InstrFormats.td | 17 ++++++++++++-----
.../AArch64/AsmParser/AArch64AsmParser.cpp | 18 ++++++++++++++++++
.../MCTargetDesc/AArch64InstPrinter.cpp | 8 --------
llvm/test/MC/AArch64/armv9-sysp-diagnostics.s | 19 +++++++++++++++----
4 files changed, 45 insertions(+), 17 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index 06a6fbee967bd..0fb21c1a5d754 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -2122,16 +2122,23 @@ class MSRpstateImm0_1
}
// SYS and SYSL generic system instructions.
-def SysCRAsmOperand : AsmOperandClass {
- let Name = "SysCR";
+class SysCRAsmOperand<int Low, int High> : AsmOperandClass {
+ let Name = "SysCR" # Low # "_" # High;
+ let RenderMethod = "addSysCROperands";
let ParserMethod = "tryParseSysCROperand";
+ let PredicateMethod = "isSysCRInRange<" # Low # "," # High # ">";
+ let DiagnosticType = "InvalidSysCR" # Low # "_" # High;
}
+def SysCRm0_7AsmOperand : SysCRAsmOperand<0, 7>;
+def SysCRn8_9AsmOperand : SysCRAsmOperand<8, 9>;
+def SysCR0_15AsmOperand : SysCRAsmOperand<0, 15>;
+
def sys_cr_op : Operand<i32>, TImmLeaf<i32, [{
return ((uint32_t)Imm) < 16;
}]> {
let PrintMethod = "printSysCROperand";
- let ParserMatchClass = SysCRAsmOperand;
+ let ParserMatchClass = SysCR0_15AsmOperand;
let OperandType = "OPERAND_IMMEDIATE";
}
@@ -2139,7 +2146,7 @@ def sysp_crn_op : Operand<i32>, ImmLeaf<i32, [{
return Imm == 8 || Imm == 9;
}]> {
let PrintMethod = "printSysCROperand";
- let ParserMatchClass = SysCRAsmOperand;
+ let ParserMatchClass = SysCRn8_9AsmOperand;
let OperandType = "OPERAND_IMMEDIATE";
}
@@ -2147,7 +2154,7 @@ def sysp_crm_op : Operand<i32>, ImmLeaf<i32, [{
return Imm >= 0 && Imm <= 7;
}]> {
let PrintMethod = "printSysCROperand";
- let ParserMatchClass = SysCRAsmOperand;
+ let ParserMatchClass = SysCRm0_7AsmOperand;
let OperandType = "OPERAND_IMMEDIATE";
}
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index d14dfa7ccfd06..2fe1aa624a993 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -1554,6 +1554,12 @@ class AArch64Operand : public MCParsedAsmOperand {
return Kind == k_Token && getToken() == Str;
}
bool isSysCR() const { return Kind == k_SysCR; }
+ template <unsigned low, unsigned high> bool isSysCRInRange() const {
+ if (!isSysCR())
+ return false;
+ unsigned Val = getSysCR();
+ return Val >= low && Val <= high;
+ }
bool isPrefetch() const { return Kind == k_Prefetch; }
bool isPSBHint() const { return Kind == k_PSBHint; }
bool isPHint() const { return Kind == k_PHint; }
@@ -6296,6 +6302,8 @@ bool AArch64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode,
return Error(Loc, "immediate must be an integer in range [0, 1].");
case Match_InvalidImm0_3:
return Error(Loc, "immediate must be an integer in range [0, 3].");
+ case Match_InvalidImm0_6:
+ return Error(Loc, "immediate must be an integer in range [0, 6].");
case Match_InvalidImm0_7:
return Error(Loc, "immediate must be an integer in range [0, 7].");
case Match_InvalidImm0_15:
@@ -6320,6 +6328,12 @@ bool AArch64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode,
return Error(Loc, "immediate must be an integer in range [1, 64].");
case Match_InvalidImmM1_62:
return Error(Loc, "immediate must be an integer in range [-1, 62].");
+ case Match_InvalidSysCR0_7:
+ return Error(Loc, "expected cM operand where 0 <= M <= 7");
+ case Match_InvalidSysCR8_9:
+ return Error(Loc, "expected cN operand where 8 <= N <= 9");
+ case Match_InvalidSysCR0_15:
+ return Error(Loc, "expected cN operand where 0 <= N <= 15");
case Match_InvalidMemoryIndexedRange2UImm0:
return Error(Loc, "vector select offset must be the immediate range 0:1.");
case Match_InvalidMemoryIndexedRange2UImm1:
@@ -7082,6 +7096,7 @@ bool AArch64AsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
case Match_InvalidImm0_0:
case Match_InvalidImm0_1:
case Match_InvalidImm0_3:
+ case Match_InvalidImm0_6:
case Match_InvalidImm0_7:
case Match_InvalidImm0_15:
case Match_InvalidImm0_31:
@@ -7094,6 +7109,9 @@ bool AArch64AsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
case Match_InvalidImm1_32:
case Match_InvalidImm1_64:
case Match_InvalidImmM1_62:
+ case Match_InvalidSysCR0_7:
+ case Match_InvalidSysCR8_9:
+ case Match_InvalidSysCR0_15:
case Match_InvalidMemoryIndexedRange2UImm0:
case Match_InvalidMemoryIndexedRange2UImm1:
case Match_InvalidMemoryIndexedRange2UImm2:
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
index f6e483f900de7..2783b559c8f5c 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
@@ -1142,14 +1142,6 @@ bool AArch64InstPrinter::printSyspAlias(const MCInst *MI,
unsigned CmVal = Cm.getImm();
unsigned Op2Val = Op2.getImm();
- // Early checks for invalid SYSP aliases
- // Op1 == 0..6
- // Op2 == 0..7
- // Cm == 0..7
- // Cn == 8 or 9
- if (Op1Val > 6 || Op2Val > 7 || CmVal > 7 || (CnVal != 8 && CnVal != 9))
- return false;
-
uint16_t Encoding = Op2Val;
Encoding |= CmVal << 3;
Encoding |= CnVal << 7;
diff --git a/llvm/test/MC/AArch64/armv9-sysp-diagnostics.s b/llvm/test/MC/AArch64/armv9-sysp-diagnostics.s
index 51bb307912fef..4e0ba1bbb1772 100644
--- a/llvm/test/MC/AArch64/armv9-sysp-diagnostics.s
+++ b/llvm/test/MC/AArch64/armv9-sysp-diagnostics.s
@@ -9,16 +9,22 @@
sysp #0, c8, c0, #0, x0, x2
// ERRORS: error: expected second odd register of a consecutive same-size even/odd register pair
-sysp #0, c8, c0, #0, x0
-// ERRORS: error: expected comma
sysp #0, c8, c0, #0, x1, x2
// ERRORS: error: expected first even register of a consecutive same-size even/odd register pair
sysp #0, c8, c0, #0, x31, x0
// ERRORS: error: xzr must be followed by xzr
sysp #0, c8, c0, #0, xzr, x30
// ERRORS: error: xzr must be followed by xzr
-sysp #0, c8, c0, #0, xzr
-// ERRORS: error: expected comma
+sysp #7, c8, c0, #0, x0, x1
+// ERRORS: error: immediate must be an integer in range [0, 6].
+sysp #0, c7, c0, #0, x0, x1
+// ERRORS: error: expected cN operand where 8 <= N <= 9
+sysp #0, c10, c0, #0, x0, x1
+// ERRORS: error: expected cN operand where 8 <= N <= 9
+sysp #0, c8, c8, #0, x0, x1
+// ERRORS: error: expected cM operand where 0 <= M <= 7
+sysp #0, c8, c0, #8, x0, x1
+// ERRORS: error: immediate must be an integer in range [0, 7].
sysp #0, c8, c0, #0, xzr,
// ERRORS: error: expected register operand
@@ -32,3 +38,8 @@ tlbip IPAS2E1, x4, x8
// ERRORS: error: specified tlbip op requires a pair of registers
tlbip RVAE3, x11, x11
// ERRORS: error: specified tlbip op requires a pair of registers
+
+sysp #0, c8, c0, #0, x0
+// ERRORS: error: expected comma
+sysp #0, c8, c0, #0, xzr
+// ERRORS: error: expected comma
>From 16830029ea5fd2599e638bfcfc9b8f97c15f1623 Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Mon, 9 Mar 2026 16:16:52 +0000
Subject: [PATCH 04/17] fixup! Remove SYSPxt_XZR and update code to reflect
this
---
.../lib/Target/AArch64/AArch64InstrFormats.td | 2 +-
llvm/lib/Target/AArch64/AArch64InstrInfo.td | 32 +---------
.../lib/Target/AArch64/AArch64RegisterInfo.td | 16 ++---
.../AArch64/AsmParser/AArch64AsmParser.cpp | 61 ++++++++-----------
.../Disassembler/AArch64Disassembler.cpp | 32 +++-------
.../MCTargetDesc/AArch64InstPrinter.cpp | 55 ++++++++++++-----
.../AArch64/MCTargetDesc/AArch64InstPrinter.h | 4 +-
llvm/test/MC/AArch64/armv9-sysp-diagnostics.s | 16 ++++-
llvm/test/MC/AArch64/armv9-sysp-invalid.s | 20 ------
llvm/test/MC/AArch64/armv9a-sysp.s | 4 ++
10 files changed, 105 insertions(+), 137 deletions(-)
delete mode 100644 llvm/test/MC/AArch64/armv9-sysp-invalid.s
diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index 0fb21c1a5d754..75ce0e76dc164 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -13368,7 +13368,7 @@ class BaseSYSPEncoding<bit L, string asm, string operands, dag outputs, dag inpu
class SystemPXtI<bit L, string asm> :
BaseSYSPEncoding<L, asm, "\t$op1, $Cn, $Cm, $op2, $Rt", (outs),
(ins imm0_6:$op1, sysp_crn_op:$Cn, sysp_crm_op:$Cm, imm0_7:$op2,
- XSeqPairClassOperand:$Rt)>;
+ SyspPairOperand:$Rt)>;
//----------------------------------------------------------------------------
// 2023 Armv9.5 Extensions
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 053d4d84a43ce..53c3f297fd068 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -11613,37 +11613,9 @@ def SYSPxt : SystemPXtI<0, "sysp"> {
let DecoderMethod = "DecodeSyspInstruction";
}
-def SYSPxt_XZR
- : BaseSystemI<0, (outs),
- (ins imm0_6:$op1, sysp_crn_op:$Cn, sysp_crm_op:$Cm, imm0_7:$op2,
- SyspXzrPairOperand:$xzr_pair),
- "sysp", "\t$op1, $Cn, $Cm, $op2, $xzr_pair">,
- Sched<[WriteSys]>
-{
- // Had to use a custom decoder because tablegen interprets this as having 4 fields (why?)
- // and therefore autogenerates a decoder that builds an MC representation that has 4 fields
- // (decodeToMCInst), but when printing we expect the MC representation to have 5 fields (one
- // extra for the XZR) because AArch64InstPrinter::printInstruction in AArch64GenAsmWriter.inc
- // is based off of the asm template (maybe) and therefore wants to print 5 operands.
- // I could add a bits<5> xzr_pair. But without a way to constrain it to 0b11111 here it would
- // overlap with the main SYSP instruction.
- let DecoderMethod = "DecodeSyspXzrInstruction";
- bits<3> op1;
- bits<4> Cn;
- bits<4> Cm;
- bits<3> op2;
- let Inst{22} = 0b1; // override BaseSystemI
- let Inst{20-19} = 0b01;
- let Inst{18-16} = op1;
- let Inst{15-12} = Cn;
- let Inst{11-8} = Cm;
- let Inst{7-5} = op2;
- let Inst{4-0} = 0b11111;
-}
-
def : InstAlias<"sysp $op1, $Cn, $Cm, $op2",
- (SYSPxt_XZR imm0_6:$op1, sysp_crn_op:$Cn, sysp_crm_op:$Cm,
- imm0_7:$op2, XZR)>;
+ (SYSPxt imm0_6:$op1, sysp_crn_op:$Cn, sysp_crm_op:$Cm,
+ imm0_7:$op2, XZR)>;
//---
// 128-bit System Registers (FEAT_SYSREG128)
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
index cd94a2590c6d2..cc2798de60943 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
@@ -833,14 +833,14 @@ def MrrsMssrPairClassOperand :
RegisterOperand<XSeqPairsClass, "printGPRSeqPairsClassOperand<64>"> {
let ParserMatchClass = XSeqPairsAsmOperandClass;
}
-def SyspXzrPairOperandMatcherClass : AsmOperandClass {
- let Name = "SyspXzrPair";
- let RenderMethod = "addSyspXzrPairOperand";
- let ParserMethod = "tryParseSyspXzrPair";
-}
-def SyspXzrPairOperand :
- RegisterOperand<GPR64, "printSyspXzrPair"> { // needed to allow alias with XZR operand
- let ParserMatchClass = SyspXzrPairOperandMatcherClass;
+def SyspPairOperandMatcherClass : AsmOperandClass {
+ let Name = "SyspPair";
+ let RenderMethod = "addRegOperands";
+ let ParserMethod = "tryParseSyspPair";
+}
+def SyspPairOperand :
+ RegisterOperand<GPR64, "printSyspPair"> {
+ let ParserMatchClass = SyspPairOperandMatcherClass;
}
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index 2fe1aa624a993..8659ea6c6832b 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -280,7 +280,7 @@ class AArch64AsmParser : public MCTargetAsmParser {
bool tryParseNeonVectorRegister(OperandVector &Operands);
ParseStatus tryParseVectorIndex(OperandVector &Operands);
ParseStatus tryParseGPRSeqPair(OperandVector &Operands);
- ParseStatus tryParseSyspXzrPair(OperandVector &Operands);
+ ParseStatus tryParseSyspPair(OperandVector &Operands);
template <bool ParseShiftExtend,
RegConstraintEqualityTy EqTy = RegConstraintEqualityTy::EqualsReg>
ParseStatus tryParseGPROperand(OperandVector &Operands);
@@ -1452,9 +1452,7 @@ class AArch64Operand : public MCParsedAsmOperand {
.contains(Reg.Reg);
}
- bool isSyspXzrPair() const {
- return isGPR64<AArch64::GPR64RegClassID>() && Reg.Reg == AArch64::XZR;
- }
+ bool isSyspPair() const { return isGPR64<AArch64::GPR64RegClassID>(); }
template<int64_t Angle, int64_t Remainder>
DiagnosticPredicate isComplexRotation() const {
@@ -2275,21 +2273,6 @@ class AArch64Operand : public MCParsedAsmOperand {
Inst.addOperand(MCOperand::createImm(Imm));
}
- void addSyspXzrPairOperand(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
-
- if (!isScalarReg())
- return;
-
- const MCRegisterInfo *RI = Ctx.getRegisterInfo();
- MCRegister Reg = RI->getRegClass(AArch64::GPR64RegClassID)
- .getRegister(RI->getEncodingValue(getReg()));
- if (Reg != AArch64::XZR)
- llvm_unreachable("wrong register");
-
- Inst.addOperand(MCOperand::createReg(AArch64::XZR));
- }
-
void addExtendOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
AArch64_AM::ShiftExtendType ET = getShiftExtendType();
@@ -3322,18 +3305,20 @@ ParseStatus AArch64AsmParser::tryParsePSBHint(OperandVector &Operands) {
return ParseStatus::Success;
}
-ParseStatus AArch64AsmParser::tryParseSyspXzrPair(OperandVector &Operands) {
+ParseStatus AArch64AsmParser::tryParseSyspPair(OperandVector &Operands) {
SMLoc StartLoc = getLoc();
- MCRegister RegNum;
-
- // The case where xzr, xzr is not present is handled by an InstAlias.
+ MCRegister FirstReg;
+ MCRegister SecondReg;
+ const MCRegisterInfo *RI = getContext().getRegisterInfo();
+ const MCRegisterClass &XRegClass =
+ AArch64MCRegisterClasses[AArch64::GPR64RegClassID];
auto RegTok = getTok(); // in case we need to backtrack
- if (!tryParseScalarRegister(RegNum).isSuccess())
+ if (!tryParseScalarRegister(FirstReg).isSuccess())
return ParseStatus::NoMatch;
- if (RegNum != AArch64::XZR) {
+ if (!XRegClass.contains(FirstReg)) {
getLexer().UnLex(RegTok);
return ParseStatus::NoMatch;
}
@@ -3341,16 +3326,26 @@ ParseStatus AArch64AsmParser::tryParseSyspXzrPair(OperandVector &Operands) {
if (parseComma())
return ParseStatus::Failure;
- if (!tryParseScalarRegister(RegNum).isSuccess())
+ if (!tryParseScalarRegister(SecondReg).isSuccess())
return TokError("expected register operand");
- if (RegNum != AArch64::XZR)
- return TokError("xzr must be followed by xzr");
+ if (FirstReg == AArch64::XZR) {
+ if (SecondReg != AArch64::XZR)
+ return TokError("xzr must be followed by xzr");
+ // The SYSP alias is UNDEFINED if Rt<0> == '1' && Rt != '11111'.
+ } else if (RI->getEncodingValue(FirstReg) & 1) {
+ return TokError("first register must be even-numbered or xzr");
+ } else if (!XRegClass.contains(SecondReg) ||
+ RI->getEncodingValue(SecondReg) !=
+ RI->getEncodingValue(FirstReg) + 1) {
+ return TokError(
+ "second register must be the next consecutive register after the "
+ "first register");
+ }
- // We need to push something, since we claim this is an operand in .td.
- // See also AArch64AsmParser::parseKeywordOperand.
+ // SYSP encodes only the first register; the second is implied as Rt+1.
Operands.push_back(AArch64Operand::CreateReg(
- RegNum, RegKind::Scalar, StartLoc, getLoc(), getContext()));
+ FirstReg, RegKind::Scalar, StartLoc, getLoc(), getContext()));
return ParseStatus::Success;
}
@@ -4286,9 +4281,7 @@ bool AArch64AsmParser::parseSyspAlias(StringRef Name, SMLoc NameLoc,
if (Tok.isNot(AsmToken::Identifier))
return TokError("expected register identifier");
- auto Result = tryParseSyspXzrPair(Operands);
- if (Result.isNoMatch())
- Result = tryParseGPRSeqPair(Operands);
+ auto Result = tryParseSyspPair(Operands);
if (!Result.isSuccess())
return TokError("specified " + Mnemonic +
" op requires a pair of registers");
diff --git a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
index c80eaad88e434..e95a0c87c6c6c 100644
--- a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
+++ b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
@@ -1387,9 +1387,9 @@ DecodeXSeqPairsClassRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Addr,
Inst, AArch64::XSeqPairsClassRegClassID, RegNo, Addr, Decoder);
}
-static DecodeStatus DecodeSyspXzrInstruction(MCInst &Inst, uint32_t insn,
- uint64_t Addr,
- const MCDisassembler *Decoder) {
+static DecodeStatus DecodeSyspInstruction(MCInst &Inst, uint32_t insn,
+ uint64_t Addr,
+ const MCDisassembler *Decoder) {
unsigned op1 = fieldFromInstruction(insn, 16, 3);
unsigned CRn = fieldFromInstruction(insn, 12, 4);
unsigned CRm = fieldFromInstruction(insn, 8, 4);
@@ -1399,40 +1399,22 @@ static DecodeStatus DecodeSyspXzrInstruction(MCInst &Inst, uint32_t insn,
if (op1 > 6 || (CRn != 8 && CRn != 9) || CRm > 7 || op2 > 7)
return Fail;
- if (Rt != 0b11111)
+ // SYSP register pairs follow the same encoding constraints as XSeqPairsClass:
+ // the first register must be even-numbered, except for the XZR/XZR case.
+ if (Rt != 31 && (Rt & 0x1))
return Fail;
Inst.addOperand(MCOperand::createImm(op1));
Inst.addOperand(MCOperand::createImm(CRn));
Inst.addOperand(MCOperand::createImm(CRm));
Inst.addOperand(MCOperand::createImm(op2));
+ // SYSP just encodes Rt. Print Rt and Rt+1 as a pair.
DecodeSimpleRegisterClass<AArch64::GPR64RegClassID, 0, 32>(Inst, Rt, Addr,
Decoder);
return Success;
}
-static DecodeStatus DecodeSyspInstruction(MCInst &Inst, uint32_t insn,
- uint64_t Addr,
- const MCDisassembler *Decoder) {
- unsigned op1 = fieldFromInstruction(insn, 16, 3);
- unsigned CRn = fieldFromInstruction(insn, 12, 4);
- unsigned CRm = fieldFromInstruction(insn, 8, 4);
- unsigned op2 = fieldFromInstruction(insn, 5, 3);
- unsigned Rt = fieldFromInstruction(insn, 0, 5);
-
- if (op1 > 6 || (CRn != 8 && CRn != 9) || CRm > 7 || op2 > 7)
- return Fail;
-
- Inst.addOperand(MCOperand::createImm(op1));
- Inst.addOperand(MCOperand::createImm(CRn));
- Inst.addOperand(MCOperand::createImm(CRm));
- Inst.addOperand(MCOperand::createImm(op2));
- DecodeXSeqPairsClassRegisterClass(Inst, Rt, Addr, Decoder);
-
- return Success;
-}
-
static DecodeStatus
DecodeSVELogicalImmInstruction(MCInst &Inst, uint32_t insn, uint64_t Addr,
const MCDisassembler *Decoder) {
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
index 2783b559c8f5c..d9f050681cc68 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
@@ -90,12 +90,26 @@ void AArch64InstPrinter::printInst(const MCInst *MI, uint64_t Address,
return;
}
- if (Opcode == AArch64::SYSPxt || Opcode == AArch64::SYSPxt_XZR)
+ if (Opcode == AArch64::SYSPxt) {
if (printSyspAlias(MI, STI, O)) {
printAnnotation(O, Annot);
return;
}
+ // Ok, so we should preserve compatibility when printing with the historic
+ // SYSP short form, when Rt encodes XZR (no explicit pair operand)
+ if (MI->getOperand(4).getReg() == AArch64::XZR) {
+ O << "\tsysp\t";
+ markup(O, Markup::Immediate) << "#" << MI->getOperand(0).getImm();
+ O << ", c" << MI->getOperand(1).getImm();
+ O << ", c" << MI->getOperand(2).getImm();
+ O << ", ";
+ markup(O, Markup::Immediate) << "#" << MI->getOperand(3).getImm();
+ printAnnotation(O, Annot);
+ return;
+ }
+ }
+
// RPRFM overlaps PRFM (reg), so try to print it as RPRFM here.
if ((Opcode == AArch64::PRFMroX) || (Opcode == AArch64::PRFMroW)) {
if (printRangePrefetchAlias(MI, STI, O, Annot))
@@ -371,7 +385,12 @@ void AArch64InstPrinter::printInst(const MCInst *MI, uint64_t Address,
return;
}
- if (!PrintAliases || !printAliasInstr(MI, Address, STI, O))
+ // SYSP alias printing is handled explicitly by printSyspAlias above.
+ // Skip the generic alias printer for SYSPxt, because its XSeqPair aliases
+ // are only valid for a subset of SYSP register pairs and can misprint
+ // odd-started regs or xzr,xzr encodings.
+ if (!PrintAliases || Opcode == AArch64::SYSPxt ||
+ !printAliasInstr(MI, Address, STI, O))
printInstruction(MI, Address, STI, O);
printAnnotation(O, Annot);
@@ -1128,8 +1147,7 @@ bool AArch64InstPrinter::printSyspAlias(const MCInst *MI,
raw_ostream &O) {
#ifndef NDEBUG
unsigned Opcode = MI->getOpcode();
- assert((Opcode == AArch64::SYSPxt || Opcode == AArch64::SYSPxt_XZR) &&
- "Invalid opcode for SYSP alias!");
+ assert(Opcode == AArch64::SYSPxt && "Invalid opcode for SYSP alias!");
#endif
const MCOperand &Op1 = MI->getOperand(0);
@@ -1168,10 +1186,8 @@ bool AArch64InstPrinter::printSyspAlias(const MCInst *MI,
O << '\t' << Str;
O << ", ";
- if (MI->getOperand(4).getReg() == AArch64::XZR)
- printSyspXzrPair(MI, 4, STI, O);
- else
- printGPRSeqPairsClassOperand<64>(MI, 4, STI, O);
+ // TLBIP alias keeps SYSP's pair formatting rules for the trailing operand.
+ printSyspPair(MI, 4, STI, O);
return true;
}
@@ -2253,13 +2269,24 @@ void AArch64InstPrinter::printGPR64x8(const MCInst *MI, unsigned OpNum,
printRegName(O, MRI.getSubReg(Reg, AArch64::x8sub_0));
}
-void AArch64InstPrinter::printSyspXzrPair(const MCInst *MI, unsigned OpNum,
- const MCSubtargetInfo &STI,
- raw_ostream &O) {
+void AArch64InstPrinter::printSyspPair(const MCInst *MI, unsigned OpNum,
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
MCRegister Reg = MI->getOperand(OpNum).getReg();
- assert(Reg == AArch64::XZR &&
- "MC representation of SyspXzrPair should be XZR");
- O << getRegisterName(Reg) << ", " << getRegisterName(Reg);
+ printRegName(O, Reg);
+ O << ", ";
+ if (Reg == AArch64::XZR) {
+ printRegName(O, AArch64::XZR);
+ return;
+ }
+
+ const MCRegisterClass &XRegClass =
+ AArch64MCRegisterClasses[AArch64::GPR64RegClassID];
+ // SYSP textual form prints the implied second register as Rt+1.
+ unsigned NextRegNo = MRI.getEncodingValue(Reg) + 1;
+ assert(NextRegNo < XRegClass.getNumRegs() &&
+ "SYSP pair starts from an invalid GPR64 register");
+ printRegName(O, XRegClass.getRegister(NextRegNo));
}
void AArch64InstPrinter::printPHintOp(const MCInst *MI, unsigned OpNum,
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h
index 3f7a3b4b0667b..0b34d9edfa82b 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h
@@ -237,8 +237,8 @@ class AArch64InstPrinter : public MCInstPrinter {
const MCSubtargetInfo &STI, raw_ostream &O);
void printGPR64x8(const MCInst *MI, unsigned OpNum,
const MCSubtargetInfo &STI, raw_ostream &O);
- void printSyspXzrPair(const MCInst *MI, unsigned OpNum,
- const MCSubtargetInfo &STI, raw_ostream &O);
+ void printSyspPair(const MCInst *MI, unsigned OpNum,
+ const MCSubtargetInfo &STI, raw_ostream &O);
template <int Width>
void printZPRasFPR(const MCInst *MI, unsigned OpNum,
const MCSubtargetInfo &STI, raw_ostream &O);
diff --git a/llvm/test/MC/AArch64/armv9-sysp-diagnostics.s b/llvm/test/MC/AArch64/armv9-sysp-diagnostics.s
index 4e0ba1bbb1772..2426acce2d95e 100644
--- a/llvm/test/MC/AArch64/armv9-sysp-diagnostics.s
+++ b/llvm/test/MC/AArch64/armv9-sysp-diagnostics.s
@@ -8,13 +8,23 @@
// For sysp, op0 is 0
sysp #0, c8, c0, #0, x0, x2
-// ERRORS: error: expected second odd register of a consecutive same-size even/odd register pair
-sysp #0, c8, c0, #0, x1, x2
-// ERRORS: error: expected first even register of a consecutive same-size even/odd register pair
+// ERRORS: error: second register must be the next consecutive register after the first register
+sysp #4, c8, c4, #1, x1, x2
+// ERRORS: error: first register must be even-numbered or xzr
+sysp #4, c8, c4, #1, x2, x4
+// ERRORS: error: second register must be the next consecutive register after the first register
+sysp #0, c8, c0, #0, x29, x31
+// ERRORS: error: first register must be even-numbered or xzr
+sysp #0, c8, c0, #0, x30, x30
+// ERRORS: error: second register must be the next consecutive register after the first register
sysp #0, c8, c0, #0, x31, x0
// ERRORS: error: xzr must be followed by xzr
+sysp #4, c8, c4, #1, xzr, x1
+// ERRORS: error: xzr must be followed by xzr
sysp #0, c8, c0, #0, xzr, x30
// ERRORS: error: xzr must be followed by xzr
+sysp #0, c8, c0, #0, w0, w1
+// ERRORS: error: invalid operand for instruction
sysp #7, c8, c0, #0, x0, x1
// ERRORS: error: immediate must be an integer in range [0, 6].
sysp #0, c7, c0, #0, x0, x1
diff --git a/llvm/test/MC/AArch64/armv9-sysp-invalid.s b/llvm/test/MC/AArch64/armv9-sysp-invalid.s
deleted file mode 100644
index 248d5ccc5056a..0000000000000
--- a/llvm/test/MC/AArch64/armv9-sysp-invalid.s
+++ /dev/null
@@ -1,20 +0,0 @@
-// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+d128 < %s \
-// RUN: | llvm-objdump -d --mattr=+d128 --no-print-imm-hex - \
-// RUN: | FileCheck %s --check-prefix=DISASM
-
-// Ensure invalid SYSP encodings are not printed as TLBIP aliases.
-
-// op1 = 7 (outside architecturally valid SYSP range for op1)
-// Cn = 8, Cm = 0, op2 = 0, Rt = 0 (x0, x1)
-.inst 0xd54f8000
-
-// Cn = 0 (outside architecturally valid SYSP range for Cn)
-.inst 0xd5480000
-
-// Cm = 8 (outside architecturally valid SYSP range for Cm)
-.inst 0xd5488800
-
-// DISASM-NOT: tlbip
-// DISASM: <unknown>
-// DISASM: <unknown>
-// DISASM: <unknown>
diff --git a/llvm/test/MC/AArch64/armv9a-sysp.s b/llvm/test/MC/AArch64/armv9a-sysp.s
index 349f75eb95424..c01e83c92fcfd 100644
--- a/llvm/test/MC/AArch64/armv9a-sysp.s
+++ b/llvm/test/MC/AArch64/armv9a-sysp.s
@@ -21,6 +21,10 @@ sysp #0, c8, c0, #1, x0, x1
// CHECK-INST: sysp #0, c8, c0, #1, x0, x1
// CHECK-ENCODING: encoding: [0x20,0x80,0x48,0xd5]
+sysp #0, c9, c0, #0, x0, x1
+// CHECK-INST: sysp #0, c9, c0, #0, x0, x1
+// CHECK-ENCODING: encoding: [0x00,0x90,0x48,0xd5]
+
sysp #0, c8, c4, #0, x0, x1
// CHECK-INST: sysp #0, c8, c4, #0, x0, x1
// CHECK-ENCODING: encoding: [0x00,0x84,0x48,0xd5]
>From 748cf7db328ac9c2f368242798f83b9c72fb67fe Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Tue, 10 Mar 2026 22:29:20 +0000
Subject: [PATCH 05/17] fixup! Add no-alias tests
---
.../lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp | 7 ++++---
llvm/test/MC/AArch64/armv9a-sysp.s | 7 +++++++
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
index d9f050681cc68..f6154459a64b7 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
@@ -96,9 +96,10 @@ void AArch64InstPrinter::printInst(const MCInst *MI, uint64_t Address,
return;
}
- // Ok, so we should preserve compatibility when printing with the historic
- // SYSP short form, when Rt encodes XZR (no explicit pair operand)
- if (MI->getOperand(4).getReg() == AArch64::XZR) {
+ // Preserve the historic SYSP short form for the XZR/XZR encoding, but
+ // only when aliases are enabled. In no-alias mode we must print the full
+ // canonical operand list.
+ if (PrintAliases && MI->getOperand(4).getReg() == AArch64::XZR) {
O << "\tsysp\t";
markup(O, Markup::Immediate) << "#" << MI->getOperand(0).getImm();
O << ", c" << MI->getOperand(1).getImm();
diff --git a/llvm/test/MC/AArch64/armv9a-sysp.s b/llvm/test/MC/AArch64/armv9a-sysp.s
index c01e83c92fcfd..3753fcc684c4f 100644
--- a/llvm/test/MC/AArch64/armv9a-sysp.s
+++ b/llvm/test/MC/AArch64/armv9a-sysp.s
@@ -2,6 +2,8 @@
// RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST
// RUN: llvm-mc -triple=aarch64 -filetype=obj < %s \
// RUN: | llvm-objdump -d --no-print-imm-hex - | FileCheck %s --check-prefix=CHECK-INST
+// RUN: llvm-mc -triple=aarch64 -filetype=obj < %s \
+// RUN: | llvm-objdump -d -M no-aliases --no-print-imm-hex - | FileCheck %s --check-prefix=CHECK-NOALIAS
// Disassemble encoding and check the re-encoding (-show-encoding) matches.
// RUN: llvm-mc -triple=aarch64 -show-encoding < %s \
// RUN: | sed '/.text/d' | sed 's/.*encoding: //g' \
@@ -147,20 +149,25 @@ sysp #0, c8, c0, #0, x30, x31
sysp #0, c8, c0, #0, x31, x31
// CHECK-INST: sysp #0, c8, c0, #0
+// CHECK-NOALIAS: sysp #0, c8, c0, #0, xzr, xzr
// CHECK-ENCODING: encoding: [0x1f,0x80,0x48,0xd5]
sysp #0, c8, c0, #0, xzr, xzr
// CHECK-INST: sysp #0, c8, c0, #0
+// CHECK-NOALIAS: sysp #0, c8, c0, #0, xzr, xzr
// CHECK-ENCODING: encoding: [0x1f,0x80,0x48,0xd5]
sysp #0, c8, c0, #0, x31, xzr
// CHECK-INST: sysp #0, c8, c0, #0
+// CHECK-NOALIAS: sysp #0, c8, c0, #0, xzr, xzr
// CHECK-ENCODING: encoding: [0x1f,0x80,0x48,0xd5]
sysp #0, c8, c0, #0, xzr, x31
// CHECK-INST: sysp #0, c8, c0, #0
+// CHECK-NOALIAS: sysp #0, c8, c0, #0, xzr, xzr
// CHECK-ENCODING: encoding: [0x1f,0x80,0x48,0xd5]
sysp #0, c8, c0, #0
// CHECK-INST: sysp #0, c8, c0, #0
+// CHECK-NOALIAS: sysp #0, c8, c0, #0, xzr, xzr
// CHECK-ENCODING: encoding: [0x1f,0x80,0x48,0xd5]
>From 5a19517bea743846ee3b19058a31fe00e9994f28 Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Thu, 12 Mar 2026 13:43:48 +0000
Subject: [PATCH 06/17] fixup! Address PR comments
---
llvm/lib/Target/AArch64/AArch64InstrFormats.td | 14 +++++---------
.../Target/AArch64/AsmParser/AArch64AsmParser.cpp | 5 ++---
.../AArch64/Disassembler/AArch64Disassembler.cpp | 3 +--
llvm/test/MC/AArch64/armv9-sysp-diagnostics.s | 2 +-
4 files changed, 9 insertions(+), 15 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index 75ce0e76dc164..63641cbbbf3db 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -2138,23 +2138,19 @@ def sys_cr_op : Operand<i32>, TImmLeaf<i32, [{
return ((uint32_t)Imm) < 16;
}]> {
let PrintMethod = "printSysCROperand";
- let ParserMatchClass = SysCR0_15AsmOperand;
+ let ParserMatchClass = SysCRAsmOperand<0, 15>;
let OperandType = "OPERAND_IMMEDIATE";
}
-def sysp_crn_op : Operand<i32>, ImmLeaf<i32, [{
- return Imm == 8 || Imm == 9;
-}]> {
+def sysp_crn_op : Operand<i32> {
let PrintMethod = "printSysCROperand";
- let ParserMatchClass = SysCRn8_9AsmOperand;
+ let ParserMatchClass = SysCRAsmOperand<8, 9>;
let OperandType = "OPERAND_IMMEDIATE";
}
-def sysp_crm_op : Operand<i32>, ImmLeaf<i32, [{
- return Imm >= 0 && Imm <= 7;
-}]> {
+def sysp_crm_op : Operand<i32> {
let PrintMethod = "printSysCROperand";
- let ParserMatchClass = SysCRm0_7AsmOperand;
+ let ParserMatchClass = SysCRAsmOperand<0, 7>;
let OperandType = "OPERAND_IMMEDIATE";
}
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index 8659ea6c6832b..2c1018bb47c1f 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -1551,9 +1551,8 @@ class AArch64Operand : public MCParsedAsmOperand {
bool isTokenEqual(StringRef Str) const {
return Kind == k_Token && getToken() == Str;
}
- bool isSysCR() const { return Kind == k_SysCR; }
template <unsigned low, unsigned high> bool isSysCRInRange() const {
- if (!isSysCR())
+ if (Kind != k_SysCR)
return false;
unsigned Val = getSysCR();
return Val >= low && Val <= high;
@@ -6322,7 +6321,7 @@ bool AArch64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode,
case Match_InvalidImmM1_62:
return Error(Loc, "immediate must be an integer in range [-1, 62].");
case Match_InvalidSysCR0_7:
- return Error(Loc, "expected cM operand where 0 <= M <= 7");
+ return Error(Loc, "expected cN operand where 0 <= N <= 7");
case Match_InvalidSysCR8_9:
return Error(Loc, "expected cN operand where 8 <= N <= 9");
case Match_InvalidSysCR0_15:
diff --git a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
index e95a0c87c6c6c..a95096e0f6120 100644
--- a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
+++ b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
@@ -1396,10 +1396,9 @@ static DecodeStatus DecodeSyspInstruction(MCInst &Inst, uint32_t insn,
unsigned op2 = fieldFromInstruction(insn, 5, 3);
unsigned Rt = fieldFromInstruction(insn, 0, 5);
- if (op1 > 6 || (CRn != 8 && CRn != 9) || CRm > 7 || op2 > 7)
+ if (op1 > 6 || (CRn != 8 && CRn != 9) || CRm > 7)
return Fail;
- // SYSP register pairs follow the same encoding constraints as XSeqPairsClass:
// the first register must be even-numbered, except for the XZR/XZR case.
if (Rt != 31 && (Rt & 0x1))
return Fail;
diff --git a/llvm/test/MC/AArch64/armv9-sysp-diagnostics.s b/llvm/test/MC/AArch64/armv9-sysp-diagnostics.s
index 2426acce2d95e..d3af63a994f5b 100644
--- a/llvm/test/MC/AArch64/armv9-sysp-diagnostics.s
+++ b/llvm/test/MC/AArch64/armv9-sysp-diagnostics.s
@@ -32,7 +32,7 @@ sysp #0, c7, c0, #0, x0, x1
sysp #0, c10, c0, #0, x0, x1
// ERRORS: error: expected cN operand where 8 <= N <= 9
sysp #0, c8, c8, #0, x0, x1
-// ERRORS: error: expected cM operand where 0 <= M <= 7
+// ERRORS: error: expected cN operand where 0 <= N <= 7
sysp #0, c8, c0, #8, x0, x1
// ERRORS: error: immediate must be an integer in range [0, 7].
sysp #0, c8, c0, #0, xzr,
>From c107ace8e17ae6931e25f29b1bff94982b40d9dd Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Mon, 23 Mar 2026 15:05:29 +0000
Subject: [PATCH 07/17] fixup! Fixes after rebasing following Marian's change
---
llvm/lib/Target/AArch64/AArch64InstrFormats.td | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index 63641cbbbf3db..eee3a33e0c3d9 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -2138,19 +2138,19 @@ def sys_cr_op : Operand<i32>, TImmLeaf<i32, [{
return ((uint32_t)Imm) < 16;
}]> {
let PrintMethod = "printSysCROperand";
- let ParserMatchClass = SysCRAsmOperand<0, 15>;
+ let ParserMatchClass = SysCR0_15AsmOperand;
let OperandType = "OPERAND_IMMEDIATE";
}
def sysp_crn_op : Operand<i32> {
let PrintMethod = "printSysCROperand";
- let ParserMatchClass = SysCRAsmOperand<8, 9>;
+ let ParserMatchClass = SysCRn8_9AsmOperand;
let OperandType = "OPERAND_IMMEDIATE";
}
def sysp_crm_op : Operand<i32> {
let PrintMethod = "printSysCROperand";
- let ParserMatchClass = SysCRAsmOperand<0, 7>;
+ let ParserMatchClass = SysCRm0_7AsmOperand;
let OperandType = "OPERAND_IMMEDIATE";
}
>From 28a27f583c6160f943cbc536d38afa9d2918267f Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Tue, 24 Mar 2026 13:27:27 +0000
Subject: [PATCH 08/17] fixup! Improve error parsing
---
.../AArch64/AsmParser/AArch64AsmParser.cpp | 71 ++++++++++++-------
llvm/test/MC/AArch64/armv9-sysp-diagnostics.s | 24 +++----
2 files changed, 58 insertions(+), 37 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index 2c1018bb47c1f..13a5a7449d38e 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -3305,46 +3305,65 @@ ParseStatus AArch64AsmParser::tryParsePSBHint(OperandVector &Operands) {
}
ParseStatus AArch64AsmParser::tryParseSyspPair(OperandVector &Operands) {
- SMLoc StartLoc = getLoc();
+ SMLoc S = getLoc();
+
+ if (getTok().isNot(AsmToken::Identifier))
+ return Error(S, "expected register");
MCRegister FirstReg;
- MCRegister SecondReg;
+ ParseStatus Res = tryParseScalarRegister(FirstReg);
+ if (!Res.isSuccess())
+ return Error(S,
+ "expected xzr/xzr or the first even register of a consecutive "
+ "64-bit register pair");
+
const MCRegisterInfo *RI = getContext().getRegisterInfo();
const MCRegisterClass &XRegClass =
AArch64MCRegisterClasses[AArch64::GPR64RegClassID];
+ if (!XRegClass.contains(FirstReg))
+ return Error(S,
+ "expected xzr/xzr or the first even register of a consecutive "
+ "64-bit register pair");
- auto RegTok = getTok(); // in case we need to backtrack
- if (!tryParseScalarRegister(FirstReg).isSuccess())
- return ParseStatus::NoMatch;
+ unsigned FirstEncoding = RI->getEncodingValue(FirstReg);
+ bool IsXZRPair = FirstReg == AArch64::XZR;
+ if (!IsXZRPair && (FirstEncoding & 1))
+ return Error(S,
+ "expected xzr/xzr or the first even register of a consecutive "
+ "64-bit register pair");
- if (!XRegClass.contains(FirstReg)) {
- getLexer().UnLex(RegTok);
- return ParseStatus::NoMatch;
- }
+ if (getTok().isNot(AsmToken::Comma))
+ return Error(getLoc(), "expected comma");
+ Lex();
- if (parseComma())
- return ParseStatus::Failure;
+ SMLoc E = getLoc();
+ MCRegister SecondReg;
+ Res = tryParseScalarRegister(SecondReg);
+ if (!Res.isSuccess())
+ return Error(
+ E, IsXZRPair ? "expected second xzr in xzr/xzr register pair"
+ : "expected second odd register of a consecutive 64-bit "
+ "register pair");
- if (!tryParseScalarRegister(SecondReg).isSuccess())
- return TokError("expected register operand");
+ if (!XRegClass.contains(SecondReg))
+ return Error(
+ E, IsXZRPair ? "expected second xzr in xzr/xzr register pair"
+ : "expected second odd register of a consecutive 64-bit "
+ "register pair");
- if (FirstReg == AArch64::XZR) {
+ if (IsXZRPair) {
if (SecondReg != AArch64::XZR)
- return TokError("xzr must be followed by xzr");
+ return Error(E, "expected second xzr in xzr/xzr register pair");
// The SYSP alias is UNDEFINED if Rt<0> == '1' && Rt != '11111'.
- } else if (RI->getEncodingValue(FirstReg) & 1) {
- return TokError("first register must be even-numbered or xzr");
- } else if (!XRegClass.contains(SecondReg) ||
- RI->getEncodingValue(SecondReg) !=
- RI->getEncodingValue(FirstReg) + 1) {
- return TokError(
- "second register must be the next consecutive register after the "
- "first register");
+ } else if (RI->getEncodingValue(SecondReg) != FirstEncoding + 1) {
+ return Error(
+ E,
+ "expected second odd register of a consecutive 64-bit register pair");
}
// SYSP encodes only the first register; the second is implied as Rt+1.
- Operands.push_back(AArch64Operand::CreateReg(
- FirstReg, RegKind::Scalar, StartLoc, getLoc(), getContext()));
+ Operands.push_back(AArch64Operand::CreateReg(FirstReg, RegKind::Scalar, S,
+ getLoc(), getContext()));
return ParseStatus::Success;
}
@@ -4281,6 +4300,8 @@ bool AArch64AsmParser::parseSyspAlias(StringRef Name, SMLoc NameLoc,
if (Tok.isNot(AsmToken::Identifier))
return TokError("expected register identifier");
auto Result = tryParseSyspPair(Operands);
+ if (Result.isFailure())
+ return true;
if (!Result.isSuccess())
return TokError("specified " + Mnemonic +
" op requires a pair of registers");
diff --git a/llvm/test/MC/AArch64/armv9-sysp-diagnostics.s b/llvm/test/MC/AArch64/armv9-sysp-diagnostics.s
index d3af63a994f5b..498f090762764 100644
--- a/llvm/test/MC/AArch64/armv9-sysp-diagnostics.s
+++ b/llvm/test/MC/AArch64/armv9-sysp-diagnostics.s
@@ -8,23 +8,23 @@
// For sysp, op0 is 0
sysp #0, c8, c0, #0, x0, x2
-// ERRORS: error: second register must be the next consecutive register after the first register
+// ERRORS: error: expected second odd register of a consecutive 64-bit register pair
sysp #4, c8, c4, #1, x1, x2
-// ERRORS: error: first register must be even-numbered or xzr
+// ERRORS: error: expected xzr/xzr or the first even register of a consecutive 64-bit register pair
sysp #4, c8, c4, #1, x2, x4
-// ERRORS: error: second register must be the next consecutive register after the first register
+// ERRORS: error: expected second odd register of a consecutive 64-bit register pair
sysp #0, c8, c0, #0, x29, x31
-// ERRORS: error: first register must be even-numbered or xzr
+// ERRORS: error: expected xzr/xzr or the first even register of a consecutive 64-bit register pair
sysp #0, c8, c0, #0, x30, x30
-// ERRORS: error: second register must be the next consecutive register after the first register
+// ERRORS: error: expected second odd register of a consecutive 64-bit register pair
sysp #0, c8, c0, #0, x31, x0
-// ERRORS: error: xzr must be followed by xzr
+// ERRORS: error: expected second xzr in xzr/xzr register pair
sysp #4, c8, c4, #1, xzr, x1
-// ERRORS: error: xzr must be followed by xzr
+// ERRORS: error: expected second xzr in xzr/xzr register pair
sysp #0, c8, c0, #0, xzr, x30
-// ERRORS: error: xzr must be followed by xzr
+// ERRORS: error: expected second xzr in xzr/xzr register pair
sysp #0, c8, c0, #0, w0, w1
-// ERRORS: error: invalid operand for instruction
+// ERRORS: error: expected xzr/xzr or the first even register of a consecutive 64-bit register pair
sysp #7, c8, c0, #0, x0, x1
// ERRORS: error: immediate must be an integer in range [0, 6].
sysp #0, c7, c0, #0, x0, x1
@@ -36,7 +36,7 @@ sysp #0, c8, c8, #0, x0, x1
sysp #0, c8, c0, #8, x0, x1
// ERRORS: error: immediate must be an integer in range [0, 7].
sysp #0, c8, c0, #0, xzr,
-// ERRORS: error: expected register operand
+// ERRORS: error: expected second xzr in xzr/xzr register pair
tlbip RVAE3IS
// ERRORS: error: expected comma
@@ -45,9 +45,9 @@ tlbip RVAE3IS,
tlbip VAE3,
// ERRORS: error: expected register identifier
tlbip IPAS2E1, x4, x8
-// ERRORS: error: specified tlbip op requires a pair of registers
+// ERRORS: error: expected second odd register of a consecutive 64-bit register pair
tlbip RVAE3, x11, x11
-// ERRORS: error: specified tlbip op requires a pair of registers
+// ERRORS: error: expected xzr/xzr or the first even register of a consecutive 64-bit register pair
sysp #0, c8, c0, #0, x0
// ERRORS: error: expected comma
>From 8a239f894443596012bf4269db95f80483b9d570 Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Thu, 2 Apr 2026 16:15:13 +0100
Subject: [PATCH 09/17] fixup! Implement Marian's suggestion to implement as
XSeqPairsClass + [XZR, XZR]
---
.../lib/Target/AArch64/AArch64RegisterInfo.td | 9 +-
.../AArch64/AsmParser/AArch64AsmParser.cpp | 142 +++++++-----------
.../Disassembler/AArch64Disassembler.cpp | 21 +--
.../MCTargetDesc/AArch64InstPrinter.cpp | 108 +++++--------
.../AArch64/MCTargetDesc/AArch64InstPrinter.h | 4 +-
llvm/test/MC/AArch64/armv9a-sysp.s | 7 -
6 files changed, 112 insertions(+), 179 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
index cc2798de60943..c43da765def2c 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
@@ -813,6 +813,13 @@ def XSeqPairsClass : RegisterClass<"AArch64", [untyped], 64,
(add XSeqPairs)>{
let Size = 128;
}
+def SyspPairsClass : RegisterClass<"AArch64", [untyped], 64,
+ (add XSeqPairs, XZR)>{
+ let Size = 128;
+ let isAllocatable = 0;
+ let GeneratePressureSet = 0;
+ let CopyCost = -1;
+}
let RenderMethod = "addRegOperands", ParserMethod="tryParseGPRSeqPair" in {
@@ -839,7 +846,7 @@ def SyspPairOperandMatcherClass : AsmOperandClass {
let ParserMethod = "tryParseSyspPair";
}
def SyspPairOperand :
- RegisterOperand<GPR64, "printSyspPair"> {
+ RegisterOperand<SyspPairsClass, "printGPRSeqPairsClassOperand<64>"> {
let ParserMatchClass = SyspPairOperandMatcherClass;
}
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index 13a5a7449d38e..c7f8e9befb836 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -281,6 +281,12 @@ class AArch64AsmParser : public MCTargetAsmParser {
ParseStatus tryParseVectorIndex(OperandVector &Operands);
ParseStatus tryParseGPRSeqPair(OperandVector &Operands);
ParseStatus tryParseSyspPair(OperandVector &Operands);
+ ParseStatus tryParseConsecutiveGPRSeqPair(OperandVector &Operands,
+ std::optional<unsigned> WPairClass,
+ unsigned XPairClass,
+ bool AllowXZRPair,
+ StringRef FirstRegExpected,
+ StringRef SecondRegExpected);
template <bool ParseShiftExtend,
RegConstraintEqualityTy EqTy = RegConstraintEqualityTy::EqualsReg>
ParseStatus tryParseGPROperand(OperandVector &Operands);
@@ -1452,7 +1458,11 @@ class AArch64Operand : public MCParsedAsmOperand {
.contains(Reg.Reg);
}
- bool isSyspPair() const { return isGPR64<AArch64::GPR64RegClassID>(); }
+ bool isSyspPair() const {
+ return Kind == k_Register && Reg.Kind == RegKind::Scalar &&
+ getAArch64MCRegisterClass(AArch64::SyspPairsClassRegClassID)
+ .contains(Reg.Reg);
+ }
template<int64_t Angle, int64_t Remainder>
DiagnosticPredicate isComplexRotation() const {
@@ -3305,67 +3315,12 @@ ParseStatus AArch64AsmParser::tryParsePSBHint(OperandVector &Operands) {
}
ParseStatus AArch64AsmParser::tryParseSyspPair(OperandVector &Operands) {
- SMLoc S = getLoc();
-
- if (getTok().isNot(AsmToken::Identifier))
- return Error(S, "expected register");
-
- MCRegister FirstReg;
- ParseStatus Res = tryParseScalarRegister(FirstReg);
- if (!Res.isSuccess())
- return Error(S,
- "expected xzr/xzr or the first even register of a consecutive "
- "64-bit register pair");
-
- const MCRegisterInfo *RI = getContext().getRegisterInfo();
- const MCRegisterClass &XRegClass =
- AArch64MCRegisterClasses[AArch64::GPR64RegClassID];
- if (!XRegClass.contains(FirstReg))
- return Error(S,
- "expected xzr/xzr or the first even register of a consecutive "
- "64-bit register pair");
-
- unsigned FirstEncoding = RI->getEncodingValue(FirstReg);
- bool IsXZRPair = FirstReg == AArch64::XZR;
- if (!IsXZRPair && (FirstEncoding & 1))
- return Error(S,
- "expected xzr/xzr or the first even register of a consecutive "
- "64-bit register pair");
-
- if (getTok().isNot(AsmToken::Comma))
- return Error(getLoc(), "expected comma");
- Lex();
-
- SMLoc E = getLoc();
- MCRegister SecondReg;
- Res = tryParseScalarRegister(SecondReg);
- if (!Res.isSuccess())
- return Error(
- E, IsXZRPair ? "expected second xzr in xzr/xzr register pair"
- : "expected second odd register of a consecutive 64-bit "
- "register pair");
-
- if (!XRegClass.contains(SecondReg))
- return Error(
- E, IsXZRPair ? "expected second xzr in xzr/xzr register pair"
- : "expected second odd register of a consecutive 64-bit "
- "register pair");
-
- if (IsXZRPair) {
- if (SecondReg != AArch64::XZR)
- return Error(E, "expected second xzr in xzr/xzr register pair");
- // The SYSP alias is UNDEFINED if Rt<0> == '1' && Rt != '11111'.
- } else if (RI->getEncodingValue(SecondReg) != FirstEncoding + 1) {
- return Error(
- E,
- "expected second odd register of a consecutive 64-bit register pair");
- }
-
- // SYSP encodes only the first register; the second is implied as Rt+1.
- Operands.push_back(AArch64Operand::CreateReg(FirstReg, RegKind::Scalar, S,
- getLoc(), getContext()));
-
- return ParseStatus::Success;
+ return tryParseConsecutiveGPRSeqPair(
+ Operands, std::nullopt, AArch64::XSeqPairsClassRegClassID,
+ /*AllowXZRPair=*/true,
+ "expected xzr/xzr or the first even register of a consecutive 64-bit "
+ "register pair",
+ "expected second odd register of a consecutive 64-bit register pair");
}
/// tryParseBTIHint - Try to parse a BTI operand, mapped to Hint command
@@ -8735,6 +8690,19 @@ unsigned AArch64AsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
}
ParseStatus AArch64AsmParser::tryParseGPRSeqPair(OperandVector &Operands) {
+ return tryParseConsecutiveGPRSeqPair(
+ Operands, AArch64::WSeqPairsClassRegClassID,
+ AArch64::XSeqPairsClassRegClassID, /*AllowXZRPair=*/false,
+ "expected first even register of a consecutive same-size even/odd "
+ "register pair",
+ "expected second odd register of a consecutive same-size even/odd "
+ "register pair");
+}
+
+ParseStatus AArch64AsmParser::tryParseConsecutiveGPRSeqPair(
+ OperandVector &Operands, std::optional<unsigned> WPairClass,
+ unsigned XPairClass, bool AllowXZRPair, StringRef FirstRegExpected,
+ StringRef SecondRegExpected) {
SMLoc S = getLoc();
@@ -8744,54 +8712,56 @@ ParseStatus AArch64AsmParser::tryParseGPRSeqPair(OperandVector &Operands) {
MCRegister FirstReg;
ParseStatus Res = tryParseScalarRegister(FirstReg);
if (!Res.isSuccess())
- return Error(S, "expected first even register of a consecutive same-size "
- "even/odd register pair");
+ return Error(S, FirstRegExpected);
const MCRegisterClass &WRegClass =
getAArch64MCRegisterClass(AArch64::GPR32RegClassID);
const MCRegisterClass &XRegClass =
getAArch64MCRegisterClass(AArch64::GPR64RegClassID);
- bool isXReg = XRegClass.contains(FirstReg),
- isWReg = WRegClass.contains(FirstReg);
- if (!isXReg && !isWReg)
- return Error(S, "expected first even register of a consecutive same-size "
- "even/odd register pair");
+ bool IsXZRPair = AllowXZRPair && FirstReg == AArch64::XZR;
+ bool IsXReg = XRegClass.contains(FirstReg);
+ bool IsWReg = WPairClass && WRegClass.contains(FirstReg);
+ if (!IsXZRPair && !IsXReg && !IsWReg)
+ return Error(S, FirstRegExpected);
const MCRegisterInfo *RI = getContext().getRegisterInfo();
unsigned FirstEncoding = RI->getEncodingValue(FirstReg);
- if (FirstEncoding & 0x1)
- return Error(S, "expected first even register of a consecutive same-size "
- "even/odd register pair");
+ if (!IsXZRPair && (FirstEncoding & 0x1))
+ return Error(S, FirstRegExpected);
if (getTok().isNot(AsmToken::Comma))
return Error(getLoc(), "expected comma");
- // Eat the comma
Lex();
SMLoc E = getLoc();
MCRegister SecondReg;
Res = tryParseScalarRegister(SecondReg);
if (!Res.isSuccess())
- return Error(E, "expected second odd register of a consecutive same-size "
- "even/odd register pair");
+ return Error(E, IsXZRPair ? "expected second xzr in xzr/xzr register pair"
+ : SecondRegExpected);
+
+ if (IsXZRPair) {
+ if (!XRegClass.contains(SecondReg) || SecondReg != AArch64::XZR)
+ return Error(E, "expected second xzr in xzr/xzr register pair");
+ Operands.push_back(AArch64Operand::CreateReg(AArch64::XZR, RegKind::Scalar,
+ S, getLoc(), getContext()));
+ return ParseStatus::Success;
+ }
if (RI->getEncodingValue(SecondReg) != FirstEncoding + 1 ||
- (isXReg && !XRegClass.contains(SecondReg)) ||
- (isWReg && !WRegClass.contains(SecondReg)))
- return Error(E, "expected second odd register of a consecutive same-size "
- "even/odd register pair");
+ (IsXReg && !XRegClass.contains(SecondReg)) ||
+ (IsWReg && !WRegClass.contains(SecondReg)))
+ return Error(E, SecondRegExpected);
MCRegister Pair;
- if (isXReg) {
- Pair = RI->getMatchingSuperReg(
- FirstReg, AArch64::sube64,
- &getAArch64MCRegisterClass(AArch64::XSeqPairsClassRegClassID));
+ if (IsXReg) {
+ Pair = RI->getMatchingSuperReg(FirstReg, AArch64::sube64,
+ &getAArch64MCRegisterClass(XPairClass));
} else {
- Pair = RI->getMatchingSuperReg(
- FirstReg, AArch64::sube32,
- &getAArch64MCRegisterClass(AArch64::WSeqPairsClassRegClassID));
+ Pair = RI->getMatchingSuperReg(FirstReg, AArch64::sube32,
+ &getAArch64MCRegisterClass(*WPairClass));
}
Operands.push_back(AArch64Operand::CreateReg(Pair, RegKind::Scalar, S,
diff --git a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
index a95096e0f6120..1756583d416fa 100644
--- a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
+++ b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
@@ -1387,6 +1387,17 @@ DecodeXSeqPairsClassRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Addr,
Inst, AArch64::XSeqPairsClassRegClassID, RegNo, Addr, Decoder);
}
+static DecodeStatus
+DecodeSyspPairClassRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Addr,
+ const MCDisassembler *Decoder) {
+ if (RegNo == 31) {
+ Inst.addOperand(MCOperand::createReg(AArch64::XZR));
+ return Success;
+ }
+
+ return DecodeXSeqPairsClassRegisterClass(Inst, RegNo, Addr, Decoder);
+}
+
static DecodeStatus DecodeSyspInstruction(MCInst &Inst, uint32_t insn,
uint64_t Addr,
const MCDisassembler *Decoder) {
@@ -1399,19 +1410,11 @@ static DecodeStatus DecodeSyspInstruction(MCInst &Inst, uint32_t insn,
if (op1 > 6 || (CRn != 8 && CRn != 9) || CRm > 7)
return Fail;
- // the first register must be even-numbered, except for the XZR/XZR case.
- if (Rt != 31 && (Rt & 0x1))
- return Fail;
-
Inst.addOperand(MCOperand::createImm(op1));
Inst.addOperand(MCOperand::createImm(CRn));
Inst.addOperand(MCOperand::createImm(CRm));
Inst.addOperand(MCOperand::createImm(op2));
- // SYSP just encodes Rt. Print Rt and Rt+1 as a pair.
- DecodeSimpleRegisterClass<AArch64::GPR64RegClassID, 0, 32>(Inst, Rt, Addr,
- Decoder);
-
- return Success;
+ return DecodeSyspPairClassRegisterClass(Inst, Rt, Addr, Decoder);
}
static DecodeStatus
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
index f6154459a64b7..6c30a175d6dd4 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
@@ -101,11 +101,12 @@ void AArch64InstPrinter::printInst(const MCInst *MI, uint64_t Address,
// canonical operand list.
if (PrintAliases && MI->getOperand(4).getReg() == AArch64::XZR) {
O << "\tsysp\t";
- markup(O, Markup::Immediate) << "#" << MI->getOperand(0).getImm();
+ markup(O, Markup::Immediate) << "#" << formatImm(MI->getOperand(0).getImm());
O << ", c" << MI->getOperand(1).getImm();
O << ", c" << MI->getOperand(2).getImm();
O << ", ";
- markup(O, Markup::Immediate) << "#" << MI->getOperand(3).getImm();
+ markup(O, Markup::Immediate) << "#"
+ << formatImm(MI->getOperand(3).getImm());
printAnnotation(O, Annot);
return;
}
@@ -914,10 +915,11 @@ bool AArch64InstPrinter::printRangePrefetchAlias(const MCInst *MI,
bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
const MCSubtargetInfo &STI,
- raw_ostream &O) {
+ raw_ostream &O, bool PairOperand) {
#ifndef NDEBUG
unsigned Opcode = MI->getOpcode();
- assert(Opcode == AArch64::SYSxt && "Invalid opcode for SYS alias!");
+ assert((Opcode == AArch64::SYSxt || Opcode == AArch64::SYSPxt) &&
+ "Invalid opcode for system alias!");
#endif
const MCOperand &Op1 = MI->getOperand(0);
@@ -940,7 +942,18 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
std::string Ins;
std::string Name;
- if (CnVal == 7) {
+ if (PairOperand) {
+ if (CnVal != 8 && CnVal != 9)
+ return false;
+
+ const AArch64TLBIP::TLBIP *TLBIP =
+ AArch64TLBIP::lookupTLBIPByEncoding(Encoding);
+ if (!TLBIP || !TLBIP->haveFeatures(STI.getFeatureBits()))
+ return false;
+
+ Ins = "tlbip\t";
+ Name = std::string(AArch64TLBIP::getTLBIPStr(TLBIP->Name));
+ } else if (CnVal == 7) {
switch (CmVal) {
default:
return false;
@@ -1072,6 +1085,16 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
} else
return false;
+ std::string Str = Ins + Name;
+ llvm::transform(Str, Str.begin(), ::tolower);
+
+ if (PairOperand) {
+ O << '\t' << Str;
+ O << ", ";
+ printGPRSeqPairsClassOperand<64>(MI, 4, STI, O);
+ return true;
+ }
+
StringRef Reg = getRegisterName(MI->getOperand(4).getReg());
bool NotXZR = Reg != "xzr";
@@ -1081,9 +1104,6 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
if (NotXZR && !NeedsReg && !OptionalReg)
return false;
- std::string Str = Ins + Name;
- llvm::transform(Str, Str.begin(), ::tolower);
-
O << '\t' << Str;
// For optional registers, don't print the value if it's xzr/x31
@@ -1146,51 +1166,7 @@ bool AArch64InstPrinter::printSyslAlias(const MCInst *MI,
bool AArch64InstPrinter::printSyspAlias(const MCInst *MI,
const MCSubtargetInfo &STI,
raw_ostream &O) {
-#ifndef NDEBUG
- unsigned Opcode = MI->getOpcode();
- assert(Opcode == AArch64::SYSPxt && "Invalid opcode for SYSP alias!");
-#endif
-
- const MCOperand &Op1 = MI->getOperand(0);
- const MCOperand &Cn = MI->getOperand(1);
- const MCOperand &Cm = MI->getOperand(2);
- const MCOperand &Op2 = MI->getOperand(3);
-
- unsigned Op1Val = Op1.getImm();
- unsigned CnVal = Cn.getImm();
- unsigned CmVal = Cm.getImm();
- unsigned Op2Val = Op2.getImm();
-
- uint16_t Encoding = Op2Val;
- Encoding |= CmVal << 3;
- Encoding |= CnVal << 7;
- Encoding |= Op1Val << 11;
-
- std::string Ins;
- std::string Name;
-
- if (CnVal == 8 || CnVal == 9) {
- // TLBIP aliases
-
- const AArch64TLBIP::TLBIP *TLBIP =
- AArch64TLBIP::lookupTLBIPByEncoding(Encoding);
- if (!TLBIP || !TLBIP->haveFeatures(STI.getFeatureBits()))
- return false;
-
- Ins = "tlbip\t";
- Name = std::string(AArch64TLBIP::getTLBIPStr(TLBIP->Name));
- } else
- return false;
-
- std::string Str = Ins + Name;
- llvm::transform(Str, Str.begin(), ::tolower);
-
- O << '\t' << Str;
- O << ", ";
- // TLBIP alias keeps SYSP's pair formatting rules for the trailing operand.
- printSyspPair(MI, 4, STI, O);
-
- return true;
+ return printSysAlias(MI, STI, O, /*PairOperand=*/true);
}
template <int EltSize>
@@ -1750,6 +1726,12 @@ void AArch64InstPrinter::printGPRSeqPairsClassOperand(const MCInst *MI,
static_assert(size == 64 || size == 32,
"Template parameter must be either 32 or 64");
MCRegister Reg = MI->getOperand(OpNum).getReg();
+ if (Reg == AArch64::XZR) {
+ printRegName(O, AArch64::XZR);
+ O << ", ";
+ printRegName(O, AArch64::XZR);
+ return;
+ }
unsigned Sube = (size == 32) ? AArch64::sube32 : AArch64::sube64;
unsigned Subo = (size == 32) ? AArch64::subo32 : AArch64::subo64;
@@ -2270,26 +2252,6 @@ void AArch64InstPrinter::printGPR64x8(const MCInst *MI, unsigned OpNum,
printRegName(O, MRI.getSubReg(Reg, AArch64::x8sub_0));
}
-void AArch64InstPrinter::printSyspPair(const MCInst *MI, unsigned OpNum,
- const MCSubtargetInfo &STI,
- raw_ostream &O) {
- MCRegister Reg = MI->getOperand(OpNum).getReg();
- printRegName(O, Reg);
- O << ", ";
- if (Reg == AArch64::XZR) {
- printRegName(O, AArch64::XZR);
- return;
- }
-
- const MCRegisterClass &XRegClass =
- AArch64MCRegisterClasses[AArch64::GPR64RegClassID];
- // SYSP textual form prints the implied second register as Rt+1.
- unsigned NextRegNo = MRI.getEncodingValue(Reg) + 1;
- assert(NextRegNo < XRegClass.getNumRegs() &&
- "SYSP pair starts from an invalid GPR64 register");
- printRegName(O, XRegClass.getRegister(NextRegNo));
-}
-
void AArch64InstPrinter::printPHintOp(const MCInst *MI, unsigned OpNum,
const MCSubtargetInfo &STI,
raw_ostream &O) {
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h
index 0b34d9edfa82b..378c6f106055d 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h
@@ -51,7 +51,7 @@ class AArch64InstPrinter : public MCInstPrinter {
protected:
bool printSysAlias(const MCInst *MI, const MCSubtargetInfo &STI,
- raw_ostream &O);
+ raw_ostream &O, bool PairOperand = false);
bool printSyslAlias(const MCInst *MI, const MCSubtargetInfo &STI,
raw_ostream &O);
bool printSyspAlias(const MCInst *MI, const MCSubtargetInfo &STI,
@@ -237,8 +237,6 @@ class AArch64InstPrinter : public MCInstPrinter {
const MCSubtargetInfo &STI, raw_ostream &O);
void printGPR64x8(const MCInst *MI, unsigned OpNum,
const MCSubtargetInfo &STI, raw_ostream &O);
- void printSyspPair(const MCInst *MI, unsigned OpNum,
- const MCSubtargetInfo &STI, raw_ostream &O);
template <int Width>
void printZPRasFPR(const MCInst *MI, unsigned OpNum,
const MCSubtargetInfo &STI, raw_ostream &O);
diff --git a/llvm/test/MC/AArch64/armv9a-sysp.s b/llvm/test/MC/AArch64/armv9a-sysp.s
index 3753fcc684c4f..c01e83c92fcfd 100644
--- a/llvm/test/MC/AArch64/armv9a-sysp.s
+++ b/llvm/test/MC/AArch64/armv9a-sysp.s
@@ -2,8 +2,6 @@
// RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST
// RUN: llvm-mc -triple=aarch64 -filetype=obj < %s \
// RUN: | llvm-objdump -d --no-print-imm-hex - | FileCheck %s --check-prefix=CHECK-INST
-// RUN: llvm-mc -triple=aarch64 -filetype=obj < %s \
-// RUN: | llvm-objdump -d -M no-aliases --no-print-imm-hex - | FileCheck %s --check-prefix=CHECK-NOALIAS
// Disassemble encoding and check the re-encoding (-show-encoding) matches.
// RUN: llvm-mc -triple=aarch64 -show-encoding < %s \
// RUN: | sed '/.text/d' | sed 's/.*encoding: //g' \
@@ -149,25 +147,20 @@ sysp #0, c8, c0, #0, x30, x31
sysp #0, c8, c0, #0, x31, x31
// CHECK-INST: sysp #0, c8, c0, #0
-// CHECK-NOALIAS: sysp #0, c8, c0, #0, xzr, xzr
// CHECK-ENCODING: encoding: [0x1f,0x80,0x48,0xd5]
sysp #0, c8, c0, #0, xzr, xzr
// CHECK-INST: sysp #0, c8, c0, #0
-// CHECK-NOALIAS: sysp #0, c8, c0, #0, xzr, xzr
// CHECK-ENCODING: encoding: [0x1f,0x80,0x48,0xd5]
sysp #0, c8, c0, #0, x31, xzr
// CHECK-INST: sysp #0, c8, c0, #0
-// CHECK-NOALIAS: sysp #0, c8, c0, #0, xzr, xzr
// CHECK-ENCODING: encoding: [0x1f,0x80,0x48,0xd5]
sysp #0, c8, c0, #0, xzr, x31
// CHECK-INST: sysp #0, c8, c0, #0
-// CHECK-NOALIAS: sysp #0, c8, c0, #0, xzr, xzr
// CHECK-ENCODING: encoding: [0x1f,0x80,0x48,0xd5]
sysp #0, c8, c0, #0
// CHECK-INST: sysp #0, c8, c0, #0
-// CHECK-NOALIAS: sysp #0, c8, c0, #0, xzr, xzr
// CHECK-ENCODING: encoding: [0x1f,0x80,0x48,0xd5]
>From 868b841fbd75677332a71f30fad14363d336a457 Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Fri, 17 Apr 2026 15:30:07 +0100
Subject: [PATCH 10/17] fixup! Address PR comment about shortened `sysp` with
xzr/xzr
---
.../MCTargetDesc/AArch64InstPrinter.cpp | 33 ++++++++++---------
1 file changed, 17 insertions(+), 16 deletions(-)
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
index 6c30a175d6dd4..3e7a02e88a4c0 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
@@ -95,21 +95,6 @@ void AArch64InstPrinter::printInst(const MCInst *MI, uint64_t Address,
printAnnotation(O, Annot);
return;
}
-
- // Preserve the historic SYSP short form for the XZR/XZR encoding, but
- // only when aliases are enabled. In no-alias mode we must print the full
- // canonical operand list.
- if (PrintAliases && MI->getOperand(4).getReg() == AArch64::XZR) {
- O << "\tsysp\t";
- markup(O, Markup::Immediate) << "#" << formatImm(MI->getOperand(0).getImm());
- O << ", c" << MI->getOperand(1).getImm();
- O << ", c" << MI->getOperand(2).getImm();
- O << ", ";
- markup(O, Markup::Immediate) << "#"
- << formatImm(MI->getOperand(3).getImm());
- printAnnotation(O, Annot);
- return;
- }
}
// RPRFM overlaps PRFM (reg), so try to print it as RPRFM here.
@@ -1166,7 +1151,23 @@ bool AArch64InstPrinter::printSyslAlias(const MCInst *MI,
bool AArch64InstPrinter::printSyspAlias(const MCInst *MI,
const MCSubtargetInfo &STI,
raw_ostream &O) {
- return printSysAlias(MI, STI, O, /*PairOperand=*/true);
+ if (printSysAlias(MI, STI, O, /*PairOperand=*/true))
+ return true;
+
+ // Preserve SYSP short form for XZR/XZR encoding:
+ // sysp #op1, cN, cM, #op2
+ // instead of:
+ // sysp #op1, cN, cM, #op2, xzr, xzr
+ if (MI->getOperand(4).getReg() != AArch64::XZR)
+ return false;
+
+ O << "\tsysp\t";
+ markup(O, Markup::Immediate) << "#" << formatImm(MI->getOperand(0).getImm());
+ O << ", c" << MI->getOperand(1).getImm();
+ O << ", c" << MI->getOperand(2).getImm();
+ O << ", ";
+ markup(O, Markup::Immediate) << "#" << formatImm(MI->getOperand(3).getImm());
+ return true;
}
template <int EltSize>
>From bb3d136856bdb1d06ddbea0cf6ea64c597cd092e Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Tue, 28 Apr 2026 17:33:06 +0100
Subject: [PATCH 11/17] fixup! Remove superfluous code
---
llvm/lib/Target/AArch64/AArch64InstrFormats.td | 7 -------
1 file changed, 7 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index eee3a33e0c3d9..4d1f91469b439 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -2154,13 +2154,6 @@ def sysp_crm_op : Operand<i32> {
let OperandType = "OPERAND_IMMEDIATE";
}
-def sysp_op1 : Operand<i64>, ImmLeaf<i64, [{
- return Imm >= 0 && Imm <= 6;
-}]> {
- let ParserMatchClass = Imm0_7Operand;
- let OperandType = "OPERAND_IMMEDIATE";
-}
-
class SystemXtI<string asm>
: RtSystemI<0, (outs),
(ins imm32_0_7:$op1, sys_cr_op:$Cn, sys_cr_op:$Cm, imm32_0_7:$op2,
>From fa3e4c0ed9eb72e553773ecf321ab99c00b0bd0f Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Fri, 1 May 2026 14:33:15 +0100
Subject: [PATCH 12/17] fixup! Address Carol's PR comments
---
llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp | 3 +++
llvm/test/MC/AArch64/armv9a-tlbip.s | 5 +++++
2 files changed, 8 insertions(+)
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index c7f8e9befb836..cde3f787dc629 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -8733,11 +8733,14 @@ ParseStatus AArch64AsmParser::tryParseConsecutiveGPRSeqPair(
if (getTok().isNot(AsmToken::Comma))
return Error(getLoc(), "expected comma");
+ // Eat the comma
Lex();
SMLoc E = getLoc();
MCRegister SecondReg;
Res = tryParseScalarRegister(SecondReg);
+ // SYSP accepts either no register pair or `xzr, xzr`. The omitted form
+ // is changed to `xzr, xzr` during assembly.
if (!Res.isSuccess())
return Error(E, IsXZRPair ? "expected second xzr in xzr/xzr register pair"
: SecondRegExpected);
diff --git a/llvm/test/MC/AArch64/armv9a-tlbip.s b/llvm/test/MC/AArch64/armv9a-tlbip.s
index 8764a83809472..ed68865f22698 100644
--- a/llvm/test/MC/AArch64/armv9a-tlbip.s
+++ b/llvm/test/MC/AArch64/armv9a-tlbip.s
@@ -55,6 +55,11 @@ tlbip VAE1, x8, x9
// CHECK-TLBID: error: instruction requires: d128
// CHECK-UNKNOWN: d5488728 sysp #0, c8, c7, #1, x8, x9
+sysp #0, c8, c7, #1, x8, x9
+// CHECK-INST: tlbip vae1, x8, x9
+// CHECK-ENCODING: encoding: [0x28,0x87,0x48,0xd5]
+// CHECK-UNKNOWN: d5488728 sysp #0, c8, c7, #1, x8, x9
+
tlbip VAE1NXS, x8, x9
// CHECK-INST: tlbip vae1nxs, x8, x9
// CHECK-ENCODING: encoding: [0x28,0x97,0x48,0xd5]
>From cc0228b0a1cb7b598bf2fd0bf83baa4b4dba184a Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Fri, 1 May 2026 15:16:35 +0100
Subject: [PATCH 13/17] fixup! Update diff because SYSP definition has changed
---
.../command-disassemble-aarch64-color.s | 4 +-
.../command-disassemble-aarch64-extensions.s | 4 +-
.../lib/Target/AArch64/AArch64InstrFormats.td | 39 +--
llvm/lib/Target/AArch64/AArch64InstrInfo.td | 3 +-
.../AArch64/AsmParser/AArch64AsmParser.cpp | 13 +-
.../Disassembler/AArch64Disassembler.cpp | 3 -
llvm/test/MC/AArch64/armv9-sysp-diagnostics.s | 40 ++-
llvm/test/MC/AArch64/armv9a-sysp.s | 240 +++++++++---------
8 files changed, 159 insertions(+), 187 deletions(-)
diff --git a/lldb/test/Shell/Commands/command-disassemble-aarch64-color.s b/lldb/test/Shell/Commands/command-disassemble-aarch64-color.s
index 6ddde3d974adc..bb97680a32970 100644
--- a/lldb/test/Shell/Commands/command-disassemble-aarch64-color.s
+++ b/lldb/test/Shell/Commands/command-disassemble-aarch64-color.s
@@ -17,7 +17,7 @@ fn:
crc32b w0, w0, w0 // AEK_CRC
// AEK_CRYPTO enables a combination of other features
smin x0, x0, #0 // AEK_CSSC
- sysp #0, c8, c0, #0, x0, x1 // AEK_D128
+ sysp #0, c2, c0, #0, x0, x1 // AEK_D128
sdot v0.2s, v1.8b, v2.8b // AEK_DOTPROD
fmmla z0.s, z1.s, z2.s // AEK_F32MM
@@ -28,6 +28,6 @@ fn:
# CHECK-NEXT: [0xc] <+12>: brb iall
# CHECK-NEXT: [0x10] <+16>: crc32b [0;36mw0[0m, [0;36mw0[0m, [0;36mw0[0m
# CHECK-NEXT: [0x14] <+20>: smin [0;36mx0[0m, [0;36mx0[0m, [0;31m#0x0[0m
-# CHECK-NEXT: [0x18] <+24>: sysp [0;31m#0x0[0m, c8, c0, [0;31m#0x0[0m, [0;36mx0[0m, [0;36mx1[0m
+# CHECK-NEXT: [0x18] <+24>: sysp [0;31m#0x0[0m, c2, c0, [0;31m#0x0[0m, [0;36mx0[0m, [0;36mx1[0m
# CHECK-NEXT: [0x1c] <+28>: sdot [0;36mv0[0m.2s, [0;36mv1[0m.8b, [0;36mv2[0m.8b
# CHECK-NEXT: [0x20] <+32>: fmmla [0;36mz0[0m.s, [0;36mz1[0m.s, [0;36mz2[0m.s
diff --git a/lldb/test/Shell/Commands/command-disassemble-aarch64-extensions.s b/lldb/test/Shell/Commands/command-disassemble-aarch64-extensions.s
index 945654e905876..4e281332a33bb 100644
--- a/lldb/test/Shell/Commands/command-disassemble-aarch64-extensions.s
+++ b/lldb/test/Shell/Commands/command-disassemble-aarch64-extensions.s
@@ -17,7 +17,7 @@ fn:
crc32b w0, w0, w0 // AEK_CRC
// AEK_CRYPTO enables a combination of other features
smin x0, x0, #0 // AEK_CSSC
- sysp #0, c8, c0, #0, x0, x1 // AEK_D128
+ sysp #0, c2, c0, #0, x0, x1 // AEK_D128
sdot v0.2s, v1.8b, v2.8b // AEK_DOTPROD
fmmla z0.s, z1.s, z2.s // AEK_F32MM
fmmla z0.d, z1.d, z2.d // AEK_F64MM
@@ -72,7 +72,7 @@ lbl:
# CHECK-NEXT: brb iall
# CHECK-NEXT: crc32b w0, w0, w0
# CHECK-NEXT: smin x0, x0, #0
-# CHECK-NEXT: sysp #0x0, c8, c0, #0x0, x0, x1
+# CHECK-NEXT: sysp #0x0, c2, c0, #0x0, x0, x1
# CHECK-NEXT: sdot v0.2s, v1.8b, v2.8b
# CHECK-NEXT: fmmla z0.s, z1.s, z2.s
# CHECK-NEXT: fmmla z0.d, z1.d, z2.d
diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index 4d1f91469b439..692b89a41a5ca 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -951,7 +951,6 @@ def Imm0_1Operand : AsmImmRange<0, 1>;
def Imm1_1Operand : AsmImmRange<1, 1>;
def Imm0_3Operand : AsmImmRange<0, 3>;
def Imm1_3Operand : AsmImmRange<1, 3>;
-def Imm0_6Operand : AsmImmRange<0, 6>;
def Imm0_7Operand : AsmImmRange<0, 7>;
def Imm1_7Operand : AsmImmRange<1, 7>;
def Imm0_15Operand : AsmImmRange<0, 15>;
@@ -1185,13 +1184,6 @@ def imm0_15 : Operand<i64>, ImmLeaf<i64, [{
let ParserMatchClass = Imm0_15Operand;
}
-// imm0_6 predicate - True if the immediate is in the range [0,6]
-def imm0_6 : Operand<i64>, ImmLeaf<i64, [{
- return ((uint64_t)Imm) < 7;
-}]> {
- let ParserMatchClass = Imm0_6Operand;
-}
-
// imm0_7 predicate - True if the immediate is in the range [0,7]
def imm0_7 : Operand<i64>, ImmLeaf<i64, [{
return ((uint64_t)Imm) < 8;
@@ -2121,36 +2113,20 @@ class MSRpstateImm0_1
let DecoderNamespace = "Fallback";
}
-// SYS and SYSL generic system instructions.
-class SysCRAsmOperand<int Low, int High> : AsmOperandClass {
- let Name = "SysCR" # Low # "_" # High;
+// SYS, SYSL and SYSP generic system instructions.
+def SysCRAsmOperand : AsmOperandClass {
+ let Name = "SysCR";
let RenderMethod = "addSysCROperands";
let ParserMethod = "tryParseSysCROperand";
- let PredicateMethod = "isSysCRInRange<" # Low # "," # High # ">";
- let DiagnosticType = "InvalidSysCR" # Low # "_" # High;
+ let PredicateMethod = "isSysCRInRange<0,15>";
+ let DiagnosticType = "InvalidSysCR0_15";
}
-def SysCRm0_7AsmOperand : SysCRAsmOperand<0, 7>;
-def SysCRn8_9AsmOperand : SysCRAsmOperand<8, 9>;
-def SysCR0_15AsmOperand : SysCRAsmOperand<0, 15>;
-
def sys_cr_op : Operand<i32>, TImmLeaf<i32, [{
return ((uint32_t)Imm) < 16;
}]> {
let PrintMethod = "printSysCROperand";
- let ParserMatchClass = SysCR0_15AsmOperand;
- let OperandType = "OPERAND_IMMEDIATE";
-}
-
-def sysp_crn_op : Operand<i32> {
- let PrintMethod = "printSysCROperand";
- let ParserMatchClass = SysCRn8_9AsmOperand;
- let OperandType = "OPERAND_IMMEDIATE";
-}
-
-def sysp_crm_op : Operand<i32> {
- let PrintMethod = "printSysCROperand";
- let ParserMatchClass = SysCRm0_7AsmOperand;
+ let ParserMatchClass = SysCRAsmOperand;
let OperandType = "OPERAND_IMMEDIATE";
}
@@ -13356,8 +13332,7 @@ class BaseSYSPEncoding<bit L, string asm, string operands, dag outputs, dag inpu
}
class SystemPXtI<bit L, string asm> :
BaseSYSPEncoding<L, asm, "\t$op1, $Cn, $Cm, $op2, $Rt", (outs),
- (ins imm0_6:$op1, sysp_crn_op:$Cn, sysp_crm_op:$Cm, imm0_7:$op2,
- SyspPairOperand:$Rt)>;
+ (ins imm0_7:$op1, sys_cr_op:$Cn, sys_cr_op:$Cm, imm0_7:$op2, SyspPairOperand:$Rt)>;
//----------------------------------------------------------------------------
// 2023 Armv9.5 Extensions
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 53c3f297fd068..bd18653227354 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -11614,8 +11614,7 @@ def SYSPxt : SystemPXtI<0, "sysp"> {
}
def : InstAlias<"sysp $op1, $Cn, $Cm, $op2",
- (SYSPxt imm0_6:$op1, sysp_crn_op:$Cn, sysp_crm_op:$Cm,
- imm0_7:$op2, XZR)>;
+ (SYSPxt imm0_7:$op1, sys_cr_op:$Cn, sys_cr_op:$Cm, imm0_7:$op2, XZR)>;
//---
// 128-bit System Registers (FEAT_SYSREG128)
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index cde3f787dc629..8695d17dc2ea1 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -6270,8 +6270,6 @@ bool AArch64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode,
return Error(Loc, "immediate must be an integer in range [0, 1].");
case Match_InvalidImm0_3:
return Error(Loc, "immediate must be an integer in range [0, 3].");
- case Match_InvalidImm0_6:
- return Error(Loc, "immediate must be an integer in range [0, 6].");
case Match_InvalidImm0_7:
return Error(Loc, "immediate must be an integer in range [0, 7].");
case Match_InvalidImm0_15:
@@ -6296,10 +6294,6 @@ bool AArch64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode,
return Error(Loc, "immediate must be an integer in range [1, 64].");
case Match_InvalidImmM1_62:
return Error(Loc, "immediate must be an integer in range [-1, 62].");
- case Match_InvalidSysCR0_7:
- return Error(Loc, "expected cN operand where 0 <= N <= 7");
- case Match_InvalidSysCR8_9:
- return Error(Loc, "expected cN operand where 8 <= N <= 9");
case Match_InvalidSysCR0_15:
return Error(Loc, "expected cN operand where 0 <= N <= 15");
case Match_InvalidMemoryIndexedRange2UImm0:
@@ -7064,7 +7058,6 @@ bool AArch64AsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
case Match_InvalidImm0_0:
case Match_InvalidImm0_1:
case Match_InvalidImm0_3:
- case Match_InvalidImm0_6:
case Match_InvalidImm0_7:
case Match_InvalidImm0_15:
case Match_InvalidImm0_31:
@@ -7077,8 +7070,6 @@ bool AArch64AsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
case Match_InvalidImm1_32:
case Match_InvalidImm1_64:
case Match_InvalidImmM1_62:
- case Match_InvalidSysCR0_7:
- case Match_InvalidSysCR8_9:
case Match_InvalidSysCR0_15:
case Match_InvalidMemoryIndexedRange2UImm0:
case Match_InvalidMemoryIndexedRange2UImm1:
@@ -8739,12 +8730,12 @@ ParseStatus AArch64AsmParser::tryParseConsecutiveGPRSeqPair(
SMLoc E = getLoc();
MCRegister SecondReg;
Res = tryParseScalarRegister(SecondReg);
- // SYSP accepts either no register pair or `xzr, xzr`. The omitted form
- // is changed to `xzr, xzr` during assembly.
if (!Res.isSuccess())
return Error(E, IsXZRPair ? "expected second xzr in xzr/xzr register pair"
: SecondRegExpected);
+ // For SYSP, Rt == 31 denotes the optional-pair default. If the explicit
+ // pair starts with xzr, the derived second register must be xzr too.
if (IsXZRPair) {
if (!XRegClass.contains(SecondReg) || SecondReg != AArch64::XZR)
return Error(E, "expected second xzr in xzr/xzr register pair");
diff --git a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
index 1756583d416fa..4fb02f74d0ca6 100644
--- a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
+++ b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
@@ -1407,9 +1407,6 @@ static DecodeStatus DecodeSyspInstruction(MCInst &Inst, uint32_t insn,
unsigned op2 = fieldFromInstruction(insn, 5, 3);
unsigned Rt = fieldFromInstruction(insn, 0, 5);
- if (op1 > 6 || (CRn != 8 && CRn != 9) || CRm > 7)
- return Fail;
-
Inst.addOperand(MCOperand::createImm(op1));
Inst.addOperand(MCOperand::createImm(CRn));
Inst.addOperand(MCOperand::createImm(CRm));
diff --git a/llvm/test/MC/AArch64/armv9-sysp-diagnostics.s b/llvm/test/MC/AArch64/armv9-sysp-diagnostics.s
index 498f090762764..25c4ab7119ab3 100644
--- a/llvm/test/MC/AArch64/armv9-sysp-diagnostics.s
+++ b/llvm/test/MC/AArch64/armv9-sysp-diagnostics.s
@@ -7,35 +7,33 @@
// registers with 128-bit formats (op0, op1, Cn, Cm, op2)
// For sysp, op0 is 0
-sysp #0, c8, c0, #0, x0, x2
+sysp #0, c2, c0, #0, x0, x2
// ERRORS: error: expected second odd register of a consecutive 64-bit register pair
-sysp #4, c8, c4, #1, x1, x2
+sysp #4, c2, c0, #1, x1, x2
// ERRORS: error: expected xzr/xzr or the first even register of a consecutive 64-bit register pair
-sysp #4, c8, c4, #1, x2, x4
+sysp #4, c2, c0, #1, x2, x4
// ERRORS: error: expected second odd register of a consecutive 64-bit register pair
-sysp #0, c8, c0, #0, x29, x31
+sysp #0, c2, c0, #0, x29, x31
// ERRORS: error: expected xzr/xzr or the first even register of a consecutive 64-bit register pair
-sysp #0, c8, c0, #0, x30, x30
+sysp #0, c2, c0, #0, x30, x30
// ERRORS: error: expected second odd register of a consecutive 64-bit register pair
-sysp #0, c8, c0, #0, x31, x0
+sysp #0, c2, c0, #0, x31, x0
// ERRORS: error: expected second xzr in xzr/xzr register pair
-sysp #4, c8, c4, #1, xzr, x1
+sysp #4, c2, c0, #1, xzr, x1
// ERRORS: error: expected second xzr in xzr/xzr register pair
-sysp #0, c8, c0, #0, xzr, x30
+sysp #0, c2, c0, #0, xzr, x30
// ERRORS: error: expected second xzr in xzr/xzr register pair
-sysp #0, c8, c0, #0, w0, w1
+sysp #0, c2, c0, #0, w0, w1
// ERRORS: error: expected xzr/xzr or the first even register of a consecutive 64-bit register pair
-sysp #7, c8, c0, #0, x0, x1
-// ERRORS: error: immediate must be an integer in range [0, 6].
-sysp #0, c7, c0, #0, x0, x1
-// ERRORS: error: expected cN operand where 8 <= N <= 9
-sysp #0, c10, c0, #0, x0, x1
-// ERRORS: error: expected cN operand where 8 <= N <= 9
-sysp #0, c8, c8, #0, x0, x1
-// ERRORS: error: expected cN operand where 0 <= N <= 7
-sysp #0, c8, c0, #8, x0, x1
+sysp #8, c2, c0, #0, x0, x1
// ERRORS: error: immediate must be an integer in range [0, 7].
-sysp #0, c8, c0, #0, xzr,
+sysp #0, c16, c0, #0, x0, x1
+// ERRORS: error: Expected cN operand where 0 <= N <= 15
+sysp #0, c2, c16, #0, x0, x1
+// ERRORS: error: Expected cN operand where 0 <= N <= 15
+sysp #0, c2, c0, #8, x0, x1
+// ERRORS: error: immediate must be an integer in range [0, 7].
+sysp #0, c2, c0, #0, xzr,
// ERRORS: error: expected second xzr in xzr/xzr register pair
tlbip RVAE3IS
@@ -49,7 +47,7 @@ tlbip IPAS2E1, x4, x8
tlbip RVAE3, x11, x11
// ERRORS: error: expected xzr/xzr or the first even register of a consecutive 64-bit register pair
-sysp #0, c8, c0, #0, x0
+sysp #0, c2, c0, #0, x0
// ERRORS: error: expected comma
-sysp #0, c8, c0, #0, xzr
+sysp #0, c2, c0, #0, xzr
// ERRORS: error: expected comma
diff --git a/llvm/test/MC/AArch64/armv9a-sysp.s b/llvm/test/MC/AArch64/armv9a-sysp.s
index c01e83c92fcfd..463f98a770cd2 100644
--- a/llvm/test/MC/AArch64/armv9a-sysp.s
+++ b/llvm/test/MC/AArch64/armv9a-sysp.s
@@ -13,154 +13,166 @@
// registers with 128-bit formats (op0, op1, Cn, Cm, op2)
// For sysp, op0 is 0
-sysp #0, c8, c0, #0, x0, x1
-// CHECK-INST: sysp #0, c8, c0, #0, x0, x1
-// CHECK-ENCODING: encoding: [0x00,0x80,0x48,0xd5]
+sysp #0, c2, c0, #0, x0, x1// TTBR0_EL1 3 0 2 0 0
+// CHECK-INST: sysp #0, c2, c0, #0, x0, x1
+// CHECK-ENCODING: encoding: [0x00,0x20,0x48,0xd5]
-sysp #0, c8, c0, #1, x0, x1
-// CHECK-INST: sysp #0, c8, c0, #1, x0, x1
-// CHECK-ENCODING: encoding: [0x20,0x80,0x48,0xd5]
+sysp #0, c2, c0, #1, x0, x1// TTBR1_EL1 3 0 2 0 1
+// CHECK-INST: sysp #0, c2, c0, #1, x0, x1
+// CHECK-ENCODING: encoding: [0x20,0x20,0x48,0xd5]
-sysp #0, c9, c0, #0, x0, x1
-// CHECK-INST: sysp #0, c9, c0, #0, x0, x1
-// CHECK-ENCODING: encoding: [0x00,0x90,0x48,0xd5]
+sysp #0, c7, c4, #0, x0, x1// PAR_EL1 3 0 7 4 0
+// CHECK-INST: sysp #0, c7, c4, #0, x0, x1
+// CHECK-ENCODING: encoding: [0x00,0x74,0x48,0xd5]
-sysp #0, c8, c4, #0, x0, x1
-// CHECK-INST: sysp #0, c8, c4, #0, x0, x1
-// CHECK-ENCODING: encoding: [0x00,0x84,0x48,0xd5]
+sysp #0, c13, c0, #3, x0, x1 // RCWSMASK_EL1 3 0 13 0 3
+// CHECK-INST: sysp #0, c13, c0, #3, x0, x1
+// CHECK-ENCODING: encoding: [0x60,0xd0,0x48,0xd5]
-sysp #0, c8, c0, #3, x0, x1
-// CHECK-INST: sysp #0, c8, c0, #3, x0, x1
-// CHECK-ENCODING: encoding: [0x60,0x80,0x48,0xd5]
+sysp #0, c13, c0, #6, x0, x1 // RCWMASK_EL1 3 0 13 0 6
+// CHECK-INST: sysp #0, c13, c0, #6, x0, x1
+// CHECK-ENCODING: encoding: [0xc0,0xd0,0x48,0xd5]
-sysp #0, c8, c0, #6, x0, x1
-// CHECK-INST: sysp #0, c8, c0, #6, x0, x1
-// CHECK-ENCODING: encoding: [0xc0,0x80,0x48,0xd5]
+sysp #4, c2, c0, #0, x0, x1// TTBR0_EL2 3 4 2 0 0
+// CHECK-INST: sysp #4, c2, c0, #0, x0, x1
+// CHECK-ENCODING: encoding: [0x00,0x20,0x4c,0xd5]
-sysp #4, c8, c0, #0, x0, x1
-// CHECK-INST: sysp #4, c8, c0, #0, x0, x1
-// CHECK-ENCODING: encoding: [0x00,0x80,0x4c,0xd5]
+sysp #4, c2, c0, #1, x0, x1// TTBR1_EL2 3 4 2 0 1
+// CHECK-INST: sysp #4, c2, c0, #1, x0, x1
+// CHECK-ENCODING: encoding: [0x20,0x20,0x4c,0xd5]
-sysp #4, c8, c0, #3, x0, x1
-// CHECK-INST: sysp #4, c8, c0, #3, x0, x1
-// CHECK-ENCODING: encoding: [0x60,0x80,0x4c,0xd5]
+sysp #4, c2, c1, #0, x0, x1// VTTBR_EL2 3 4 2 1 0
+// CHECK-INST: sysp #4, c2, c1, #0, x0, x1
+// CHECK-ENCODING: encoding: [0x00,0x21,0x4c,0xd5]
-sysp #4, c8, c1, #0, x0, x1
-// CHECK-INST: sysp #4, c8, c1, #0, x0, x1
-// CHECK-ENCODING: encoding: [0x00,0x81,0x4c,0xd5]
+sysp #7, c2, c0, #0, x0, x1
+// CHECK-INST: sysp #7, c2, c0, #0, x0, x1
+// CHECK-ENCODING: encoding: [0x00,0x20,0x4f,0xd5]
-sysp #0, c8, c0, #0, x0, x1
-// CHECK-INST: sysp #0, c8, c0, #0, x0, x1
-// CHECK-ENCODING: encoding: [0x00,0x80,0x48,0xd5]
+sysp #0, c0, c0, #0, x0, x1
+// CHECK-INST: sysp #0, c0, c0, #0, x0, x1
+// CHECK-ENCODING: encoding: [0x00,0x00,0x48,0xd5]
-sysp #0, c8, c0, #1, x0, x1
-// CHECK-INST: sysp #0, c8, c0, #1, x0, x1
-// CHECK-ENCODING: encoding: [0x20,0x80,0x48,0xd5]
+sysp #0, c15, c0, #0, x0, x1
+// CHECK-INST: sysp #0, c15, c0, #0, x0, x1
+// CHECK-ENCODING: encoding: [0x00,0xf0,0x48,0xd5]
-sysp #0, c8, c4, #0, x0, x1
-// CHECK-INST: sysp #0, c8, c4, #0, x0, x1
-// CHECK-ENCODING: encoding: [0x00,0x84,0x48,0xd5]
+sysp #0, c2, c15, #0, x0, x1
+// CHECK-INST: sysp #0, c2, c15, #0, x0, x1
+// CHECK-ENCODING: encoding: [0x00,0x2f,0x48,0xd5]
-sysp #0, c8, c0, #3, x0, x1
-// CHECK-INST: sysp #0, c8, c0, #3, x0, x1
-// CHECK-ENCODING: encoding: [0x60,0x80,0x48,0xd5]
+sysp #0, c2, c0, #0, x0, x1
+// CHECK-INST: sysp #0, c2, c0, #0, x0, x1
+// CHECK-ENCODING: encoding: [0x00,0x20,0x48,0xd5]
-sysp #0, c8, c0, #6, x0, x1
-// CHECK-INST: sysp #0, c8, c0, #6, x0, x1
-// CHECK-ENCODING: encoding: [0xc0,0x80,0x48,0xd5]
+sysp #0, c2, c0, #1, x0, x1
+// CHECK-INST: sysp #0, c2, c0, #1, x0, x1
+// CHECK-ENCODING: encoding: [0x20,0x20,0x48,0xd5]
-sysp #4, c8, c0, #0, x0, x1
-// CHECK-INST: sysp #4, c8, c0, #0, x0, x1
-// CHECK-ENCODING: encoding: [0x00,0x80,0x4c,0xd5]
+sysp #0, c7, c4, #0, x0, x1
+// CHECK-INST: sysp #0, c7, c4, #0, x0, x1
+// CHECK-ENCODING: encoding: [0x00,0x74,0x48,0xd5]
-sysp #4, c8, c0, #3, x0, x1
-// CHECK-INST: sysp #4, c8, c0, #3, x0, x1
-// CHECK-ENCODING: encoding: [0x60,0x80,0x4c,0xd5]
+sysp #0, c13, c0, #3, x0, x1
+// CHECK-INST: sysp #0, c13, c0, #3, x0, x1
+// CHECK-ENCODING: encoding: [0x60,0xd0,0x48,0xd5]
-sysp #4, c8, c1, #0, x0, x1
-// CHECK-INST: sysp #4, c8, c1, #0, x0, x1
-// CHECK-ENCODING: encoding: [0x00,0x81,0x4c,0xd5]
+sysp #0, c13, c0, #6, x0, x1
+// CHECK-INST: sysp #0, c13, c0, #6, x0, x1
+// CHECK-ENCODING: encoding: [0xc0,0xd0,0x48,0xd5]
-sysp #0, c8, c0, #0, x0, x1
-// CHECK-INST: sysp #0, c8, c0, #0, x0, x1
-// CHECK-ENCODING: encoding: [0x00,0x80,0x48,0xd5]
+sysp #4, c2, c0, #0, x0, x1
+// CHECK-INST: sysp #4, c2, c0, #0, x0, x1
+// CHECK-ENCODING: encoding: [0x00,0x20,0x4c,0xd5]
-sysp #0, c8, c0, #0, x2, x3
-// CHECK-INST: sysp #0, c8, c0, #0, x2, x3
-// CHECK-ENCODING: encoding: [0x02,0x80,0x48,0xd5]
+sysp #4, c2, c0, #1, x0, x1
+// CHECK-INST: sysp #4, c2, c0, #1, x0, x1
+// CHECK-ENCODING: encoding: [0x20,0x20,0x4c,0xd5]
-sysp #0, c8, c0, #0, x4, x5
-// CHECK-INST: sysp #0, c8, c0, #0, x4, x5
-// CHECK-ENCODING: encoding: [0x04,0x80,0x48,0xd5]
+sysp #4, c2, c1, #0, x0, x1
+// CHECK-INST: sysp #4, c2, c1, #0, x0, x1
+// CHECK-ENCODING: encoding: [0x00,0x21,0x4c,0xd5]
-sysp #0, c8, c0, #0, x6, x7
-// CHECK-INST: sysp #0, c8, c0, #0, x6, x7
-// CHECK-ENCODING: encoding: [0x06,0x80,0x48,0xd5]
+sysp #0, c2, c0, #0, x0, x1
+// CHECK-INST: sysp #0, c2, c0, #0, x0, x1
+// CHECK-ENCODING: encoding: [0x00,0x20,0x48,0xd5]
-sysp #0, c8, c0, #0, x8, x9
-// CHECK-INST: sysp #0, c8, c0, #0, x8, x9
-// CHECK-ENCODING: encoding: [0x08,0x80,0x48,0xd5]
+sysp #0, c2, c0, #0, x2, x3
+// CHECK-INST: sysp #0, c2, c0, #0, x2, x3
+// CHECK-ENCODING: encoding: [0x02,0x20,0x48,0xd5]
-sysp #0, c8, c0, #0, x10, x11
-// CHECK-INST: sysp #0, c8, c0, #0, x10, x11
-// CHECK-ENCODING: encoding: [0x0a,0x80,0x48,0xd5]
+sysp #0, c2, c0, #0, x4, x5
+// CHECK-INST: sysp #0, c2, c0, #0, x4, x5
+// CHECK-ENCODING: encoding: [0x04,0x20,0x48,0xd5]
-sysp #0, c8, c0, #0, x12, x13
-// CHECK-INST: sysp #0, c8, c0, #0, x12, x13
-// CHECK-ENCODING: encoding: [0x0c,0x80,0x48,0xd5]
+sysp #0, c2, c0, #0, x6, x7
+// CHECK-INST: sysp #0, c2, c0, #0, x6, x7
+// CHECK-ENCODING: encoding: [0x06,0x20,0x48,0xd5]
-sysp #0, c8, c0, #0, x14, x15
-// CHECK-INST: sysp #0, c8, c0, #0, x14, x15
-// CHECK-ENCODING: encoding: [0x0e,0x80,0x48,0xd5]
+sysp #0, c2, c0, #0, x8, x9
+// CHECK-INST: sysp #0, c2, c0, #0, x8, x9
+// CHECK-ENCODING: encoding: [0x08,0x20,0x48,0xd5]
-sysp #0, c8, c0, #0, x16, x17
-// CHECK-INST: sysp #0, c8, c0, #0, x16, x17
-// CHECK-ENCODING: encoding: [0x10,0x80,0x48,0xd5]
+sysp #0, c2, c0, #0, x10, x11
+// CHECK-INST: sysp #0, c2, c0, #0, x10, x11
+// CHECK-ENCODING: encoding: [0x0a,0x20,0x48,0xd5]
-sysp #0, c8, c0, #0, x18, x19
-// CHECK-INST: sysp #0, c8, c0, #0, x18, x19
-// CHECK-ENCODING: encoding: [0x12,0x80,0x48,0xd5]
+sysp #0, c2, c0, #0, x12, x13
+// CHECK-INST: sysp #0, c2, c0, #0, x12, x13
+// CHECK-ENCODING: encoding: [0x0c,0x20,0x48,0xd5]
-sysp #0, c8, c0, #0, x20, x21
-// CHECK-INST: sysp #0, c8, c0, #0, x20, x21
-// CHECK-ENCODING: encoding: [0x14,0x80,0x48,0xd5]
+sysp #0, c2, c0, #0, x14, x15
+// CHECK-INST: sysp #0, c2, c0, #0, x14, x15
+// CHECK-ENCODING: encoding: [0x0e,0x20,0x48,0xd5]
-sysp #0, c8, c0, #0, x22, x23
-// CHECK-INST: sysp #0, c8, c0, #0, x22, x23
-// CHECK-ENCODING: encoding: [0x16,0x80,0x48,0xd5]
+sysp #0, c2, c0, #0, x16, x17
+// CHECK-INST: sysp #0, c2, c0, #0, x16, x17
+// CHECK-ENCODING: encoding: [0x10,0x20,0x48,0xd5]
-sysp #0, c8, c0, #0, x24, x25
-// CHECK-INST: sysp #0, c8, c0, #0, x24, x25
-// CHECK-ENCODING: encoding: [0x18,0x80,0x48,0xd5]
+sysp #0, c2, c0, #0, x18, x19
+// CHECK-INST: sysp #0, c2, c0, #0, x18, x19
+// CHECK-ENCODING: encoding: [0x12,0x20,0x48,0xd5]
-sysp #0, c8, c0, #0, x26, x27
-// CHECK-INST: sysp #0, c8, c0, #0, x26, x27
-// CHECK-ENCODING: encoding: [0x1a,0x80,0x48,0xd5]
+sysp #0, c2, c0, #0, x20, x21
+// CHECK-INST: sysp #0, c2, c0, #0, x20, x21
+// CHECK-ENCODING: encoding: [0x14,0x20,0x48,0xd5]
-sysp #0, c8, c0, #0, x28, x29
-// CHECK-INST: sysp #0, c8, c0, #0, x28, x29
-// CHECK-ENCODING: encoding: [0x1c,0x80,0x48,0xd5]
+sysp #0, c2, c0, #0, x22, x23
+// CHECK-INST: sysp #0, c2, c0, #0, x22, x23
+// CHECK-ENCODING: encoding: [0x16,0x20,0x48,0xd5]
-sysp #0, c8, c0, #0, x30, x31
-// CHECK-INST: sysp #0, c8, c0, #0, x30, xzr
-// CHECK-ENCODING: encoding: [0x1e,0x80,0x48,0xd5]
+sysp #0, c2, c0, #0, x24, x25
+// CHECK-INST: sysp #0, c2, c0, #0, x24, x25
+// CHECK-ENCODING: encoding: [0x18,0x20,0x48,0xd5]
-sysp #0, c8, c0, #0, x31, x31
-// CHECK-INST: sysp #0, c8, c0, #0
-// CHECK-ENCODING: encoding: [0x1f,0x80,0x48,0xd5]
+sysp #0, c2, c0, #0, x26, x27
+// CHECK-INST: sysp #0, c2, c0, #0, x26, x27
+// CHECK-ENCODING: encoding: [0x1a,0x20,0x48,0xd5]
-sysp #0, c8, c0, #0, xzr, xzr
-// CHECK-INST: sysp #0, c8, c0, #0
-// CHECK-ENCODING: encoding: [0x1f,0x80,0x48,0xd5]
+sysp #0, c2, c0, #0, x28, x29
+// CHECK-INST: sysp #0, c2, c0, #0, x28, x29
+// CHECK-ENCODING: encoding: [0x1c,0x20,0x48,0xd5]
-sysp #0, c8, c0, #0, x31, xzr
-// CHECK-INST: sysp #0, c8, c0, #0
-// CHECK-ENCODING: encoding: [0x1f,0x80,0x48,0xd5]
+sysp #0, c2, c0, #0, x30, x31
+// CHECK-INST: sysp #0, c2, c0, #0, x30, xzr
+// CHECK-ENCODING: encoding: [0x1e,0x20,0x48,0xd5]
-sysp #0, c8, c0, #0, xzr, x31
-// CHECK-INST: sysp #0, c8, c0, #0
-// CHECK-ENCODING: encoding: [0x1f,0x80,0x48,0xd5]
+sysp #0, c2, c0, #0, x31, x31
+// CHECK-INST: sysp #0, c2, c0, #0
+// CHECK-ENCODING: encoding: [0x1f,0x20,0x48,0xd5]
-sysp #0, c8, c0, #0
-// CHECK-INST: sysp #0, c8, c0, #0
-// CHECK-ENCODING: encoding: [0x1f,0x80,0x48,0xd5]
+sysp #0, c2, c0, #0, xzr, xzr
+// CHECK-INST: sysp #0, c2, c0, #0
+// CHECK-ENCODING: encoding: [0x1f,0x20,0x48,0xd5]
+
+sysp #0, c2, c0, #0, x31, xzr
+// CHECK-INST: sysp #0, c2, c0, #0
+// CHECK-ENCODING: encoding: [0x1f,0x20,0x48,0xd5]
+
+sysp #0, c2, c0, #0, xzr, x31
+// CHECK-INST: sysp #0, c2, c0, #0
+// CHECK-ENCODING: encoding: [0x1f,0x20,0x48,0xd5]
+
+sysp #0, c2, c0, #0
+// CHECK-INST: sysp #0, c2, c0, #0
+// CHECK-ENCODING: encoding: [0x1f,0x20,0x48,0xd5]
>From 3ac07a6980a4ee0502a8ae30be4c0c8439cd9e8f Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Fri, 1 May 2026 18:49:06 +0100
Subject: [PATCH 14/17] fixup! More optimisations spotted by Marian after the
specs changed
---
.../lib/Target/AArch64/AArch64InstrFormats.td | 11 ++-
llvm/lib/Target/AArch64/AArch64InstrInfo.td | 4 +-
.../lib/Target/AArch64/AArch64RegisterInfo.td | 9 +-
.../AArch64/AsmParser/AArch64AsmParser.cpp | 57 ++++---------
.../Disassembler/AArch64Disassembler.cpp | 46 ++++-------
.../MCTargetDesc/AArch64InstPrinter.cpp | 82 +++++++++----------
.../AArch64/MCTargetDesc/AArch64InstPrinter.h | 2 +-
7 files changed, 85 insertions(+), 126 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index 692b89a41a5ca..f4a2dfc1fbf05 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -2118,7 +2118,6 @@ def SysCRAsmOperand : AsmOperandClass {
let Name = "SysCR";
let RenderMethod = "addSysCROperands";
let ParserMethod = "tryParseSysCROperand";
- let PredicateMethod = "isSysCRInRange<0,15>";
let DiagnosticType = "InvalidSysCR0_15";
}
@@ -13318,8 +13317,11 @@ class RtSystemI128<bit L, dag oops, dag iops, string asm, string operands, list<
let Inst{22} = 0b1; // override BaseSystemI
}
-class BaseSYSPEncoding<bit L, string asm, string operands, dag outputs, dag inputs>
- : RtSystemI128<L, outputs, inputs, asm, operands> {
+class SystemPXtI<bit L, string asm> :
+ RtSystemI128<L, (outs),
+ (ins imm0_7:$op1, sys_cr_op:$Cn, sys_cr_op:$Cm, imm0_7:$op2,
+ SyspPairOperand:$Rt),
+ asm, "\t$op1, $Cn, $Cm, $op2, $Rt"> {
bits<3> op1;
bits<4> Cn;
bits<4> Cm;
@@ -13330,9 +13332,6 @@ class BaseSYSPEncoding<bit L, string asm, string operands, dag outputs, dag inpu
let Inst{11-8} = Cm;
let Inst{7-5} = op2;
}
-class SystemPXtI<bit L, string asm> :
- BaseSYSPEncoding<L, asm, "\t$op1, $Cn, $Cm, $op2, $Rt", (outs),
- (ins imm0_7:$op1, sys_cr_op:$Cn, sys_cr_op:$Cm, imm0_7:$op2, SyspPairOperand:$Rt)>;
//----------------------------------------------------------------------------
// 2023 Armv9.5 Extensions
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index bd18653227354..07f60cf9fd00e 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -11609,9 +11609,7 @@ let Predicates = [HasRCPC3, HasNEON] in {
//===----------------------------------------------------------------------===//
// 128-bit System Instructions (FEAT_SYSINSTR128)
//===----------------------------------------------------------------------===//
-def SYSPxt : SystemPXtI<0, "sysp"> {
- let DecoderMethod = "DecodeSyspInstruction";
-}
+def SYSPxt : SystemPXtI<0, "sysp">;
def : InstAlias<"sysp $op1, $Cn, $Cm, $op2",
(SYSPxt imm0_7:$op1, sys_cr_op:$Cn, sys_cr_op:$Cm, imm0_7:$op2, XZR)>;
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
index c43da765def2c..e0a21bad80faa 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
@@ -814,15 +814,14 @@ def XSeqPairsClass : RegisterClass<"AArch64", [untyped], 64,
let Size = 128;
}
def SyspPairsClass : RegisterClass<"AArch64", [untyped], 64,
- (add XSeqPairs, XZR)>{
+ (add XSeqPairs, [XZR, XZR])>{
let Size = 128;
let isAllocatable = 0;
- let GeneratePressureSet = 0;
- let CopyCost = -1;
}
-let RenderMethod = "addRegOperands", ParserMethod="tryParseGPRSeqPair" in {
+let RenderMethod = "addRegOperands",
+ ParserMethod="tryParseConsecutiveGPRSeqPair<false>" in {
def WSeqPairsAsmOperandClass : AsmOperandClass { let Name = "WSeqPair"; }
def XSeqPairsAsmOperandClass : AsmOperandClass { let Name = "XSeqPair"; }
}
@@ -843,7 +842,7 @@ def MrrsMssrPairClassOperand :
def SyspPairOperandMatcherClass : AsmOperandClass {
let Name = "SyspPair";
let RenderMethod = "addRegOperands";
- let ParserMethod = "tryParseSyspPair";
+ let ParserMethod = "tryParseConsecutiveGPRSeqPair<true>";
}
def SyspPairOperand :
RegisterOperand<SyspPairsClass, "printGPRSeqPairsClassOperand<64>"> {
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index 8695d17dc2ea1..339ffc1fc8452 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -279,14 +279,8 @@ class AArch64AsmParser : public MCTargetAsmParser {
ParseStatus tryParseGPR64sp0Operand(OperandVector &Operands);
bool tryParseNeonVectorRegister(OperandVector &Operands);
ParseStatus tryParseVectorIndex(OperandVector &Operands);
- ParseStatus tryParseGPRSeqPair(OperandVector &Operands);
- ParseStatus tryParseSyspPair(OperandVector &Operands);
- ParseStatus tryParseConsecutiveGPRSeqPair(OperandVector &Operands,
- std::optional<unsigned> WPairClass,
- unsigned XPairClass,
- bool AllowXZRPair,
- StringRef FirstRegExpected,
- StringRef SecondRegExpected);
+ template <bool AllowXZRPair>
+ ParseStatus tryParseConsecutiveGPRSeqPair(OperandVector &Operands);
template <bool ParseShiftExtend,
RegConstraintEqualityTy EqTy = RegConstraintEqualityTy::EqualsReg>
ParseStatus tryParseGPROperand(OperandVector &Operands);
@@ -1561,12 +1555,7 @@ class AArch64Operand : public MCParsedAsmOperand {
bool isTokenEqual(StringRef Str) const {
return Kind == k_Token && getToken() == Str;
}
- template <unsigned low, unsigned high> bool isSysCRInRange() const {
- if (Kind != k_SysCR)
- return false;
- unsigned Val = getSysCR();
- return Val >= low && Val <= high;
- }
+ bool isSysCR() const { return Kind == k_SysCR; }
bool isPrefetch() const { return Kind == k_Prefetch; }
bool isPSBHint() const { return Kind == k_PSBHint; }
bool isPHint() const { return Kind == k_PHint; }
@@ -3314,15 +3303,6 @@ ParseStatus AArch64AsmParser::tryParsePSBHint(OperandVector &Operands) {
return ParseStatus::Success;
}
-ParseStatus AArch64AsmParser::tryParseSyspPair(OperandVector &Operands) {
- return tryParseConsecutiveGPRSeqPair(
- Operands, std::nullopt, AArch64::XSeqPairsClassRegClassID,
- /*AllowXZRPair=*/true,
- "expected xzr/xzr or the first even register of a consecutive 64-bit "
- "register pair",
- "expected second odd register of a consecutive 64-bit register pair");
-}
-
/// tryParseBTIHint - Try to parse a BTI operand, mapped to Hint command
ParseStatus AArch64AsmParser::tryParseBTIHint(OperandVector &Operands) {
SMLoc S = getLoc();
@@ -4254,7 +4234,7 @@ bool AArch64AsmParser::parseSyspAlias(StringRef Name, SMLoc NameLoc,
if (Tok.isNot(AsmToken::Identifier))
return TokError("expected register identifier");
- auto Result = tryParseSyspPair(Operands);
+ auto Result = tryParseConsecutiveGPRSeqPair</*AllowXZRPair=*/true>(Operands);
if (Result.isFailure())
return true;
if (!Result.isSuccess())
@@ -8680,20 +8660,19 @@ unsigned AArch64AsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
}
}
-ParseStatus AArch64AsmParser::tryParseGPRSeqPair(OperandVector &Operands) {
- return tryParseConsecutiveGPRSeqPair(
- Operands, AArch64::WSeqPairsClassRegClassID,
- AArch64::XSeqPairsClassRegClassID, /*AllowXZRPair=*/false,
- "expected first even register of a consecutive same-size even/odd "
- "register pair",
- "expected second odd register of a consecutive same-size even/odd "
- "register pair");
-}
-
-ParseStatus AArch64AsmParser::tryParseConsecutiveGPRSeqPair(
- OperandVector &Operands, std::optional<unsigned> WPairClass,
- unsigned XPairClass, bool AllowXZRPair, StringRef FirstRegExpected,
- StringRef SecondRegExpected) {
+template <bool AllowXZRPair>
+ParseStatus
+AArch64AsmParser::tryParseConsecutiveGPRSeqPair(OperandVector &Operands) {
+ const char *FirstRegExpected =
+ AllowXZRPair ? "expected xzr/xzr or the first even register of a "
+ "consecutive 64-bit register pair"
+ : "expected first even register of a consecutive same-size "
+ "even/odd register pair";
+ const char *SecondRegExpected =
+ AllowXZRPair ? "expected second odd register of a consecutive 64-bit "
+ "register pair"
+ : "expected second odd register of a consecutive same-size "
+ "even/odd register pair";
SMLoc S = getLoc();
@@ -8712,7 +8691,7 @@ ParseStatus AArch64AsmParser::tryParseConsecutiveGPRSeqPair(
bool IsXZRPair = AllowXZRPair && FirstReg == AArch64::XZR;
bool IsXReg = XRegClass.contains(FirstReg);
- bool IsWReg = WPairClass && WRegClass.contains(FirstReg);
+ bool IsWReg = !AllowXZRPair && WRegClass.contains(FirstReg);
if (!IsXZRPair && !IsXReg && !IsWReg)
return Error(S, FirstRegExpected);
diff --git a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
index 4fb02f74d0ca6..1e3dc98feecbd 100644
--- a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
+++ b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
@@ -1360,10 +1360,15 @@ static DecodeStatus DecodeTestAndBranch(MCInst &Inst, uint32_t insn,
return Success;
}
+template <unsigned RegClassID, bool AllowXZRPair = false>
static DecodeStatus
-DecodeGPRSeqPairsClassRegisterClass(MCInst &Inst, unsigned RegClassID,
- unsigned RegNo, uint64_t Addr,
+DecodeGPRSeqPairsClassRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Addr,
const MCDisassembler *Decoder) {
+ if (AllowXZRPair && RegNo == 31) {
+ Inst.addOperand(MCOperand::createReg(AArch64::XZR));
+ return Success;
+ }
+
// Register number must be even (see CASP instruction)
if (RegNo & 0x1)
return Fail;
@@ -1376,42 +1381,23 @@ DecodeGPRSeqPairsClassRegisterClass(MCInst &Inst, unsigned RegClassID,
static DecodeStatus
DecodeWSeqPairsClassRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Addr,
const MCDisassembler *Decoder) {
- return DecodeGPRSeqPairsClassRegisterClass(
- Inst, AArch64::WSeqPairsClassRegClassID, RegNo, Addr, Decoder);
+ return DecodeGPRSeqPairsClassRegisterClass<AArch64::WSeqPairsClassRegClassID>(
+ Inst, RegNo, Addr, Decoder);
}
static DecodeStatus
DecodeXSeqPairsClassRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Addr,
const MCDisassembler *Decoder) {
- return DecodeGPRSeqPairsClassRegisterClass(
- Inst, AArch64::XSeqPairsClassRegClassID, RegNo, Addr, Decoder);
+ return DecodeGPRSeqPairsClassRegisterClass<AArch64::XSeqPairsClassRegClassID>(
+ Inst, RegNo, Addr, Decoder);
}
static DecodeStatus
-DecodeSyspPairClassRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Addr,
- const MCDisassembler *Decoder) {
- if (RegNo == 31) {
- Inst.addOperand(MCOperand::createReg(AArch64::XZR));
- return Success;
- }
-
- return DecodeXSeqPairsClassRegisterClass(Inst, RegNo, Addr, Decoder);
-}
-
-static DecodeStatus DecodeSyspInstruction(MCInst &Inst, uint32_t insn,
- uint64_t Addr,
- const MCDisassembler *Decoder) {
- unsigned op1 = fieldFromInstruction(insn, 16, 3);
- unsigned CRn = fieldFromInstruction(insn, 12, 4);
- unsigned CRm = fieldFromInstruction(insn, 8, 4);
- unsigned op2 = fieldFromInstruction(insn, 5, 3);
- unsigned Rt = fieldFromInstruction(insn, 0, 5);
-
- Inst.addOperand(MCOperand::createImm(op1));
- Inst.addOperand(MCOperand::createImm(CRn));
- Inst.addOperand(MCOperand::createImm(CRm));
- Inst.addOperand(MCOperand::createImm(op2));
- return DecodeSyspPairClassRegisterClass(Inst, Rt, Addr, Decoder);
+DecodeSyspPairsClassRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Addr,
+ const MCDisassembler *Decoder) {
+ return DecodeGPRSeqPairsClassRegisterClass<AArch64::XSeqPairsClassRegClassID,
+ /*AllowXZRPair=*/true>(
+ Inst, RegNo, Addr, Decoder);
}
static DecodeStatus
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
index 3e7a02e88a4c0..94f10c559736b 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
@@ -90,12 +90,11 @@ void AArch64InstPrinter::printInst(const MCInst *MI, uint64_t Address,
return;
}
- if (Opcode == AArch64::SYSPxt) {
+ if (Opcode == AArch64::SYSPxt)
if (printSyspAlias(MI, STI, O)) {
printAnnotation(O, Annot);
return;
}
- }
// RPRFM overlaps PRFM (reg), so try to print it as RPRFM here.
if ((Opcode == AArch64::PRFMroX) || (Opcode == AArch64::PRFMroW)) {
@@ -372,12 +371,7 @@ void AArch64InstPrinter::printInst(const MCInst *MI, uint64_t Address,
return;
}
- // SYSP alias printing is handled explicitly by printSyspAlias above.
- // Skip the generic alias printer for SYSPxt, because its XSeqPair aliases
- // are only valid for a subset of SYSP register pairs and can misprint
- // odd-started regs or xzr,xzr encodings.
- if (!PrintAliases || Opcode == AArch64::SYSPxt ||
- !printAliasInstr(MI, Address, STI, O))
+ if (!PrintAliases || !printAliasInstr(MI, Address, STI, O))
printInstruction(MI, Address, STI, O);
printAnnotation(O, Annot);
@@ -898,13 +892,21 @@ bool AArch64InstPrinter::printRangePrefetchAlias(const MCInst *MI,
return true;
}
+static uint16_t getSystemEncoding(const MCOperand &Op1, const MCOperand &Cn,
+ const MCOperand &Cm, const MCOperand &Op2) {
+ uint16_t Encoding = Op2.getImm();
+ Encoding |= Cn.getImm() << 7;
+ Encoding |= Cm.getImm() << 3;
+ Encoding |= Op1.getImm() << 11;
+ return Encoding;
+}
+
bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
const MCSubtargetInfo &STI,
- raw_ostream &O, bool PairOperand) {
+ raw_ostream &O) {
#ifndef NDEBUG
unsigned Opcode = MI->getOpcode();
- assert((Opcode == AArch64::SYSxt || Opcode == AArch64::SYSPxt) &&
- "Invalid opcode for system alias!");
+ assert(Opcode == AArch64::SYSxt && "Invalid opcode for SYS alias!");
#endif
const MCOperand &Op1 = MI->getOperand(0);
@@ -917,28 +919,14 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
unsigned CmVal = Cm.getImm();
unsigned Op2Val = Op2.getImm();
- uint16_t Encoding = Op2Val;
- Encoding |= CmVal << 3;
- Encoding |= CnVal << 7;
- Encoding |= Op1Val << 11;
+ uint16_t Encoding = getSystemEncoding(Op1, Cn, Cm, Op2);
bool NeedsReg = false;
bool OptionalReg = false;
std::string Ins;
std::string Name;
- if (PairOperand) {
- if (CnVal != 8 && CnVal != 9)
- return false;
-
- const AArch64TLBIP::TLBIP *TLBIP =
- AArch64TLBIP::lookupTLBIPByEncoding(Encoding);
- if (!TLBIP || !TLBIP->haveFeatures(STI.getFeatureBits()))
- return false;
-
- Ins = "tlbip\t";
- Name = std::string(AArch64TLBIP::getTLBIPStr(TLBIP->Name));
- } else if (CnVal == 7) {
+ if (CnVal == 7) {
switch (CmVal) {
default:
return false;
@@ -1073,13 +1061,6 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
std::string Str = Ins + Name;
llvm::transform(Str, Str.begin(), ::tolower);
- if (PairOperand) {
- O << '\t' << Str;
- O << ", ";
- printGPRSeqPairsClassOperand<64>(MI, 4, STI, O);
- return true;
- }
-
StringRef Reg = getRegisterName(MI->getOperand(4).getReg());
bool NotXZR = Reg != "xzr";
@@ -1113,15 +1094,10 @@ bool AArch64InstPrinter::printSyslAlias(const MCInst *MI,
const MCOperand &Cm = MI->getOperand(3);
const MCOperand &Op2 = MI->getOperand(4);
- unsigned Op1Val = Op1.getImm();
unsigned CnVal = Cn.getImm();
unsigned CmVal = Cm.getImm();
- unsigned Op2Val = Op2.getImm();
- uint16_t Encoding = Op2Val;
- Encoding |= CmVal << 3;
- Encoding |= CnVal << 7;
- Encoding |= Op1Val << 11;
+ uint16_t Encoding = getSystemEncoding(Op1, Cn, Cm, Op2);
std::string Ins;
std::string Name;
@@ -1151,8 +1127,30 @@ bool AArch64InstPrinter::printSyslAlias(const MCInst *MI,
bool AArch64InstPrinter::printSyspAlias(const MCInst *MI,
const MCSubtargetInfo &STI,
raw_ostream &O) {
- if (printSysAlias(MI, STI, O, /*PairOperand=*/true))
- return true;
+#ifndef NDEBUG
+ unsigned Opcode = MI->getOpcode();
+ assert(Opcode == AArch64::SYSPxt && "Invalid opcode for SYSP alias!");
+#endif
+
+ const MCOperand &Op1 = MI->getOperand(0);
+ const MCOperand &Cn = MI->getOperand(1);
+ const MCOperand &Cm = MI->getOperand(2);
+ const MCOperand &Op2 = MI->getOperand(3);
+
+ unsigned CnVal = Cn.getImm();
+
+ if (CnVal == 8 || CnVal == 9) {
+ const AArch64TLBIP::TLBIP *TLBIP = AArch64TLBIP::lookupTLBIPByEncoding(
+ getSystemEncoding(Op1, Cn, Cm, Op2));
+ if (TLBIP && TLBIP->haveFeatures(STI.getFeatureBits())) {
+ std::string Str = (Twine("tlbip\t") + TLBIP->Name).str();
+ llvm::transform(Str, Str.begin(), ::tolower);
+
+ O << '\t' << Str << ", ";
+ printGPRSeqPairsClassOperand<64>(MI, 4, STI, O);
+ return true;
+ }
+ }
// Preserve SYSP short form for XZR/XZR encoding:
// sysp #op1, cN, cM, #op2
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h
index 378c6f106055d..678cb18940141 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h
@@ -51,7 +51,7 @@ class AArch64InstPrinter : public MCInstPrinter {
protected:
bool printSysAlias(const MCInst *MI, const MCSubtargetInfo &STI,
- raw_ostream &O, bool PairOperand = false);
+ raw_ostream &O);
bool printSyslAlias(const MCInst *MI, const MCSubtargetInfo &STI,
raw_ostream &O);
bool printSyspAlias(const MCInst *MI, const MCSubtargetInfo &STI,
>From 4fed856e5c549ee8b1fabfb99ad0544baeb31d0e Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Mon, 29 Jun 2026 02:49:46 +0100
Subject: [PATCH 15/17] fixup! Address Marian's comments
---
llvm/lib/Target/AArch64/AArch64InstrInfo.td | 2 +-
.../lib/Target/AArch64/AArch64RegisterInfo.td | 8 +++-
.../AArch64/AsmParser/AArch64AsmParser.cpp | 47 ++++++++++---------
.../Disassembler/AArch64Disassembler.cpp | 6 ++-
.../MCTargetDesc/AArch64InstPrinter.cpp | 5 +-
5 files changed, 40 insertions(+), 28 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 07f60cf9fd00e..849b57b42f69a 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -11612,7 +11612,7 @@ let Predicates = [HasRCPC3, HasNEON] in {
def SYSPxt : SystemPXtI<0, "sysp">;
def : InstAlias<"sysp $op1, $Cn, $Cm, $op2",
- (SYSPxt imm0_7:$op1, sys_cr_op:$Cn, sys_cr_op:$Cm, imm0_7:$op2, XZR)>;
+ (SYSPxt imm0_7:$op1, sys_cr_op:$Cn, sys_cr_op:$Cm, imm0_7:$op2, XZR_XZR)>;
//---
// 128-bit System Registers (FEAT_SYSREG128)
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
index e0a21bad80faa..27257ebf84ea5 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
@@ -804,6 +804,10 @@ def WSeqPairs : RegisterTuples<[sube32, subo32],
def XSeqPairs : RegisterTuples<[sube64, subo64],
[(decimate (rotl GPR64, 0), 2),
(decimate (rotl GPR64, 1), 2)]>;
+def XZR_XZR : AArch64Reg<31, "xzr_xzr"> {
+ let isArtificial = 1;
+ let isConstant = true;
+}
def WSeqPairsClass : RegisterClass<"AArch64", [untyped], 32,
(add WSeqPairs)>{
@@ -814,8 +818,10 @@ def XSeqPairsClass : RegisterClass<"AArch64", [untyped], 64,
let Size = 128;
}
def SyspPairsClass : RegisterClass<"AArch64", [untyped], 64,
- (add XSeqPairs, [XZR, XZR])>{
+ (add XSeqPairs, XZR_XZR)>{
let Size = 128;
+ // This is an asm/disasm operand class. XZR_XZR is an artificial register
+ // used to model the SYSP Rt == 31 encoding and must not be allocated.
let isAllocatable = 0;
}
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index 339ffc1fc8452..3be1eb8241076 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -47,6 +47,7 @@
#include "llvm/Support/AArch64BuildAttributes.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/SMLoc.h"
#include "llvm/Support/raw_ostream.h"
@@ -8663,16 +8664,16 @@ unsigned AArch64AsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
template <bool AllowXZRPair>
ParseStatus
AArch64AsmParser::tryParseConsecutiveGPRSeqPair(OperandVector &Operands) {
- const char *FirstRegExpected =
- AllowXZRPair ? "expected xzr/xzr or the first even register of a "
- "consecutive 64-bit register pair"
- : "expected first even register of a consecutive same-size "
- "even/odd register pair";
- const char *SecondRegExpected =
- AllowXZRPair ? "expected second odd register of a consecutive 64-bit "
- "register pair"
- : "expected second odd register of a consecutive same-size "
- "even/odd register pair";
+ std::string FirstRegExpected =
+ formatv("expected {0}first even register of a consecutive {1} register "
+ "pair",
+ AllowXZRPair ? "xzr/xzr or the " : "",
+ AllowXZRPair ? "64-bit" : "same-size even/odd")
+ .str();
+ std::string SecondRegExpected =
+ formatv("expected second odd register of a consecutive {0} register pair",
+ AllowXZRPair ? "64-bit" : "same-size even/odd")
+ .str();
SMLoc S = getLoc();
@@ -8689,10 +8690,11 @@ AArch64AsmParser::tryParseConsecutiveGPRSeqPair(OperandVector &Operands) {
const MCRegisterClass &XRegClass =
getAArch64MCRegisterClass(AArch64::GPR64RegClassID);
- bool IsXZRPair = AllowXZRPair && FirstReg == AArch64::XZR;
+ bool IsXZR = FirstReg == AArch64::XZR;
bool IsXReg = XRegClass.contains(FirstReg);
- bool IsWReg = !AllowXZRPair && WRegClass.contains(FirstReg);
- if (!IsXZRPair && !IsXReg && !IsWReg)
+ bool IsWReg = WRegClass.contains(FirstReg);
+ bool IsXZRPair = AllowXZRPair && IsXZR;
+ if (AllowXZRPair ? (!IsXReg && !IsXZRPair) : (!IsXReg && !IsWReg))
return Error(S, FirstRegExpected);
const MCRegisterInfo *RI = getContext().getRegisterInfo();
@@ -8716,25 +8718,26 @@ AArch64AsmParser::tryParseConsecutiveGPRSeqPair(OperandVector &Operands) {
// For SYSP, Rt == 31 denotes the optional-pair default. If the explicit
// pair starts with xzr, the derived second register must be xzr too.
if (IsXZRPair) {
- if (!XRegClass.contains(SecondReg) || SecondReg != AArch64::XZR)
+ if (SecondReg != AArch64::XZR)
return Error(E, "expected second xzr in xzr/xzr register pair");
- Operands.push_back(AArch64Operand::CreateReg(AArch64::XZR, RegKind::Scalar,
- S, getLoc(), getContext()));
- return ParseStatus::Success;
}
- if (RI->getEncodingValue(SecondReg) != FirstEncoding + 1 ||
+ if ((!IsXZRPair && RI->getEncodingValue(SecondReg) != FirstEncoding + 1) ||
(IsXReg && !XRegClass.contains(SecondReg)) ||
(IsWReg && !WRegClass.contains(SecondReg)))
return Error(E, SecondRegExpected);
MCRegister Pair;
- if (IsXReg) {
- Pair = RI->getMatchingSuperReg(FirstReg, AArch64::sube64,
- &getAArch64MCRegisterClass(XPairClass));
+ if (IsXZRPair) {
+ Pair = AArch64::XZR_XZR;
+ } else if (IsXReg) {
+ Pair = RI->getMatchingSuperReg(
+ FirstReg, AArch64::sube64,
+ &getAArch64MCRegisterClass(AArch64::XSeqPairsClassRegClassID));
} else {
Pair = RI->getMatchingSuperReg(FirstReg, AArch64::sube32,
- &getAArch64MCRegisterClass(*WPairClass));
+ &getAArch64MCRegisterClass(
+ AArch64::WSeqPairsClassRegClassID));
}
Operands.push_back(AArch64Operand::CreateReg(Pair, RegKind::Scalar, S,
diff --git a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
index 1e3dc98feecbd..e1afb58d38835 100644
--- a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
+++ b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
@@ -1365,7 +1365,9 @@ static DecodeStatus
DecodeGPRSeqPairsClassRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Addr,
const MCDisassembler *Decoder) {
if (AllowXZRPair && RegNo == 31) {
- Inst.addOperand(MCOperand::createReg(AArch64::XZR));
+ const MCRegisterClass &RegClass = AArch64MCRegisterClasses[RegClassID];
+ Inst.addOperand(
+ MCOperand::createReg(RegClass.getRegister(RegClass.getNumRegs() - 1)));
return Success;
}
@@ -1395,7 +1397,7 @@ DecodeXSeqPairsClassRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Addr,
static DecodeStatus
DecodeSyspPairsClassRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Addr,
const MCDisassembler *Decoder) {
- return DecodeGPRSeqPairsClassRegisterClass<AArch64::XSeqPairsClassRegClassID,
+ return DecodeGPRSeqPairsClassRegisterClass<AArch64::SyspPairsClassRegClassID,
/*AllowXZRPair=*/true>(
Inst, RegNo, Addr, Decoder);
}
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
index 94f10c559736b..c2b0a51040268 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
@@ -1143,7 +1143,8 @@ bool AArch64InstPrinter::printSyspAlias(const MCInst *MI,
const AArch64TLBIP::TLBIP *TLBIP = AArch64TLBIP::lookupTLBIPByEncoding(
getSystemEncoding(Op1, Cn, Cm, Op2));
if (TLBIP && TLBIP->haveFeatures(STI.getFeatureBits())) {
- std::string Str = (Twine("tlbip\t") + TLBIP->Name).str();
+ std::string Str =
+ (Twine("tlbip\t") + AArch64TLBIP::getTLBIPStr(TLBIP->Name)).str();
llvm::transform(Str, Str.begin(), ::tolower);
O << '\t' << Str << ", ";
@@ -1725,7 +1726,7 @@ void AArch64InstPrinter::printGPRSeqPairsClassOperand(const MCInst *MI,
static_assert(size == 64 || size == 32,
"Template parameter must be either 32 or 64");
MCRegister Reg = MI->getOperand(OpNum).getReg();
- if (Reg == AArch64::XZR) {
+ if (Reg == AArch64::XZR_XZR) {
printRegName(O, AArch64::XZR);
O << ", ";
printRegName(O, AArch64::XZR);
>From 57256b310b8cddda7b06cfcefb556a382f843162 Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Wed, 1 Jul 2026 00:17:30 +0100
Subject: [PATCH 16/17] fixup! Small improvement
---
llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp | 4 +---
llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp | 2 +-
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
index e1afb58d38835..1755227997d18 100644
--- a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
+++ b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
@@ -1365,9 +1365,7 @@ static DecodeStatus
DecodeGPRSeqPairsClassRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Addr,
const MCDisassembler *Decoder) {
if (AllowXZRPair && RegNo == 31) {
- const MCRegisterClass &RegClass = AArch64MCRegisterClasses[RegClassID];
- Inst.addOperand(
- MCOperand::createReg(RegClass.getRegister(RegClass.getNumRegs() - 1)));
+ Inst.addOperand(MCOperand::createReg(AArch64::XZR_XZR));
return Success;
}
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
index c2b0a51040268..b8f48a3ac00c3 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
@@ -1157,7 +1157,7 @@ bool AArch64InstPrinter::printSyspAlias(const MCInst *MI,
// sysp #op1, cN, cM, #op2
// instead of:
// sysp #op1, cN, cM, #op2, xzr, xzr
- if (MI->getOperand(4).getReg() != AArch64::XZR)
+ if (MI->getOperand(4).getReg() != AArch64::XZR_XZR)
return false;
O << "\tsysp\t";
>From 22fc1ed8853aaa5af9410bfe2e23d0c944c4012c Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Wed, 1 Jul 2026 17:14:38 +0100
Subject: [PATCH 17/17] fixup! Remove XZR_XZR
---
llvm/lib/Target/AArch64/AArch64InstrInfo.td | 2 +-
llvm/lib/Target/AArch64/AArch64RegisterInfo.td | 10 +++-------
llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp | 8 ++++----
.../AArch64/Disassembler/AArch64Disassembler.cpp | 2 +-
.../Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp | 4 ++--
5 files changed, 11 insertions(+), 15 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 849b57b42f69a..07f60cf9fd00e 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -11612,7 +11612,7 @@ let Predicates = [HasRCPC3, HasNEON] in {
def SYSPxt : SystemPXtI<0, "sysp">;
def : InstAlias<"sysp $op1, $Cn, $Cm, $op2",
- (SYSPxt imm0_7:$op1, sys_cr_op:$Cn, sys_cr_op:$Cm, imm0_7:$op2, XZR_XZR)>;
+ (SYSPxt imm0_7:$op1, sys_cr_op:$Cn, sys_cr_op:$Cm, imm0_7:$op2, XZR)>;
//---
// 128-bit System Registers (FEAT_SYSREG128)
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
index 27257ebf84ea5..747a6a9950b1e 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
@@ -804,10 +804,6 @@ def WSeqPairs : RegisterTuples<[sube32, subo32],
def XSeqPairs : RegisterTuples<[sube64, subo64],
[(decimate (rotl GPR64, 0), 2),
(decimate (rotl GPR64, 1), 2)]>;
-def XZR_XZR : AArch64Reg<31, "xzr_xzr"> {
- let isArtificial = 1;
- let isConstant = true;
-}
def WSeqPairsClass : RegisterClass<"AArch64", [untyped], 32,
(add WSeqPairs)>{
@@ -818,10 +814,10 @@ def XSeqPairsClass : RegisterClass<"AArch64", [untyped], 64,
let Size = 128;
}
def SyspPairsClass : RegisterClass<"AArch64", [untyped], 64,
- (add XSeqPairs, XZR_XZR)>{
+ (add XSeqPairs, XZR)>{
let Size = 128;
- // This is an asm/disasm operand class. XZR_XZR is an artificial register
- // used to model the SYSP Rt == 31 encoding and must not be allocated.
+ // This is an asm/disasm operand class. XZR is used to model the SYSP
+ // Rt == 31 encoding and must not be allocated as a register pair.
let isAllocatable = 0;
}
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index 3be1eb8241076..acb5b5d1853e7 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -8729,15 +8729,15 @@ AArch64AsmParser::tryParseConsecutiveGPRSeqPair(OperandVector &Operands) {
MCRegister Pair;
if (IsXZRPair) {
- Pair = AArch64::XZR_XZR;
+ Pair = AArch64::XZR;
} else if (IsXReg) {
Pair = RI->getMatchingSuperReg(
FirstReg, AArch64::sube64,
&getAArch64MCRegisterClass(AArch64::XSeqPairsClassRegClassID));
} else {
- Pair = RI->getMatchingSuperReg(FirstReg, AArch64::sube32,
- &getAArch64MCRegisterClass(
- AArch64::WSeqPairsClassRegClassID));
+ Pair = RI->getMatchingSuperReg(
+ FirstReg, AArch64::sube32,
+ &getAArch64MCRegisterClass(AArch64::WSeqPairsClassRegClassID));
}
Operands.push_back(AArch64Operand::CreateReg(Pair, RegKind::Scalar, S,
diff --git a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
index 1755227997d18..16a22dab0eb8c 100644
--- a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
+++ b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
@@ -1365,7 +1365,7 @@ static DecodeStatus
DecodeGPRSeqPairsClassRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Addr,
const MCDisassembler *Decoder) {
if (AllowXZRPair && RegNo == 31) {
- Inst.addOperand(MCOperand::createReg(AArch64::XZR_XZR));
+ Inst.addOperand(MCOperand::createReg(AArch64::XZR));
return Success;
}
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
index b8f48a3ac00c3..a86d7481cd544 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
@@ -1157,7 +1157,7 @@ bool AArch64InstPrinter::printSyspAlias(const MCInst *MI,
// sysp #op1, cN, cM, #op2
// instead of:
// sysp #op1, cN, cM, #op2, xzr, xzr
- if (MI->getOperand(4).getReg() != AArch64::XZR_XZR)
+ if (MI->getOperand(4).getReg() != AArch64::XZR)
return false;
O << "\tsysp\t";
@@ -1726,7 +1726,7 @@ void AArch64InstPrinter::printGPRSeqPairsClassOperand(const MCInst *MI,
static_assert(size == 64 || size == 32,
"Template parameter must be either 32 or 64");
MCRegister Reg = MI->getOperand(OpNum).getReg();
- if (Reg == AArch64::XZR_XZR) {
+ if (Reg == AArch64::XZR) {
printRegName(O, AArch64::XZR);
O << ", ";
printRegName(O, AArch64::XZR);
More information about the llvm-commits
mailing list