Skip to content

[RISCV] Add Qualcomm uC Xqciio (External Input Output) extension #132721

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

Merged
merged 5 commits into from
Mar 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/test/Driver/print-supported-extensions-riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@
// CHECK-NEXT: xqcics 0.2 'Xqcics' (Qualcomm uC Conditional Select Extension)
// CHECK-NEXT: xqcicsr 0.2 'Xqcicsr' (Qualcomm uC CSR Extension)
// CHECK-NEXT: xqciint 0.4 'Xqciint' (Qualcomm uC Interrupts Extension)
// CHECK-NEXT: xqciio 0.1 'Xqciio' (Qualcomm uC External Input Output Extension)
// CHECK-NEXT: xqcilb 0.2 'Xqcilb' (Qualcomm uC Long Branch Extension)
// CHECK-NEXT: xqcili 0.2 'Xqcili' (Qualcomm uC Load Large Immediate Extension)
// CHECK-NEXT: xqcilia 0.2 'Xqcilia' (Qualcomm uC Large Immediate Arithmetic Extension)
Expand Down
3 changes: 3 additions & 0 deletions llvm/docs/RISCVUsage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,9 @@ The current vendor extensions supported are:
``experimental-Xqcicsr``
LLVM implements `version 0.2 of the Qualcomm uC CSR 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.

``experimental-Xqciio``
LLVM implements `version 0.1 of the Qualcomm uC External Input Output 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.

``experimental-Xqciint``
LLVM implements `version 0.4 of the Qualcomm uC Interrupts 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.

Expand Down
2 changes: 2 additions & 0 deletions llvm/docs/ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ Changes to the RISC-V Backend
extension.
* Adds experimental assembler support for the Qualcomm uC 'Xqcisync` (Sync Delay)
extension.
* Adds experimental assembler support for the Qualcomm uC 'Xqciio` (External Input Output)
extension.
* Adds assembler support for the 'Zilsd` (Load/Store Pair Instructions)
extension.
* Adds assembler support for the 'Zclsd` (Compressed Load/Store Pair Instructions)
Expand Down
6 changes: 6 additions & 0 deletions llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,8 @@ struct RISCVOperand final : public MCParsedAsmOperand {

bool isUImm9Lsb000() const { return isUImmShifted<6, 3>(); }

bool isUImm14Lsb00() const { return isUImmShifted<12, 2>(); }

bool isUImm10Lsb00NonZero() const {
return isUImmPred(
[](int64_t Imm) { return isShiftedUInt<8, 2>(Imm) && (Imm != 0); });
Expand Down Expand Up @@ -1521,6 +1523,10 @@ bool RISCVAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 10) - 1);
case Match_InvalidUImm11:
return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 11) - 1);
case Match_InvalidUImm14Lsb00:
return generateImmOutOfRangeError(
Operands, ErrorInfo, 0, (1 << 14) - 4,
"immediate must be a multiple of 4 bytes in the range");
case Match_InvalidUImm16NonZero:
return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 16) - 1);
case Match_InvalidSImm12:
Expand Down
18 changes: 9 additions & 9 deletions llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -671,15 +671,15 @@ static constexpr FeatureBitset XRivosFeatureGroup = {
};

static constexpr FeatureBitset XqciFeatureGroup = {
RISCV::FeatureVendorXqcia, RISCV::FeatureVendorXqciac,
RISCV::FeatureVendorXqcibi, RISCV::FeatureVendorXqcibm,
RISCV::FeatureVendorXqcicli, RISCV::FeatureVendorXqcicm,
RISCV::FeatureVendorXqcics, RISCV::FeatureVendorXqcicsr,
RISCV::FeatureVendorXqciint, RISCV::FeatureVendorXqcilb,
RISCV::FeatureVendorXqcili, RISCV::FeatureVendorXqcilia,
RISCV::FeatureVendorXqcilo, RISCV::FeatureVendorXqcilsm,
RISCV::FeatureVendorXqcisim, RISCV::FeatureVendorXqcisls,
RISCV::FeatureVendorXqcisync,
RISCV::FeatureVendorXqcia, RISCV::FeatureVendorXqciac,
RISCV::FeatureVendorXqcibi, RISCV::FeatureVendorXqcibm,
RISCV::FeatureVendorXqcicli, RISCV::FeatureVendorXqcicm,
RISCV::FeatureVendorXqcics, RISCV::FeatureVendorXqcicsr,
RISCV::FeatureVendorXqciint, RISCV::FeatureVendorXqciio,
RISCV::FeatureVendorXqcilb, RISCV::FeatureVendorXqcili,
RISCV::FeatureVendorXqcilia, RISCV::FeatureVendorXqcilo,
RISCV::FeatureVendorXqcilsm, RISCV::FeatureVendorXqcisim,
RISCV::FeatureVendorXqcisls, RISCV::FeatureVendorXqcisync,
};

static constexpr FeatureBitset XSfVectorGroup = {
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ enum OperandType : unsigned {
OPERAND_UIMM10_LSB00_NONZERO,
OPERAND_UIMM11,
OPERAND_UIMM12,
OPERAND_UIMM14_LSB00,
OPERAND_UIMM16,
OPERAND_UIMM16_NONZERO,
OPERAND_UIMM20,
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/Target/RISCV/RISCVFeatures.td
Original file line number Diff line number Diff line change
Expand Up @@ -1376,6 +1376,13 @@ def HasVendorXqcicm
AssemblerPredicate<(all_of FeatureVendorXqcicm),
"'Xqcicm' (Qualcomm uC Conditional Move Extension)">;

def FeatureVendorXqciio
: RISCVExperimentalExtension<0, 1, "Qualcomm uC External Input Output Extension">;
def HasVendorXqciio
: Predicate<"Subtarget->hasVendorXqciio()">,
AssemblerPredicate<(all_of FeatureVendorXqciio),
"'Xqciio' (Qualcomm uC External Input Output Extension)">;

def FeatureVendorXqciint
: RISCVExperimentalExtension<0, 4, "Qualcomm uC Interrupts Extension",
[FeatureStdExtZca]>;
Expand Down
40 changes: 40 additions & 0 deletions llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,15 @@ def uimm10 : RISCVUImmLeafOp<10>;

def uimm11 : RISCVUImmLeafOp<11>;

// A 14-bit unsigned immediate where the least significant two bits are zero.
def uimm14lsb00 : RISCVOp,
ImmLeaf<XLenVT, [{return isShiftedUInt<12, 2>(Imm);}]> {
let ParserMatchClass = UImmAsmOperand<14, "Lsb00">;
let EncoderMethod = "getImmOpValue";
let DecoderMethod = "decodeUImmOperand<14>";
let OperandType = "OPERAND_UIMM14_LSB00";
}

def uimm16nonzero : RISCVOp<XLenVT>,
ImmLeaf<XLenVT, [{return (Imm != 0) && isUInt<16>(Imm);}]> {
let ParserMatchClass = UImmAsmOperand<16, "NonZero">;
Expand Down Expand Up @@ -742,6 +751,28 @@ def QC_C_MILEAVERET : QCIRVInst16CI_NONE<0b10100, "qc.c.mileaveret">;

} // Predicates = [HasVendorXqciint, IsRV32], hasSideEffects = 1

let Predicates = [HasVendorXqciio, IsRV32] in {
let hasSideEffects = 1, mayLoad = 0, mayStore = 0 in {
def QC_OUTW : RVInstI<0b100, OPC_CUSTOM_0, (outs),
(ins GPR:$rs2, GPR:$rs1, uimm14lsb00:$imm14),
"qc.outw", "$rs2, ${imm14}(${rs1})"> {
bits<5> rs2;
bits<14> imm14;

let rd = rs2;
let imm12 = imm14{13-2};
}

def QC_INW : RVInstI<0b101, OPC_CUSTOM_0, (outs GPRNoX0:$rd),
(ins GPR:$rs1, uimm14lsb00:$imm14),
"qc.inw", "$rd, ${imm14}(${rs1})"> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both this and qc.outw need aliases where $imm14 is omitted from the assembly - in which case the immediate value should be 0.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, I'm looking at using MIOperandInfo to create sub-operands and change how we do parsing so we can get rid of these kinds of InstAliases.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be good. I did wonder if there was a nice way with optional operands, but I think that gets messy as the optionality is on the immediate and not on the combination.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lenary I added aliases for both of them.

bits<14> imm14;

let imm12 = imm14{13-2};
}
} // hasSideEffects = 1, mayLoad = 0, mayStore = 0
} // Predicates = [HasVendorXqciio, IsRV32]

let Predicates = [HasVendorXqcilo, IsRV32] in {
def QC_E_LB : QCIRVInstEILoad<0b101, 0b00, "qc.e.lb">;
def QC_E_LBU : QCIRVInstEILoad<0b101, 0b01, "qc.e.lbu">;
Expand Down Expand Up @@ -859,6 +890,15 @@ let mayLoad = 0, mayStore = 0, hasSideEffects = 1 in {
// Aliases
//===----------------------------------------------------------------------===//

let Predicates = [HasVendorXqciio, IsRV32] in {
let EmitPriority = 0 in {
def : InstAlias<"qc.outw $rs2, (${rs1})",
(QC_OUTW GPR:$rs2, GPR:$rs1, 0)>;
def : InstAlias<"qc.inw $rd, (${rs1})",
(QC_INW GPRNoX0:$rd, GPR:$rs1, 0)>;
} // EmitPriority = 0
} // Predicates = [HasVendorXqciio, IsRV32]

let Predicates = [HasVendorXqcilsm, IsRV32] in {
let EmitPriority = 0 in {
def : InstAlias<"qc.swm $rs3, $rs2, (${rs1})",
Expand Down
6 changes: 3 additions & 3 deletions llvm/lib/TargetParser/RISCVISAInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -745,9 +745,9 @@ Error RISCVISAInfo::checkDependency() {

static constexpr StringLiteral XqciExts[] = {
{"xqcia"}, {"xqciac"}, {"xqcibi"}, {"xqcibm"}, {"xqcicli"},
{"xqcicm"}, {"xqcics"}, {"xqcicsr"}, {"xqciint"}, {"xqcilb"},
{"xqcili"}, {"xqcilia"}, {"xqcilo"}, {"xqcilsm"}, {"xqcisim"},
{"xqcisls"}, {"xqcisync"}};
{"xqcicm"}, {"xqcics"}, {"xqcicsr"}, {"xqciint"}, {"xqciio"},
{"xqcilb"}, {"xqcili"}, {"xqcilia"}, {"xqcilo"}, {"xqcilsm"},
{"xqcisim"}, {"xqcisls"}, {"xqcisync"}};
static constexpr StringLiteral ZcdOverlaps[] = {
{"zcmt"}, {"zcmp"}, {"xqccmp"}, {"xqciac"}, {"xqcicm"}};

Expand Down
2 changes: 2 additions & 0 deletions llvm/test/CodeGen/RISCV/attributes.ll
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
; RUN: llc -mtriple=riscv32 -mattr=+experimental-xqcics %s -o - | FileCheck --check-prefix=RV32XQCICS %s
; RUN: llc -mtriple=riscv32 -mattr=+experimental-xqcicsr %s -o - | FileCheck --check-prefix=RV32XQCICSR %s
; RUN: llc -mtriple=riscv32 -mattr=+experimental-xqciint %s -o - | FileCheck --check-prefix=RV32XQCIINT %s
; RUN: llc -mtriple=riscv32 -mattr=+experimental-xqciio %s -o - | FileCheck --check-prefix=RV32XQCIIO %s
; RUN: llc -mtriple=riscv32 -mattr=+experimental-xqcilb %s -o - | FileCheck --check-prefix=RV32XQCILB %s
; RUN: llc -mtriple=riscv32 -mattr=+experimental-xqcili %s -o - | FileCheck --check-prefix=RV32XQCILI %s
; RUN: llc -mtriple=riscv32 -mattr=+experimental-xqcilia %s -o - | FileCheck --check-prefix=RV32XQCILIA %s
Expand Down Expand Up @@ -431,6 +432,7 @@
; RV32XQCICS: .attribute 5, "rv32i2p1_xqcics0p2"
; RV32XQCICSR: .attribute 5, "rv32i2p1_xqcicsr0p2"
; RV32XQCIINT: .attribute 5, "rv32i2p1_zca1p0_xqciint0p4"
; RV32XQCIIO: .attribute 5, "rv32i2p1_xqciio0p1"
; RV32XQCILB: .attribute 5, "rv32i2p1_zca1p0_xqcilb0p2"
; RV32XQCILI: .attribute 5, "rv32i2p1_zca1p0_xqcili0p2"
; RV32XQCILIA: .attribute 5, "rv32i2p1_zca1p0_xqcilia0p2"
Expand Down
1 change: 1 addition & 0 deletions llvm/test/CodeGen/RISCV/features-info.ll
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
; CHECK-NEXT: experimental-xqcics - 'Xqcics' (Qualcomm uC Conditional Select Extension).
; CHECK-NEXT: experimental-xqcicsr - 'Xqcicsr' (Qualcomm uC CSR Extension).
; CHECK-NEXT: experimental-xqciint - 'Xqciint' (Qualcomm uC Interrupts Extension).
; CHECK-NEXT: experimental-xqciio - 'Xqciio' (Qualcomm uC External Input Output Extension).
; CHECK-NEXT: experimental-xqcilb - 'Xqcilb' (Qualcomm uC Long Branch Extension).
; CHECK-NEXT: experimental-xqcili - 'Xqcili' (Qualcomm uC Load Large Immediate Extension).
; CHECK-NEXT: experimental-xqcilia - 'Xqcilia' (Qualcomm uC Large Immediate Arithmetic Extension).
Expand Down
20 changes: 20 additions & 0 deletions llvm/test/MC/RISCV/xqciio-aliases-valid.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Xqciio - Qualcomm uC External Input Output extension
# RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-xqciio -riscv-no-aliases -show-encoding \
# RUN: | FileCheck -check-prefixes=CHECK-ENC,CHECK-INST %s
# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+experimental-xqciio < %s \
# RUN: | llvm-objdump --mattr=+experimental-xqciio -M no-aliases --no-print-imm-hex -d - \
# RUN: | FileCheck -check-prefix=CHECK-INST %s
# RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-xqciio -show-encoding \
# RUN: | FileCheck -check-prefixes=CHECK-ENC,CHECK-INST %s
# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+experimental-xqciio < %s \
# RUN: | llvm-objdump --mattr=+experimental-xqciio --no-print-imm-hex -d - \
# RUN: | FileCheck -check-prefix=CHECK-INST %s

# CHECK-INST: qc.outw t0, 0(a0)
# CHECK-ENC: encoding: [0x8b,0x42,0x05,0x00]
qc.outw x5, (x10)


# CHECK-INST: qc.inw t0, 0(a0)
# CHECK-ENC: encoding: [0x8b,0x52,0x05,0x00]
qc.inw x5, (x10)
40 changes: 40 additions & 0 deletions llvm/test/MC/RISCV/xqciio-invalid.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Xqciio - Qualcomm uC External Input Output Extension
# RUN: not llvm-mc -triple riscv32 -mattr=+experimental-xqciio < %s 2>&1 \
# RUN: | FileCheck -check-prefixes=CHECK,CHECK-PLUS %s
# RUN: not llvm-mc -triple riscv32 -mattr=-experimental-xqciio < %s 2>&1 \
# RUN: | FileCheck -check-prefixes=CHECK,CHECK-MINUS %s

# CHECK: :[[@LINE+1]]:18: error: expected register
qc.outw x5, 2048(10)

# CHECK-PLUS: :[[@LINE+1]]:13: error: immediate must be a multiple of 4 bytes in the range [0, 16380]
qc.outw x5, x10

# CHECK-MINUS: :[[@LINE+1]]:13: error: invalid operand for instruction
qc.outw x5, x10

# CHECK-PLUS: :[[@LINE+1]]:13: error: immediate must be a multiple of 4 bytes in the range [0, 16380]
qc.outw x5, 4099(x10)

# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqciio' (Qualcomm uC External Input Output Extension)
qc.outw x5, 2048(x10)


# CHECK: :[[@LINE+1]]:19: error: expected register
qc.inw x23, 16380(17)

# CHECK-PLUS: :[[@LINE+1]]:13: error: immediate must be a multiple of 4 bytes in the range [0, 16380]
qc.inw x23, x17

# CHECK-MINUS: :[[@LINE+1]]:13: error: invalid operand for instruction
qc.inw x23, x17

# CHECK-PLUS: :[[@LINE+2]]:8: error: register must be a GPR excluding zero (x0)
# CHECK-MINUS: :[[@LINE+1]]:8: error: invalid operand for instruction
qc.inw x0, 16380(x17)

# CHECK-PLUS: :[[@LINE+1]]:13: error: immediate must be a multiple of 4 bytes in the range [0, 16380]
qc.inw x23, 16384(x17)

# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqciio' (Qualcomm uC External Input Output Extension)
qc.inw x23, 16380(x17)
20 changes: 20 additions & 0 deletions llvm/test/MC/RISCV/xqciio-valid.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Xqciio - Qualcomm uC External Input Output Extension
# RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-xqciio -riscv-no-aliases -show-encoding \
# RUN: | FileCheck -check-prefixes=CHECK-ENC,CHECK-INST %s
# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+experimental-xqciio < %s \
# RUN: | llvm-objdump --mattr=+experimental-xqciio -M no-aliases --no-print-imm-hex -d - \
# RUN: | FileCheck -check-prefix=CHECK-INST %s
# RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-xqciio -show-encoding \
# RUN: | FileCheck -check-prefixes=CHECK-ENC,CHECK-INST %s
# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+experimental-xqciio < %s \
# RUN: | llvm-objdump --mattr=+experimental-xqciio --no-print-imm-hex -d - \
# RUN: | FileCheck -check-prefix=CHECK-INST %s


# CHECK-INST: qc.outw t0, 2048(a0)
# CHECK-ENC: encoding: [0x8b,0x42,0x05,0x20]
qc.outw x5, 2048(x10)

# CHECK-INST: qc.inw s7, 16380(a7)
# CHECK-ENC: encoding: [0x8b,0xdb,0xf8,0xff]
qc.inw x23, 16380(x17)
7 changes: 4 additions & 3 deletions llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -667,9 +667,9 @@ TEST(ParseArchString, RejectsConflictingExtensions) {
{"rv64i_xqcisls0p2", "rv64i_xqcia0p4", "rv64i_xqciac0p3",
"rv64i_xqcicsr0p2", "rv64i_xqcilsm0p2", "rv64i_xqcicm0p2",
"rv64i_xqcics0p2", "rv64i_xqcicli0p2", "rv64i_xqciint0p4",
"rv64i_xqcilo0p2", "rv64i_xqcilia0p2", "rv64i_xqcibm0p4",
"rv64i_xqcibi0p2", "rv64i_xqcili0p2", "rv64i_xqcisim0p2",
"rv64i_xqcilb0p2", "rv64i_xqcisync0p2"}) {
"rv64i_xqciio0p1", "rv64i_xqcilo0p2", "rv64i_xqcilia0p2",
"rv64i_xqcibm0p4", "rv64i_xqcibi0p2", "rv64i_xqcili0p2",
"rv64i_xqcisim0p2", "rv64i_xqcilb0p2", "rv64i_xqcisync0p2"}) {
EXPECT_THAT(
toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
::testing::EndsWith(" is only supported for 'rv32'"));
Expand Down Expand Up @@ -1159,6 +1159,7 @@ Experimental extensions
xqcics 0.2
xqcicsr 0.2
xqciint 0.4
xqciio 0.1
xqcilb 0.2
xqcili 0.2
xqcilia 0.2
Expand Down