From b59becf6f2935114409be5b8faafece631bc5ca3 Mon Sep 17 00:00:00 2001 From: Sudharsan Veeravalli Date: Wed, 9 Apr 2025 21:50:58 +0530 Subject: [PATCH 1/3] [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 &Fixups, const MCSubtargetInfo &STI) const; + void expandQCJump(const MCInst &MI, SmallVectorImpl &CB, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + void expandTLSDESCCall(const MCInst &MI, SmallVectorImpl &CB, SmallVectorImpl &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 &CB, + SmallVectorImpl &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 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 &CB, SmallVectorImpl &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 { 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 { + let ParserMatchClass = PseudoQCJumpSymbol; +} + //===----------------------------------------------------------------------===// // Instruction Formats //===----------------------------------------------------------------------===// @@ -708,7 +720,7 @@ class QCIRVInstEI funct3, bits<2> funct2, string opcodestr> let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in class QCIRVInst48EJ 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 From 6a52127bd5c1bcc078d60257271af8830cd4453d Mon Sep 17 00:00:00 2001 From: Sudharsan Veeravalli Date: Thu, 10 Apr 2025 08:51:57 +0530 Subject: [PATCH 2/3] 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@rlt From c2f909938d845eb19e00c8aea2c39b13a7ece8c7 Mon Sep 17 00:00:00 2001 From: Sudharsan Veeravalli Date: Fri, 11 Apr 2025 10:29:43 +0530 Subject: [PATCH 3/3] Use getEndloc() --- llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp index 252111313bbc0..55f1a90b2a01a 100644 --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -2156,17 +2156,17 @@ ParseStatus RISCVAsmParser::parsePseudoQCJumpSymbol(OperandVector &Operands) { return ParseStatus::NoMatch; std::string Identifier(getTok().getIdentifier()); - SMLoc E = SMLoc::getFromPointer(S.getPointer() + Identifier.size()); + SMLoc E = getTok().getEndLoc(); if (getLexer().peekTok().is(AsmToken::At)) { Lex(); Lex(); SMLoc PLTLoc = getLoc(); StringRef PLT; + E = getTok().getEndLoc(); if (getParser().parseIdentifier(PLT) || PLT != "plt") return Error(PLTLoc, "'@plt' is the only valid operand for this instruction"); - E = SMLoc::getFromPointer(S.getPointer() + /*@plt*/ 4); } else { Lex(); }