Skip to content

Commit d23bb42

Browse files
lenaryjoaosaffran
authored andcommitted
[RISCV] Add Xqccmp 0.1 Assembly Support (llvm#128731)
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
1 parent fb5b3d3 commit d23bb42

17 files changed

+830
-4
lines changed

clang/test/Driver/print-supported-extensions-riscv.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@
193193
// CHECK-NEXT: smctr 1.0 'Smctr' (Control Transfer Records Machine Level)
194194
// CHECK-NEXT: ssctr 1.0 'Ssctr' (Control Transfer Records Supervisor Level)
195195
// CHECK-NEXT: svukte 0.3 'Svukte' (Address-Independent Latency of User-Mode Faults to Supervisor Addresses)
196+
// CHECK-NEXT: xqccmp 0.1 'Xqccmp' (Qualcomm 16-bit Push/Pop and Double Moves)
196197
// CHECK-NEXT: xqcia 0.4 'Xqcia' (Qualcomm uC Arithmetic Extension)
197198
// CHECK-NEXT: xqciac 0.3 'Xqciac' (Qualcomm uC Load-Store Address Calculation Extension)
198199
// CHECK-NEXT: xqcicli 0.2 'Xqcicli' (Qualcomm uC Conditional Load Immediate Extension)

llvm/docs/RISCVUsage.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,9 @@ The current vendor extensions supported are:
429429
``Xwchc``
430430
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".
431431

432+
``experimental-Xqccmp``
433+
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.
434+
432435
``experimental-Xqcia``
433436
LLVM implements `version 0.4 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.
434437

llvm/docs/ReleaseNotes.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ Changes to the RISC-V Backend
109109

110110
* Adds experimental assembler support for the Qualcomm uC 'Xqcilia` (Large Immediate Arithmetic)
111111
extension.
112+
* Adds experimental assembler support for the Qualcomm 'Xqccmp' extension, which
113+
is a frame-pointer convention compatible version of Zcmp.
112114

113115
Changes to the WebAssembly Backend
114116
----------------------------------

llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1682,6 +1682,17 @@ bool RISCVAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
16821682
case Match_InvalidRnumArg: {
16831683
return generateImmOutOfRangeError(Operands, ErrorInfo, 0, 10);
16841684
}
1685+
case Match_InvalidStackAdj: {
1686+
SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
1687+
StringRef SpecName = "Zc";
1688+
if (getSTI().hasFeature(RISCV::FeatureVendorXqccmp))
1689+
SpecName = "Xqccmp";
1690+
1691+
return Error(ErrorLoc,
1692+
Twine("stack adjustment is invalid for this instruction") +
1693+
" and register list; refer to " + SpecName +
1694+
" spec for a detailed range of stack adjustment");
1695+
}
16851696
}
16861697

16871698
if (const char *MatchDiag = getMatchKindDiag((RISCVMatchResultTy)Result)) {
@@ -3640,7 +3651,7 @@ bool RISCVAsmParser::validateInstruction(MCInst &Inst,
36403651
}
36413652
}
36423653

3643-
if (Opcode == RISCV::CM_MVSA01) {
3654+
if (Opcode == RISCV::CM_MVSA01 || Opcode == RISCV::QC_CM_MVSA01) {
36443655
MCRegister Rd1 = Inst.getOperand(0).getReg();
36453656
MCRegister Rd2 = Inst.getOperand(1).getReg();
36463657
if (Rd1 == Rd2) {

llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -748,7 +748,9 @@ DecodeStatus RISCVDisassembler::getInstruction16(MCInst &MI, uint64_t &Size,
748748

749749
TRY_TO_DECODE_FEATURE_ANY(XqciFeatureGroup, DecoderTableXqci16,
750750
"Qualcomm uC 16bit");
751-
751+
TRY_TO_DECODE_FEATURE(
752+
RISCV::FeatureVendorXqccmp, DecoderTableXqccmp16,
753+
"Xqccmp (Qualcomm 16-bit Push/Pop & Double Move Instructions)");
752754
TRY_TO_DECODE_AND_ADD_SP(STI.hasFeature(RISCV::FeatureVendorXwchc),
753755
DecoderTableXwchc16, "WCH QingKe XW");
754756
TRY_TO_DECODE_AND_ADD_SP(true, DecoderTable16,

llvm/lib/Target/RISCV/RISCVFeatures.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1374,6 +1374,14 @@ def HasVendorXqcilo
13741374
AssemblerPredicate<(all_of FeatureVendorXqcilo),
13751375
"'Xqcilo' (Qualcomm uC Large Offset Load Store Extension)">;
13761376

1377+
def FeatureVendorXqccmp
1378+
: RISCVExperimentalExtension<0, 1,
1379+
"Qualcomm 16-bit Push/Pop and Double Moves",
1380+
[FeatureStdExtZca]>;
1381+
def HasVendorXqccmp : Predicate<"Subtarget->hasVendorXqccmp()">,
1382+
AssemblerPredicate<(all_of FeatureVendorXqccmp),
1383+
"'Xqccmp' (Qualcomm 16-bit Push/Pop and Double Moves)">;
1384+
13771385
// Rivos Extension(s)
13781386

13791387
def FeatureVendorXRivosVisni

llvm/lib/Target/RISCV/RISCVInstrInfo.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2153,6 +2153,7 @@ include "RISCVInstrInfoSFB.td"
21532153
include "RISCVInstrInfoXCV.td"
21542154
include "RISCVInstrInfoXwch.td"
21552155
include "RISCVInstrInfoXqci.td"
2156+
include "RISCVInstrInfoXqccmp.td"
21562157
include "RISCVInstrInfoXMips.td"
21572158
include "RISCVInstrInfoXRivos.td"
21582159

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
//===---------------- RISCVInstrInfoXqccmp.td --------------*- tablegen -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file describes Qualcomm's Xqccmp extension.
10+
//
11+
// Xqccmp is broadly equivalent to (and incompatible with) Zcmp except the
12+
// following changes:
13+
//
14+
// - The registers are pushed in the opposite order, so `ra` and `fp` are
15+
// closest to the incoming stack pointer (to be compatible with the
16+
// frame-pointer convention), and
17+
//
18+
// - There is a new `qc.cm.pushfp` instruction which is `qc.cm.push` but it sets
19+
// `fp` to the incoming stack pointer value, as expected by the frame-pointer
20+
// convention.
21+
//
22+
//===----------------------------------------------------------------------===//
23+
24+
//===----------------------------------------------------------------------===//
25+
// Operand and SDNode transformation definitions.
26+
//===----------------------------------------------------------------------===//
27+
28+
//===----------------------------------------------------------------------===//
29+
// Instruction Formats
30+
//===----------------------------------------------------------------------===//
31+
32+
//===----------------------------------------------------------------------===//
33+
// Instruction Class Templates
34+
//===----------------------------------------------------------------------===//
35+
36+
//===----------------------------------------------------------------------===//
37+
// Instructions
38+
//===----------------------------------------------------------------------===//
39+
40+
let DecoderNamespace = "Xqccmp", Predicates = [HasVendorXqccmp] in {
41+
42+
let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in {
43+
let Defs = [X10, X11] in
44+
def QC_CM_MVA01S : RVInst16CA<0b101011, 0b11, 0b10, (outs),
45+
(ins SR07:$rs1, SR07:$rs2), "qc.cm.mva01s", "$rs1, $rs2">,
46+
Sched<[WriteIALU, WriteIALU, ReadIALU, ReadIALU]>;
47+
48+
let Uses = [X10, X11] in
49+
def QC_CM_MVSA01 : RVInst16CA<0b101011, 0b01, 0b10, (outs SR07:$rs1, SR07:$rs2),
50+
(ins), "qc.cm.mvsa01", "$rs1, $rs2">,
51+
Sched<[WriteIALU, WriteIALU, ReadIALU, ReadIALU]>;
52+
} // hasSideEffects = 0, mayLoad = 0, mayStore = 0
53+
54+
let hasSideEffects = 0, mayLoad = 0, mayStore = 1, Uses = [X2], Defs = [X2] in
55+
def QC_CM_PUSH : RVInstZcCPPP<0b11000, "qc.cm.push", negstackadj>,
56+
Sched<[WriteIALU, ReadIALU, ReadStoreData, ReadStoreData,
57+
ReadStoreData, ReadStoreData, ReadStoreData, ReadStoreData,
58+
ReadStoreData, ReadStoreData, ReadStoreData, ReadStoreData,
59+
ReadStoreData, ReadStoreData, ReadStoreData]>;
60+
61+
let hasSideEffects = 0, mayLoad = 0, mayStore = 1, Uses = [X2], Defs = [X2, X8] in
62+
def QC_CM_PUSHFP : RVInstZcCPPP<0b11001, "qc.cm.pushfp", negstackadj>,
63+
Sched<[WriteIALU, WriteIALU, ReadIALU, ReadStoreData, ReadStoreData,
64+
ReadStoreData, ReadStoreData, ReadStoreData, ReadStoreData,
65+
ReadStoreData, ReadStoreData, ReadStoreData, ReadStoreData,
66+
ReadStoreData, ReadStoreData, ReadStoreData]>;
67+
68+
let hasSideEffects = 0, mayLoad = 1, mayStore = 0, isReturn = 1,
69+
Uses = [X2], Defs = [X2] in
70+
def QC_CM_POPRET : RVInstZcCPPP<0b11110, "qc.cm.popret">,
71+
Sched<[WriteIALU, WriteLDW, WriteLDW, WriteLDW, WriteLDW,
72+
WriteLDW, WriteLDW, WriteLDW, WriteLDW, WriteLDW,
73+
WriteLDW, WriteLDW, WriteLDW, WriteLDW, ReadIALU]>;
74+
75+
let hasSideEffects = 0, mayLoad = 1, mayStore = 0, isReturn = 1,
76+
Uses = [X2], Defs = [X2, X10] in
77+
def QC_CM_POPRETZ : RVInstZcCPPP<0b11100, "qc.cm.popretz">,
78+
Sched<[WriteIALU, WriteIALU, WriteLDW, WriteLDW, WriteLDW,
79+
WriteLDW, WriteLDW, WriteLDW, WriteLDW, WriteLDW,
80+
WriteLDW, WriteLDW, WriteLDW, WriteLDW, WriteLDW,
81+
ReadIALU]>;
82+
83+
let hasSideEffects = 0, mayLoad = 1, mayStore = 0,
84+
Uses = [X2], Defs = [X2] in
85+
def QC_CM_POP : RVInstZcCPPP<0b11010, "qc.cm.pop">,
86+
Sched<[WriteIALU, WriteLDW, WriteLDW, WriteLDW, WriteLDW,
87+
WriteLDW, WriteLDW, WriteLDW, WriteLDW, WriteLDW, WriteLDW,
88+
WriteLDW, WriteLDW, WriteLDW, ReadIALU]>;
89+
90+
} // DecoderNamespace = "Xqccmp", Predicates = [HasVendorXqccmp]
91+
92+
//===----------------------------------------------------------------------===//
93+
// Aliases
94+
//===----------------------------------------------------------------------===//
95+

llvm/lib/Target/RISCV/RISCVInstrInfoZc.td

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@ def StackAdjAsmOperand : AsmOperandClass {
4646
let Name = "StackAdj";
4747
let ParserMethod = "parseZcmpStackAdj";
4848
let DiagnosticType = "InvalidStackAdj";
49-
let DiagnosticString = "stack adjustment is invalid for this instruction and register list; "
50-
"refer to Zc spec for a detailed range of stack adjustment";
5149
let PredicateMethod = "isSpimm";
5250
let RenderMethod = "addSpimmOperands";
5351
}

llvm/lib/TargetParser/RISCVISAInfo.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,8 @@ Error RISCVISAInfo::checkDependency() {
745745
{"xqcia"}, {"xqciac"}, {"xqcicli"}, {"xqcicm"},
746746
{"xqcics"}, {"xqcicsr"}, {"xqciint"}, {"xqcilia"},
747747
{"xqcilo"}, {"xqcilsm"}, {"xqcisls"}};
748+
bool HasZcmp = Exts.count("zcmp") != 0;
749+
bool HasXqccmp = Exts.count("xqccmp") != 0;
748750

749751
if (HasI && HasE)
750752
return getIncompatibleError("i", "e");
@@ -779,6 +781,9 @@ Error RISCVISAInfo::checkDependency() {
779781
if (Exts.count(Ext.str()) && (XLen != 32))
780782
return getError("'" + Twine(Ext) + "'" + " is only supported for 'rv32'");
781783

784+
if (HasZcmp && HasXqccmp)
785+
return getIncompatibleError("zcmp", "xqccmp");
786+
782787
return Error::success();
783788
}
784789

llvm/test/CodeGen/RISCV/attributes.ll

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
; RUN: llc -mtriple=riscv32 -mattr=+xtheadmempair %s -o - | FileCheck --check-prefix=RV32XTHEADMEMPAIR %s
8282
; RUN: llc -mtriple=riscv32 -mattr=+xtheadsync %s -o - | FileCheck --check-prefix=RV32XTHEADSYNC %s
8383
; RUN: llc -mtriple=riscv32 -mattr=+xwchc %s -o - | FileCheck --check-prefix=RV32XWCHC %s
84+
; RUN: llc -mtriple=riscv32 -mattr=+experimental-xqccmp %s -o - | FileCheck --check-prefix=RV32XQCCMP %s
8485
; RUN: llc -mtriple=riscv32 -mattr=+experimental-xqcia %s -o - | FileCheck --check-prefix=RV32XQCIA %s
8586
; RUN: llc -mtriple=riscv32 -mattr=+experimental-xqciac %s -o - | FileCheck --check-prefix=RV32XQCIAC %s
8687
; RUN: llc -mtriple=riscv32 -mattr=+experimental-xqcicli %s -o - | FileCheck --check-prefix=RV32XQCICLI %s
@@ -302,6 +303,8 @@
302303
; RUN: llc -mtriple=riscv64 -mattr=+experimental-ssctr %s -o - | FileCheck --check-prefix=RV64SSCTR %s
303304
; RUN: llc -mtriple=riscv64 -mattr=+experimental-sdext %s -o - | FileCheck --check-prefix=RV64SDEXT %s
304305
; RUN: llc -mtriple=riscv64 -mattr=+experimental-sdtrig %s -o - | FileCheck --check-prefix=RV64SDTRIG %s
306+
; RUN: llc -mtriple=riscv64 -mattr=+experimental-xqccmp %s -o - | FileCheck --check-prefix=RV64XQCCMP %s
307+
305308

306309
; Tests for profile features.
307310
; RUN: llc -mtriple=riscv32 -mattr=+rvi20u32 %s -o - | FileCheck --check-prefix=RVI20U32 %s
@@ -398,6 +401,7 @@
398401
; RV32XTHEADMEMPAIR: .attribute 5, "rv32i2p1_xtheadmempair1p0"
399402
; RV32XTHEADSYNC: .attribute 5, "rv32i2p1_xtheadsync1p0"
400403
; RV32XWCHC: .attribute 5, "rv32i2p1_xwchc2p2"
404+
; RV32XQCCMP: .attribute 5, "rv32i2p1_zca1p0_xqccmp0p1"
401405
; RV32XQCIA: .attribute 5, "rv32i2p1_xqcia0p4"
402406
; RV32XQCIAC: .attribute 5, "rv32i2p1_zca1p0_xqciac0p3"
403407
; RV32XQCICLI: .attribute 5, "rv32i2p1_xqcicli0p2"
@@ -617,6 +621,7 @@
617621
; RV64SSCTR: .attribute 5, "rv64i2p1_sscsrind1p0_ssctr1p0"
618622
; RV64SDEXT: .attribute 5, "rv64i2p1_sdext1p0"
619623
; RV64SDTRIG: .attribute 5, "rv64i2p1_sdtrig1p0"
624+
; RV64XQCCMP: .attribute 5, "rv64i2p1_zca1p0_xqccmp0p1"
620625

621626
; RVI20U32: .attribute 5, "rv32i2p1"
622627
; RVI20U64: .attribute 5, "rv64i2p1"
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# RUN: not llvm-mc -triple=riscv32 -mattr=+experimental-xqccmp -M no-aliases -show-encoding < %s 2>&1 \
2+
# RUN: | FileCheck -check-prefixes=CHECK-ERROR %s
3+
4+
# CHECK-ERROR: error: invalid operand for instruction
5+
qc.cm.mvsa01 a1, a2
6+
7+
# CHECK-ERROR: error: rs1 and rs2 must be different
8+
qc.cm.mvsa01 s0, s0
9+
10+
# CHECK-ERROR: error: invalid operand for instruction
11+
qc.cm.mva01s a1, a2
12+
13+
# CHECK-ERROR: error: invalid register list, {ra, s0-s10} or {x1, x8-x9, x18-x26} is not supported
14+
qc.cm.popretz {ra, s0-s10}, 112
15+
16+
# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Xqccmp spec for a detailed range of stack adjustment
17+
qc.cm.popretz {ra, s0-s1}, 112
18+
19+
# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Xqccmp spec for a detailed range of stack adjustment
20+
qc.cm.push {ra}, 16
21+
22+
# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Xqccmp spec for a detailed range of stack adjustment
23+
qc.cm.pushfp {ra, s0}, 16
24+
25+
# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Xqccmp spec for a detailed range of stack adjustment
26+
qc.cm.pop {ra, s0-s1}, -32
27+
28+
# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Xqccmp spec for a detailed range of stack adjustment
29+
qc.cm.push {ra}, -8
30+
31+
# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Xqccmp spec for a detailed range of stack adjustment
32+
qc.cm.pushfp {ra, s0}, -12
33+
34+
# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Xqccmp spec for a detailed range of stack adjustment
35+
qc.cm.pop {ra, s0-s1}, -40

0 commit comments

Comments
 (0)