[llvm] [RISCV] Add symbol parsing support for Xqcilb long branch instructions (PR #135044)
Sudharsan Veeravalli via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 9 20:23:08 PDT 2025
https://github.com/svs-quic updated https://github.com/llvm/llvm-project/pull/135044
>From b59becf6f2935114409be5b8faafece631bc5ca3 Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <quic_svs at quicinc.com>
Date: Wed, 9 Apr 2025 21:50:58 +0530
Subject: [PATCH 1/2] [RISCV] Add symbol parsing support for Xqcilb long branch
instructions
---
.../Target/RISCV/AsmParser/RISCVAsmParser.cpp | 40 +++++++++++++
.../RISCV/MCTargetDesc/RISCVAsmBackend.cpp | 16 +++++
.../MCTargetDesc/RISCVELFObjectWriter.cpp | 2 +
.../RISCV/MCTargetDesc/RISCVFixupKinds.h | 2 +
.../RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp | 32 ++++++++++
.../Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp | 5 +-
.../Target/RISCV/MCTargetDesc/RISCVMCExpr.h | 1 +
llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td | 24 +++++++-
llvm/test/MC/RISCV/xqcilb-relocations.s | 59 +++++++++++++++++++
9 files changed, 179 insertions(+), 2 deletions(-)
create mode 100644 llvm/test/MC/RISCV/xqcilb-relocations.s
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index c57c123ab01dc..2af8282ac6361 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -202,6 +202,7 @@ class RISCVAsmParser : public MCTargetAsmParser {
ParseStatus parseOperandWithSpecifier(OperandVector &Operands);
ParseStatus parseBareSymbol(OperandVector &Operands);
ParseStatus parseCallSymbol(OperandVector &Operands);
+ ParseStatus parsePseudoQCJumpSymbol(OperandVector &Operands);
ParseStatus parsePseudoJumpSymbol(OperandVector &Operands);
ParseStatus parseJALOffset(OperandVector &Operands);
ParseStatus parseVTypeI(OperandVector &Operands);
@@ -590,6 +591,17 @@ struct RISCVOperand final : public MCParsedAsmOperand {
(VK == RISCVMCExpr::VK_CALL || VK == RISCVMCExpr::VK_CALL_PLT);
}
+ bool isPseudoQCJumpSymbol() const {
+ int64_t Imm;
+ // Must be of 'immediate' type but not a constant.
+ if (!isImm() || evaluateConstantImm(getImm(), Imm))
+ return false;
+
+ RISCVMCExpr::Specifier VK = RISCVMCExpr::VK_None;
+ return RISCVAsmParser::classifySymbolRef(getImm(), VK) &&
+ VK == RISCVMCExpr::VK_QC_E_JUMP_PLT;
+ }
+
bool isPseudoJumpSymbol() const {
int64_t Imm;
// Must be of 'immediate' type but not a constant.
@@ -2136,6 +2148,34 @@ ParseStatus RISCVAsmParser::parseCallSymbol(OperandVector &Operands) {
return ParseStatus::Success;
}
+ParseStatus RISCVAsmParser::parsePseudoQCJumpSymbol(OperandVector &Operands) {
+ SMLoc S = getLoc();
+ const MCExpr *Res;
+
+ if (getLexer().getKind() != AsmToken::Identifier)
+ return ParseStatus::NoMatch;
+ std::string Identifier(getTok().getIdentifier());
+
+ if (getLexer().peekTok().is(AsmToken::At)) {
+ Lex();
+ Lex();
+ StringRef PLT;
+ if (getParser().parseIdentifier(PLT) || PLT != "plt")
+ return ParseStatus::Failure;
+ } else {
+ Lex();
+ }
+
+ SMLoc E = SMLoc::getFromPointer(S.getPointer() + Identifier.size());
+ RISCVMCExpr::Specifier Kind = RISCVMCExpr::VK_QC_E_JUMP_PLT;
+
+ MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier);
+ Res = MCSymbolRefExpr::create(Sym, getContext());
+ Res = RISCVMCExpr::create(Res, Kind, getContext());
+ Operands.push_back(RISCVOperand::createImm(Res, S, E, isRV64()));
+ return ParseStatus::Success;
+}
+
ParseStatus RISCVAsmParser::parsePseudoJumpSymbol(OperandVector &Operands) {
SMLoc S = getLoc();
SMLoc E;
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
index c6c2e0810b75e..49c8c6957aa34 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
@@ -95,6 +95,7 @@ RISCVAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
{"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},
+ {"fixup_riscv_qc_e_jump_plt", 0, 48, MCFixupKindInfo::FKF_IsPCRel},
};
static_assert((std::size(Infos)) == RISCV::NumTargetFixupKinds,
"Not all fixup kinds added to Infos array");
@@ -575,6 +576,21 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
Value = (Bit19 << 31) | (Bit14_0 << 16) | (Bit18_15 << 12);
return Value;
}
+ case RISCV::fixup_riscv_qc_e_jump_plt: {
+ if (!isInt<32>(Value))
+ Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
+ if (Value & 0x1)
+ Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned");
+ uint64_t Bit31_16 = (Value >> 16) & 0xffff;
+ uint64_t Bit12 = (Value >> 12) & 0x1;
+ uint64_t Bit10_5 = (Value >> 5) & 0x3f;
+ uint64_t Bit15_13 = (Value >> 13) & 0x7;
+ uint64_t Bit4_1 = (Value >> 1) & 0xf;
+ uint64_t Bit11 = (Value >> 11) & 0x1;
+ Value = (Bit31_16 << 32ull) | (Bit12 << 31) | (Bit10_5 << 25) |
+ (Bit15_13 << 17) | (Bit4_1 << 8) | (Bit11 << 7);
+ return Value;
+ }
}
}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
index 9859bf39bcc5e..59dc79b57b456 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
@@ -119,6 +119,8 @@ unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx,
return ELF::R_RISCV_CALL_PLT;
case RISCV::fixup_riscv_qc_e_branch:
return ELF::R_RISCV_QC_E_BRANCH;
+ case RISCV::fixup_riscv_qc_e_jump_plt:
+ return ELF::R_RISCV_QC_E_JUMP_PLT;
}
}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
index a4f5673fca225..596c4eb5fffaa 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
@@ -84,6 +84,8 @@ enum Fixups {
fixup_riscv_qc_e_32,
// 20-bit fixup for symbol references in the 32-bit qc.li instruction
fixup_riscv_qc_abs20_u,
+ // 32-bit fixup for symbol references in the 48-bit qc.j/qc.jal instructions
+ fixup_riscv_qc_e_jump_plt,
// 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 95858da45f202..f324907d49fd9 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
@@ -56,6 +56,10 @@ class RISCVMCCodeEmitter : public MCCodeEmitter {
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
+ void expandQCJump(const MCInst &MI, SmallVectorImpl<char> &CB,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
void expandTLSDESCCall(const MCInst &MI, SmallVectorImpl<char> &CB,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
@@ -169,6 +173,26 @@ void RISCVMCCodeEmitter::expandFunctionCall(const MCInst &MI,
support::endian::write(CB, Binary, llvm::endianness::little);
}
+void RISCVMCCodeEmitter::expandQCJump(const MCInst &MI,
+ SmallVectorImpl<char> &CB,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ MCOperand Func = MI.getOperand(0);
+ assert(Func.isExpr() && "Expected expression");
+
+ auto Opcode =
+ (MI.getOpcode() == RISCV::PseudoQC_E_J) ? RISCV::QC_E_J : RISCV::QC_E_JAL;
+ MCInst Jump = MCInstBuilder(Opcode).addExpr(Func.getExpr());
+
+ uint64_t Bits = getBinaryCodeForInstr(Jump, Fixups, STI) & 0xffff'ffff'ffffu;
+ SmallVector<char, 8> Encoding;
+ support::endian::write(Encoding, Bits, llvm::endianness::little);
+ assert(Encoding[6] == 0 && Encoding[7] == 0 &&
+ "Unexpected encoding for 48-bit instruction");
+ Encoding.truncate(6);
+ CB.append(Encoding);
+}
+
void RISCVMCCodeEmitter::expandTLSDESCCall(const MCInst &MI,
SmallVectorImpl<char> &CB,
SmallVectorImpl<MCFixup> &Fixups,
@@ -440,6 +464,11 @@ void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI,
expandTLSDESCCall(MI, CB, Fixups, STI);
MCNumEmitted += 1;
return;
+ case RISCV::PseudoQC_E_J:
+ case RISCV::PseudoQC_E_JAL:
+ expandQCJump(MI, CB, Fixups, STI);
+ MCNumEmitted += 1;
+ return;
}
switch (Size) {
@@ -656,6 +685,9 @@ uint64_t RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo,
case RISCVMCExpr::VK_QC_ABS20:
FixupKind = RISCV::fixup_riscv_qc_abs20_u;
break;
+ case RISCVMCExpr::VK_QC_E_JUMP_PLT:
+ FixupKind = RISCV::fixup_riscv_qc_e_jump_plt;
+ break;
}
} else if (Kind == MCExpr::SymbolRef || Kind == MCExpr::Binary) {
// FIXME: Sub kind binary exprs have chance of underflow.
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
index d6650e156c8b3..99f72620f97ed 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
@@ -34,7 +34,8 @@ const RISCVMCExpr *RISCVMCExpr::create(const MCExpr *Expr, Specifier S,
void RISCVMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
Specifier S = getSpecifier();
- bool HasVariant = ((S != VK_None) && (S != VK_CALL) && (S != VK_CALL_PLT));
+ bool HasVariant = ((S != VK_None) && (S != VK_CALL) && (S != VK_CALL_PLT) &&
+ (S != VK_QC_E_JUMP_PLT));
if (HasVariant)
OS << '%' << getSpecifierName(S) << '(';
@@ -167,6 +168,8 @@ StringRef RISCVMCExpr::getSpecifierName(Specifier S) {
return "pltpcrel";
case VK_QC_ABS20:
return "qc.abs20";
+ case VK_QC_E_JUMP_PLT:
+ return "qc_e_jump_plt";
}
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 e0aa7ff244521..d60879d34dc17 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h
@@ -44,6 +44,7 @@ class RISCVMCExpr : public MCTargetExpr {
VK_TLSDESC_ADD_LO,
VK_TLSDESC_CALL,
VK_QC_ABS20,
+ VK_QC_E_JUMP_PLT
};
private:
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
index 78bf6337b4a00..4ac17c8283866 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
@@ -153,6 +153,18 @@ def simm32_lsb0 : Operand<OtherVT> {
let OperandType = "OPERAND_PCREL";
}
+def PseudoQCJumpSymbol : AsmOperandClass {
+ let Name = "PseudoQCJumpSymbol";
+ let RenderMethod = "addImmOperands";
+ let DiagnosticType = "InvalidPseudoQCJumpSymbol";
+ let DiagnosticString = "operand must be a valid jump target";
+ let ParserMethod = "parsePseudoQCJumpSymbol";
+}
+
+def pseudo_qc_jump_symbol : Operand<XLenVT> {
+ let ParserMatchClass = PseudoQCJumpSymbol;
+}
+
//===----------------------------------------------------------------------===//
// Instruction Formats
//===----------------------------------------------------------------------===//
@@ -708,7 +720,7 @@ class QCIRVInstEI<bits<3> funct3, bits<2> funct2, string opcodestr>
let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
class QCIRVInst48EJ<bits<2> func2, string opcodestr>
: RVInst48<(outs), (ins simm32_lsb0:$imm31),
- opcodestr, "$imm31", [], InstFormatOther> {
+ opcodestr, "$imm31", [], InstFormatQC_EJ> {
bits<31> imm31;
let Inst{47-32} = imm31{30-15};
@@ -1219,6 +1231,16 @@ def PseudoQC_E_SH : PseudoStore<"qc.e.sh">;
def PseudoQC_E_SW : PseudoStore<"qc.e.sw">;
} // Predicates = [HasVendorXqcilo, IsRV32]
+let isCall = 0, isBarrier = 1, isTerminator = 1,
+ isCodeGenOnly = 0, hasSideEffects = 0, mayStore = 0, mayLoad = 0 in
+def PseudoQC_E_J : Pseudo<(outs), (ins pseudo_qc_jump_symbol:$func), [],
+ "qc.e.j", "$func">;
+
+let isCall = 1, Defs = [X1], isCodeGenOnly = 0, hasSideEffects = 0,
+ mayStore = 0, mayLoad = 0 in
+def PseudoQC_E_JAL: Pseudo<(outs), (ins pseudo_qc_jump_symbol:$func), [],
+ "qc.e.jal", "$func">;
+
//===----------------------------------------------------------------------===//
// Code Gen Patterns
//===----------------------------------------------------------------------===//
diff --git a/llvm/test/MC/RISCV/xqcilb-relocations.s b/llvm/test/MC/RISCV/xqcilb-relocations.s
new file mode 100644
index 0000000000000..a475cde3f6bfd
--- /dev/null
+++ b/llvm/test/MC/RISCV/xqcilb-relocations.s
@@ -0,0 +1,59 @@
+# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcilb %s -show-encoding \
+# RUN: | FileCheck -check-prefix=INSTR -check-prefix=FIXUP %s
+# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+experimental-xqcilb %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.e.j foo
+# RELOC: R_RISCV_CUSTOM195 foo 0x0
+# INSTR: qc.e.j foo
+# FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_qc_e_jump_plt
+
+qc.e.j foo at plt
+# RELOC: R_RISCV_CUSTOM195 foo 0x0
+# INSTR: qc.e.j foo
+# FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_qc_e_jump_plt
+
+qc.e.jal foo at plt
+# RELOC: R_RISCV_CUSTOM195 foo 0x0
+# INSTR: qc.e.jal foo
+# FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_qc_e_jump_plt
+
+qc.e.jal foo
+# RELOC: R_RISCV_CUSTOM195 foo 0x0
+# INSTR: qc.e.jal foo
+# FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_qc_e_jump_plt
+
+# Check that a label in a different section is handled similar to an undefined symbol
+qc.e.j .bar
+# RELOC: R_RISCV_CUSTOM195 .bar 0x0
+# INSTR: qc.e.j .bar
+# FIXUP: fixup A - offset: 0, value: .bar, kind: fixup_riscv_qc_e_jump_plt
+
+qc.e.jal .bar
+# RELOC: R_RISCV_CUSTOM195 .bar 0x0
+# INSTR: qc.e.jal .bar
+# FIXUP: fixup A - offset: 0, value: .bar, kind: fixup_riscv_qc_e_jump_plt
+
+# Check that jumps to a defined symbol are handled correctly
+qc.e.j .L1
+# INSTR:qc.e.j .L1
+# FIXUP: fixup A - offset: 0, value: .L1, kind: fixup_riscv_qc_e_jump_plt
+
+qc.e.jal .L1
+# INSTR:qc.e.jal .L1
+# FIXUP: fixup A - offset: 0, value: .L1, kind: fixup_riscv_qc_e_jump_plt
+
+.L1:
+ ret
+
+.section .t2
+
+.bar:
+ ret
>From 6a52127bd5c1bcc078d60257271af8830cd4453d Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <quic_svs at quicinc.com>
Date: Thu, 10 Apr 2025 08:51:57 +0530
Subject: [PATCH 2/2] Add error and correct EndLoc
---
llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp | 8 ++++++--
llvm/test/MC/RISCV/xqcilb-invalid.s | 3 +++
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index 2af8282ac6361..252111313bbc0 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -2154,19 +2154,23 @@ ParseStatus RISCVAsmParser::parsePseudoQCJumpSymbol(OperandVector &Operands) {
if (getLexer().getKind() != AsmToken::Identifier)
return ParseStatus::NoMatch;
+
std::string Identifier(getTok().getIdentifier());
+ SMLoc E = SMLoc::getFromPointer(S.getPointer() + Identifier.size());
if (getLexer().peekTok().is(AsmToken::At)) {
Lex();
Lex();
+ SMLoc PLTLoc = getLoc();
StringRef PLT;
if (getParser().parseIdentifier(PLT) || PLT != "plt")
- return ParseStatus::Failure;
+ return Error(PLTLoc,
+ "'@plt' is the only valid operand for this instruction");
+ E = SMLoc::getFromPointer(S.getPointer() + /*@plt*/ 4);
} else {
Lex();
}
- SMLoc E = SMLoc::getFromPointer(S.getPointer() + Identifier.size());
RISCVMCExpr::Specifier Kind = RISCVMCExpr::VK_QC_E_JUMP_PLT;
MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier);
diff --git a/llvm/test/MC/RISCV/xqcilb-invalid.s b/llvm/test/MC/RISCV/xqcilb-invalid.s
index 1a9009b26b691..10d456c8ac0aa 100644
--- a/llvm/test/MC/RISCV/xqcilb-invalid.s
+++ b/llvm/test/MC/RISCV/xqcilb-invalid.s
@@ -22,3 +22,6 @@ qc.e.jal 2147483649
# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcilb' (Qualcomm uC Long Branch Extension)
qc.e.jal 2147483640
+
+# CHECK: :[[@LINE+1]]:12: error: '@plt' is the only valid operand for this instruction
+qc.e.j foo at rlt
More information about the llvm-commits
mailing list