[llvm] [RISCV] Add symbol parsing support for Xqcili load large immediate instructions (PR #134581)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Apr 6 22:37:00 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mc
Author: Sudharsan Veeravalli (svs-quic)
<details>
<summary>Changes</summary>
This patch adds support for parsing symbols in the Xqcili load large immediate instructions. The 32 bit `qc.li` instructions uses the `R_RISCV_QC_ABS20_U` relocation while the 48 bit `qc.e.li` instruction uses the `R_RISCV_QC_E_32` relocation and the `InstFormatQC_EAI` instruction format.
Vendor relocation support will be added in a later patch.
---
Full diff: https://github.com/llvm/llvm-project/pull/134581.diff
12 Files Affected:
- (modified) llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp (+31-5)
- (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp (+16-1)
- (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h (+1-1)
- (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp (+4)
- (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h (+4)
- (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp (+5)
- (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp (+3)
- (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h (+1)
- (modified) llvm/lib/Target/RISCV/RISCVInstrInfo.cpp (+3-1)
- (modified) llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td (+15-4)
- (modified) llvm/test/MC/RISCV/xqcili-invalid.s (+1-1)
- (added) llvm/test/MC/RISCV/xqcili-relocations.s (+49)
``````````diff
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index dba78fef0bad8..c682722cdb701 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -794,9 +794,7 @@ struct RISCVOperand final : public MCParsedAsmOperand {
bool isSImm6() const { return isSImm<6>(); }
bool isSImm11() const { return isSImm<11>(); }
bool isSImm16() const { return isSImm<16>(); }
- bool isSImm20() const { return isSImm<20>(); }
bool isSImm26() const { return isSImm<26>(); }
- bool isSImm32() const { return isSImm<32>(); }
bool isSImm5NonZero() const {
return isSImmPred([](int64_t Imm) { return Imm != 0 && isInt<5>(Imm); });
@@ -876,6 +874,32 @@ struct RISCVOperand final : public MCParsedAsmOperand {
return isUImmPred([](int64_t Imm) { return isUInt<16>(Imm) && Imm != 0; });
}
+ bool isSImm20LI() const {
+ if (!isImm())
+ return false;
+
+ int64_t Imm;
+ if (evaluateConstantImm(getImm(), Imm))
+ return isInt<20>(fixImmediateForRV32(Imm, isRV64Imm()));
+
+ RISCVMCExpr::Specifier VK = RISCVMCExpr::VK_None;
+ return RISCVAsmParser::classifySymbolRef(getImm(), VK) &&
+ VK == RISCVMCExpr::VK_QC_ABS20;
+ }
+
+ bool isSImm32() const {
+ if (!isImm())
+ return false;
+
+ int64_t Imm;
+ if (evaluateConstantImm(getImm(), Imm))
+ return isInt<32>(fixImmediateForRV32(Imm, isRV64Imm()));
+
+ RISCVMCExpr::Specifier VK = RISCVMCExpr::VK_None;
+ return RISCVAsmParser::classifySymbolRef(getImm(), VK) &&
+ VK == RISCVMCExpr::VK_None;
+ }
+
bool isUImm20LUI() const {
if (!isImm())
return false;
@@ -1519,6 +1543,11 @@ bool RISCVAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
return generateImmOutOfRangeError(
Operands, ErrorInfo, -(1 << 15), (1 << 15) - 1,
"immediate must be non-zero in the range");
+ case Match_InvalidSImm20LI:
+ return generateImmOutOfRangeError(
+ Operands, ErrorInfo, -(1 << 19), (1 << 19) - 1,
+ "operand must be a symbol with a %qc.abs20 specifier or an integer "
+ " in the range");
case Match_InvalidUImm20LUI:
return generateImmOutOfRangeError(
Operands, ErrorInfo, 0, (1 << 20) - 1,
@@ -1555,9 +1584,6 @@ bool RISCVAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
case Match_InvalidSImm26:
return generateImmOutOfRangeError(Operands, ErrorInfo, -(1 << 25),
(1 << 25) - 1);
- case Match_InvalidSImm20:
- return generateImmOutOfRangeError(Operands, ErrorInfo, -(1 << 19),
- (1 << 19) - 1);
case Match_InvalidSImm32:
return generateImmOutOfRangeError(Operands, ErrorInfo,
std::numeric_limits<int32_t>::min(),
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
index 6641116db9a19..9ae6ba04f262e 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
@@ -93,6 +93,8 @@ RISCVAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
{"fixup_riscv_tlsdesc_add_lo12", 20, 12, 0},
{"fixup_riscv_tlsdesc_call", 0, 0, 0},
{"fixup_riscv_qc_e_branch", 0, 48, MCFixupKindInfo::FKF_IsPCRel},
+ {"fixup_riscv_qc_e_32", 16, 32, 0},
+ {"fixup_riscv_qc_abs20_u", 12, 20, 0},
};
static_assert((std::size(Infos)) == RISCV::NumTargetFixupKinds,
"Not all fixup kinds added to Infos array");
@@ -559,7 +561,20 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
(Bit5 << 2);
return Value;
}
-
+ case RISCV::fixup_riscv_qc_e_32: {
+ if (!isInt<32>(Value))
+ Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
+ return ((Value & 0xffffffff) << 16);
+ }
+ case RISCV::fixup_riscv_qc_abs20_u: {
+ if (!isInt<20>(Value))
+ Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
+ uint64_t Bit20 = (Value >> 20) & 0x1;
+ uint64_t Bit15_1 = (Value >> 1) & 0x7fff;
+ uint64_t Bit19_16 = (Value >> 16) & 0xf;
+ Value = (Bit20 << 31) | (Bit15_1 << 16) | (Bit19_16 << 12);
+ return Value;
+ }
}
}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
index 506c638c83a72..17b99f26a1b8c 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
@@ -340,7 +340,7 @@ enum OperandType : unsigned {
OPERAND_SIMM12_LSB00000,
OPERAND_SIMM16,
OPERAND_SIMM16_NONZERO,
- OPERAND_SIMM20,
+ OPERAND_SIMM20_LI,
OPERAND_SIMM26,
OPERAND_SIMM32,
OPERAND_CLUI_IMM,
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
index 5fdf8e23d1214..9859bf39bcc5e 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
@@ -173,6 +173,10 @@ unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx,
return ELF::R_RISCV_RELAX;
case RISCV::fixup_riscv_align:
return ELF::R_RISCV_ALIGN;
+ case RISCV::fixup_riscv_qc_e_32:
+ return ELF::R_RISCV_QC_E_32;
+ case RISCV::fixup_riscv_qc_abs20_u:
+ return ELF::R_RISCV_QC_ABS20_U;
}
}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
index df7916a4490b7..a4f5673fca225 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
@@ -80,6 +80,10 @@ enum Fixups {
// 12-bit fixup for symbol references in the 48-bit Xqcibi branch immediate
// instructions
fixup_riscv_qc_e_branch,
+ // 32-bit fixup for symbol references in the 48-bit qc.e.li instruction
+ fixup_riscv_qc_e_32,
+ // 20-bit fixup for symbol references in the 32-bit qc.li instruction
+ fixup_riscv_qc_abs20_u,
// Used as a sentinel, must be the last
fixup_riscv_invalid,
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
index 37a2ac336d20c..95858da45f202 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
@@ -653,6 +653,9 @@ uint64_t RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo,
case RISCVMCExpr::VK_TLSDESC_CALL:
FixupKind = RISCV::fixup_riscv_tlsdesc_call;
break;
+ case RISCVMCExpr::VK_QC_ABS20:
+ FixupKind = RISCV::fixup_riscv_qc_abs20_u;
+ break;
}
} else if (Kind == MCExpr::SymbolRef || Kind == MCExpr::Binary) {
// FIXME: Sub kind binary exprs have chance of underflow.
@@ -668,6 +671,8 @@ uint64_t RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo,
FixupKind = RISCV::fixup_riscv_12_i;
} else if (MIFrm == RISCVII::InstFormatQC_EB) {
FixupKind = RISCV::fixup_riscv_qc_e_branch;
+ } else if (MIFrm == RISCVII::InstFormatQC_EAI) {
+ FixupKind = RISCV::fixup_riscv_qc_e_32;
}
}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
index a48dca7be0d28..d6650e156c8b3 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
@@ -116,6 +116,7 @@ RISCVMCExpr::getSpecifierForName(StringRef name) {
.Case("tlsdesc_load_lo", VK_TLSDESC_LOAD_LO)
.Case("tlsdesc_add_lo", VK_TLSDESC_ADD_LO)
.Case("tlsdesc_call", VK_TLSDESC_CALL)
+ .Case("qc.abs20", VK_QC_ABS20)
// Used in data directives
.Case("pltpcrel", VK_PLTPCREL)
.Case("gotpcrel", VK_GOTPCREL)
@@ -164,6 +165,8 @@ StringRef RISCVMCExpr::getSpecifierName(Specifier S) {
return "gotpcrel";
case VK_PLTPCREL:
return "pltpcrel";
+ case VK_QC_ABS20:
+ return "qc.abs20";
}
llvm_unreachable("Invalid ELF symbol kind");
}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h
index fd6993c18d820..e0aa7ff244521 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h
@@ -43,6 +43,7 @@ class RISCVMCExpr : public MCTargetExpr {
VK_TLSDESC_LOAD_LO,
VK_TLSDESC_ADD_LO,
VK_TLSDESC_CALL,
+ VK_QC_ABS20,
};
private:
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
index 44894365b6d41..3eca78bb063f3 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
@@ -2654,7 +2654,6 @@ bool RISCVInstrInfo::verifyInstruction(const MachineInstr &MI,
CASE_OPERAND_SIMM(6)
CASE_OPERAND_SIMM(11)
CASE_OPERAND_SIMM(12)
- CASE_OPERAND_SIMM(20)
CASE_OPERAND_SIMM(26)
CASE_OPERAND_SIMM(32)
// clang-format on
@@ -2673,6 +2672,9 @@ bool RISCVInstrInfo::verifyInstruction(const MachineInstr &MI,
case RISCVOp::OPERAND_SIMM12_LSB00000:
Ok = isShiftedInt<7, 5>(Imm);
break;
+ case RISCVOp::OPERAND_SIMM20_LI:
+ Ok = isInt<20>(Imm);
+ break;
case RISCVOp::OPERAND_UIMMLOG2XLEN:
Ok = STI.is64Bit() ? isUInt<6>(Imm) : isUInt<5>(Imm);
break;
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
index f762c4943f630..5368aa63fea6c 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
@@ -103,7 +103,18 @@ def simm16nonzero : RISCVOp<XLenVT>,
let OperandType = "OPERAND_SIMM16_NONZERO";
}
-def simm20 : RISCVSImmLeafOp<20>;
+def simm20_li : RISCVOp<XLenVT> {
+ let ParserMatchClass = SImmAsmOperand<20, "LI">;
+ let EncoderMethod = "getImmOpValue";
+ let DecoderMethod = "decodeSImmOperand<20>";
+ let OperandType = "OPERAND_SIMM20_LI";
+ let MCOperandPredicate = [{
+ int64_t Imm;
+ if (MCOp.evaluateAsConstantImm(Imm))
+ return isInt<20>(Imm);
+ return MCOp.isBareSymbolRef();
+ }];
+}
def simm26 : RISCVSImmLeafOp<26>;
@@ -118,7 +129,7 @@ def simm32 : RISCVOp<XLenVT> {
int64_t Imm;
if (MCOp.evaluateAsConstantImm(Imm))
return isInt<32>(Imm);
- return false;
+ return MCOp.isBareSymbolRef();
}];
}
@@ -1009,7 +1020,7 @@ let Predicates = [HasVendorXqcilb, IsRV32] in {
let Predicates = [HasVendorXqcili, IsRV32] in {
let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in {
- def QC_LI : RVInstU<OPC_OP_IMM_32, (outs GPRNoX0:$rd), (ins simm20:$imm20),
+ def QC_LI : RVInstU<OPC_OP_IMM_32, (outs GPRNoX0:$rd), (ins simm20_li:$imm20),
"qc.li", "$rd, $imm20"> {
let Inst{31} = imm20{19};
let Inst{30-16} = imm20{14-0};
@@ -1017,7 +1028,7 @@ let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in {
}
def QC_E_LI : RVInst48<(outs GPRNoX0:$rd), (ins simm32:$imm),
- "qc.e.li", "$rd, $imm", [], InstFormatOther> {
+ "qc.e.li", "$rd, $imm", [], InstFormatQC_EAI> {
bits<5> rd;
bits<32> imm;
diff --git a/llvm/test/MC/RISCV/xqcili-invalid.s b/llvm/test/MC/RISCV/xqcili-invalid.s
index 0c4b4f04e86e9..567ed8ba89736 100644
--- a/llvm/test/MC/RISCV/xqcili-invalid.s
+++ b/llvm/test/MC/RISCV/xqcili-invalid.s
@@ -25,7 +25,7 @@ qc.li x0, 114514
# CHECK: :[[@LINE+1]]:1: error: too few operands for instruction
qc.li x10
-# CHECK-IMM: :[[@LINE+1]]:12: error: immediate must be an integer in the range [-524288, 524287]
+# CHECK-IMM: :[[@LINE+1]]:12: error: operand must be a symbol with a %qc.abs20 specifier or an integer in the range [-524288, 524287]
qc.li x10, 33554432
# CHECK-EXT: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcili' (Qualcomm uC Load Large Immediate Extension)
diff --git a/llvm/test/MC/RISCV/xqcili-relocations.s b/llvm/test/MC/RISCV/xqcili-relocations.s
new file mode 100644
index 0000000000000..b0a3f3bae11d5
--- /dev/null
+++ b/llvm/test/MC/RISCV/xqcili-relocations.s
@@ -0,0 +1,49 @@
+# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcili %s -show-encoding \
+# RUN: | FileCheck -check-prefix=INSTR -check-prefix=FIXUP %s
+# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+experimental-xqcili %s -o %t.o
+# RUN: llvm-readobj -r %t.o | FileCheck -check-prefix=RELOC %s
+
+# Check prefixes:
+# RELOC - Check the relocation in the object.
+# FIXUP - Check the fixup on the instruction.
+# INSTR - Check the instruction is handled properly by the ASMPrinter.
+
+.text
+
+qc.li x4, %qc.abs20(foo)
+# RELOC: R_RISCV_CUSTOM192 foo 0x0
+# INSTR: qc.li tp, %qc.abs20(foo)
+# FIXUP: fixup A - offset: 0, value: %qc.abs20(foo), kind: fixup_riscv_qc_abs20_u
+
+qc.e.li x5, foo
+# RELOC: R_RISCV_CUSTOM194 foo 0x0
+# INSTR: qc.e.li t0, foo
+# FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_qc_e_32
+
+# Check that a label in a different section is handled similar to an undefined symbol
+qc.li x9, %qc.abs20(.bar)
+# RELOC: R_RISCV_CUSTOM192 .bar 0x0
+# INSTR: qc.li s1, %qc.abs20(.bar)
+# FIXUP: fixup A - offset: 0, value: %qc.abs20(.bar), kind: fixup_riscv_qc_abs20_u
+
+qc.e.li x8, .bar
+# RELOC: R_RISCV_CUSTOM194 .bar 0x0
+# INSTR: qc.e.li s0, .bar
+# FIXUP: fixup A - offset: 0, value: .bar, kind: fixup_riscv_qc_e_32
+
+# Check that branches to a defined symbol are handled correctly
+qc.li x7, %qc.abs20(.L1)
+# INSTR: qc.li t2, %qc.abs20(.L1)
+# FIXUP: fixup A - offset: 0, value: %qc.abs20(.L1), kind: fixup_riscv_qc_abs20_u
+
+qc.e.li x6, .L1
+# INSTR: qc.e.li t1, .L1
+# FIXUP: fixup A - offset: 0, value: .L1, kind: fixup_riscv_qc_e_32
+
+.L1:
+ ret
+
+.section .t2
+
+.bar:
+ ret
``````````
</details>
https://github.com/llvm/llvm-project/pull/134581
More information about the llvm-commits
mailing list