[clang] [llvm] [RISCV] Add Xqccmp Assembly Support (PR #128731)

Sam Elliott via cfe-commits cfe-commits at lists.llvm.org
Wed Feb 26 14:01:13 PST 2025


https://github.com/lenary updated https://github.com/llvm/llvm-project/pull/128731

>From 6f8c6d152033505db6f6b1f8a424c01fcfc05c0d Mon Sep 17 00:00:00 2001
From: Sam Elliott <quic_aelliott at quicinc.com>
Date: Mon, 24 Feb 2025 23:07:05 -0800
Subject: [PATCH 1/8] [RISCV] Add Xqccmp Assembly Support

Xqccmp is a new spec by Qualcomm that makes a vendor-specific effort to
solve the push/pop + frame pointers issue. Broadly, it takes the Zcmp
instructions and reverse the order they push/pop registers in, which
ends up matching the frame pointer convention.

This extension adds a new instruction not present in Xqccmp,
`qc.cm.pushfp`, which will set `fp` to the incoming `sp` value after it
has pushed the registers in rlist.

This change duplicates the Zcmp implementation, with minor changes to
mnemonics (for the `qc.` prefix), predicates, and the addition of
`qc.cm.pushfp`. There is also new logic to prevent combining Xqccmp and
Zcmp. Xqccmp is kept separate to Xqci for decoding/encoding etc, as the
specs are separate today.

Specification: https://github.com/quic/riscv-unified-db/releases/tag/Xqccmp_extension-0.1.0
---
 .../Driver/print-supported-extensions-riscv.c |   1 +
 .../Target/RISCV/AsmParser/RISCVAsmParser.cpp |   2 +-
 .../RISCV/Disassembler/RISCVDisassembler.cpp  |   2 +
 llvm/lib/Target/RISCV/RISCVFeatures.td        |   8 +
 llvm/lib/Target/RISCV/RISCVInstrInfo.td       |   1 +
 llvm/lib/Target/RISCV/RISCVInstrInfoXqccmp.td |  95 +++++
 llvm/lib/TargetParser/RISCVISAInfo.cpp        |   5 +
 llvm/test/MC/RISCV/rv32xqccmp-invalid.s       |  35 ++
 llvm/test/MC/RISCV/rv32xqccmp-valid.s         | 353 ++++++++++++++++++
 llvm/test/MC/RISCV/rv64e-xqccmp-valid.s       |  85 +++++
 llvm/test/MC/RISCV/rv64xqccmp-invalid.s       |  35 ++
 llvm/test/MC/RISCV/rv64xqccmp-valid.s         | 181 +++++++++
 .../TargetParser/RISCVISAInfoTest.cpp         |   6 +
 13 files changed, 808 insertions(+), 1 deletion(-)
 create mode 100644 llvm/lib/Target/RISCV/RISCVInstrInfoXqccmp.td
 create mode 100644 llvm/test/MC/RISCV/rv32xqccmp-invalid.s
 create mode 100644 llvm/test/MC/RISCV/rv32xqccmp-valid.s
 create mode 100644 llvm/test/MC/RISCV/rv64e-xqccmp-valid.s
 create mode 100644 llvm/test/MC/RISCV/rv64xqccmp-invalid.s
 create mode 100644 llvm/test/MC/RISCV/rv64xqccmp-valid.s

diff --git a/clang/test/Driver/print-supported-extensions-riscv.c b/clang/test/Driver/print-supported-extensions-riscv.c
index fcd820464e2d1..1c29ae98c96f0 100644
--- a/clang/test/Driver/print-supported-extensions-riscv.c
+++ b/clang/test/Driver/print-supported-extensions-riscv.c
@@ -193,6 +193,7 @@
 // CHECK-NEXT:     smctr                1.0       'Smctr' (Control Transfer Records Machine Level)
 // CHECK-NEXT:     ssctr                1.0       'Ssctr' (Control Transfer Records Supervisor Level)
 // CHECK-NEXT:     svukte               0.3       'Svukte' (Address-Independent Latency of User-Mode Faults to Supervisor Addresses)
+// CHECK-NEXT:     xqccmp               0.1       'Xqccmp' (Qualcomm 16-bit Push/Pop and Double Moves)
 // CHECK-NEXT:     xqcia                0.2       'Xqcia' (Qualcomm uC Arithmetic Extension)
 // CHECK-NEXT:     xqciac               0.3       'Xqciac' (Qualcomm uC Load-Store Address Calculation Extension)
 // CHECK-NEXT:     xqcicli              0.2       'Xqcicli' (Qualcomm uC Conditional Load Immediate Extension)
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index 650ad48e50de0..697dfac48e4a0 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -3640,7 +3640,7 @@ bool RISCVAsmParser::validateInstruction(MCInst &Inst,
     }
   }
 
-  if (Opcode == RISCV::CM_MVSA01) {
+  if (Opcode == RISCV::CM_MVSA01 || Opcode == RISCV::QC_CM_MVSA01) {
     MCRegister Rd1 = Inst.getOperand(0).getReg();
     MCRegister Rd2 = Inst.getOperand(1).getReg();
     if (Rd1 == Rd2) {
diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
index 8c07d87680d65..c17e0de111a85 100644
--- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
+++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
@@ -745,6 +745,8 @@ DecodeStatus RISCVDisassembler::getInstruction16(MCInst &MI, uint64_t &Size,
                         "Qualcomm uC Conditional Move 16bit");
   TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXqciint, DecoderTableXqciint16,
                         "Qualcomm uC Interrupts 16bit");
+  TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXqccmp, DecoderTableXqccmp16,
+                        "Xqccmp (Qualcomm 16-bit Push/Pop & Double Move Instructions)");
   TRY_TO_DECODE_AND_ADD_SP(STI.hasFeature(RISCV::FeatureVendorXwchc),
                            DecoderTableXwchc16, "WCH QingKe XW");
   TRY_TO_DECODE_AND_ADD_SP(true, DecoderTable16,
diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td
index 1a93371a4d92f..2b5b7173f2a68 100644
--- a/llvm/lib/Target/RISCV/RISCVFeatures.td
+++ b/llvm/lib/Target/RISCV/RISCVFeatures.td
@@ -1374,6 +1374,14 @@ def HasVendorXqcilo
       AssemblerPredicate<(all_of FeatureVendorXqcilo),
                          "'Xqcilo' (Qualcomm uC Large Offset Load Store Extension)">;
 
+def FeatureVendorXqccmp
+    : RISCVExperimentalExtension<0, 1,
+                                 "Qualcomm 16-bit Push/Pop and Double Moves",
+                                 [FeatureStdExtZca]>;
+def HasVendorXqccmp : Predicate<"Subtarget->hasVendorXqccmp()">,
+                      AssemblerPredicate<(all_of FeatureVendorXqccmp),
+                        "'Xqccmp' (Qualcomm 16-bit Push/Pop and Double Moves)">;
+
 // Rivos Extension(s)
 
 def FeatureVendorXRivosVizip
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index a962e64581797..c84caa76b1b4d 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -2147,6 +2147,7 @@ include "RISCVInstrInfoSFB.td"
 include "RISCVInstrInfoXCV.td"
 include "RISCVInstrInfoXwch.td"
 include "RISCVInstrInfoXqci.td"
+include "RISCVInstrInfoXqccmp.td"
 include "RISCVInstrInfoXMips.td"
 include "RISCVInstrInfoXRivos.td"
 
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXqccmp.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXqccmp.td
new file mode 100644
index 0000000000000..043d985e39903
--- /dev/null
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXqccmp.td
@@ -0,0 +1,95 @@
+//===---------------- RISCVInstrInfoXqccmp.td --------------*- tablegen -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file describes Qualcomm's Xqccmp extension.
+//
+// Xqccmp is broadly equivalent to (and incompatible with) Zcmp except the
+// following changes:
+//
+// - The registers are pushed in the opposite order, so `ra` and `fp` are
+//   closest to the incoming stack pointer (to be compatible with the
+//   frame-pointer convention), and
+//
+// - There is a new `qc.cm.pushfp` instruction which is `qc.cm.push` but it sets
+//   `fp` to the incoming stack pointer value, as expected by the frame-pointer
+//   convention.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Operand and SDNode transformation definitions.
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Instruction Formats
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Instruction Class Templates
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Instructions
+//===----------------------------------------------------------------------===//
+
+// Zcmp
+let DecoderNamespace = "Xqccmp", Predicates = [HasVendorXqccmp],
+    hasSideEffects = 0, mayLoad = 0, mayStore = 0 in {
+let Defs = [X10, X11] in
+def QC_CM_MVA01S : RVInst16CA<0b101011, 0b11, 0b10, (outs),
+                              (ins SR07:$rs1, SR07:$rs2), "qc.cm.mva01s", "$rs1, $rs2">,
+                   Sched<[WriteIALU, WriteIALU, ReadIALU, ReadIALU]>;
+
+let Uses = [X10, X11] in
+def QC_CM_MVSA01 : RVInst16CA<0b101011, 0b01, 0b10, (outs SR07:$rs1, SR07:$rs2),
+                              (ins), "qc.cm.mvsa01", "$rs1, $rs2">,
+                   Sched<[WriteIALU, WriteIALU, ReadIALU, ReadIALU]>;
+} // DecoderNamespace = "Xqccmp", Predicates = [HasVendorXqccmp]...
+
+let DecoderNamespace = "Xqccmp", Predicates = [HasVendorXqccmp] in {
+let hasSideEffects = 0, mayLoad = 0, mayStore = 1, Uses = [X2], Defs = [X2] in
+def QC_CM_PUSH : RVInstZcCPPP<0b11000, "qc.cm.push", negstackadj>,
+                 Sched<[WriteIALU, ReadIALU, ReadStoreData, ReadStoreData,
+                        ReadStoreData, ReadStoreData, ReadStoreData, ReadStoreData,
+                        ReadStoreData, ReadStoreData, ReadStoreData, ReadStoreData,
+                        ReadStoreData, ReadStoreData, ReadStoreData]>;
+
+let hasSideEffects = 0, mayLoad = 0, mayStore = 1, Uses = [X2], Defs = [X2, X8] in
+def QC_CM_PUSHFP : RVInstZcCPPP<0b11001, "qc.cm.pushfp", negstackadj>,
+                   Sched<[WriteIALU, WriteIALU, ReadIALU, ReadStoreData, ReadStoreData,
+                          ReadStoreData, ReadStoreData, ReadStoreData, ReadStoreData,
+                          ReadStoreData, ReadStoreData, ReadStoreData, ReadStoreData,
+                          ReadStoreData, ReadStoreData, ReadStoreData]>;
+
+let hasSideEffects = 0, mayLoad = 1, mayStore = 0, isReturn = 1,
+    Uses = [X2], Defs = [X2] in
+def QC_CM_POPRET : RVInstZcCPPP<0b11110, "qc.cm.popret">,
+                   Sched<[WriteIALU, WriteLDW, WriteLDW, WriteLDW, WriteLDW,
+                          WriteLDW, WriteLDW, WriteLDW, WriteLDW, WriteLDW,
+                          WriteLDW, WriteLDW, WriteLDW, WriteLDW, ReadIALU]>;
+
+let hasSideEffects = 0, mayLoad = 1, mayStore = 0, isReturn = 1,
+    Uses = [X2], Defs = [X2, X10] in
+def QC_CM_POPRETZ : RVInstZcCPPP<0b11100, "qc.cm.popretz">,
+                    Sched<[WriteIALU, WriteIALU, WriteLDW, WriteLDW, WriteLDW,
+                           WriteLDW, WriteLDW, WriteLDW, WriteLDW, WriteLDW,
+                           WriteLDW, WriteLDW, WriteLDW, WriteLDW, WriteLDW,
+                           ReadIALU]>;
+
+let hasSideEffects = 0, mayLoad = 1, mayStore = 0,
+    Uses = [X2], Defs = [X2] in
+def QC_CM_POP : RVInstZcCPPP<0b11010, "qc.cm.pop">,
+                Sched<[WriteIALU, WriteLDW, WriteLDW, WriteLDW, WriteLDW,
+                       WriteLDW, WriteLDW, WriteLDW, WriteLDW, WriteLDW, WriteLDW,
+                       WriteLDW, WriteLDW, WriteLDW, ReadIALU]>;
+} // DecoderNamespace = "RVZcmp", Predicates = [HasVendorXqccmp]...
+
+//===----------------------------------------------------------------------===//
+// Aliases
+//===----------------------------------------------------------------------===//
+
diff --git a/llvm/lib/TargetParser/RISCVISAInfo.cpp b/llvm/lib/TargetParser/RISCVISAInfo.cpp
index 132c47ca631b6..932db759cb7ac 100644
--- a/llvm/lib/TargetParser/RISCVISAInfo.cpp
+++ b/llvm/lib/TargetParser/RISCVISAInfo.cpp
@@ -745,6 +745,8 @@ Error RISCVISAInfo::checkDependency() {
       {"xqcia"},  {"xqciac"},  {"xqcicli"}, {"xqcicm"},
       {"xqcics"}, {"xqcicsr"}, {"xqciint"}, {"xqcilia"},
       {"xqcilo"}, {"xqcilsm"}, {"xqcisls"}};
+  bool HasZcmp = Exts.count("zcmp") != 0;
+  bool HasXqccmp = Exts.count("xqccmp") != 0;
 
   if (HasI && HasE)
     return getIncompatibleError("i", "e");
@@ -779,6 +781,9 @@ Error RISCVISAInfo::checkDependency() {
     if (Exts.count(Ext.str()) && (XLen != 32))
       return getError("'" + Twine(Ext) + "'" + " is only supported for 'rv32'");
 
+  if (HasZcmp && HasXqccmp)
+    return getIncompatibleError("zcmp", "xqccmp");
+
   return Error::success();
 }
 
diff --git a/llvm/test/MC/RISCV/rv32xqccmp-invalid.s b/llvm/test/MC/RISCV/rv32xqccmp-invalid.s
new file mode 100644
index 0000000000000..d0be361b786cb
--- /dev/null
+++ b/llvm/test/MC/RISCV/rv32xqccmp-invalid.s
@@ -0,0 +1,35 @@
+# RUN: not llvm-mc -triple=riscv32 -mattr=+experimental-xqccmp -M no-aliases -show-encoding < %s 2>&1 \
+# RUN:     | FileCheck -check-prefixes=CHECK-ERROR %s
+
+# CHECK-ERROR: error: invalid operand for instruction
+qc.cm.mvsa01 a1, a2
+
+# CHECK-ERROR: error: rs1 and rs2 must be different
+qc.cm.mvsa01 s0, s0
+
+# CHECK-ERROR: error: invalid operand for instruction
+qc.cm.mva01s a1, a2
+
+# CHECK-ERROR: error: invalid register list, {ra, s0-s10} or {x1, x8-x9, x18-x26} is not supported
+qc.cm.popretz {ra, s0-s10}, 112
+
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+qc.cm.popretz {ra, s0-s1}, 112
+
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+qc.cm.push {ra}, 16
+
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+qc.cm.pushfp {ra, s0}, 16
+
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+qc.cm.pop {ra, s0-s1}, -32
+
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+qc.cm.push {ra}, -8
+
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+qc.cm.pushfp {ra, s0}, -12
+
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+qc.cm.pop {ra, s0-s1}, -40
diff --git a/llvm/test/MC/RISCV/rv32xqccmp-valid.s b/llvm/test/MC/RISCV/rv32xqccmp-valid.s
new file mode 100644
index 0000000000000..5827777e524ca
--- /dev/null
+++ b/llvm/test/MC/RISCV/rv32xqccmp-valid.s
@@ -0,0 +1,353 @@
+# RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-xqccmp -M no-aliases -show-encoding \
+# RUN:     | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s
+# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+experimental-xqccmp < %s \
+# RUN:     | llvm-objdump --mattr=-c,+experimental-xqccmp -M no-aliases -d -r - \
+# RUN:     | FileCheck --check-prefixes=CHECK-ASM-AND-OBJ %s
+
+# CHECK-ASM-AND-OBJ: qc.cm.mvsa01 s1, s0
+# CHECK-ASM: encoding: [0xa2,0xac]
+qc.cm.mvsa01 s1, s0
+
+# CHECK-ASM-AND-OBJ: qc.cm.mva01s s1, s0
+# CHECK-ASM: encoding: [0xe2,0xac]
+qc.cm.mva01s s1, s0
+
+# CHECK-ASM-AND-OBJ: qc.cm.mva01s s0, s0
+# CHECK-ASM: encoding: [0x62,0xac] 
+qc.cm.mva01s s0, s0
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra}, 16
+# CHECK-ASM: encoding: [0x42,0xbe]
+qc.cm.popret {ra}, 16
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra}, 16
+# CHECK-ASM: encoding: [0x42,0xbe]
+qc.cm.popret {x1}, 16
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra}, 32
+# CHECK-ASM: encoding: [0x46,0xbe]
+qc.cm.popret {ra}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra}, 32
+# CHECK-ASM: encoding: [0x46,0xbe]
+qc.cm.popret {x1}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra, s0}, 64
+# CHECK-ASM: encoding: [0x5e,0xbe]
+qc.cm.popret {ra, s0}, 64
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra, s0}, 64
+# CHECK-ASM: encoding: [0x5e,0xbe]
+qc.cm.popret {x1, x8}, 64
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra, s0-s1}, 16
+# CHECK-ASM: encoding: [0x62,0xbe]
+qc.cm.popret {ra,s0-s1}, 16
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra, s0-s1}, 16
+# CHECK-ASM: encoding: [0x62,0xbe]
+qc.cm.popret {x1, x8-x9}, 16
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra, s0-s2}, 32
+# CHECK-ASM: encoding: [0x76,0xbe]
+qc.cm.popret {ra, s0-s2}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra, s0-s2}, 32
+# CHECK-ASM: encoding: [0x76,0xbe]
+qc.cm.popret {x1, x8-x9, x18}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra, s0-s3}, 32
+# CHECK-ASM: encoding: [0x82,0xbe]
+qc.cm.popret {ra, s0-s3}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra, s0-s3}, 32
+# CHECK-ASM: encoding: [0x82,0xbe]
+qc.cm.popret {x1, x8-x9, x18-x19}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra, s0-s5}, 32
+# CHECK-ASM: encoding: [0xa2,0xbe]
+qc.cm.popret {ra, s0-s5}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra, s0-s5}, 32
+# CHECK-ASM: encoding: [0xa2,0xbe]
+qc.cm.popret {x1, x8-x9, x18-x21}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra, s0-s7}, 48
+# CHECK-ASM: encoding: [0xc2,0xbe]
+qc.cm.popret {ra, s0-s7}, 48
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra, s0-s7}, 48
+# CHECK-ASM: encoding: [0xc2,0xbe]
+qc.cm.popret {x1, x8-x9, x18-x23}, 48
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra, s0-s11}, 112
+# CHECK-ASM: encoding: [0xfe,0xbe]
+qc.cm.popret {ra, s0-s11}, 112
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra, s0-s11}, 112
+# CHECK-ASM: encoding: [0xfe,0xbe]
+qc.cm.popret {x1, x8-x9, x18-x27}, 112
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra}, 16
+# CHECK-ASM: encoding: [0x42,0xbc]
+qc.cm.popretz {ra}, 16
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra}, 16
+# CHECK-ASM: encoding: [0x42,0xbc]
+qc.cm.popretz {x1}, 16
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra}, 32
+# CHECK-ASM: encoding: [0x46,0xbc]
+qc.cm.popretz {ra}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra}, 32
+# CHECK-ASM: encoding: [0x46,0xbc]
+qc.cm.popretz {x1}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra, s0}, 64
+# CHECK-ASM: encoding: [0x5e,0xbc]
+qc.cm.popretz {ra, s0}, 64
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra, s0}, 64
+# CHECK-ASM: encoding: [0x5e,0xbc]
+qc.cm.popretz {x1, x8}, 64
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra, s0-s1}, 16
+# CHECK-ASM: encoding: [0x62,0xbc]
+qc.cm.popretz {ra, s0-s1}, 16
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra, s0-s1}, 16
+# CHECK-ASM: encoding: [0x62,0xbc]
+qc.cm.popretz {x1, x8-x9}, 16
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra, s0-s2}, 32
+# CHECK-ASM: encoding: [0x76,0xbc]
+qc.cm.popretz {ra, s0-s2}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra, s0-s2}, 32
+# CHECK-ASM: encoding: [0x76,0xbc]
+qc.cm.popretz {x1, x8-x9, x18}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra, s0-s3}, 32
+# CHECK-ASM: encoding: [0x82,0xbc]
+qc.cm.popretz {ra, s0-s3}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra, s0-s3}, 32
+# CHECK-ASM: encoding: [0x82,0xbc]
+qc.cm.popretz {x1, x8-x9, x18-x19}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra, s0-s5}, 32
+# CHECK-ASM: encoding: [0xa2,0xbc]
+qc.cm.popretz {ra, s0-s5}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra, s0-s5}, 32
+# CHECK-ASM: encoding: [0xa2,0xbc]
+qc.cm.popretz {x1, x8-x9, x18-x21}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra, s0-s7}, 48
+# CHECK-ASM: encoding: [0xc2,0xbc]
+qc.cm.popretz {ra, s0-s7}, 48
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra, s0-s7}, 48
+# CHECK-ASM: encoding: [0xc2,0xbc]
+qc.cm.popretz {x1, x8-x9, x18-x23}, 48
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra, s0-s11}, 112
+# CHECK-ASM: encoding: [0xfe,0xbc]
+qc.cm.popretz {ra, s0-s11}, 112
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra, s0-s11}, 112
+# CHECK-ASM: encoding: [0xfe,0xbc]
+qc.cm.popretz {x1, x8-x9, x18-x27}, 112
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra}, 16
+# CHECK-ASM: encoding: [0x42,0xba]
+qc.cm.pop {ra}, 16
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra}, 16
+# CHECK-ASM: encoding: [0x42,0xba]
+qc.cm.pop {x1}, 16
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra}, 32
+# CHECK-ASM: encoding: [0x46,0xba]
+qc.cm.pop {ra}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra}, 32
+# CHECK-ASM: encoding: [0x46,0xba]
+qc.cm.pop {x1}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra, s0}, 16
+# CHECK-ASM: encoding: [0x52,0xba]
+qc.cm.pop {ra, s0}, 16
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra, s0}, 16
+# CHECK-ASM: encoding: [0x52,0xba]
+qc.cm.pop {x1, x8}, 16
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra, s0-s1}, 32
+# CHECK-ASM: encoding: [0x66,0xba]
+qc.cm.pop {ra, s0-s1}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra, s0-s1}, 32
+# CHECK-ASM: encoding: [0x66,0xba]
+qc.cm.pop {x1, x8-x9}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra, s0-s2}, 32
+# CHECK-ASM: encoding: [0x76,0xba]
+qc.cm.pop {ra, s0-s2}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra, s0-s2}, 32
+# CHECK-ASM: encoding: [0x76,0xba]
+qc.cm.pop {x1, x8-x9, x18}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra, s0-s5}, 32
+# CHECK-ASM: encoding: [0xa2,0xba]
+qc.cm.pop {ra, s0-s5}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra, s0-s5}, 32
+# CHECK-ASM: encoding: [0xa2,0xba]
+qc.cm.pop {x1, x8-x9, x18-x21}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra, s0-s7}, 48
+# CHECK-ASM: encoding: [0xc2,0xba]
+qc.cm.pop {ra, s0-s7}, 48
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra, s0-s7}, 48
+# CHECK-ASM: encoding: [0xc2,0xba]
+qc.cm.pop {x1, x8-x9, x18-x23}, 48
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra, s0-s11}, 64
+# CHECK-ASM: encoding: [0xf2,0xba]
+qc.cm.pop {ra, s0-s11}, 64
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra, s0-s11}, 64
+# CHECK-ASM: encoding: [0xf2,0xba]
+qc.cm.pop {x1, x8-x9, x18-x27}, 64
+
+# CHECK-ASM-AND-OBJ: qc.cm.push {ra}, -16
+# CHECK-ASM: encoding: [0x42,0xb8]
+qc.cm.push {ra}, -16
+
+# CHECK-ASM-AND-OBJ: qc.cm.push {ra}, -16
+# CHECK-ASM: encoding: [0x42,0xb8]
+qc.cm.push {x1}, -16
+
+# CHECK-ASM-AND-OBJ: qc.cm.push {ra, s0}, -32
+# CHECK-ASM: encoding: [0x56,0xb8]
+qc.cm.push {ra, s0}, -32
+
+# CHECK-ASM-AND-OBJ: qc.cm.push {ra, s0}, -32
+# CHECK-ASM: encoding: [0x56,0xb8]
+qc.cm.push {x1, x8}, -32
+
+# CHECK-ASM-AND-OBJ: qc.cm.push {ra, s0-s1}, -16
+# CHECK-ASM: encoding: [0x62,0xb8]
+qc.cm.push {ra, s0-s1}, -16
+
+# CHECK-ASM-AND-OBJ: qc.cm.push {ra, s0-s1}, -16
+# CHECK-ASM: encoding: [0x62,0xb8]
+qc.cm.push {x1, x8-x9}, -16
+
+# CHECK-ASM-AND-OBJ: qc.cm.push {ra, s0-s3}, -32
+# CHECK-ASM: encoding: [0x82,0xb8]
+qc.cm.push {ra, s0-s3}, -32
+
+# CHECK-ASM-AND-OBJ: qc.cm.push {ra, s0-s3}, -32
+# CHECK-ASM: encoding: [0x82,0xb8]
+qc.cm.push {x1, x8-x9, x18-x19}, -32
+
+# CHECK-ASM-AND-OBJ: qc.cm.push {ra, s0-s7}, -48
+# CHECK-ASM: encoding: [0xc2,0xb8]
+qc.cm.push {ra, s0-s7}, -48
+
+# CHECK-ASM-AND-OBJ: qc.cm.push {ra, s0-s7}, -48
+# CHECK-ASM: encoding: [0xc2,0xb8]
+qc.cm.push {x1, x8-x9, x18-x23}, -48
+
+# CHECK-ASM-AND-OBJ: qc.cm.push {ra, s0-s7}, -64
+# CHECK-ASM: encoding: [0xc6,0xb8]
+qc.cm.push {ra, s0-s7}, -64
+
+# CHECK-ASM-AND-OBJ: qc.cm.push {ra, s0-s7}, -64
+# CHECK-ASM: encoding: [0xc6,0xb8]
+qc.cm.push {x1, x8-x9, x18-x23}, -64
+
+# CHECK-ASM-AND-OBJ: qc.cm.push {ra, s0-s11}, -80
+# CHECK-ASM: encoding: [0xf6,0xb8]
+qc.cm.push {ra, s0-s11}, -80
+
+# CHECK-ASM-AND-OBJ: qc.cm.push {ra, s0-s11}, -80
+# CHECK-ASM: encoding: [0xf6,0xb8]
+qc.cm.push {x1, x8-x9, x18-x27}, -80
+
+# CHECK-ASM-AND-OBJ: qc.cm.push {ra, s0-s11}, -112
+# CHECK-ASM: encoding: [0xfe,0xb8]
+qc.cm.push {ra, s0-s11}, -112
+
+# CHECK-ASM-AND-OBJ: qc.cm.push {ra, s0-s11}, -112
+# CHECK-ASM: encoding: [0xfe,0xb8]
+qc.cm.push {x1, x8-x9, x18-x27}, -112
+
+# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra}, -16
+# CHECK-ASM: encoding: [0x42,0xb9]
+qc.cm.pushfp {ra}, -16
+
+# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra}, -16
+# CHECK-ASM: encoding: [0x42,0xb9]
+qc.cm.pushfp {x1}, -16
+
+# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0}, -32
+# CHECK-ASM: encoding: [0x56,0xb9]
+qc.cm.pushfp {ra, s0}, -32
+
+# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0}, -32
+# CHECK-ASM: encoding: [0x56,0xb9]
+qc.cm.pushfp {x1, x8}, -32
+
+# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0-s1}, -16
+# CHECK-ASM: encoding: [0x62,0xb9]
+qc.cm.pushfp {ra, s0-s1}, -16
+
+# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0-s1}, -16
+# CHECK-ASM: encoding: [0x62,0xb9]
+qc.cm.pushfp {x1, x8-x9}, -16
+
+# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0-s3}, -32
+# CHECK-ASM: encoding: [0x82,0xb9]
+qc.cm.pushfp {ra, s0-s3}, -32
+
+# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0-s3}, -32
+# CHECK-ASM: encoding: [0x82,0xb9]
+qc.cm.pushfp {x1, x8-x9, x18-x19}, -32
+
+# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0-s7}, -48
+# CHECK-ASM: encoding: [0xc2,0xb9]
+qc.cm.pushfp {ra, s0-s7}, -48
+
+# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0-s7}, -48
+# CHECK-ASM: encoding: [0xc2,0xb9]
+qc.cm.pushfp {x1, x8-x9, x18-x23}, -48
+
+# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0-s7}, -64
+# CHECK-ASM: encoding: [0xc6,0xb9]
+qc.cm.pushfp {ra, s0-s7}, -64
+
+# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0-s7}, -64
+# CHECK-ASM: encoding: [0xc6,0xb9]
+qc.cm.pushfp {x1, x8-x9, x18-x23}, -64
+
+# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0-s11}, -80
+# CHECK-ASM: encoding: [0xf6,0xb9]
+qc.cm.pushfp {ra, s0-s11}, -80
+
+# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0-s11}, -80
+# CHECK-ASM: encoding: [0xf6,0xb9]
+qc.cm.pushfp {x1, x8-x9, x18-x27}, -80
+
+# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0-s11}, -112
+# CHECK-ASM: encoding: [0xfe,0xb9]
+qc.cm.pushfp {ra, s0-s11}, -112
+
+# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0-s11}, -112
+# CHECK-ASM: encoding: [0xfe,0xb9]
+qc.cm.pushfp {x1, x8-x9, x18-x27}, -112
diff --git a/llvm/test/MC/RISCV/rv64e-xqccmp-valid.s b/llvm/test/MC/RISCV/rv64e-xqccmp-valid.s
new file mode 100644
index 0000000000000..8f9e3ce7ee533
--- /dev/null
+++ b/llvm/test/MC/RISCV/rv64e-xqccmp-valid.s
@@ -0,0 +1,85 @@
+# RUN: llvm-mc %s -triple=riscv64 -mattr=+experimental-xqccmp,+e -M no-aliases -show-encoding \
+# RUN:     | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s
+# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+experimental-xqccmp < %s \
+# RUN:     | llvm-objdump --mattr=-c,+experimental-xqccmp -M no-aliases -d -r - \
+# RUN:     | FileCheck --check-prefixes=CHECK-ASM-AND-OBJ %s
+
+# CHECK-ASM-AND-OBJ: qc.cm.mvsa01 s1, s0
+# CHECK-ASM: encoding: [0xa2,0xac]
+qc.cm.mvsa01 s1, s0
+
+# CHECK-ASM-AND-OBJ: qc.cm.mva01s s1, s0
+# CHECK-ASM: encoding: [0xe2,0xac]
+qc.cm.mva01s s1, s0
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra}, 16
+# CHECK-ASM: encoding: [0x42,0xbe]
+qc.cm.popret {ra}, 16
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra}, 32
+# CHECK-ASM: encoding: [0x46,0xbe]
+qc.cm.popret {ra}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra, s0}, 64
+# CHECK-ASM: encoding: [0x5e,0xbe]
+qc.cm.popret {ra, s0}, 64
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra, s0-s1}, 32
+# CHECK-ASM: encoding: [0x62,0xbe]
+qc.cm.popret {ra,s0-s1}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra}, 16
+# CHECK-ASM: encoding: [0x42,0xbc]
+qc.cm.popretz {ra}, 16
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra}, 32
+# CHECK-ASM: encoding: [0x46,0xbc]
+qc.cm.popretz {ra}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra, s0}, 64
+# CHECK-ASM: encoding: [0x5e,0xbc]
+qc.cm.popretz {ra, s0}, 64
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra, s0-s1}, 32
+# CHECK-ASM: encoding: [0x62,0xbc]
+qc.cm.popretz {ra, s0-s1}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra}, 16
+# CHECK-ASM: encoding: [0x42,0xba]
+qc.cm.pop {ra}, 16
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra}, 32
+# CHECK-ASM: encoding: [0x46,0xba]
+qc.cm.pop {ra}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra, s0}, 16
+# CHECK-ASM: encoding: [0x52,0xba]
+qc.cm.pop {ra, s0}, 16
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra, s0-s1}, 32
+# CHECK-ASM: encoding: [0x62,0xba]
+qc.cm.pop {ra, s0-s1}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.push {ra}, -16
+# CHECK-ASM: encoding: [0x42,0xb8]
+qc.cm.push {ra}, -16
+
+# CHECK-ASM-AND-OBJ: qc.cm.push {ra, s0}, -32
+# CHECK-ASM: encoding: [0x56,0xb8]
+qc.cm.push {ra, s0}, -32
+
+# CHECK-ASM-AND-OBJ: qc.cm.push {ra, s0-s1}, -32
+# CHECK-ASM: encoding: [0x62,0xb8]
+qc.cm.push {ra, s0-s1}, -32
+
+# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra}, -16
+# CHECK-ASM: encoding: [0x42,0xb9]
+qc.cm.pushfp {ra}, -16
+
+# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0}, -32
+# CHECK-ASM: encoding: [0x56,0xb9]
+qc.cm.pushfp {ra, s0}, -32
+
+# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0-s1}, -32
+# CHECK-ASM: encoding: [0x62,0xb9]
+qc.cm.pushfp {ra, s0-s1}, -32
diff --git a/llvm/test/MC/RISCV/rv64xqccmp-invalid.s b/llvm/test/MC/RISCV/rv64xqccmp-invalid.s
new file mode 100644
index 0000000000000..1d602d75389f3
--- /dev/null
+++ b/llvm/test/MC/RISCV/rv64xqccmp-invalid.s
@@ -0,0 +1,35 @@
+# RUN: not llvm-mc -triple=riscv64 -mattr=experimental-xqccmp -M no-aliases -show-encoding < %s 2>&1 \
+# RUN:     | FileCheck -check-prefixes=CHECK-ERROR %s
+
+# CHECK-ERROR: error: invalid operand for instruction
+qc.cm.mvsa01 a1, a2
+
+# CHECK-ERROR: error: rs1 and rs2 must be different
+qc.cm.mvsa01 s0, s0
+
+# CHECK-ERROR: error: invalid operand for instruction
+qc.cm.mva01s a1, a2
+
+# CHECK-ERROR: error: invalid register list, {ra, s0-s10} or {x1, x8-x9, x18-x26} is not supported
+qc.cm.popretz {ra, s0-s10}, 112
+
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+qc.cm.popretz {ra, s0-s1}, 112
+
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+qc.cm.push {ra}, 16
+
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+qc.cm.pushfp {ra, s0}, 16
+
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+qc.cm.pop {ra, s0-s1}, -32
+
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+qc.cm.push {ra}, -15
+
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+qc.cm.push {ra, s0}, -15
+
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+qc.cm.pop {ra, s0-s1}, -33
diff --git a/llvm/test/MC/RISCV/rv64xqccmp-valid.s b/llvm/test/MC/RISCV/rv64xqccmp-valid.s
new file mode 100644
index 0000000000000..06ba33fe8a495
--- /dev/null
+++ b/llvm/test/MC/RISCV/rv64xqccmp-valid.s
@@ -0,0 +1,181 @@
+# RUN: llvm-mc %s -triple=riscv64 -mattr=+experimental-xqccmp -M no-aliases -show-encoding \
+# RUN:     | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s
+# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+experimental-xqccmp < %s \
+# RUN:     | llvm-objdump --mattr=-c,+experimental-xqccmp -M no-aliases -d -r - \
+# RUN:     | FileCheck --check-prefixes=CHECK-ASM-AND-OBJ %s
+
+# CHECK-ASM-AND-OBJ: qc.cm.mvsa01 s1, s0
+# CHECK-ASM: encoding: [0xa2,0xac]
+qc.cm.mvsa01 s1, s0
+
+# CHECK-ASM-AND-OBJ: qc.cm.mva01s s1, s0
+# CHECK-ASM: encoding: [0xe2,0xac]
+qc.cm.mva01s s1, s0
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra}, 16
+# CHECK-ASM: encoding: [0x42,0xbe]
+qc.cm.popret {ra}, 16
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra}, 32
+# CHECK-ASM: encoding: [0x46,0xbe]
+qc.cm.popret {ra}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra, s0}, 64
+# CHECK-ASM: encoding: [0x5e,0xbe]
+qc.cm.popret {ra, s0}, 64
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra, s0-s1}, 32
+# CHECK-ASM: encoding: [0x62,0xbe]
+qc.cm.popret {ra,s0-s1}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra, s0-s2}, 32
+# CHECK-ASM: encoding: [0x72,0xbe]
+qc.cm.popret {ra, s0-s2}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra, s0-s3}, 64
+# CHECK-ASM: encoding: [0x86,0xbe]
+qc.cm.popret {ra, s0-s3}, 64
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra, s0-s5}, 64
+# CHECK-ASM: encoding: [0xa2,0xbe]
+qc.cm.popret {ra, s0-s5}, 64
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra, s0-s7}, 80
+# CHECK-ASM: encoding: [0xc2,0xbe]
+qc.cm.popret {ra, s0-s7}, 80
+
+# CHECK-ASM-AND-OBJ: qc.cm.popret   {ra, s0-s11}, 112
+# CHECK-ASM: encoding: [0xf2,0xbe]
+qc.cm.popret {ra, s0-s11}, 112
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra}, 16
+# CHECK-ASM: encoding: [0x42,0xbc]
+qc.cm.popretz {ra}, 16
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra}, 32
+# CHECK-ASM: encoding: [0x46,0xbc]
+qc.cm.popretz {ra}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra, s0}, 64
+# CHECK-ASM: encoding: [0x5e,0xbc]
+qc.cm.popretz {ra, s0}, 64
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra, s0-s1}, 32
+# CHECK-ASM: encoding: [0x62,0xbc]
+qc.cm.popretz {ra, s0-s1}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra, s0-s2}, 32
+# CHECK-ASM: encoding: [0x72,0xbc]
+qc.cm.popretz {ra, s0-s2}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra, s0-s3}, 64
+# CHECK-ASM: encoding: [0x86,0xbc]
+qc.cm.popretz {ra, s0-s3}, 64
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra, s0-s5}, 64
+# CHECK-ASM: encoding: [0xa2,0xbc]
+qc.cm.popretz {ra, s0-s5}, 64
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra, s0-s7}, 80
+# CHECK-ASM: encoding: [0xc2,0xbc]
+qc.cm.popretz {ra, s0-s7}, 80
+
+# CHECK-ASM-AND-OBJ: qc.cm.popretz   {ra, s0-s11}, 112
+# CHECK-ASM: encoding: [0xf2,0xbc]
+qc.cm.popretz {ra, s0-s11}, 112
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra}, 16
+# CHECK-ASM: encoding: [0x42,0xba]
+qc.cm.pop {ra}, 16
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra}, 32
+# CHECK-ASM: encoding: [0x46,0xba]
+qc.cm.pop {ra}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra, s0}, 16
+# CHECK-ASM: encoding: [0x52,0xba]
+qc.cm.pop {ra, s0}, 16
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra, s0-s1}, 32
+# CHECK-ASM: encoding: [0x62,0xba]
+qc.cm.pop {ra, s0-s1}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra, s0-s2}, 32
+# CHECK-ASM: encoding: [0x72,0xba]
+qc.cm.pop {ra, s0-s2}, 32
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra, s0-s5}, 64
+# CHECK-ASM: encoding: [0xa2,0xba]
+qc.cm.pop {ra, s0-s5}, 64
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra, s0-s7}, 80
+# CHECK-ASM: encoding: [0xc2,0xba]
+qc.cm.pop {ra, s0-s7}, 80
+
+# CHECK-ASM-AND-OBJ: qc.cm.pop  {ra, s0-s11}, 112
+# CHECK-ASM: encoding: [0xf2,0xba]
+qc.cm.pop {ra, s0-s11}, 112
+
+# CHECK-ASM-AND-OBJ: qc.cm.push {ra}, -16
+# CHECK-ASM: encoding: [0x42,0xb8]
+qc.cm.push {ra}, -16
+
+# CHECK-ASM-AND-OBJ: qc.cm.push {ra, s0}, -32
+# CHECK-ASM: encoding: [0x56,0xb8]
+qc.cm.push {ra, s0}, -32
+
+# CHECK-ASM-AND-OBJ: qc.cm.push {ra, s0-s1}, -32
+# CHECK-ASM: encoding: [0x62,0xb8]
+qc.cm.push {ra, s0-s1}, -32
+
+# CHECK-ASM-AND-OBJ: qc.cm.push {ra, s0-s3}, -64
+# CHECK-ASM: encoding: [0x86,0xb8]
+qc.cm.push {ra, s0-s3}, -64
+
+# CHECK-ASM-AND-OBJ: qc.cm.push {ra, s0-s7}, -80
+# CHECK-ASM: encoding: [0xc2,0xb8]
+qc.cm.push {ra, s0-s7}, -80
+
+# CHECK-ASM-AND-OBJ: qc.cm.push {ra, s0-s7}, -80
+# CHECK-ASM: encoding: [0xc2,0xb8]
+qc.cm.push {ra, s0-s7}, -80
+
+# CHECK-ASM-AND-OBJ: qc.cm.push {ra, s0-s11}, -112
+# CHECK-ASM: encoding: [0xf2,0xb8]
+qc.cm.push {ra, s0-s11}, -112
+
+# CHECK-ASM-AND-OBJ: qc.cm.push {ra, s0-s11}, -128
+# CHECK-ASM: encoding: [0xf6,0xb8]
+qc.cm.push {ra, s0-s11}, -128
+
+# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra}, -16
+# CHECK-ASM: encoding: [0x42,0xb9]
+qc.cm.pushfp {ra}, -16
+
+# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0}, -32
+# CHECK-ASM: encoding: [0x56,0xb9]
+qc.cm.pushfp {ra, s0}, -32
+
+# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0-s1}, -32
+# CHECK-ASM: encoding: [0x62,0xb9]
+qc.cm.pushfp {ra, s0-s1}, -32
+
+# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0-s3}, -64
+# CHECK-ASM: encoding: [0x86,0xb9]
+qc.cm.pushfp {ra, s0-s3}, -64
+
+# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0-s7}, -80
+# CHECK-ASM: encoding: [0xc2,0xb9]
+qc.cm.pushfp {ra, s0-s7}, -80
+
+# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0-s7}, -80
+# CHECK-ASM: encoding: [0xc2,0xb9]
+qc.cm.pushfp {ra, s0-s7}, -80
+
+# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0-s11}, -112
+# CHECK-ASM: encoding: [0xf2,0xb9]
+qc.cm.pushfp {ra, s0-s11}, -112
+
+# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0-s11}, -128
+# CHECK-ASM: encoding: [0xf6,0xb9]
+qc.cm.pushfp {ra, s0-s11}, -128
diff --git a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
index f734b4e25551b..faca72df3b0b1 100644
--- a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
+++ b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
@@ -662,6 +662,11 @@ TEST(ParseArchString, RejectsConflictingExtensions) {
         toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
         ::testing::EndsWith(" is only supported for 'rv32'"));
   }
+
+  for (StringRef Input : {"rv32i_zcmp_xqccmp0p1", "rv64i_zcmp_xqccmp0p1"}) {
+    EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
+              "'zcmp' and 'xqccmp' extensions are incompatible");
+  }
 }
 
 TEST(ParseArchString, MissingDepency) {
@@ -1119,6 +1124,7 @@ Experimental extensions
     smctr                1.0
     ssctr                1.0
     svukte               0.3
+    xqccmp               0.1
     xqcia                0.2
     xqciac               0.3
     xqcicli              0.2

>From 1d712566260623bfe99c5e7c8993730299f2e2e6 Mon Sep 17 00:00:00 2001
From: Sam Elliott <quic_aelliott at quicinc.com>
Date: Tue, 25 Feb 2025 08:01:02 -0800
Subject: [PATCH 2/8] fixup! [RISCV] Add Xqccmp Assembly Support

---
 llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
index c17e0de111a85..7beed1d157024 100644
--- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
+++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
@@ -745,8 +745,9 @@ DecodeStatus RISCVDisassembler::getInstruction16(MCInst &MI, uint64_t &Size,
                         "Qualcomm uC Conditional Move 16bit");
   TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXqciint, DecoderTableXqciint16,
                         "Qualcomm uC Interrupts 16bit");
-  TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXqccmp, DecoderTableXqccmp16,
-                        "Xqccmp (Qualcomm 16-bit Push/Pop & Double Move Instructions)");
+  TRY_TO_DECODE_FEATURE(
+      RISCV::FeatureVendorXqccmp, DecoderTableXqccmp16,
+      "Xqccmp (Qualcomm 16-bit Push/Pop & Double Move Instructions)");
   TRY_TO_DECODE_AND_ADD_SP(STI.hasFeature(RISCV::FeatureVendorXwchc),
                            DecoderTableXwchc16, "WCH QingKe XW");
   TRY_TO_DECODE_AND_ADD_SP(true, DecoderTable16,

>From 8162983ea5eb35900fcb29a537bb4f579d3c2fae Mon Sep 17 00:00:00 2001
From: Sam Elliott <quic_aelliott at quicinc.com>
Date: Tue, 25 Feb 2025 08:05:36 -0800
Subject: [PATCH 3/8] fixup! [RISCV] Add Xqccmp Assembly Support

---
 llvm/test/CodeGen/RISCV/attributes.ll | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/llvm/test/CodeGen/RISCV/attributes.ll b/llvm/test/CodeGen/RISCV/attributes.ll
index daab7b236879f..b624bf2903fc1 100644
--- a/llvm/test/CodeGen/RISCV/attributes.ll
+++ b/llvm/test/CodeGen/RISCV/attributes.ll
@@ -81,6 +81,7 @@
 ; RUN: llc -mtriple=riscv32 -mattr=+xtheadmempair %s -o - | FileCheck --check-prefix=RV32XTHEADMEMPAIR %s
 ; RUN: llc -mtriple=riscv32 -mattr=+xtheadsync %s -o - | FileCheck --check-prefix=RV32XTHEADSYNC %s
 ; RUN: llc -mtriple=riscv32 -mattr=+xwchc %s -o - | FileCheck --check-prefix=RV32XWCHC %s
+; RUN: llc -mtriple=riscv32 -mattr=+experimental-xqccmp %s -o - | FileCheck --check-prefix=RV32XQCCMP %s
 ; RUN: llc -mtriple=riscv32 -mattr=+experimental-xqcia %s -o - | FileCheck --check-prefix=RV32XQCIA %s
 ; RUN: llc -mtriple=riscv32 -mattr=+experimental-xqciac %s -o - | FileCheck --check-prefix=RV32XQCIAC %s
 ; RUN: llc -mtriple=riscv32 -mattr=+experimental-xqcicli %s -o - | FileCheck --check-prefix=RV32XQCICLI %s
@@ -302,6 +303,8 @@
 ; RUN: llc -mtriple=riscv64 -mattr=+experimental-ssctr  %s -o - | FileCheck --check-prefix=RV64SSCTR %s
 ; RUN: llc -mtriple=riscv64 -mattr=+experimental-sdext  %s -o - | FileCheck --check-prefix=RV64SDEXT %s
 ; RUN: llc -mtriple=riscv64 -mattr=+experimental-sdtrig  %s -o - | FileCheck --check-prefix=RV64SDTRIG %s
+; RUN: llc -mtriple=riscv64 -mattr=+experimental-xqccmp %s -o - | FileCheck --check-prefix=RV64XQCCMP %s
+
 
 ; Tests for profile features.
 ; RUN: llc -mtriple=riscv32 -mattr=+rvi20u32 %s -o - | FileCheck --check-prefix=RVI20U32 %s
@@ -398,6 +401,7 @@
 ; RV32XTHEADMEMPAIR: .attribute 5, "rv32i2p1_xtheadmempair1p0"
 ; RV32XTHEADSYNC: .attribute 5, "rv32i2p1_xtheadsync1p0"
 ; RV32XWCHC: .attribute 5, "rv32i2p1_xwchc2p2"
+; RV32XQCCMP: .attribute 5, "rv32i2p1_zca1p0_xqccmp0p1"
 ; RV32XQCIA: .attribute 5, "rv32i2p1_xqcia0p2"
 ; RV32XQCIAC: .attribute 5, "rv32i2p1_zca1p0_xqciac0p3"
 ; RV32XQCICLI: .attribute 5, "rv32i2p1_xqcicli0p2"
@@ -617,6 +621,7 @@
 ; RV64SSCTR: .attribute 5, "rv64i2p1_sscsrind1p0_ssctr1p0"
 ; RV64SDEXT: .attribute 5, "rv64i2p1_sdext1p0"
 ; RV64SDTRIG: .attribute 5, "rv64i2p1_sdtrig1p0"
+; RV64XQCCMP: .attribute 5, "rv64i2p1_zca1p0_xqccmp0p1"
 
 ; RVI20U32: .attribute 5, "rv32i2p1"
 ; RVI20U64: .attribute 5, "rv64i2p1"

>From 7e1337276df3b8d0ba33b62e6f374b2217776565 Mon Sep 17 00:00:00 2001
From: Sam Elliott <quic_aelliott at quicinc.com>
Date: Tue, 25 Feb 2025 08:47:06 -0800
Subject: [PATCH 4/8] fixup! [RISCV] Add Xqccmp Assembly Support

---
 llvm/lib/Target/RISCV/RISCVInstrInfoXqccmp.td | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXqccmp.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXqccmp.td
index 043d985e39903..b9853070b9ef0 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXqccmp.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXqccmp.td
@@ -87,7 +87,7 @@ def QC_CM_POP : RVInstZcCPPP<0b11010, "qc.cm.pop">,
                 Sched<[WriteIALU, WriteLDW, WriteLDW, WriteLDW, WriteLDW,
                        WriteLDW, WriteLDW, WriteLDW, WriteLDW, WriteLDW, WriteLDW,
                        WriteLDW, WriteLDW, WriteLDW, ReadIALU]>;
-} // DecoderNamespace = "RVZcmp", Predicates = [HasVendorXqccmp]...
+} // DecoderNamespace = "Xqccmp", Predicates = [HasVendorXqccmp]...
 
 //===----------------------------------------------------------------------===//
 // Aliases

>From b33add597169fda80d460cc82b7399ccca2d144d Mon Sep 17 00:00:00 2001
From: Sam Elliott <quic_aelliott at quicinc.com>
Date: Tue, 25 Feb 2025 11:16:54 -0800
Subject: [PATCH 5/8] fixup! [RISCV] Add Xqccmp Assembly Support

---
 llvm/lib/Target/RISCV/RISCVInstrInfoXqccmp.td | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXqccmp.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXqccmp.td
index b9853070b9ef0..5bb9c1e4b228b 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXqccmp.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXqccmp.td
@@ -37,9 +37,9 @@
 // Instructions
 //===----------------------------------------------------------------------===//
 
-// Zcmp
-let DecoderNamespace = "Xqccmp", Predicates = [HasVendorXqccmp],
-    hasSideEffects = 0, mayLoad = 0, mayStore = 0 in {
+let DecoderNamespace = "Xqccmp", Predicates = [HasVendorXqccmp] in {
+
+let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in {
 let Defs = [X10, X11] in
 def QC_CM_MVA01S : RVInst16CA<0b101011, 0b11, 0b10, (outs),
                               (ins SR07:$rs1, SR07:$rs2), "qc.cm.mva01s", "$rs1, $rs2">,
@@ -49,9 +49,8 @@ let Uses = [X10, X11] in
 def QC_CM_MVSA01 : RVInst16CA<0b101011, 0b01, 0b10, (outs SR07:$rs1, SR07:$rs2),
                               (ins), "qc.cm.mvsa01", "$rs1, $rs2">,
                    Sched<[WriteIALU, WriteIALU, ReadIALU, ReadIALU]>;
-} // DecoderNamespace = "Xqccmp", Predicates = [HasVendorXqccmp]...
+} // hasSideEffects = 0, mayLoad = 0, mayStore = 0
 
-let DecoderNamespace = "Xqccmp", Predicates = [HasVendorXqccmp] in {
 let hasSideEffects = 0, mayLoad = 0, mayStore = 1, Uses = [X2], Defs = [X2] in
 def QC_CM_PUSH : RVInstZcCPPP<0b11000, "qc.cm.push", negstackadj>,
                  Sched<[WriteIALU, ReadIALU, ReadStoreData, ReadStoreData,
@@ -87,7 +86,8 @@ def QC_CM_POP : RVInstZcCPPP<0b11010, "qc.cm.pop">,
                 Sched<[WriteIALU, WriteLDW, WriteLDW, WriteLDW, WriteLDW,
                        WriteLDW, WriteLDW, WriteLDW, WriteLDW, WriteLDW, WriteLDW,
                        WriteLDW, WriteLDW, WriteLDW, ReadIALU]>;
-} // DecoderNamespace = "Xqccmp", Predicates = [HasVendorXqccmp]...
+
+} // DecoderNamespace = "Xqccmp", Predicates = [HasVendorXqccmp]
 
 //===----------------------------------------------------------------------===//
 // Aliases

>From 47e63a8c650f678076c087b61de5d848f40f7bc4 Mon Sep 17 00:00:00 2001
From: Sam Elliott <quic_aelliott at quicinc.com>
Date: Tue, 25 Feb 2025 13:56:10 -0800
Subject: [PATCH 6/8] fixup! [RISCV] Add Xqccmp Assembly Support

---
 llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp | 11 +++++++++++
 llvm/lib/Target/RISCV/RISCVInstrInfoZc.td          |  2 --
 llvm/test/MC/RISCV/rv32xqccmp-invalid.s            | 14 +++++++-------
 llvm/test/MC/RISCV/rv64xqccmp-invalid.s            | 14 +++++++-------
 4 files changed, 25 insertions(+), 16 deletions(-)

diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index 697dfac48e4a0..fb0ff9a73159d 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -1682,6 +1682,17 @@ bool RISCVAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
   case Match_InvalidRnumArg: {
     return generateImmOutOfRangeError(Operands, ErrorInfo, 0, 10);
   }
+  case Match_InvalidStackAdj: {
+    SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
+    StringRef SpecName = "Zc";
+    if (getSTI().hasFeature(RISCV::FeatureVendorXqccmp))
+      SpecName = "Xqccmp";
+
+    return Error(
+        ErrorLoc,
+        "stack adjustment is invalid for this instruction and register list; "
+        "refer to " + SpecName + " spec for a detailed range of stack adjustment");
+  }
   }
 
   if (const char *MatchDiag = getMatchKindDiag((RISCVMatchResultTy)Result)) {
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZc.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZc.td
index 9dfbcf678d6eb..4944e85cbbcbb 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoZc.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZc.td
@@ -46,8 +46,6 @@ def StackAdjAsmOperand : AsmOperandClass {
   let Name = "StackAdj";
   let ParserMethod = "parseZcmpStackAdj";
   let DiagnosticType = "InvalidStackAdj";
-  let DiagnosticString = "stack adjustment is invalid for this instruction and register list; "
-        "refer to Zc spec for a detailed range of stack adjustment";
   let PredicateMethod = "isSpimm";
   let RenderMethod = "addSpimmOperands";
 }
diff --git a/llvm/test/MC/RISCV/rv32xqccmp-invalid.s b/llvm/test/MC/RISCV/rv32xqccmp-invalid.s
index d0be361b786cb..899979cb4c601 100644
--- a/llvm/test/MC/RISCV/rv32xqccmp-invalid.s
+++ b/llvm/test/MC/RISCV/rv32xqccmp-invalid.s
@@ -13,23 +13,23 @@ qc.cm.mva01s a1, a2
 # CHECK-ERROR: error: invalid register list, {ra, s0-s10} or {x1, x8-x9, x18-x26} is not supported
 qc.cm.popretz {ra, s0-s10}, 112
 
-# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Xqccmp spec for a detailed range of stack adjustment
 qc.cm.popretz {ra, s0-s1}, 112
 
-# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Xqccmp spec for a detailed range of stack adjustment
 qc.cm.push {ra}, 16
 
-# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Xqccmp spec for a detailed range of stack adjustment
 qc.cm.pushfp {ra, s0}, 16
 
-# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Xqccmp spec for a detailed range of stack adjustment
 qc.cm.pop {ra, s0-s1}, -32
 
-# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Xqccmp spec for a detailed range of stack adjustment
 qc.cm.push {ra}, -8
 
-# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Xqccmp spec for a detailed range of stack adjustment
 qc.cm.pushfp {ra, s0}, -12
 
-# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Xqccmp spec for a detailed range of stack adjustment
 qc.cm.pop {ra, s0-s1}, -40
diff --git a/llvm/test/MC/RISCV/rv64xqccmp-invalid.s b/llvm/test/MC/RISCV/rv64xqccmp-invalid.s
index 1d602d75389f3..e922572a44749 100644
--- a/llvm/test/MC/RISCV/rv64xqccmp-invalid.s
+++ b/llvm/test/MC/RISCV/rv64xqccmp-invalid.s
@@ -13,23 +13,23 @@ qc.cm.mva01s a1, a2
 # CHECK-ERROR: error: invalid register list, {ra, s0-s10} or {x1, x8-x9, x18-x26} is not supported
 qc.cm.popretz {ra, s0-s10}, 112
 
-# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Xqccmp spec for a detailed range of stack adjustment
 qc.cm.popretz {ra, s0-s1}, 112
 
-# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Xqccmp spec for a detailed range of stack adjustment
 qc.cm.push {ra}, 16
 
-# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Xqccmp spec for a detailed range of stack adjustment
 qc.cm.pushfp {ra, s0}, 16
 
-# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Xqccmp spec for a detailed range of stack adjustment
 qc.cm.pop {ra, s0-s1}, -32
 
-# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Xqccmp spec for a detailed range of stack adjustment
 qc.cm.push {ra}, -15
 
-# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Xqccmp spec for a detailed range of stack adjustment
 qc.cm.push {ra, s0}, -15
 
-# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Xqccmp spec for a detailed range of stack adjustment
 qc.cm.pop {ra, s0-s1}, -33

>From 009a1cb3778c35a211915cdb0467f5f3bc8fe495 Mon Sep 17 00:00:00 2001
From: Sam Elliott <quic_aelliott at quicinc.com>
Date: Tue, 25 Feb 2025 21:09:20 -0800
Subject: [PATCH 7/8] fixup! [RISCV] Add Xqccmp Assembly Support

---
 llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index fb0ff9a73159d..36e2fa0262f9d 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -1688,10 +1688,10 @@ bool RISCVAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
     if (getSTI().hasFeature(RISCV::FeatureVendorXqccmp))
       SpecName = "Xqccmp";
 
-    return Error(
-        ErrorLoc,
-        "stack adjustment is invalid for this instruction and register list; "
-        "refer to " + SpecName + " spec for a detailed range of stack adjustment");
+    return Error(ErrorLoc,
+                 Twine("stack adjustment is invalid for this instruction") +
+                     " and register list; refer to " + SpecName +
+                     " spec for a detailed range of stack adjustment");
   }
   }
 

>From 607d6f4940458b3e08eeb52140113e4258574071 Mon Sep 17 00:00:00 2001
From: Sam Elliott <quic_aelliott at quicinc.com>
Date: Wed, 26 Feb 2025 13:53:32 -0800
Subject: [PATCH 8/8] fixup! [RISCV] Add Xqccmp Assembly Support

---
 llvm/docs/RISCVUsage.rst  | 3 +++
 llvm/docs/ReleaseNotes.md | 2 ++
 2 files changed, 5 insertions(+)

diff --git a/llvm/docs/RISCVUsage.rst b/llvm/docs/RISCVUsage.rst
index 051eaf6999edb..44adedec49a83 100644
--- a/llvm/docs/RISCVUsage.rst
+++ b/llvm/docs/RISCVUsage.rst
@@ -429,6 +429,9 @@ The current vendor extensions supported are:
 ``Xwchc``
   LLVM implements `the custom compressed opcodes present in some QingKe cores` by WCH / Nanjing Qinheng Microelectronics. The vendor refers to these opcodes by the name "XW".
 
+``experimental-Xqccmp``
+  LLVM implements `version 0.1 of the 16-bit Push/Pop instructions and double-moves extension specification <https://github.com/quic/riscv-unified-db/releases/tag/Xqccmp_extension-0.1.0>`__ by Qualcomm. All instructions are prefixed with `qc.` as described in the specification.
+
 ``experimental-Xqcia``
   LLVM implements `version 0.2 of the Qualcomm uC Arithmetic extension specification <https://github.com/quic/riscv-unified-db/releases/latest>`__ by Qualcomm.  All instructions are prefixed with `qc.` as described in the specification. These instructions are only available for riscv32.
 
diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index 2a617901a1146..12dd09ad41135 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -109,6 +109,8 @@ Changes to the RISC-V Backend
 
 * Adds experimental assembler support for the Qualcomm uC 'Xqcilia` (Large Immediate Arithmetic)
   extension.
+* Adds experimental assembler support for the Qualcomm 'Xqccmp' extension, which
+  is a frame-pointer convention compatible version of Zcmp.
 
 Changes to the WebAssembly Backend
 ----------------------------------



More information about the cfe-commits mailing list