diff options
author | Fangrui Song <i@maskray.me> | 2025-03-29 11:08:13 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-03-29 11:08:13 -0700 |
commit | fe6fb910df9d1b9a9e2e7a6e8228d020668e0129 (patch) | |
tree | b03e644f0516ae2281f3354235c81e48f8ac891d /llvm/lib | |
parent | 666faa7fd98b7a58e089a38083f33c067ed5b955 (diff) | |
download | llvm-fe6fb910df9d1b9a9e2e7a6e8228d020668e0129.zip llvm-fe6fb910df9d1b9a9e2e7a6e8228d020668e0129.tar.gz llvm-fe6fb910df9d1b9a9e2e7a6e8228d020668e0129.tar.bz2 |
[RISCV] Replace @plt/@gotpcrel in data directives with %pltpcrel %gotpcrel
clang -fexperimental-relative-c++-abi-vtables might generate `@plt` and
`@gotpcrel` specifiers in data directives. The syntax is not used in
humand-written assembly code, and is not supported by GNU assembler.
Note: the `@plt` in `.word foo@plt` is different from
the legacy `call func@plt` (where `@plt` is simply ignored).
The `@plt` syntax was selected was simply due to a quirk of AsmParser:
the syntax was supported by all targets until I updated it
to be an opt-in feature in a0671758eb6e52a758bd1b096a9b421eec60204c
RISC-V favors the `%specifier(expr)` syntax following MIPS and Sparc,
and we should follow this convention.
This PR adds support for `.word %pltpcrel(foo+offset)` and
`.word %gotpcrel(foo)`, and drops `@plt` and `@gotpcrel`.
* MCValue::SymA can no longer have a SymbolVariant. Add an assert
similar to that of AArch64ELFObjectWriter.cpp before
https://reviews.llvm.org/D81446 (see my analysis at
https://maskray.me/blog/2025-03-16-relocation-generation-in-assemblers
if intrigued)
* `jump foo@plt, x31` now has a different diagnostic.
Pull Request: https://github.com/llvm/llvm-project/pull/132569
Diffstat (limited to 'llvm/lib')
18 files changed, 197 insertions, 102 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 40abe28..c626202 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -3363,7 +3363,9 @@ void AsmPrinter::emitAlignment(Align Alignment, const GlobalObject *GV, // Constant emission. //===----------------------------------------------------------------------===// -const MCExpr *AsmPrinter::lowerConstant(const Constant *CV) { +const MCExpr *AsmPrinter::lowerConstant(const Constant *CV, + const Constant *BaseCV, + uint64_t Offset) { MCContext &Ctx = OutContext; if (CV->isNullValue() || isa<UndefValue>(CV)) @@ -3382,7 +3384,8 @@ const MCExpr *AsmPrinter::lowerConstant(const Constant *CV) { return lowerBlockAddressConstant(*BA); if (const auto *Equiv = dyn_cast<DSOLocalEquivalent>(CV)) - return getObjFileLowering().lowerDSOLocalEquivalent(Equiv, TM); + return getObjFileLowering().lowerDSOLocalEquivalent( + getSymbol(Equiv->getGlobalValue()), nullptr, 0, std::nullopt, TM); if (const NoCFIValue *NC = dyn_cast<NoCFIValue>(CV)) return MCSymbolRefExpr::create(getSymbol(NC->getGlobalValue()), Ctx); @@ -3428,7 +3431,7 @@ const MCExpr *AsmPrinter::lowerConstant(const Constant *CV) { // is reasonable to treat their delta as a 32-bit value. [[fallthrough]]; case Instruction::BitCast: - return lowerConstant(CE->getOperand(0)); + return lowerConstant(CE->getOperand(0), BaseCV, Offset); case Instruction::IntToPtr: { const DataLayout &DL = getDataLayout(); @@ -3467,33 +3470,42 @@ const MCExpr *AsmPrinter::lowerConstant(const Constant *CV) { } case Instruction::Sub: { - GlobalValue *LHSGV; - APInt LHSOffset; + GlobalValue *LHSGV, *RHSGV; + APInt LHSOffset, RHSOffset; DSOLocalEquivalent *DSOEquiv; if (IsConstantOffsetFromGlobal(CE->getOperand(0), LHSGV, LHSOffset, - getDataLayout(), &DSOEquiv)) { - GlobalValue *RHSGV; - APInt RHSOffset; - if (IsConstantOffsetFromGlobal(CE->getOperand(1), RHSGV, RHSOffset, - getDataLayout())) { - const MCExpr *RelocExpr = - getObjFileLowering().lowerRelativeReference(LHSGV, RHSGV, TM); - if (!RelocExpr) { - const MCExpr *LHSExpr = - MCSymbolRefExpr::create(getSymbol(LHSGV), Ctx); - if (DSOEquiv && - getObjFileLowering().supportDSOLocalEquivalentLowering()) - LHSExpr = - getObjFileLowering().lowerDSOLocalEquivalent(DSOEquiv, TM); - RelocExpr = MCBinaryExpr::createSub( - LHSExpr, MCSymbolRefExpr::create(getSymbol(RHSGV), Ctx), Ctx); - } - int64_t Addend = (LHSOffset - RHSOffset).getSExtValue(); + getDataLayout(), &DSOEquiv) && + IsConstantOffsetFromGlobal(CE->getOperand(1), RHSGV, RHSOffset, + getDataLayout())) { + auto *LHSSym = getSymbol(LHSGV); + auto *RHSSym = getSymbol(RHSGV); + int64_t Addend = (LHSOffset - RHSOffset).getSExtValue(); + std::optional<int64_t> PCRelativeOffset; + if (getObjFileLowering().hasPLTPCRelative() && RHSGV == BaseCV) + PCRelativeOffset = Offset; + + // Try the generic symbol difference first. + const MCExpr *Res = getObjFileLowering().lowerRelativeReference( + LHSGV, RHSGV, Addend, PCRelativeOffset, TM); + + // (ELF-specific) If the generic symbol difference does not apply, and + // LHS is a dso_local_equivalent of a dso_preemptable function, + // reference the PLT entry instead. + if (DSOEquiv && TM.getTargetTriple().isOSBinFormatELF() && + !(LHSGV->isDSOLocal() || LHSGV->isImplicitDSOLocal())) + Res = getObjFileLowering().lowerDSOLocalEquivalent( + LHSSym, RHSSym, Addend, PCRelativeOffset, TM); + + // Otherwise, return LHS-RHS+Addend. + if (!Res) { + Res = + MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHSSym, Ctx), + MCSymbolRefExpr::create(RHSSym, Ctx), Ctx); if (Addend != 0) - RelocExpr = MCBinaryExpr::createAdd( - RelocExpr, MCConstantExpr::create(Addend, Ctx), Ctx); - return RelocExpr; + Res = MCBinaryExpr::createAdd( + Res, MCConstantExpr::create(Addend, Ctx), Ctx); } + return Res; } const MCExpr *LHS = lowerConstant(CE->getOperand(0)); @@ -4023,7 +4035,7 @@ static void emitGlobalConstantImpl(const DataLayout &DL, const Constant *CV, // Otherwise, it must be a ConstantExpr. Lower it to an MCExpr, then emit it // thread the streamer with EmitValue. - const MCExpr *ME = AP.lowerConstant(CV); + const MCExpr *ME = AP.lowerConstant(CV, BaseCV, Offset); // Since lowerConstant already folded and got rid of all IR pointer and // integer casts, detect GOT equivalent accesses by looking into the MCExpr diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp index 0e44acd..dd6d85e 100644 --- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -115,10 +115,6 @@ static void GetObjCImageInfo(Module &M, unsigned &Version, unsigned &Flags, // ELF //===----------------------------------------------------------------------===// -TargetLoweringObjectFileELF::TargetLoweringObjectFileELF() { - SupportDSOLocalEquivalentLowering = true; -} - void TargetLoweringObjectFileELF::Initialize(MCContext &Ctx, const TargetMachine &TgtM) { TargetLoweringObjectFile::Initialize(Ctx, TgtM); @@ -1174,9 +1170,37 @@ MCSection *TargetLoweringObjectFileELF::getStaticDtorSection( KeySym); } +const MCExpr *TargetLoweringObjectFileELF::lowerSymbolDifference( + const MCSymbol *LHS, const MCSymbol *RHS, int64_t Addend, + std::optional<int64_t> PCRelativeOffset) const { + auto &Ctx = getContext(); + const MCExpr *Res; + // Return a relocatable expression with the PLT specifier, %plt(GV) or + // %plt(GV-RHS). + if (PCRelativeOffset && PLTPCRelativeSpecifier) { + Res = MCSymbolRefExpr::create(LHS, Ctx); + // The current location is RHS plus *PCRelativeOffset. Compensate for it. + Addend += *PCRelativeOffset; + if (Addend) + Res = MCBinaryExpr::createAdd(Res, MCConstantExpr::create(Addend, Ctx), + Ctx); + return createTargetMCExpr(Res, PLTPCRelativeSpecifier); + } + + if (!PLTRelativeSpecifier) + return nullptr; + Res = MCBinaryExpr::createSub( + MCSymbolRefExpr::create(LHS, PLTRelativeSpecifier, Ctx), + MCSymbolRefExpr::create(RHS, Ctx), Ctx); + if (Addend) + Res = + MCBinaryExpr::createAdd(Res, MCConstantExpr::create(Addend, Ctx), Ctx); + return Res; +} + const MCExpr *TargetLoweringObjectFileELF::lowerRelativeReference( - const GlobalValue *LHS, const GlobalValue *RHS, - const TargetMachine &TM) const { + const GlobalValue *LHS, const GlobalValue *RHS, int64_t Addend, + std::optional<int64_t> PCRelativeOffset, const TargetMachine &TM) const { // We may only use a PLT-relative relocation to refer to unnamed_addr // functions. if (!LHS->hasGlobalUnnamedAddr() || !LHS->getValueType()->isFunctionTy()) @@ -1188,24 +1212,22 @@ const MCExpr *TargetLoweringObjectFileELF::lowerRelativeReference( RHS->isThreadLocal()) return nullptr; - return MCBinaryExpr::createSub( - MCSymbolRefExpr::create(TM.getSymbol(LHS), PLTRelativeSpecifier, - getContext()), - MCSymbolRefExpr::create(TM.getSymbol(RHS), getContext()), getContext()); + return lowerSymbolDifference(TM.getSymbol(LHS), TM.getSymbol(RHS), Addend, + PCRelativeOffset); } +// Reference the PLT entry of a function, optionally with a subtrahend (`RHS`). const MCExpr *TargetLoweringObjectFileELF::lowerDSOLocalEquivalent( - const DSOLocalEquivalent *Equiv, const TargetMachine &TM) const { - assert(supportDSOLocalEquivalentLowering()); - - const auto *GV = Equiv->getGlobalValue(); - - // A PLT entry is not needed for dso_local globals. - if (GV->isDSOLocal() || GV->isImplicitDSOLocal()) - return MCSymbolRefExpr::create(TM.getSymbol(GV), getContext()); - - return MCSymbolRefExpr::create(TM.getSymbol(GV), PLTRelativeSpecifier, - getContext()); + const MCSymbol *LHS, const MCSymbol *RHS, int64_t Addend, + std::optional<int64_t> PCRelativeOffset, const TargetMachine &TM) const { + if (RHS) + return lowerSymbolDifference(LHS, RHS, Addend, PCRelativeOffset); + + // Only the legacy MCSymbolRefExpr::VariantKind approach is implemented. + // Reference LHS@plt or LHS@plt - RHS. + if (PLTRelativeSpecifier) + return MCSymbolRefExpr::create(LHS, PLTRelativeSpecifier, getContext()); + return nullptr; } MCSection *TargetLoweringObjectFileELF::getSectionForCommandLines() const { @@ -2044,8 +2066,8 @@ MCSection *TargetLoweringObjectFileCOFF::getStaticDtorSection( } const MCExpr *TargetLoweringObjectFileCOFF::lowerRelativeReference( - const GlobalValue *LHS, const GlobalValue *RHS, - const TargetMachine &TM) const { + const GlobalValue *LHS, const GlobalValue *RHS, int64_t Addend, + std::optional<int64_t> PCRelativeOffset, const TargetMachine &TM) const { const Triple &T = TM.getTargetTriple(); if (T.isOSCygMing()) return nullptr; @@ -2069,9 +2091,12 @@ const MCExpr *TargetLoweringObjectFileCOFF::lowerRelativeReference( cast<GlobalVariable>(RHS)->hasInitializer() || RHS->hasSection()) return nullptr; - return MCSymbolRefExpr::create(TM.getSymbol(LHS), - MCSymbolRefExpr::VK_COFF_IMGREL32, - getContext()); + const MCExpr *Res = MCSymbolRefExpr::create( + TM.getSymbol(LHS), MCSymbolRefExpr::VK_COFF_IMGREL32, getContext()); + if (Addend != 0) + Res = MCBinaryExpr::createAdd( + Res, MCConstantExpr::create(Addend, getContext()), getContext()); + return Res; } static std::string APIntToHexString(const APInt &AI) { diff --git a/llvm/lib/MC/MCAssembler.cpp b/llvm/lib/MC/MCAssembler.cpp index 6ae99ec..1c79af4 100644 --- a/llvm/lib/MC/MCAssembler.cpp +++ b/llvm/lib/MC/MCAssembler.cpp @@ -237,7 +237,7 @@ bool MCAssembler::evaluateFixup(const MCFixup &Fixup, const MCFragment *DF, // A linker relaxation target may emit ADD/SUB relocations for A-B+C. Let // recordRelocation handle non-VK_None cases like A@plt-B+C. if (!IsResolved && Target.getSymA() && Target.getSubSym() && - Target.getSymA()->getKind() == MCSymbolRefExpr::VK_None && + Target.getRefKind() == 0 && getBackend().handleAddSubRelocations(*this, *DF, Fixup, Target, Value)) return true; diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp index 9448e7b..65a3800 100644 --- a/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/llvm/lib/MC/MCParser/AsmParser.cpp @@ -3144,7 +3144,7 @@ bool AsmParser::parseDirectiveValue(StringRef IDVal, unsigned Size) { auto parseOp = [&]() -> bool { const MCExpr *Value; SMLoc ExprLoc = getLexer().getLoc(); - if (checkForValidSection() || parseExpression(Value)) + if (checkForValidSection() || getTargetParser().parseDataExpr(Value)) return true; // Special case constant expressions to match code generator. if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) { diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index e3ad085..ff1aee9 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -254,7 +254,9 @@ public: return false; } - const MCExpr *lowerConstant(const Constant *CV) override; + const MCExpr *lowerConstant(const Constant *CV, + const Constant *BaseCV = nullptr, + uint64_t Offset = 0) override; private: void printOperand(const MachineInstr *MI, unsigned OpNum, raw_ostream &O); @@ -3496,13 +3498,15 @@ void AArch64AsmPrinter::emitMachOIFuncStubHelperBody(Module &M, .addReg(AArch64::X16)); } -const MCExpr *AArch64AsmPrinter::lowerConstant(const Constant *CV) { +const MCExpr *AArch64AsmPrinter::lowerConstant(const Constant *CV, + const Constant *BaseCV, + uint64_t Offset) { if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV)) { return MCSymbolRefExpr::create(MCInstLowering.GetGlobalValueSymbol(GV, 0), OutContext); } - return AsmPrinter::lowerConstant(CV); + return AsmPrinter::lowerConstant(CV, BaseCV, Offset); } // Force static initialization. diff --git a/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.h b/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.h index 2c959d7..4183bb6 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.h +++ b/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.h @@ -107,7 +107,8 @@ public: /// Lower the specified LLVM Constant to an MCExpr. /// The AsmPrinter::lowerConstantof does not know how to lower /// addrspacecast, therefore they should be lowered by this function. - const MCExpr *lowerConstant(const Constant *CV) override; + const MCExpr *lowerConstant(const Constant *CV, const Constant *BaseCV, + uint64_t Offset) override; /// tblgen'erated driver function for lowering simple MI->MC pseudo /// instructions. diff --git a/llvm/lib/Target/AMDGPU/AMDGPUMCInstLower.cpp b/llvm/lib/Target/AMDGPU/AMDGPUMCInstLower.cpp index 895d1e7..6fa97d8 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUMCInstLower.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUMCInstLower.cpp @@ -223,20 +223,23 @@ bool AMDGPUAsmPrinter::lowerOperand(const MachineOperand &MO, return MCInstLowering.lowerOperand(MO, MCOp); } -const MCExpr *AMDGPUAsmPrinter::lowerConstant(const Constant *CV) { +const MCExpr *AMDGPUAsmPrinter::lowerConstant(const Constant *CV, + const Constant *BaseCV, + uint64_t Offset) { // Intercept LDS variables with known addresses if (const GlobalVariable *GV = dyn_cast<const GlobalVariable>(CV)) { if (std::optional<uint32_t> Address = AMDGPUMachineFunction::getLDSAbsoluteAddress(*GV)) { auto *IntTy = Type::getInt32Ty(CV->getContext()); - return AsmPrinter::lowerConstant(ConstantInt::get(IntTy, *Address)); + return AsmPrinter::lowerConstant(ConstantInt::get(IntTy, *Address), + BaseCV, Offset); } } if (const MCExpr *E = lowerAddrSpaceCast(TM, CV, OutContext)) return E; - return AsmPrinter::lowerConstant(CV); + return AsmPrinter::lowerConstant(CV, BaseCV, Offset); } void AMDGPUAsmPrinter::emitInstruction(const MachineInstr *MI) { diff --git a/llvm/lib/Target/AMDGPU/R600AsmPrinter.h b/llvm/lib/Target/AMDGPU/R600AsmPrinter.h index 552d01f..936fe9bc 100644 --- a/llvm/lib/Target/AMDGPU/R600AsmPrinter.h +++ b/llvm/lib/Target/AMDGPU/R600AsmPrinter.h @@ -30,7 +30,8 @@ public: /// Lower the specified LLVM Constant to an MCExpr. /// The AsmPrinter::lowerConstantof does not know how to lower /// addrspacecast, therefore they should be lowered by this function. - const MCExpr *lowerConstant(const Constant *CV) override; + const MCExpr *lowerConstant(const Constant *CV, const Constant *BaseCV, + uint64_t Offset) override; private: void EmitProgramInfoR600(const MachineFunction &MF); diff --git a/llvm/lib/Target/AMDGPU/R600MCInstLower.cpp b/llvm/lib/Target/AMDGPU/R600MCInstLower.cpp index 6da5456..6d7e834 100644 --- a/llvm/lib/Target/AMDGPU/R600MCInstLower.cpp +++ b/llvm/lib/Target/AMDGPU/R600MCInstLower.cpp @@ -72,8 +72,10 @@ void R600AsmPrinter::emitInstruction(const MachineInstr *MI) { } } -const MCExpr *R600AsmPrinter::lowerConstant(const Constant *CV) { +const MCExpr *R600AsmPrinter::lowerConstant(const Constant *CV, + const Constant *BaseCV, + uint64_t Offset) { if (const MCExpr *E = lowerAddrSpaceCast(TM, CV, OutContext)) return E; - return AsmPrinter::lowerConstant(CV); + return AsmPrinter::lowerConstant(CV, BaseCV, Offset); } diff --git a/llvm/lib/Target/AVR/AVRAsmPrinter.cpp b/llvm/lib/Target/AVR/AVRAsmPrinter.cpp index a63aa542..a8621ab 100644 --- a/llvm/lib/Target/AVR/AVRAsmPrinter.cpp +++ b/llvm/lib/Target/AVR/AVRAsmPrinter.cpp @@ -59,7 +59,8 @@ public: void emitInstruction(const MachineInstr *MI) override; - const MCExpr *lowerConstant(const Constant *CV) override; + const MCExpr *lowerConstant(const Constant *CV, const Constant *BaseCV, + uint64_t Offset) override; void emitXXStructor(const DataLayout &DL, const Constant *CV) override; @@ -199,7 +200,9 @@ void AVRAsmPrinter::emitInstruction(const MachineInstr *MI) { EmitToStreamer(*OutStreamer, I); } -const MCExpr *AVRAsmPrinter::lowerConstant(const Constant *CV) { +const MCExpr *AVRAsmPrinter::lowerConstant(const Constant *CV, + const Constant *BaseCV, + uint64_t Offset) { MCContext &Ctx = OutContext; if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV)) { @@ -210,7 +213,7 @@ const MCExpr *AVRAsmPrinter::lowerConstant(const Constant *CV) { } } - return AsmPrinter::lowerConstant(CV); + return AsmPrinter::lowerConstant(CV, BaseCV, Offset); } void AVRAsmPrinter::emitXXStructor(const DataLayout &DL, const Constant *CV) { diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp index b4365cd..861ccde 100644 --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -232,6 +232,8 @@ class RISCVAsmParser : public MCTargetAsmParser { } bool parseOperand(OperandVector &Operands, StringRef Mnemonic); + bool parseExprWithSpecifier(const MCExpr *&Res, SMLoc &E); + bool parseDataExpr(const MCExpr *&Res) override; bool parseDirectiveOption(); bool parseDirectiveAttribute(); @@ -2019,8 +2021,17 @@ ParseStatus RISCVAsmParser::parseOperandWithSpecifier(OperandVector &Operands) { SMLoc S = getLoc(); SMLoc E; - if (!parseOptionalToken(AsmToken::Percent) || - getLexer().getKind() != AsmToken::Identifier) + if (parseToken(AsmToken::Percent, "expected '%' relocation specifier")) + return ParseStatus::Failure; + const MCExpr *Expr = nullptr; + bool Failed = parseExprWithSpecifier(Expr, E); + if (!Failed) + Operands.push_back(RISCVOperand::createImm(Expr, S, E, isRV64())); + return Failed; +} + +bool RISCVAsmParser::parseExprWithSpecifier(const MCExpr *&Res, SMLoc &E) { + if (getLexer().getKind() != AsmToken::Identifier) return Error(getLoc(), "expected '%' relocation specifier"); StringRef Identifier = getParser().getTok().getIdentifier(); auto Spec = RISCVMCExpr::getSpecifierForName(Identifier); @@ -2029,15 +2040,21 @@ ParseStatus RISCVAsmParser::parseOperandWithSpecifier(OperandVector &Operands) { getParser().Lex(); // Eat the identifier if (parseToken(AsmToken::LParen, "expected '('")) - return ParseStatus::Failure; + return true; const MCExpr *SubExpr; if (getParser().parseParenExpression(SubExpr, E)) - return ParseStatus::Failure; + return true; - const MCExpr *ModExpr = RISCVMCExpr::create(SubExpr, *Spec, getContext()); - Operands.push_back(RISCVOperand::createImm(ModExpr, S, E, isRV64())); - return ParseStatus::Success; + Res = RISCVMCExpr::create(SubExpr, *Spec, getContext()); + return false; +} + +bool RISCVAsmParser::parseDataExpr(const MCExpr *&Res) { + SMLoc E; + if (parseOptionalToken(AsmToken::Percent)) + return parseExprWithSpecifier(Res, E); + return getParser().parseExpression(Res); } ParseStatus RISCVAsmParser::parseBareSymbol(OperandVector &Operands) { @@ -2129,7 +2146,7 @@ ParseStatus RISCVAsmParser::parsePseudoJumpSymbol(OperandVector &Operands) { return ParseStatus::Failure; if (Res->getKind() != MCExpr::ExprKind::SymbolRef || - getSpecifier(cast<MCSymbolRefExpr>(Res)) == RISCVMCExpr::VK_PLT) + getSpecifier(cast<MCSymbolRefExpr>(Res)) == RISCVMCExpr::VK_PLTPCREL) return Error(S, "operand must be a valid jump target"); Res = RISCVMCExpr::create(Res, RISCVMCExpr::VK_CALL, getContext()); diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp index f8841dd..5faeb98 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp @@ -50,13 +50,17 @@ unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const { + assert((!Target.getSymA() || + Target.getSymA()->getKind() == MCSymbolRefExpr::VK_None) && + "sym@specifier should have been rejected"); const MCExpr *Expr = Fixup.getValue(); // Determine the type of the relocation unsigned Kind = Fixup.getTargetKind(); if (Kind >= FirstLiteralRelocationKind) return Kind - FirstLiteralRelocationKind; - switch (Target.getRefKind()) { + auto Spec = RISCVMCExpr::Specifier(Target.getRefKind()); + switch (Spec) { case RISCVMCExpr::VK_TPREL_HI: case RISCVMCExpr::VK_TLS_GOT_HI: case RISCVMCExpr::VK_TLS_GD_HI: @@ -64,6 +68,16 @@ unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx, if (auto *S = Target.getSymA()) cast<MCSymbolELF>(S->getSymbol()).setType(ELF::STT_TLS); break; + case RISCVMCExpr::VK_PLTPCREL: + case RISCVMCExpr::VK_GOTPCREL: + if (Kind == FK_Data_4) + break; + Ctx.reportError(Fixup.getLoc(), + "%" + RISCVMCExpr::getSpecifierName(Spec) + + " can only be used in a .word directive"); + return ELF::R_RISCV_NONE; + default: + break; } if (IsPCRel) { @@ -73,9 +87,7 @@ unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx, return ELF::R_RISCV_NONE; case FK_Data_4: case FK_PCRel_4: - return uint8_t(Target.getAccessVariant()) == RISCVMCExpr::VK_PLT - ? ELF::R_RISCV_PLT32 - : ELF::R_RISCV_32_PCREL; + return ELF::R_RISCV_32_PCREL; case RISCV::fixup_riscv_pcrel_hi20: return ELF::R_RISCV_PCREL_HI20; case RISCV::fixup_riscv_pcrel_lo12_i: @@ -129,11 +141,18 @@ unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx, Ctx.reportError(Fixup.getLoc(), "2-byte data relocations not supported"); return ELF::R_RISCV_NONE; case FK_Data_4: - if (Expr->getKind() == MCExpr::Target && - cast<RISCVMCExpr>(Expr)->getSpecifier() == RISCVMCExpr::VK_32_PCREL) - return ELF::R_RISCV_32_PCREL; - if (getSpecifier(Target.getSymA()) == RISCVMCExpr::VK_GOTPCREL) - return ELF::R_RISCV_GOT32_PCREL; + if (Expr->getKind() == MCExpr::Target) { + switch (cast<RISCVMCExpr>(Expr)->getSpecifier()) { + case RISCVMCExpr::VK_32_PCREL: + return ELF::R_RISCV_32_PCREL; + case RISCVMCExpr::VK_GOTPCREL: + return ELF::R_RISCV_GOT32_PCREL; + case RISCVMCExpr::VK_PLTPCREL: + return ELF::R_RISCV_PLT32; + default: + break; + } + } return ELF::R_RISCV_32; case FK_Data_8: return ELF::R_RISCV_64; diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp index c327f9d..7e9b312 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp @@ -18,11 +18,6 @@ #include "llvm/TargetParser/Triple.h" using namespace llvm; -const MCAsmInfo::VariantKindDesc variantKindDescs[] = { - {RISCVMCExpr::VK_GOTPCREL, "GOTPCREL"}, - {RISCVMCExpr::VK_PLT, "PLT"}, -}; - void RISCVMCAsmInfo::anchor() {} RISCVMCAsmInfo::RISCVMCAsmInfo(const Triple &TT) { @@ -33,8 +28,6 @@ RISCVMCAsmInfo::RISCVMCAsmInfo(const Triple &TT) { ExceptionsType = ExceptionHandling::DwarfCFI; Data16bitsDirective = "\t.half\t"; Data32bitsDirective = "\t.word\t"; - - initializeVariantKinds(variantKindDescs); } const MCExpr *RISCVMCAsmInfo::getExprForFDESymbol(const MCSymbol *Sym, diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp index f333ffe..b27f13e 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp @@ -479,7 +479,7 @@ uint64_t RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo, case RISCVMCExpr::VK_None: case RISCVMCExpr::VK_32_PCREL: case RISCVMCExpr::VK_GOTPCREL: - case RISCVMCExpr::VK_PLT: + case RISCVMCExpr::VK_PLTPCREL: llvm_unreachable("unhandled specifier"); case RISCVMCExpr::VK_TPREL_ADD: // tprel_add is only used to indicate that a relocation should be emitted diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp index b73496b..e7c0f95 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp @@ -118,14 +118,15 @@ 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) + // Used in data directives + .Case("pltpcrel", VK_PLTPCREL) + .Case("gotpcrel", VK_GOTPCREL) .Default(std::nullopt); } StringRef RISCVMCExpr::getSpecifierName(Specifier S) { switch (S) { case VK_None: - case VK_PLT: - case VK_GOTPCREL: llvm_unreachable("not used as %specifier()"); case VK_LO: return "lo"; @@ -161,6 +162,10 @@ StringRef RISCVMCExpr::getSpecifierName(Specifier S) { return "call_plt"; case VK_32_PCREL: return "32_pcrel"; + case VK_GOTPCREL: + return "gotpcrel"; + case VK_PLTPCREL: + return "pltpcrel"; } 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 af178ff..604d2eb 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h @@ -38,7 +38,7 @@ public: VK_CALL_PLT, VK_32_PCREL, VK_GOTPCREL, - VK_PLT, + VK_PLTPCREL, VK_TLSDESC_HI, VK_TLSDESC_LOAD_LO, VK_TLSDESC_ADD_LO, diff --git a/llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp b/llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp index e546815..57c0af7 100644 --- a/llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp +++ b/llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp @@ -27,7 +27,7 @@ void RISCVELFTargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &TM) { TargetLoweringObjectFileELF::Initialize(Ctx, TM); - PLTRelativeSpecifier = RISCVMCExpr::VK_PLT; + PLTPCRelativeSpecifier = RISCVMCExpr::VK_PLTPCREL; SupportIndirectSymViaGOTPCRel = true; SmallDataSection = getContext().getELFSection( @@ -49,11 +49,11 @@ void RISCVELFTargetObjectFile::Initialize(MCContext &Ctx, const MCExpr *RISCVELFTargetObjectFile::getIndirectSymViaGOTPCRel( const GlobalValue *GV, const MCSymbol *Sym, const MCValue &MV, int64_t Offset, MachineModuleInfo *MMI, MCStreamer &Streamer) const { - int64_t FinalOffset = Offset + MV.getConstant(); - const MCExpr *Res = - MCSymbolRefExpr::create(Sym, RISCVMCExpr::VK_GOTPCREL, getContext()); - const MCExpr *Off = MCConstantExpr::create(FinalOffset, getContext()); - return MCBinaryExpr::createAdd(Res, Off, getContext()); + auto &Ctx = getContext(); + const MCExpr *Res = MCSymbolRefExpr::create(Sym, Ctx); + Res = MCBinaryExpr::createAdd( + Res, MCConstantExpr::create(Offset + MV.getConstant(), Ctx), Ctx); + return RISCVMCExpr::create(Res, RISCVMCExpr::VK_GOTPCREL, Ctx); } // A address must be loaded from a small section if its size is less than the @@ -180,3 +180,10 @@ MCSection *RISCVELFTargetObjectFile::getSectionForConstant( return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C, Alignment); } + +const MCExpr * +RISCVELFTargetObjectFile::createTargetMCExpr(const MCExpr *Expr, + uint8_t Specifier) const { + return RISCVMCExpr::create(Expr, RISCVMCExpr::Specifier(Specifier), + getContext()); +} diff --git a/llvm/lib/Target/RISCV/RISCVTargetObjectFile.h b/llvm/lib/Target/RISCV/RISCVTargetObjectFile.h index ff7e3e4..b6da3f4 100644 --- a/llvm/lib/Target/RISCV/RISCVTargetObjectFile.h +++ b/llvm/lib/Target/RISCV/RISCVTargetObjectFile.h @@ -48,6 +48,9 @@ public: bool isInSmallSection(uint64_t Size) const; + const MCExpr *createTargetMCExpr(const MCExpr *Expr, + uint8_t Specifier) const override; + const MCExpr *getIndirectSymViaGOTPCRel(const GlobalValue *GV, const MCSymbol *Sym, const MCValue &MV, int64_t Offset, |