Skip to content

[RISCV] Add Qualcomm uC Xqcia (Arithmetic) extension #118113

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 1 commit into from
Dec 1, 2024

Conversation

svs-quic
Copy link
Contributor

This extension adds 11 instructions that perform integer arithmetic.

The current spec can be found at:
https://github.com/quic/riscv-unified-db/releases/latest

This patch adds assembler only support.

This extension adds 11 instructions that perform integer arithmetic.

The current spec can be found at:
https://github.com/quic/riscv-unified-db/releases/latest

This patch adds assembler only support.
@llvmbot llvmbot added clang Clang issues not falling into any other category backend:RISC-V clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' mc Machine (object) code labels Nov 29, 2024
@llvmbot
Copy link
Member

llvmbot commented Nov 29, 2024

@llvm/pr-subscribers-clang-driver

@llvm/pr-subscribers-backend-risc-v

Author: Sudharsan Veeravalli (svs-quic)

Changes

This extension adds 11 instructions that perform integer arithmetic.

The current spec can be found at:
https://github.com/quic/riscv-unified-db/releases/latest

This patch adds assembler only support.


Patch is 20.04 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/118113.diff

13 Files Affected:

  • (modified) clang/test/Driver/print-supported-extensions-riscv.c (+1)
  • (modified) llvm/docs/RISCVUsage.rst (+3)
  • (modified) llvm/docs/ReleaseNotes.md (+2)
  • (modified) llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp (+3)
  • (modified) llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp (+2)
  • (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h (+1)
  • (modified) llvm/lib/Target/RISCV/RISCVFeatures.td (+8)
  • (modified) llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td (+36)
  • (modified) llvm/lib/TargetParser/RISCVISAInfo.cpp (+2-1)
  • (modified) llvm/test/CodeGen/RISCV/attributes.ll (+2)
  • (added) llvm/test/MC/RISCV/xqcia-invalid.s (+201)
  • (added) llvm/test/MC/RISCV/xqcia-valid.s (+55)
  • (modified) llvm/unittests/TargetParser/RISCVISAInfoTest.cpp (+6)
diff --git a/clang/test/Driver/print-supported-extensions-riscv.c b/clang/test/Driver/print-supported-extensions-riscv.c
index 70b7a96daf1daf..9df903115b57c1 100644
--- a/clang/test/Driver/print-supported-extensions-riscv.c
+++ b/clang/test/Driver/print-supported-extensions-riscv.c
@@ -188,6 +188,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:     xqcia                0.2       'Xqcia' (Qualcomm uC Arithmetic Extension)
 // CHECK-NEXT:     xqcicsr              0.2       'Xqcicsr' (Qualcomm uC CSR Extension)
 // CHECK-NEXT:     xqcisls              0.2       'Xqcisls' (Qualcomm uC Scaled Load Store Extension)
 // CHECK-EMPTY:
diff --git a/llvm/docs/RISCVUsage.rst b/llvm/docs/RISCVUsage.rst
index 230bf66fcf461b..3978332b1149a9 100644
--- a/llvm/docs/RISCVUsage.rst
+++ b/llvm/docs/RISCVUsage.rst
@@ -426,6 +426,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-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.
+
 ``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.
 
diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index 6d50839d68953e..dc3f3aeb735f87 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -215,6 +215,8 @@ Changes to the RISC-V Backend
   extension.
 * Adds experimental assembler support for the Qualcomm uC 'Xqcisls` (Scaled Load Store)
   extension.
+* Adds experimental assembler support for the Qualcomm uC 'Xqcia` (Arithmetic)
+  extension.
 
 Changes to the WebAssembly Backend
 ----------------------------------
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index b843bb5ae43100..7c91dc07bbd3e5 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -717,6 +717,7 @@ struct RISCVOperand final : public MCParsedAsmOperand {
   bool isUImm6() const { return IsUImm<6>(); }
   bool isUImm7() const { return IsUImm<7>(); }
   bool isUImm8() const { return IsUImm<8>(); }
+  bool isUImm11() const { return IsUImm<11>(); }
   bool isUImm16() const { return IsUImm<16>(); }
   bool isUImm20() const { return IsUImm<20>(); }
   bool isUImm32() const { return IsUImm<32>(); }
@@ -1563,6 +1564,8 @@ bool RISCVAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
     return generateImmOutOfRangeError(
         Operands, ErrorInfo, -(1 << 9), (1 << 9) - 16,
         "immediate must be a multiple of 16 bytes and non-zero in the range");
+  case Match_InvalidUImm11:
+    return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 11) - 1);
   case Match_InvalidSImm12:
     return generateImmOutOfRangeError(
         Operands, ErrorInfo, -(1 << 11), (1 << 11) - 1,
diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
index 95658f24f79e1c..4d563046923a58 100644
--- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
+++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
@@ -686,6 +686,8 @@ DecodeStatus RISCVDisassembler::getInstruction32(MCInst &MI, uint64_t &Size,
                         "Qualcomm uC CSR custom opcode table");
   TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXqcisls, DecoderTableXqcisls32,
                         "Qualcomm uC Scaled Load Store custom opcode table");
+  TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXqcia, DecoderTableXqcia32,
+                        "Qualcomm uC Arithmetic custom opcode table");
   TRY_TO_DECODE(true, DecoderTable32, "RISCV32 table");
 
   return MCDisassembler::Fail;
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
index ca2f868cd4e764..9e36d62352ae51 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
@@ -312,6 +312,7 @@ enum OperandType : unsigned {
   OPERAND_UIMM8_GE32,
   OPERAND_UIMM9_LSB000,
   OPERAND_UIMM10_LSB00_NONZERO,
+  OPERAND_UIMM11,
   OPERAND_UIMM12,
   OPERAND_UIMM16,
   OPERAND_UIMM32,
diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td
index 95a37a76836729..52268c3fa62ccb 100644
--- a/llvm/lib/Target/RISCV/RISCVFeatures.td
+++ b/llvm/lib/Target/RISCV/RISCVFeatures.td
@@ -1359,6 +1359,14 @@ def HasVendorXqcisls
       AssemblerPredicate<(all_of FeatureVendorXqcisls),
                          "'Xqcisls' (Qualcomm uC Scaled Load Store Extension)">;
 
+def FeatureVendorXqcia
+    : RISCVExperimentalExtension<"xqcia", 0, 2,
+                                 "'Xqcia' (Qualcomm uC Arithmetic Extension)">;
+def HasVendorXqcia
+    : Predicate<"Subtarget->hasVendorXqcia()">,
+      AssemblerPredicate<(all_of FeatureVendorXqcia),
+                         "'Xqcia' (Qualcomm uC Arithmetic Extension)">;
+
 //===----------------------------------------------------------------------===//
 // LLVM specific features and extensions
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
index 3f53165d5235e6..29758014f73edf 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
@@ -14,6 +14,8 @@
 // Operand and SDNode transformation definitions.
 //===----------------------------------------------------------------------===//
 
+def uimm11 : RISCVUImmLeafOp<11>;
+
 //===----------------------------------------------------------------------===//
 // Instruction Formats
 //===----------------------------------------------------------------------===//
@@ -45,6 +47,16 @@ class QCIStore_ScaleIdx<bits<4> func4, string opcodestr>
 }
 }
 
+class QCIRVInstR<bits<4> func4, string opcodestr>
+    : RVInstR<{0b000, func4}, 0b011, OPC_CUSTOM_0, (outs GPRNoX0:$rd),
+              (ins GPRNoX0:$rs1), opcodestr, "$rd, $rs1"> {
+  let rs2 = 0;
+}
+
+class QCIRVInstRR<bits<5> func5, DAGOperand InTyRs1, string opcodestr>
+    : RVInstR<{0b00, func5}, 0b011, OPC_CUSTOM_0, (outs GPRNoX0:$rd),
+              (ins InTyRs1:$rs1, GPRNoX0:$rs2), opcodestr, "$rd, $rs1, $rs2">;
+
 //===----------------------------------------------------------------------===//
 // Instructions
 //===----------------------------------------------------------------------===//
@@ -72,3 +84,27 @@ let Predicates = [HasVendorXqcisls, IsRV32], DecoderNamespace = "Xqcisls" in {
   def  QC_SRH  : QCIStore_ScaleIdx<0b1110, "qc.srh">;
   def  QC_SRW  : QCIStore_ScaleIdx<0b1111, "qc.srw">;
 } // Predicates = [HasVendorXqcisls, IsRV32], DecoderNamespace = "Xqcisls"
+
+let Predicates = [HasVendorXqcia, IsRV32], DecoderNamespace = "Xqcia" in {
+let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in {
+  def QC_SLASAT : QCIRVInstRR<0b01010, GPRNoX0, "qc.slasat">;
+  def QC_SLLSAT : QCIRVInstRR<0b01100, GPRNoX0, "qc.sllsat">;
+  def QC_ADDSAT : QCIRVInstRR<0b01110, GPRNoX0, "qc.addsat">;
+  def QC_ADDUSAT : QCIRVInstRR<0b01111, GPRNoX0, "qc.addusat">;
+  def QC_SUBSAT : QCIRVInstRR<0b10000, GPRNoX0, "qc.subsat">;
+  def QC_SUBUSAT : QCIRVInstRR<0b10001, GPRNoX0, "qc.subusat">;
+
+  def QC_WRAP : QCIRVInstRR<0b10010, GPR, "qc.wrap">;
+  def QC_WRAPI : RVInstI<0b000, OPC_CUSTOM_0, (outs GPRNoX0:$rd),
+                         (ins GPRNoX0:$rs1, uimm11:$imm11), "qc.wrapi",
+                         "$rd, $rs1, $imm11"> {
+    bits<11> imm11;
+
+    let imm12 = {0b0, imm11};
+  }
+
+  def QC_NORM : QCIRVInstR<0b0111, "qc.norm">;
+  def QC_NORMU : QCIRVInstR<0b1000, "qc.normu">;
+  def QC_NORMEU : QCIRVInstR<0b1001, "qc.normeu">;
+} // hasSideEffects = 0, mayLoad = 0, mayStore = 0
+} // Predicates = [HasVendorXqcia, IsRV32], DecoderNamespace = "Xqcia"
diff --git a/llvm/lib/TargetParser/RISCVISAInfo.cpp b/llvm/lib/TargetParser/RISCVISAInfo.cpp
index 5673866f9d9d9d..d54b81e0d39810 100644
--- a/llvm/lib/TargetParser/RISCVISAInfo.cpp
+++ b/llvm/lib/TargetParser/RISCVISAInfo.cpp
@@ -741,7 +741,8 @@ Error RISCVISAInfo::checkDependency() {
   bool HasVector = Exts.count("zve32x") != 0;
   bool HasZvl = MinVLen != 0;
   bool HasZcmt = Exts.count("zcmt") != 0;
-  static constexpr StringLiteral XqciExts[] = {{"xqcicsr"}, {"xqcisls"}};
+  static constexpr StringLiteral XqciExts[] = {
+      {"xqcia"}, {"xqcicsr"}, {"xqcisls"}};
 
   if (HasI && HasE)
     return getIncompatibleError("i", "e");
diff --git a/llvm/test/CodeGen/RISCV/attributes.ll b/llvm/test/CodeGen/RISCV/attributes.ll
index 8a3d5e5cfe6216..356dce29795658 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-xqcia %s -o - | FileCheck --check-prefix=RV32XQCIA %s
 ; RUN: llc -mtriple=riscv32 -mattr=+experimental-xqcicsr %s -o - | FileCheck --check-prefix=RV32XQCICSR %s
 ; RUN: llc -mtriple=riscv32 -mattr=+experimental-xqcisls %s -o - | FileCheck --check-prefix=RV32XQCISLS %s
 ; RUN: llc -mtriple=riscv32 -mattr=+zaamo %s -o - | FileCheck --check-prefix=RV32ZAAMO %s
@@ -387,6 +388,7 @@
 ; RV32XTHEADMEMPAIR: .attribute 5, "rv32i2p1_xtheadmempair1p0"
 ; RV32XTHEADSYNC: .attribute 5, "rv32i2p1_xtheadsync1p0"
 ; RV32XWCHC: .attribute 5, "rv32i2p1_xwchc2p2"
+; RV32XQCIA: .attribute 5, "rv32i2p1_xqcia0p2"
 ; RV32XQCICSR: .attribute 5, "rv32i2p1_xqcicsr0p2"
 ; RV32XQCISLS: .attribute 5, "rv32i2p1_xqcisls0p2"
 ; RV32ZAAMO: .attribute 5, "rv32i2p1_zaamo1p0"
diff --git a/llvm/test/MC/RISCV/xqcia-invalid.s b/llvm/test/MC/RISCV/xqcia-invalid.s
new file mode 100644
index 00000000000000..a410fb63fad9c9
--- /dev/null
+++ b/llvm/test/MC/RISCV/xqcia-invalid.s
@@ -0,0 +1,201 @@
+# Xqcia - Qualcomm uC Arithmetic Extension
+# RUN: not llvm-mc -triple riscv32 -mattr=+experimental-xqcia < %s 2>&1 \
+# RUN:     | FileCheck -check-prefixes=CHECK,CHECK-PLUS %s
+# RUN: not llvm-mc -triple riscv32 -mattr=-experimental-xqcia < %s 2>&1 \
+# RUN:     | FileCheck -check-prefixes=CHECK,CHECK-MINUS %s
+
+# CHECK: :[[@LINE+1]]:20: error: invalid operand for instruction
+qc.slasat x10, x3, 17
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.slasat x10, x3
+
+# CHECK: :[[@LINE+1]]:11: error: invalid operand for instruction
+qc.slasat x0, x3, x17
+
+# CHECK: :[[@LINE+1]]:16: error: invalid operand for instruction
+qc.slasat x10, x0, x17
+
+# CHECK: :[[@LINE+1]]:20: error: invalid operand for instruction
+qc.slasat x10, x3, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.slasat x10, x3, x17
+
+
+# CHECK: :[[@LINE+1]]:21: error: invalid operand for instruction
+qc.sllsat x23, x25, 27
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.sllsat x23, x25
+
+# CHECK: :[[@LINE+1]]:11: error: invalid operand for instruction
+qc.sllsat x0, x25, x27
+
+# CHECK: :[[@LINE+1]]:16: error: invalid operand for instruction
+qc.sllsat x23, x0, x27
+
+# CHECK: :[[@LINE+1]]:21: error: invalid operand for instruction
+qc.sllsat x23, x25, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.sllsat x23, x25, x27
+
+
+# CHECK: :[[@LINE+1]]:21: error: invalid operand for instruction
+qc.addsat x17, x14, 7
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.addsat x17, x14
+
+# CHECK: :[[@LINE+1]]:11: error: invalid operand for instruction
+qc.addsat x0, x14, x7
+
+# CHECK: :[[@LINE+1]]:16: error: invalid operand for instruction
+qc.addsat x17, x0, x7
+
+# CHECK: :[[@LINE+1]]:21: error: invalid operand for instruction
+qc.addsat x17, x14, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.addsat x17, x14, x7
+
+
+# CHECK: :[[@LINE+1]]:21: error: invalid operand for instruction
+qc.addusat x8, x18, 28
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.addusat x8, x18
+
+# CHECK: :[[@LINE+1]]:12: error: invalid operand for instruction
+qc.addusat x0, x18, x28
+
+# CHECK: :[[@LINE+1]]:16: error: invalid operand for instruction
+qc.addusat x8, x0, x28
+
+# CHECK: :[[@LINE+1]]:21: error: invalid operand for instruction
+qc.addusat x8, x18, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.addusat x8, x18, x28
+
+
+# CHECK: :[[@LINE+1]]:20: error: invalid operand for instruction
+qc.subsat x22, x2, 12
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.subsat x22, x2
+
+# CHECK: :[[@LINE+1]]:11: error: invalid operand for instruction
+qc.subsat x0, x2, x12
+
+# CHECK: :[[@LINE+1]]:16: error: invalid operand for instruction
+qc.subsat x22, x0, x12
+
+# CHECK: :[[@LINE+1]]:20: error: invalid operand for instruction
+qc.subsat x22, x2, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.subsat x22, x2, x12
+
+
+# CHECK: :[[@LINE+1]]:21: error: invalid operand for instruction
+qc.subusat x9, x14, 17
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.subusat x9, x14
+
+# CHECK: :[[@LINE+1]]:12: error: invalid operand for instruction
+qc.subusat x0, x14, x17
+
+# CHECK: :[[@LINE+1]]:16: error: invalid operand for instruction
+qc.subusat x9, x0, x17
+
+# CHECK: :[[@LINE+1]]:21: error: invalid operand for instruction
+qc.subusat x9, x14, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.subusat x9, x14, x17
+
+
+# CHECK: :[[@LINE+1]]:18: error: invalid operand for instruction
+qc.wrap x3, x30, 23
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.wrap x3, x30
+
+# CHECK: :[[@LINE+1]]:9: error: invalid operand for instruction
+qc.wrap x0, x30, x23
+
+# CHECK: :[[@LINE+1]]:18: error: invalid operand for instruction
+qc.wrap x3, x30, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.wrap x3, x30, x23
+
+
+# CHECK: :[[@LINE+1]]:10: error: invalid operand for instruction
+qc.wrapi x0, 12, 2047
+
+# CHECK: :[[@LINE+1]]:10: error: invalid operand for instruction
+qc.wrapi x0, x12, 2047
+
+# CHECK: :[[@LINE+1]]:14: error: invalid operand for instruction
+qc.wrapi x6, x0, 2047
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.wrapi x6, x12
+
+# CHECK-PLUS: :[[@LINE+1]]:19: error: immediate must be an integer in the range [0, 2047]
+qc.wrapi x6, x12, 2048
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.wrapi x6, x12, 2047
+
+
+# CHECK: :[[@LINE+1]]:13: error: invalid operand for instruction
+qc.norm x3, 7
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.norm x3
+
+# CHECK: :[[@LINE+1]]:9: error: invalid operand for instruction
+qc.norm x0, x7
+
+# CHECK: :[[@LINE+1]]:13: error: invalid operand for instruction
+qc.norm x3, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.norm x3, x7
+
+
+# CHECK: :[[@LINE+1]]:15: error: invalid operand for instruction
+qc.normu x11, 17
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.normu x11
+
+# CHECK: :[[@LINE+1]]:10: error: invalid operand for instruction
+qc.normu x0, x17
+
+# CHECK: :[[@LINE+1]]:15: error: invalid operand for instruction
+qc.normu x11, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.normu x11, x17
+
+
+# CHECK: :[[@LINE+1]]:16: error: invalid operand for instruction
+qc.normeu x26, 31
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.normeu x26
+
+# CHECK: :[[@LINE+1]]:11: error: invalid operand for instruction
+qc.normeu x0, x31
+
+# CHECK: :[[@LINE+1]]:16: error: invalid operand for instruction
+qc.normeu x26, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.normeu x26, x31
diff --git a/llvm/test/MC/RISCV/xqcia-valid.s b/llvm/test/MC/RISCV/xqcia-valid.s
new file mode 100644
index 00000000000000..6bd10492d4d6ab
--- /dev/null
+++ b/llvm/test/MC/RISCV/xqcia-valid.s
@@ -0,0 +1,55 @@
+# Xqcia - Qualcomm uC Arithmetic Extesnsion
+# RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-xqcia -riscv-no-aliases -show-encoding \
+# RUN:     | FileCheck -check-prefixes=CHECK-ENC,CHECK-INST %s
+# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+experimental-xqcia < %s \
+# RUN:     | llvm-objdump --mattr=+experimental-xqcia -M no-aliases --no-print-imm-hex -d - \
+# RUN:     | FileCheck -check-prefix=CHECK-INST %s
+# RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-xqcia -show-encoding \
+# RUN:     | FileCheck -check-prefixes=CHECK-ENC,CHECK-INST %s
+# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+experimental-xqcia < %s \
+# RUN:     | llvm-objdump --mattr=+experimental-xqcia --no-print-imm-hex -d - \
+# RUN:     | FileCheck -check-prefix=CHECK-INST %s
+
+# CHECK-INST: qc.slasat    a0, gp, a7
+# CHECK-ENC: encoding: [0x0b,0xb5,0x11,0x15]
+qc.slasat x10, x3, x17
+
+# CHECK-INST: qc.sllsat    s7, s9, s11
+# CHECK-ENC: encoding: [0x8b,0xbb,0xbc,0x19]
+qc.sllsat x23, x25, x27
+
+# CHECK-INST: qc.addsat    a7, a4, t2
+# CHECK-ENC: encoding: [0x8b,0x38,0x77,0x1c]
+qc.addsat x17, x14, x7
+
+# CHECK-INST: qc.addusat   s0, s2, t3
+# CHECK-ENC: encoding: [0x0b,0x34,0xc9,0x1f]
+qc.addusat x8, x18, x28
+
+# CHECK-INST: qc.subsat    s6, sp, a2
+# CHECK-ENC: encoding: [0x0b,0x3b,0xc1,0x20]
+qc.subsat x22, x2, x12
+
+# CHECK-INST: qc.subusat   s1, a4, a7
+# CHECK-ENC: encoding: [0x8b,0x34,0x17,0x23]
+qc.subusat x9, x14, x17
+
+# CHECK-INST: qc.wrap  gp, t5, s7
+# CHECK-ENC: encoding: [0x8b,0x31,0x7f,0x25]
+qc.wrap x3, x30, x23
+
+# CHECK-INST: qc.wrapi   t1, a2, 2047
+# CHECK-ENC: encoding: [0x0b,0x03,0xf6,0x7f]
+qc.wrapi x6, x12, 2047
+
+# CHECK-INST: qc.norm    gp, t2
+# CHECK-ENC: encoding: [0x8b,0xb1,0x03,0x0e]
+qc.norm x3, x7
+
+# CHECK-INST: qc.normu   a1, a7
+# CHECK-ENC: encoding: [0x8b,0xb5,0x08,0x10]
+qc.normu x11, x17
+
+# CHECK-INST: qc.normeu  s10, t6
+# CHECK-ENC: encoding: [0x0b,0xbd,0x0f,0x12]
+qc.normeu x26, x31
diff --git a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
index 23f1d832773ccf..f9ff45f1166039 100644
--- a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
+++ b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
@@ -657,6 +657,11 @@ TEST(ParseArchString, RejectsConflictingExtensions) {
     EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
               "'xqcisls' is only supported for 'rv32'");
   }
+
+  for (StringRef Input : {"rv64i_xqcia0p2"}) {
+    EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
+              "'xqcia' is only supported for 'rv32'");
+  }
 }
 
 TEST(ParseArchString, MissingDepency) {
@@ -1109,6 +1114,7 @@ Experimental extensions
     smctr                1.0
     ssctr                1.0
     svukte               0.3
+    xqcia                0.2
     xqcicsr        ...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Nov 29, 2024

@llvm/pr-subscribers-mc

Author: Sudharsan Veeravalli (svs-quic)

Changes

This extension adds 11 instructions that perform integer arithmetic.

The current spec can be found at:
https://github.com/quic/riscv-unified-db/releases/latest

This patch adds assembler only support.


Patch is 20.04 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/118113.diff

13 Files Affected:

  • (modified) clang/test/Driver/print-supported-extensions-riscv.c (+1)
  • (modified) llvm/docs/RISCVUsage.rst (+3)
  • (modified) llvm/docs/ReleaseNotes.md (+2)
  • (modified) llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp (+3)
  • (modified) llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp (+2)
  • (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h (+1)
  • (modified) llvm/lib/Target/RISCV/RISCVFeatures.td (+8)
  • (modified) llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td (+36)
  • (modified) llvm/lib/TargetParser/RISCVISAInfo.cpp (+2-1)
  • (modified) llvm/test/CodeGen/RISCV/attributes.ll (+2)
  • (added) llvm/test/MC/RISCV/xqcia-invalid.s (+201)
  • (added) llvm/test/MC/RISCV/xqcia-valid.s (+55)
  • (modified) llvm/unittests/TargetParser/RISCVISAInfoTest.cpp (+6)
diff --git a/clang/test/Driver/print-supported-extensions-riscv.c b/clang/test/Driver/print-supported-extensions-riscv.c
index 70b7a96daf1daf..9df903115b57c1 100644
--- a/clang/test/Driver/print-supported-extensions-riscv.c
+++ b/clang/test/Driver/print-supported-extensions-riscv.c
@@ -188,6 +188,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:     xqcia                0.2       'Xqcia' (Qualcomm uC Arithmetic Extension)
 // CHECK-NEXT:     xqcicsr              0.2       'Xqcicsr' (Qualcomm uC CSR Extension)
 // CHECK-NEXT:     xqcisls              0.2       'Xqcisls' (Qualcomm uC Scaled Load Store Extension)
 // CHECK-EMPTY:
diff --git a/llvm/docs/RISCVUsage.rst b/llvm/docs/RISCVUsage.rst
index 230bf66fcf461b..3978332b1149a9 100644
--- a/llvm/docs/RISCVUsage.rst
+++ b/llvm/docs/RISCVUsage.rst
@@ -426,6 +426,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-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.
+
 ``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.
 
diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index 6d50839d68953e..dc3f3aeb735f87 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -215,6 +215,8 @@ Changes to the RISC-V Backend
   extension.
 * Adds experimental assembler support for the Qualcomm uC 'Xqcisls` (Scaled Load Store)
   extension.
+* Adds experimental assembler support for the Qualcomm uC 'Xqcia` (Arithmetic)
+  extension.
 
 Changes to the WebAssembly Backend
 ----------------------------------
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index b843bb5ae43100..7c91dc07bbd3e5 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -717,6 +717,7 @@ struct RISCVOperand final : public MCParsedAsmOperand {
   bool isUImm6() const { return IsUImm<6>(); }
   bool isUImm7() const { return IsUImm<7>(); }
   bool isUImm8() const { return IsUImm<8>(); }
+  bool isUImm11() const { return IsUImm<11>(); }
   bool isUImm16() const { return IsUImm<16>(); }
   bool isUImm20() const { return IsUImm<20>(); }
   bool isUImm32() const { return IsUImm<32>(); }
@@ -1563,6 +1564,8 @@ bool RISCVAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
     return generateImmOutOfRangeError(
         Operands, ErrorInfo, -(1 << 9), (1 << 9) - 16,
         "immediate must be a multiple of 16 bytes and non-zero in the range");
+  case Match_InvalidUImm11:
+    return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 11) - 1);
   case Match_InvalidSImm12:
     return generateImmOutOfRangeError(
         Operands, ErrorInfo, -(1 << 11), (1 << 11) - 1,
diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
index 95658f24f79e1c..4d563046923a58 100644
--- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
+++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
@@ -686,6 +686,8 @@ DecodeStatus RISCVDisassembler::getInstruction32(MCInst &MI, uint64_t &Size,
                         "Qualcomm uC CSR custom opcode table");
   TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXqcisls, DecoderTableXqcisls32,
                         "Qualcomm uC Scaled Load Store custom opcode table");
+  TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXqcia, DecoderTableXqcia32,
+                        "Qualcomm uC Arithmetic custom opcode table");
   TRY_TO_DECODE(true, DecoderTable32, "RISCV32 table");
 
   return MCDisassembler::Fail;
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
index ca2f868cd4e764..9e36d62352ae51 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
@@ -312,6 +312,7 @@ enum OperandType : unsigned {
   OPERAND_UIMM8_GE32,
   OPERAND_UIMM9_LSB000,
   OPERAND_UIMM10_LSB00_NONZERO,
+  OPERAND_UIMM11,
   OPERAND_UIMM12,
   OPERAND_UIMM16,
   OPERAND_UIMM32,
diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td
index 95a37a76836729..52268c3fa62ccb 100644
--- a/llvm/lib/Target/RISCV/RISCVFeatures.td
+++ b/llvm/lib/Target/RISCV/RISCVFeatures.td
@@ -1359,6 +1359,14 @@ def HasVendorXqcisls
       AssemblerPredicate<(all_of FeatureVendorXqcisls),
                          "'Xqcisls' (Qualcomm uC Scaled Load Store Extension)">;
 
+def FeatureVendorXqcia
+    : RISCVExperimentalExtension<"xqcia", 0, 2,
+                                 "'Xqcia' (Qualcomm uC Arithmetic Extension)">;
+def HasVendorXqcia
+    : Predicate<"Subtarget->hasVendorXqcia()">,
+      AssemblerPredicate<(all_of FeatureVendorXqcia),
+                         "'Xqcia' (Qualcomm uC Arithmetic Extension)">;
+
 //===----------------------------------------------------------------------===//
 // LLVM specific features and extensions
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
index 3f53165d5235e6..29758014f73edf 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
@@ -14,6 +14,8 @@
 // Operand and SDNode transformation definitions.
 //===----------------------------------------------------------------------===//
 
+def uimm11 : RISCVUImmLeafOp<11>;
+
 //===----------------------------------------------------------------------===//
 // Instruction Formats
 //===----------------------------------------------------------------------===//
@@ -45,6 +47,16 @@ class QCIStore_ScaleIdx<bits<4> func4, string opcodestr>
 }
 }
 
+class QCIRVInstR<bits<4> func4, string opcodestr>
+    : RVInstR<{0b000, func4}, 0b011, OPC_CUSTOM_0, (outs GPRNoX0:$rd),
+              (ins GPRNoX0:$rs1), opcodestr, "$rd, $rs1"> {
+  let rs2 = 0;
+}
+
+class QCIRVInstRR<bits<5> func5, DAGOperand InTyRs1, string opcodestr>
+    : RVInstR<{0b00, func5}, 0b011, OPC_CUSTOM_0, (outs GPRNoX0:$rd),
+              (ins InTyRs1:$rs1, GPRNoX0:$rs2), opcodestr, "$rd, $rs1, $rs2">;
+
 //===----------------------------------------------------------------------===//
 // Instructions
 //===----------------------------------------------------------------------===//
@@ -72,3 +84,27 @@ let Predicates = [HasVendorXqcisls, IsRV32], DecoderNamespace = "Xqcisls" in {
   def  QC_SRH  : QCIStore_ScaleIdx<0b1110, "qc.srh">;
   def  QC_SRW  : QCIStore_ScaleIdx<0b1111, "qc.srw">;
 } // Predicates = [HasVendorXqcisls, IsRV32], DecoderNamespace = "Xqcisls"
+
+let Predicates = [HasVendorXqcia, IsRV32], DecoderNamespace = "Xqcia" in {
+let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in {
+  def QC_SLASAT : QCIRVInstRR<0b01010, GPRNoX0, "qc.slasat">;
+  def QC_SLLSAT : QCIRVInstRR<0b01100, GPRNoX0, "qc.sllsat">;
+  def QC_ADDSAT : QCIRVInstRR<0b01110, GPRNoX0, "qc.addsat">;
+  def QC_ADDUSAT : QCIRVInstRR<0b01111, GPRNoX0, "qc.addusat">;
+  def QC_SUBSAT : QCIRVInstRR<0b10000, GPRNoX0, "qc.subsat">;
+  def QC_SUBUSAT : QCIRVInstRR<0b10001, GPRNoX0, "qc.subusat">;
+
+  def QC_WRAP : QCIRVInstRR<0b10010, GPR, "qc.wrap">;
+  def QC_WRAPI : RVInstI<0b000, OPC_CUSTOM_0, (outs GPRNoX0:$rd),
+                         (ins GPRNoX0:$rs1, uimm11:$imm11), "qc.wrapi",
+                         "$rd, $rs1, $imm11"> {
+    bits<11> imm11;
+
+    let imm12 = {0b0, imm11};
+  }
+
+  def QC_NORM : QCIRVInstR<0b0111, "qc.norm">;
+  def QC_NORMU : QCIRVInstR<0b1000, "qc.normu">;
+  def QC_NORMEU : QCIRVInstR<0b1001, "qc.normeu">;
+} // hasSideEffects = 0, mayLoad = 0, mayStore = 0
+} // Predicates = [HasVendorXqcia, IsRV32], DecoderNamespace = "Xqcia"
diff --git a/llvm/lib/TargetParser/RISCVISAInfo.cpp b/llvm/lib/TargetParser/RISCVISAInfo.cpp
index 5673866f9d9d9d..d54b81e0d39810 100644
--- a/llvm/lib/TargetParser/RISCVISAInfo.cpp
+++ b/llvm/lib/TargetParser/RISCVISAInfo.cpp
@@ -741,7 +741,8 @@ Error RISCVISAInfo::checkDependency() {
   bool HasVector = Exts.count("zve32x") != 0;
   bool HasZvl = MinVLen != 0;
   bool HasZcmt = Exts.count("zcmt") != 0;
-  static constexpr StringLiteral XqciExts[] = {{"xqcicsr"}, {"xqcisls"}};
+  static constexpr StringLiteral XqciExts[] = {
+      {"xqcia"}, {"xqcicsr"}, {"xqcisls"}};
 
   if (HasI && HasE)
     return getIncompatibleError("i", "e");
diff --git a/llvm/test/CodeGen/RISCV/attributes.ll b/llvm/test/CodeGen/RISCV/attributes.ll
index 8a3d5e5cfe6216..356dce29795658 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-xqcia %s -o - | FileCheck --check-prefix=RV32XQCIA %s
 ; RUN: llc -mtriple=riscv32 -mattr=+experimental-xqcicsr %s -o - | FileCheck --check-prefix=RV32XQCICSR %s
 ; RUN: llc -mtriple=riscv32 -mattr=+experimental-xqcisls %s -o - | FileCheck --check-prefix=RV32XQCISLS %s
 ; RUN: llc -mtriple=riscv32 -mattr=+zaamo %s -o - | FileCheck --check-prefix=RV32ZAAMO %s
@@ -387,6 +388,7 @@
 ; RV32XTHEADMEMPAIR: .attribute 5, "rv32i2p1_xtheadmempair1p0"
 ; RV32XTHEADSYNC: .attribute 5, "rv32i2p1_xtheadsync1p0"
 ; RV32XWCHC: .attribute 5, "rv32i2p1_xwchc2p2"
+; RV32XQCIA: .attribute 5, "rv32i2p1_xqcia0p2"
 ; RV32XQCICSR: .attribute 5, "rv32i2p1_xqcicsr0p2"
 ; RV32XQCISLS: .attribute 5, "rv32i2p1_xqcisls0p2"
 ; RV32ZAAMO: .attribute 5, "rv32i2p1_zaamo1p0"
diff --git a/llvm/test/MC/RISCV/xqcia-invalid.s b/llvm/test/MC/RISCV/xqcia-invalid.s
new file mode 100644
index 00000000000000..a410fb63fad9c9
--- /dev/null
+++ b/llvm/test/MC/RISCV/xqcia-invalid.s
@@ -0,0 +1,201 @@
+# Xqcia - Qualcomm uC Arithmetic Extension
+# RUN: not llvm-mc -triple riscv32 -mattr=+experimental-xqcia < %s 2>&1 \
+# RUN:     | FileCheck -check-prefixes=CHECK,CHECK-PLUS %s
+# RUN: not llvm-mc -triple riscv32 -mattr=-experimental-xqcia < %s 2>&1 \
+# RUN:     | FileCheck -check-prefixes=CHECK,CHECK-MINUS %s
+
+# CHECK: :[[@LINE+1]]:20: error: invalid operand for instruction
+qc.slasat x10, x3, 17
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.slasat x10, x3
+
+# CHECK: :[[@LINE+1]]:11: error: invalid operand for instruction
+qc.slasat x0, x3, x17
+
+# CHECK: :[[@LINE+1]]:16: error: invalid operand for instruction
+qc.slasat x10, x0, x17
+
+# CHECK: :[[@LINE+1]]:20: error: invalid operand for instruction
+qc.slasat x10, x3, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.slasat x10, x3, x17
+
+
+# CHECK: :[[@LINE+1]]:21: error: invalid operand for instruction
+qc.sllsat x23, x25, 27
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.sllsat x23, x25
+
+# CHECK: :[[@LINE+1]]:11: error: invalid operand for instruction
+qc.sllsat x0, x25, x27
+
+# CHECK: :[[@LINE+1]]:16: error: invalid operand for instruction
+qc.sllsat x23, x0, x27
+
+# CHECK: :[[@LINE+1]]:21: error: invalid operand for instruction
+qc.sllsat x23, x25, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.sllsat x23, x25, x27
+
+
+# CHECK: :[[@LINE+1]]:21: error: invalid operand for instruction
+qc.addsat x17, x14, 7
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.addsat x17, x14
+
+# CHECK: :[[@LINE+1]]:11: error: invalid operand for instruction
+qc.addsat x0, x14, x7
+
+# CHECK: :[[@LINE+1]]:16: error: invalid operand for instruction
+qc.addsat x17, x0, x7
+
+# CHECK: :[[@LINE+1]]:21: error: invalid operand for instruction
+qc.addsat x17, x14, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.addsat x17, x14, x7
+
+
+# CHECK: :[[@LINE+1]]:21: error: invalid operand for instruction
+qc.addusat x8, x18, 28
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.addusat x8, x18
+
+# CHECK: :[[@LINE+1]]:12: error: invalid operand for instruction
+qc.addusat x0, x18, x28
+
+# CHECK: :[[@LINE+1]]:16: error: invalid operand for instruction
+qc.addusat x8, x0, x28
+
+# CHECK: :[[@LINE+1]]:21: error: invalid operand for instruction
+qc.addusat x8, x18, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.addusat x8, x18, x28
+
+
+# CHECK: :[[@LINE+1]]:20: error: invalid operand for instruction
+qc.subsat x22, x2, 12
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.subsat x22, x2
+
+# CHECK: :[[@LINE+1]]:11: error: invalid operand for instruction
+qc.subsat x0, x2, x12
+
+# CHECK: :[[@LINE+1]]:16: error: invalid operand for instruction
+qc.subsat x22, x0, x12
+
+# CHECK: :[[@LINE+1]]:20: error: invalid operand for instruction
+qc.subsat x22, x2, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.subsat x22, x2, x12
+
+
+# CHECK: :[[@LINE+1]]:21: error: invalid operand for instruction
+qc.subusat x9, x14, 17
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.subusat x9, x14
+
+# CHECK: :[[@LINE+1]]:12: error: invalid operand for instruction
+qc.subusat x0, x14, x17
+
+# CHECK: :[[@LINE+1]]:16: error: invalid operand for instruction
+qc.subusat x9, x0, x17
+
+# CHECK: :[[@LINE+1]]:21: error: invalid operand for instruction
+qc.subusat x9, x14, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.subusat x9, x14, x17
+
+
+# CHECK: :[[@LINE+1]]:18: error: invalid operand for instruction
+qc.wrap x3, x30, 23
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.wrap x3, x30
+
+# CHECK: :[[@LINE+1]]:9: error: invalid operand for instruction
+qc.wrap x0, x30, x23
+
+# CHECK: :[[@LINE+1]]:18: error: invalid operand for instruction
+qc.wrap x3, x30, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.wrap x3, x30, x23
+
+
+# CHECK: :[[@LINE+1]]:10: error: invalid operand for instruction
+qc.wrapi x0, 12, 2047
+
+# CHECK: :[[@LINE+1]]:10: error: invalid operand for instruction
+qc.wrapi x0, x12, 2047
+
+# CHECK: :[[@LINE+1]]:14: error: invalid operand for instruction
+qc.wrapi x6, x0, 2047
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.wrapi x6, x12
+
+# CHECK-PLUS: :[[@LINE+1]]:19: error: immediate must be an integer in the range [0, 2047]
+qc.wrapi x6, x12, 2048
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.wrapi x6, x12, 2047
+
+
+# CHECK: :[[@LINE+1]]:13: error: invalid operand for instruction
+qc.norm x3, 7
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.norm x3
+
+# CHECK: :[[@LINE+1]]:9: error: invalid operand for instruction
+qc.norm x0, x7
+
+# CHECK: :[[@LINE+1]]:13: error: invalid operand for instruction
+qc.norm x3, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.norm x3, x7
+
+
+# CHECK: :[[@LINE+1]]:15: error: invalid operand for instruction
+qc.normu x11, 17
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.normu x11
+
+# CHECK: :[[@LINE+1]]:10: error: invalid operand for instruction
+qc.normu x0, x17
+
+# CHECK: :[[@LINE+1]]:15: error: invalid operand for instruction
+qc.normu x11, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.normu x11, x17
+
+
+# CHECK: :[[@LINE+1]]:16: error: invalid operand for instruction
+qc.normeu x26, 31
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.normeu x26
+
+# CHECK: :[[@LINE+1]]:11: error: invalid operand for instruction
+qc.normeu x0, x31
+
+# CHECK: :[[@LINE+1]]:16: error: invalid operand for instruction
+qc.normeu x26, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.normeu x26, x31
diff --git a/llvm/test/MC/RISCV/xqcia-valid.s b/llvm/test/MC/RISCV/xqcia-valid.s
new file mode 100644
index 00000000000000..6bd10492d4d6ab
--- /dev/null
+++ b/llvm/test/MC/RISCV/xqcia-valid.s
@@ -0,0 +1,55 @@
+# Xqcia - Qualcomm uC Arithmetic Extesnsion
+# RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-xqcia -riscv-no-aliases -show-encoding \
+# RUN:     | FileCheck -check-prefixes=CHECK-ENC,CHECK-INST %s
+# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+experimental-xqcia < %s \
+# RUN:     | llvm-objdump --mattr=+experimental-xqcia -M no-aliases --no-print-imm-hex -d - \
+# RUN:     | FileCheck -check-prefix=CHECK-INST %s
+# RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-xqcia -show-encoding \
+# RUN:     | FileCheck -check-prefixes=CHECK-ENC,CHECK-INST %s
+# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+experimental-xqcia < %s \
+# RUN:     | llvm-objdump --mattr=+experimental-xqcia --no-print-imm-hex -d - \
+# RUN:     | FileCheck -check-prefix=CHECK-INST %s
+
+# CHECK-INST: qc.slasat    a0, gp, a7
+# CHECK-ENC: encoding: [0x0b,0xb5,0x11,0x15]
+qc.slasat x10, x3, x17
+
+# CHECK-INST: qc.sllsat    s7, s9, s11
+# CHECK-ENC: encoding: [0x8b,0xbb,0xbc,0x19]
+qc.sllsat x23, x25, x27
+
+# CHECK-INST: qc.addsat    a7, a4, t2
+# CHECK-ENC: encoding: [0x8b,0x38,0x77,0x1c]
+qc.addsat x17, x14, x7
+
+# CHECK-INST: qc.addusat   s0, s2, t3
+# CHECK-ENC: encoding: [0x0b,0x34,0xc9,0x1f]
+qc.addusat x8, x18, x28
+
+# CHECK-INST: qc.subsat    s6, sp, a2
+# CHECK-ENC: encoding: [0x0b,0x3b,0xc1,0x20]
+qc.subsat x22, x2, x12
+
+# CHECK-INST: qc.subusat   s1, a4, a7
+# CHECK-ENC: encoding: [0x8b,0x34,0x17,0x23]
+qc.subusat x9, x14, x17
+
+# CHECK-INST: qc.wrap  gp, t5, s7
+# CHECK-ENC: encoding: [0x8b,0x31,0x7f,0x25]
+qc.wrap x3, x30, x23
+
+# CHECK-INST: qc.wrapi   t1, a2, 2047
+# CHECK-ENC: encoding: [0x0b,0x03,0xf6,0x7f]
+qc.wrapi x6, x12, 2047
+
+# CHECK-INST: qc.norm    gp, t2
+# CHECK-ENC: encoding: [0x8b,0xb1,0x03,0x0e]
+qc.norm x3, x7
+
+# CHECK-INST: qc.normu   a1, a7
+# CHECK-ENC: encoding: [0x8b,0xb5,0x08,0x10]
+qc.normu x11, x17
+
+# CHECK-INST: qc.normeu  s10, t6
+# CHECK-ENC: encoding: [0x0b,0xbd,0x0f,0x12]
+qc.normeu x26, x31
diff --git a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
index 23f1d832773ccf..f9ff45f1166039 100644
--- a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
+++ b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
@@ -657,6 +657,11 @@ TEST(ParseArchString, RejectsConflictingExtensions) {
     EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
               "'xqcisls' is only supported for 'rv32'");
   }
+
+  for (StringRef Input : {"rv64i_xqcia0p2"}) {
+    EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
+              "'xqcia' is only supported for 'rv32'");
+  }
 }
 
 TEST(ParseArchString, MissingDepency) {
@@ -1109,6 +1114,7 @@ Experimental extensions
     smctr                1.0
     ssctr                1.0
     svukte               0.3
+    xqcia                0.2
     xqcicsr        ...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Nov 29, 2024

@llvm/pr-subscribers-clang

Author: Sudharsan Veeravalli (svs-quic)

Changes

This extension adds 11 instructions that perform integer arithmetic.

The current spec can be found at:
https://github.com/quic/riscv-unified-db/releases/latest

This patch adds assembler only support.


Patch is 20.04 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/118113.diff

13 Files Affected:

  • (modified) clang/test/Driver/print-supported-extensions-riscv.c (+1)
  • (modified) llvm/docs/RISCVUsage.rst (+3)
  • (modified) llvm/docs/ReleaseNotes.md (+2)
  • (modified) llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp (+3)
  • (modified) llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp (+2)
  • (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h (+1)
  • (modified) llvm/lib/Target/RISCV/RISCVFeatures.td (+8)
  • (modified) llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td (+36)
  • (modified) llvm/lib/TargetParser/RISCVISAInfo.cpp (+2-1)
  • (modified) llvm/test/CodeGen/RISCV/attributes.ll (+2)
  • (added) llvm/test/MC/RISCV/xqcia-invalid.s (+201)
  • (added) llvm/test/MC/RISCV/xqcia-valid.s (+55)
  • (modified) llvm/unittests/TargetParser/RISCVISAInfoTest.cpp (+6)
diff --git a/clang/test/Driver/print-supported-extensions-riscv.c b/clang/test/Driver/print-supported-extensions-riscv.c
index 70b7a96daf1daf..9df903115b57c1 100644
--- a/clang/test/Driver/print-supported-extensions-riscv.c
+++ b/clang/test/Driver/print-supported-extensions-riscv.c
@@ -188,6 +188,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:     xqcia                0.2       'Xqcia' (Qualcomm uC Arithmetic Extension)
 // CHECK-NEXT:     xqcicsr              0.2       'Xqcicsr' (Qualcomm uC CSR Extension)
 // CHECK-NEXT:     xqcisls              0.2       'Xqcisls' (Qualcomm uC Scaled Load Store Extension)
 // CHECK-EMPTY:
diff --git a/llvm/docs/RISCVUsage.rst b/llvm/docs/RISCVUsage.rst
index 230bf66fcf461b..3978332b1149a9 100644
--- a/llvm/docs/RISCVUsage.rst
+++ b/llvm/docs/RISCVUsage.rst
@@ -426,6 +426,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-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.
+
 ``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.
 
diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index 6d50839d68953e..dc3f3aeb735f87 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -215,6 +215,8 @@ Changes to the RISC-V Backend
   extension.
 * Adds experimental assembler support for the Qualcomm uC 'Xqcisls` (Scaled Load Store)
   extension.
+* Adds experimental assembler support for the Qualcomm uC 'Xqcia` (Arithmetic)
+  extension.
 
 Changes to the WebAssembly Backend
 ----------------------------------
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index b843bb5ae43100..7c91dc07bbd3e5 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -717,6 +717,7 @@ struct RISCVOperand final : public MCParsedAsmOperand {
   bool isUImm6() const { return IsUImm<6>(); }
   bool isUImm7() const { return IsUImm<7>(); }
   bool isUImm8() const { return IsUImm<8>(); }
+  bool isUImm11() const { return IsUImm<11>(); }
   bool isUImm16() const { return IsUImm<16>(); }
   bool isUImm20() const { return IsUImm<20>(); }
   bool isUImm32() const { return IsUImm<32>(); }
@@ -1563,6 +1564,8 @@ bool RISCVAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
     return generateImmOutOfRangeError(
         Operands, ErrorInfo, -(1 << 9), (1 << 9) - 16,
         "immediate must be a multiple of 16 bytes and non-zero in the range");
+  case Match_InvalidUImm11:
+    return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 11) - 1);
   case Match_InvalidSImm12:
     return generateImmOutOfRangeError(
         Operands, ErrorInfo, -(1 << 11), (1 << 11) - 1,
diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
index 95658f24f79e1c..4d563046923a58 100644
--- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
+++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
@@ -686,6 +686,8 @@ DecodeStatus RISCVDisassembler::getInstruction32(MCInst &MI, uint64_t &Size,
                         "Qualcomm uC CSR custom opcode table");
   TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXqcisls, DecoderTableXqcisls32,
                         "Qualcomm uC Scaled Load Store custom opcode table");
+  TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXqcia, DecoderTableXqcia32,
+                        "Qualcomm uC Arithmetic custom opcode table");
   TRY_TO_DECODE(true, DecoderTable32, "RISCV32 table");
 
   return MCDisassembler::Fail;
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
index ca2f868cd4e764..9e36d62352ae51 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
@@ -312,6 +312,7 @@ enum OperandType : unsigned {
   OPERAND_UIMM8_GE32,
   OPERAND_UIMM9_LSB000,
   OPERAND_UIMM10_LSB00_NONZERO,
+  OPERAND_UIMM11,
   OPERAND_UIMM12,
   OPERAND_UIMM16,
   OPERAND_UIMM32,
diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td
index 95a37a76836729..52268c3fa62ccb 100644
--- a/llvm/lib/Target/RISCV/RISCVFeatures.td
+++ b/llvm/lib/Target/RISCV/RISCVFeatures.td
@@ -1359,6 +1359,14 @@ def HasVendorXqcisls
       AssemblerPredicate<(all_of FeatureVendorXqcisls),
                          "'Xqcisls' (Qualcomm uC Scaled Load Store Extension)">;
 
+def FeatureVendorXqcia
+    : RISCVExperimentalExtension<"xqcia", 0, 2,
+                                 "'Xqcia' (Qualcomm uC Arithmetic Extension)">;
+def HasVendorXqcia
+    : Predicate<"Subtarget->hasVendorXqcia()">,
+      AssemblerPredicate<(all_of FeatureVendorXqcia),
+                         "'Xqcia' (Qualcomm uC Arithmetic Extension)">;
+
 //===----------------------------------------------------------------------===//
 // LLVM specific features and extensions
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
index 3f53165d5235e6..29758014f73edf 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
@@ -14,6 +14,8 @@
 // Operand and SDNode transformation definitions.
 //===----------------------------------------------------------------------===//
 
+def uimm11 : RISCVUImmLeafOp<11>;
+
 //===----------------------------------------------------------------------===//
 // Instruction Formats
 //===----------------------------------------------------------------------===//
@@ -45,6 +47,16 @@ class QCIStore_ScaleIdx<bits<4> func4, string opcodestr>
 }
 }
 
+class QCIRVInstR<bits<4> func4, string opcodestr>
+    : RVInstR<{0b000, func4}, 0b011, OPC_CUSTOM_0, (outs GPRNoX0:$rd),
+              (ins GPRNoX0:$rs1), opcodestr, "$rd, $rs1"> {
+  let rs2 = 0;
+}
+
+class QCIRVInstRR<bits<5> func5, DAGOperand InTyRs1, string opcodestr>
+    : RVInstR<{0b00, func5}, 0b011, OPC_CUSTOM_0, (outs GPRNoX0:$rd),
+              (ins InTyRs1:$rs1, GPRNoX0:$rs2), opcodestr, "$rd, $rs1, $rs2">;
+
 //===----------------------------------------------------------------------===//
 // Instructions
 //===----------------------------------------------------------------------===//
@@ -72,3 +84,27 @@ let Predicates = [HasVendorXqcisls, IsRV32], DecoderNamespace = "Xqcisls" in {
   def  QC_SRH  : QCIStore_ScaleIdx<0b1110, "qc.srh">;
   def  QC_SRW  : QCIStore_ScaleIdx<0b1111, "qc.srw">;
 } // Predicates = [HasVendorXqcisls, IsRV32], DecoderNamespace = "Xqcisls"
+
+let Predicates = [HasVendorXqcia, IsRV32], DecoderNamespace = "Xqcia" in {
+let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in {
+  def QC_SLASAT : QCIRVInstRR<0b01010, GPRNoX0, "qc.slasat">;
+  def QC_SLLSAT : QCIRVInstRR<0b01100, GPRNoX0, "qc.sllsat">;
+  def QC_ADDSAT : QCIRVInstRR<0b01110, GPRNoX0, "qc.addsat">;
+  def QC_ADDUSAT : QCIRVInstRR<0b01111, GPRNoX0, "qc.addusat">;
+  def QC_SUBSAT : QCIRVInstRR<0b10000, GPRNoX0, "qc.subsat">;
+  def QC_SUBUSAT : QCIRVInstRR<0b10001, GPRNoX0, "qc.subusat">;
+
+  def QC_WRAP : QCIRVInstRR<0b10010, GPR, "qc.wrap">;
+  def QC_WRAPI : RVInstI<0b000, OPC_CUSTOM_0, (outs GPRNoX0:$rd),
+                         (ins GPRNoX0:$rs1, uimm11:$imm11), "qc.wrapi",
+                         "$rd, $rs1, $imm11"> {
+    bits<11> imm11;
+
+    let imm12 = {0b0, imm11};
+  }
+
+  def QC_NORM : QCIRVInstR<0b0111, "qc.norm">;
+  def QC_NORMU : QCIRVInstR<0b1000, "qc.normu">;
+  def QC_NORMEU : QCIRVInstR<0b1001, "qc.normeu">;
+} // hasSideEffects = 0, mayLoad = 0, mayStore = 0
+} // Predicates = [HasVendorXqcia, IsRV32], DecoderNamespace = "Xqcia"
diff --git a/llvm/lib/TargetParser/RISCVISAInfo.cpp b/llvm/lib/TargetParser/RISCVISAInfo.cpp
index 5673866f9d9d9d..d54b81e0d39810 100644
--- a/llvm/lib/TargetParser/RISCVISAInfo.cpp
+++ b/llvm/lib/TargetParser/RISCVISAInfo.cpp
@@ -741,7 +741,8 @@ Error RISCVISAInfo::checkDependency() {
   bool HasVector = Exts.count("zve32x") != 0;
   bool HasZvl = MinVLen != 0;
   bool HasZcmt = Exts.count("zcmt") != 0;
-  static constexpr StringLiteral XqciExts[] = {{"xqcicsr"}, {"xqcisls"}};
+  static constexpr StringLiteral XqciExts[] = {
+      {"xqcia"}, {"xqcicsr"}, {"xqcisls"}};
 
   if (HasI && HasE)
     return getIncompatibleError("i", "e");
diff --git a/llvm/test/CodeGen/RISCV/attributes.ll b/llvm/test/CodeGen/RISCV/attributes.ll
index 8a3d5e5cfe6216..356dce29795658 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-xqcia %s -o - | FileCheck --check-prefix=RV32XQCIA %s
 ; RUN: llc -mtriple=riscv32 -mattr=+experimental-xqcicsr %s -o - | FileCheck --check-prefix=RV32XQCICSR %s
 ; RUN: llc -mtriple=riscv32 -mattr=+experimental-xqcisls %s -o - | FileCheck --check-prefix=RV32XQCISLS %s
 ; RUN: llc -mtriple=riscv32 -mattr=+zaamo %s -o - | FileCheck --check-prefix=RV32ZAAMO %s
@@ -387,6 +388,7 @@
 ; RV32XTHEADMEMPAIR: .attribute 5, "rv32i2p1_xtheadmempair1p0"
 ; RV32XTHEADSYNC: .attribute 5, "rv32i2p1_xtheadsync1p0"
 ; RV32XWCHC: .attribute 5, "rv32i2p1_xwchc2p2"
+; RV32XQCIA: .attribute 5, "rv32i2p1_xqcia0p2"
 ; RV32XQCICSR: .attribute 5, "rv32i2p1_xqcicsr0p2"
 ; RV32XQCISLS: .attribute 5, "rv32i2p1_xqcisls0p2"
 ; RV32ZAAMO: .attribute 5, "rv32i2p1_zaamo1p0"
diff --git a/llvm/test/MC/RISCV/xqcia-invalid.s b/llvm/test/MC/RISCV/xqcia-invalid.s
new file mode 100644
index 00000000000000..a410fb63fad9c9
--- /dev/null
+++ b/llvm/test/MC/RISCV/xqcia-invalid.s
@@ -0,0 +1,201 @@
+# Xqcia - Qualcomm uC Arithmetic Extension
+# RUN: not llvm-mc -triple riscv32 -mattr=+experimental-xqcia < %s 2>&1 \
+# RUN:     | FileCheck -check-prefixes=CHECK,CHECK-PLUS %s
+# RUN: not llvm-mc -triple riscv32 -mattr=-experimental-xqcia < %s 2>&1 \
+# RUN:     | FileCheck -check-prefixes=CHECK,CHECK-MINUS %s
+
+# CHECK: :[[@LINE+1]]:20: error: invalid operand for instruction
+qc.slasat x10, x3, 17
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.slasat x10, x3
+
+# CHECK: :[[@LINE+1]]:11: error: invalid operand for instruction
+qc.slasat x0, x3, x17
+
+# CHECK: :[[@LINE+1]]:16: error: invalid operand for instruction
+qc.slasat x10, x0, x17
+
+# CHECK: :[[@LINE+1]]:20: error: invalid operand for instruction
+qc.slasat x10, x3, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.slasat x10, x3, x17
+
+
+# CHECK: :[[@LINE+1]]:21: error: invalid operand for instruction
+qc.sllsat x23, x25, 27
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.sllsat x23, x25
+
+# CHECK: :[[@LINE+1]]:11: error: invalid operand for instruction
+qc.sllsat x0, x25, x27
+
+# CHECK: :[[@LINE+1]]:16: error: invalid operand for instruction
+qc.sllsat x23, x0, x27
+
+# CHECK: :[[@LINE+1]]:21: error: invalid operand for instruction
+qc.sllsat x23, x25, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.sllsat x23, x25, x27
+
+
+# CHECK: :[[@LINE+1]]:21: error: invalid operand for instruction
+qc.addsat x17, x14, 7
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.addsat x17, x14
+
+# CHECK: :[[@LINE+1]]:11: error: invalid operand for instruction
+qc.addsat x0, x14, x7
+
+# CHECK: :[[@LINE+1]]:16: error: invalid operand for instruction
+qc.addsat x17, x0, x7
+
+# CHECK: :[[@LINE+1]]:21: error: invalid operand for instruction
+qc.addsat x17, x14, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.addsat x17, x14, x7
+
+
+# CHECK: :[[@LINE+1]]:21: error: invalid operand for instruction
+qc.addusat x8, x18, 28
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.addusat x8, x18
+
+# CHECK: :[[@LINE+1]]:12: error: invalid operand for instruction
+qc.addusat x0, x18, x28
+
+# CHECK: :[[@LINE+1]]:16: error: invalid operand for instruction
+qc.addusat x8, x0, x28
+
+# CHECK: :[[@LINE+1]]:21: error: invalid operand for instruction
+qc.addusat x8, x18, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.addusat x8, x18, x28
+
+
+# CHECK: :[[@LINE+1]]:20: error: invalid operand for instruction
+qc.subsat x22, x2, 12
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.subsat x22, x2
+
+# CHECK: :[[@LINE+1]]:11: error: invalid operand for instruction
+qc.subsat x0, x2, x12
+
+# CHECK: :[[@LINE+1]]:16: error: invalid operand for instruction
+qc.subsat x22, x0, x12
+
+# CHECK: :[[@LINE+1]]:20: error: invalid operand for instruction
+qc.subsat x22, x2, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.subsat x22, x2, x12
+
+
+# CHECK: :[[@LINE+1]]:21: error: invalid operand for instruction
+qc.subusat x9, x14, 17
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.subusat x9, x14
+
+# CHECK: :[[@LINE+1]]:12: error: invalid operand for instruction
+qc.subusat x0, x14, x17
+
+# CHECK: :[[@LINE+1]]:16: error: invalid operand for instruction
+qc.subusat x9, x0, x17
+
+# CHECK: :[[@LINE+1]]:21: error: invalid operand for instruction
+qc.subusat x9, x14, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.subusat x9, x14, x17
+
+
+# CHECK: :[[@LINE+1]]:18: error: invalid operand for instruction
+qc.wrap x3, x30, 23
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.wrap x3, x30
+
+# CHECK: :[[@LINE+1]]:9: error: invalid operand for instruction
+qc.wrap x0, x30, x23
+
+# CHECK: :[[@LINE+1]]:18: error: invalid operand for instruction
+qc.wrap x3, x30, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.wrap x3, x30, x23
+
+
+# CHECK: :[[@LINE+1]]:10: error: invalid operand for instruction
+qc.wrapi x0, 12, 2047
+
+# CHECK: :[[@LINE+1]]:10: error: invalid operand for instruction
+qc.wrapi x0, x12, 2047
+
+# CHECK: :[[@LINE+1]]:14: error: invalid operand for instruction
+qc.wrapi x6, x0, 2047
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.wrapi x6, x12
+
+# CHECK-PLUS: :[[@LINE+1]]:19: error: immediate must be an integer in the range [0, 2047]
+qc.wrapi x6, x12, 2048
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.wrapi x6, x12, 2047
+
+
+# CHECK: :[[@LINE+1]]:13: error: invalid operand for instruction
+qc.norm x3, 7
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.norm x3
+
+# CHECK: :[[@LINE+1]]:9: error: invalid operand for instruction
+qc.norm x0, x7
+
+# CHECK: :[[@LINE+1]]:13: error: invalid operand for instruction
+qc.norm x3, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.norm x3, x7
+
+
+# CHECK: :[[@LINE+1]]:15: error: invalid operand for instruction
+qc.normu x11, 17
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.normu x11
+
+# CHECK: :[[@LINE+1]]:10: error: invalid operand for instruction
+qc.normu x0, x17
+
+# CHECK: :[[@LINE+1]]:15: error: invalid operand for instruction
+qc.normu x11, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.normu x11, x17
+
+
+# CHECK: :[[@LINE+1]]:16: error: invalid operand for instruction
+qc.normeu x26, 31
+
+# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
+qc.normeu x26
+
+# CHECK: :[[@LINE+1]]:11: error: invalid operand for instruction
+qc.normeu x0, x31
+
+# CHECK: :[[@LINE+1]]:16: error: invalid operand for instruction
+qc.normeu x26, x0
+
+# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcia' (Qualcomm uC Arithmetic Extension)
+qc.normeu x26, x31
diff --git a/llvm/test/MC/RISCV/xqcia-valid.s b/llvm/test/MC/RISCV/xqcia-valid.s
new file mode 100644
index 00000000000000..6bd10492d4d6ab
--- /dev/null
+++ b/llvm/test/MC/RISCV/xqcia-valid.s
@@ -0,0 +1,55 @@
+# Xqcia - Qualcomm uC Arithmetic Extesnsion
+# RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-xqcia -riscv-no-aliases -show-encoding \
+# RUN:     | FileCheck -check-prefixes=CHECK-ENC,CHECK-INST %s
+# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+experimental-xqcia < %s \
+# RUN:     | llvm-objdump --mattr=+experimental-xqcia -M no-aliases --no-print-imm-hex -d - \
+# RUN:     | FileCheck -check-prefix=CHECK-INST %s
+# RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-xqcia -show-encoding \
+# RUN:     | FileCheck -check-prefixes=CHECK-ENC,CHECK-INST %s
+# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+experimental-xqcia < %s \
+# RUN:     | llvm-objdump --mattr=+experimental-xqcia --no-print-imm-hex -d - \
+# RUN:     | FileCheck -check-prefix=CHECK-INST %s
+
+# CHECK-INST: qc.slasat    a0, gp, a7
+# CHECK-ENC: encoding: [0x0b,0xb5,0x11,0x15]
+qc.slasat x10, x3, x17
+
+# CHECK-INST: qc.sllsat    s7, s9, s11
+# CHECK-ENC: encoding: [0x8b,0xbb,0xbc,0x19]
+qc.sllsat x23, x25, x27
+
+# CHECK-INST: qc.addsat    a7, a4, t2
+# CHECK-ENC: encoding: [0x8b,0x38,0x77,0x1c]
+qc.addsat x17, x14, x7
+
+# CHECK-INST: qc.addusat   s0, s2, t3
+# CHECK-ENC: encoding: [0x0b,0x34,0xc9,0x1f]
+qc.addusat x8, x18, x28
+
+# CHECK-INST: qc.subsat    s6, sp, a2
+# CHECK-ENC: encoding: [0x0b,0x3b,0xc1,0x20]
+qc.subsat x22, x2, x12
+
+# CHECK-INST: qc.subusat   s1, a4, a7
+# CHECK-ENC: encoding: [0x8b,0x34,0x17,0x23]
+qc.subusat x9, x14, x17
+
+# CHECK-INST: qc.wrap  gp, t5, s7
+# CHECK-ENC: encoding: [0x8b,0x31,0x7f,0x25]
+qc.wrap x3, x30, x23
+
+# CHECK-INST: qc.wrapi   t1, a2, 2047
+# CHECK-ENC: encoding: [0x0b,0x03,0xf6,0x7f]
+qc.wrapi x6, x12, 2047
+
+# CHECK-INST: qc.norm    gp, t2
+# CHECK-ENC: encoding: [0x8b,0xb1,0x03,0x0e]
+qc.norm x3, x7
+
+# CHECK-INST: qc.normu   a1, a7
+# CHECK-ENC: encoding: [0x8b,0xb5,0x08,0x10]
+qc.normu x11, x17
+
+# CHECK-INST: qc.normeu  s10, t6
+# CHECK-ENC: encoding: [0x0b,0xbd,0x0f,0x12]
+qc.normeu x26, x31
diff --git a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
index 23f1d832773ccf..f9ff45f1166039 100644
--- a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
+++ b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
@@ -657,6 +657,11 @@ TEST(ParseArchString, RejectsConflictingExtensions) {
     EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
               "'xqcisls' is only supported for 'rv32'");
   }
+
+  for (StringRef Input : {"rv64i_xqcia0p2"}) {
+    EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
+              "'xqcia' is only supported for 'rv32'");
+  }
 }
 
 TEST(ParseArchString, MissingDepency) {
@@ -1109,6 +1114,7 @@ Experimental extensions
     smctr                1.0
     ssctr                1.0
     svukte               0.3
+    xqcia                0.2
     xqcicsr        ...
[truncated]

}

def QC_NORM : QCIRVInstR<0b0111, "qc.norm">;
def QC_NORMU : QCIRVInstR<0b1000, "qc.normu">;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I have a question about the semantics of qc.normu in the spec

XReg clz = (xlen() - 1) - $signed(highest_set_bit(X[rs1]));
XReg exp = (X[rs1] << clz);
XReg mnt = (-clz);
X[rd] = {mnt[23:0], exp[7:0]};

Are the assignments of mnt and exp swapped? Unless I'm misunderstanding, I would expect exp to be based only on clz and mnt to be baed on (X[rs1] << clz).

Also the assignment of X[rd] = {mnt[23:0], exp[7:0]}; seems like it should be taking the upper 24 bits of mnt not the lower 24 bits? But maybe I've misunderstood?

Copy link
Member

@lenary lenary left a comment

Choose a reason for hiding this comment

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

LGTM.

I note Craig has questions about the spec, we will ensure those are relayed to the spec authors, but they don't relate to encoding/assembling problems, so I'm not sure if they should block landing this.

@topperc
Copy link
Collaborator

topperc commented Nov 30, 2024

LGTM.

I note Craig has questions about the spec, we will ensure those are relayed to the spec authors, but they don't relate to encoding/assembling problems, so I'm not sure if they should block landing this.

I don't consider my questions blocking. I just didn't know where else to ask.

Copy link
Collaborator

@topperc topperc left a comment

Choose a reason for hiding this comment

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

LGTM

@svs-quic svs-quic merged commit 6881c6d into llvm:main Dec 1, 2024
14 checks passed
@svs-quic svs-quic deleted the xqcia branch December 1, 2024 11:36
@llvm-ci
Copy link
Collaborator

llvm-ci commented Dec 1, 2024

LLVM Buildbot has detected a new failure on builder lld-x86_64-win running on as-worker-93 while building clang,llvm at step 7 "test-build-unified-tree-check-all".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/146/builds/1731

Here is the relevant piece of the build log for the reference
Step 7 (test-build-unified-tree-check-all) failure: test (failure)
******************** TEST 'LLVM-Unit :: Support/./SupportTests.exe/37/87' FAILED ********************
Script(shard):
--
GTEST_OUTPUT=json:C:\a\lld-x86_64-win\build\unittests\Support\.\SupportTests.exe-LLVM-Unit-10980-37-87.json GTEST_SHUFFLE=0 GTEST_TOTAL_SHARDS=87 GTEST_SHARD_INDEX=37 C:\a\lld-x86_64-win\build\unittests\Support\.\SupportTests.exe
--

Script:
--
C:\a\lld-x86_64-win\build\unittests\Support\.\SupportTests.exe --gtest_filter=ProgramEnvTest.CreateProcessLongPath
--
C:\a\lld-x86_64-win\llvm-project\llvm\unittests\Support\ProgramTest.cpp(160): error: Expected equality of these values:
  0
  RC
    Which is: -2

C:\a\lld-x86_64-win\llvm-project\llvm\unittests\Support\ProgramTest.cpp(163): error: fs::remove(Twine(LongPath)): did not return errc::success.
error number: 13
error message: permission denied



C:\a\lld-x86_64-win\llvm-project\llvm\unittests\Support\ProgramTest.cpp:160
Expected equality of these values:
  0
  RC
    Which is: -2

C:\a\lld-x86_64-win\llvm-project\llvm\unittests\Support\ProgramTest.cpp:163
fs::remove(Twine(LongPath)): did not return errc::success.
error number: 13
error message: permission denied




********************


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:RISC-V clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang Clang issues not falling into any other category mc Machine (object) code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants