-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[RISCV] Add symbol parsing support for Xqcilb long branch instructions #135044
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
Conversation
@llvm/pr-subscribers-backend-risc-v Author: Sudharsan Veeravalli (svs-quic) ChangesThis patch adds support for parsing symbols in the Xqcilb long branch instructions. The instructions use the Vendor relocation support will be added in a later patch. Full diff: https://github.com/llvm/llvm-project/pull/135044.diff 9 Files Affected:
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@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@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
|
@llvm/pr-subscribers-mc Author: Sudharsan Veeravalli (svs-quic) ChangesThis patch adds support for parsing symbols in the Xqcilb long branch instructions. The instructions use the Vendor relocation support will be added in a later patch. Full diff: https://github.com/llvm/llvm-project/pull/135044.diff 9 Files Affected:
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@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@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
|
Lex(); | ||
} | ||
|
||
SMLoc E = SMLoc::getFromPointer(S.getPointer() + Identifier.size()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The end location should include the @plt
if present
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I have made this change. It looks like ParseCallSymbol above has the same issue as well along with not printing any error message if we dont have @plt
. Will look at fixing them in a separate patch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about this a bit more. Given that we parse and drop the @plt
in the assembly that is being printed, shouldn't the end location be the end location of the Identifier (eg foo) which is basically what the code was doing previously?
@topperc do you have any other comments on this? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
…parsing Follow-up to the just landed #135044 . Remove `@plt` parsing (only needed by legacy `call foo@plt`). MCParser's `@` parsing is problematic. Supporting target variations like (`foo+2@plt foo@plt+2 (foo+2)@plt`) involves messy hacks. We should refrain from adding new `@` uses. Remove unneeded `RISCVMCExpr::VK_QC_E_JUMP_PLT` (should only be used when an instruction might have multiple reasonable relocations https://maskray.me/blog/2025-03-16-relocation-generation-in-assemblers). --- GCC's initial initial RISC-V port made a mistake by having both `call foo` (non-PIC) and `call foo@plt` (PIC), likely misled by x86/SystemZ. It was determined that the `@plt` was not needed. Since R_RISCV_CALL had questionable undefined weak semantics in GNU ld (which has been removed then), we kept R_RISCV_CALL_PLT and deprecated R_RISCV_CALL. For RISC-V instructions, we only keep `@` in call/jump for backward compatibility and discourage it for all other instructions. ( There is disagreement about whether `PLT` in `JUMP_PLT` is useful or misleading. MaskRay's opnion: For new branch relocations with procedure call semantics, use `_CALL` and avoid `_PLT` in the relocation name. `_PLT` should only be used in data directives (e.g. R_RISCV_PLT32) to indicate that the address of a function is not significant. ) Pull Request: #135507
llvm#135044) This patch adds support for parsing symbols in the Xqcilb long branch instructions. The instructions use the `R_RISCV_QC_E_JUMP_PLT` relocation and the `InstFormatQC_EJ` instruction format. Vendor relocation support will be added in a later patch.
…parsing Follow-up to the just landed llvm#135044 . Remove `@plt` parsing (only needed by legacy `call foo@plt`). MCParser's `@` parsing is problematic. Supporting target variations like (`foo+2@plt foo@plt+2 (foo+2)@plt`) involves messy hacks. We should refrain from adding new `@` uses. Remove unneeded `RISCVMCExpr::VK_QC_E_JUMP_PLT` (should only be used when an instruction might have multiple reasonable relocations https://maskray.me/blog/2025-03-16-relocation-generation-in-assemblers). --- GCC's initial initial RISC-V port made a mistake by having both `call foo` (non-PIC) and `call foo@plt` (PIC), likely misled by x86/SystemZ. It was determined that the `@plt` was not needed. Since R_RISCV_CALL had questionable undefined weak semantics in GNU ld (which has been removed then), we kept R_RISCV_CALL_PLT and deprecated R_RISCV_CALL. For RISC-V instructions, we only keep `@` in call/jump for backward compatibility and discourage it for all other instructions. ( There is disagreement about whether `PLT` in `JUMP_PLT` is useful or misleading. MaskRay's opnion: For new branch relocations with procedure call semantics, use `_CALL` and avoid `_PLT` in the relocation name. `_PLT` should only be used in data directives (e.g. R_RISCV_PLT32) to indicate that the address of a function is not significant. ) Pull Request: llvm#135507
This patch adds support for parsing symbols in the Xqcilb long branch instructions. The instructions use the
R_RISCV_QC_E_JUMP_PLT
relocation and theInstFormatQC_EJ
instruction format.Vendor relocation support will be added in a later patch.