-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[RISCV] Add Xqccmp Assembly Support #128731
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
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
@llvm/pr-subscribers-mc @llvm/pr-subscribers-clang Author: Sam Elliott (lenary) ChangesXqccmp 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, This change duplicates the Zcmp implementation, with minor changes to mnemonics (for the Specification: https://github.com/quic/riscv-unified-db/releases/tag/Xqccmp_extension-0.1.0 Patch is 33.74 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/128731.diff 13 Files Affected:
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
+# ...
[truncated]
|
I realise this extension will generate questions about what we do for CodeGen support for this extension. I have been thinking about this, and I do think it will be possible to extend the current codegen (prolog epilog inserter mostly) to support this, fairly easily. I can put up a draft patch, based on this one, in time for Thursday's RISC-V sync-up. |
✅ With the latest revision this PR passed the C/C++ code formatter. |
Sched<[WriteIALU, WriteLDW, WriteLDW, WriteLDW, WriteLDW, | ||
WriteLDW, WriteLDW, WriteLDW, WriteLDW, WriteLDW, WriteLDW, | ||
WriteLDW, WriteLDW, WriteLDW, ReadIALU]>; | ||
} // DecoderNamespace = "RVZcmp", Predicates = [HasVendorXqccmp]... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Xqccmp
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
Should that say not present in Zcmp? |
// Instructions | ||
//===----------------------------------------------------------------------===// | ||
|
||
// Zcmp |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Drop the Zcmp comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
# 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message refers to "Zc". Probably should say Zcmp for the standard instruction and Xqccmp for Qualcomm's?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hoped I could "get away" with referring to Zc, but I will update it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've done something here, but I'm not sure it's exactly what we want. Let me know what you think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'm ok with it for the purposes of this patch. I may see about generating a better error that doesn't point to a spec.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
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 Zcmp, `qc.cm.pushfp`, which will set `fp` to the incoming `sp` value after it has pushed the registers. 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
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 Zcmp,
qc.cm.pushfp
, which will setfp
to the incomingsp
value after it has pushed the registers.This change duplicates the Zcmp implementation, with minor changes to mnemonics (for the
qc.
prefix), predicates, and the addition ofqc.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