diff --git a/lld/test/ELF/riscv-reloc-plt32.s b/lld/test/ELF/riscv-reloc-plt32.s index 8cbc2d3f442c0..8ead933a8a0e4 100644 --- a/lld/test/ELF/riscv-reloc-plt32.s +++ b/lld/test/ELF/riscv-reloc-plt32.s @@ -18,6 +18,6 @@ .globl _start _start: .data - .word foo@PLT - . - .word foo@PLT - . + 1 - .word foo@PLT - . - 1 + .word %pltpcrel(foo) + .word %pltpcrel(foo + 1) + .word %pltpcrel(foo - 1) diff --git a/lld/test/ELF/riscv-undefined-weak.s b/lld/test/ELF/riscv-undefined-weak.s index 8a78e1f838338..57841127792ff 100644 --- a/lld/test/ELF/riscv-undefined-weak.s +++ b/lld/test/ELF/riscv-undefined-weak.s @@ -97,4 +97,4 @@ branch: # PC-NOT: .plt: # PLT: .plt: -.word target@plt - . +.word %pltpcrel(target) diff --git a/lld/test/ELF/riscv64-reloc-got32-pcrel.s b/lld/test/ELF/riscv64-reloc-got32-pcrel.s index 24bd828235b25..a8f42ae6df2b9 100644 --- a/lld/test/ELF/riscv64-reloc-got32-pcrel.s +++ b/lld/test/ELF/riscv64-reloc-got32-pcrel.s @@ -12,16 +12,16 @@ bar: .globl _start _start: // PC = 0x33a8 -// bar@GOTPCREL = 0x2398 (got entry for `bar`) - 0x33a8 (.) = 0xf0efffff -// bar@GOTPCREL+4 = 0x2398 (got entry for `bar`) - 0x33ac (.) + 4 = 0xf0efffff -// bar@GOTPCREL-4 = 0x2398 (got entry for `bar`) - 0x33b0 (.) - 4 = 0xe4efffff +// %gotpcrel(bar) = 0x2398 (got entry for `bar`) - 0x33a8 (.) = 0xf0efffff +// %gotpcrel(bar+4) = 0x2398 (got entry for `bar`) - 0x33ac (.) + 4 = 0xf0efffff +// %gotpcrel(bar-4) = 0x2398 (got entry for `bar`) - 0x33b0 (.) - 4 = 0xe4efffff // CHECK: Contents of section .data: // CHECK-NEXT: {{.*}} f0efffff f0efffff e4efffff - .word bar@GOTPCREL - .word bar@GOTPCREL+4 - .word bar@GOTPCREL-4 + .word %gotpcrel(bar) + .word %gotpcrel(bar+4) + .word %gotpcrel(bar-4) // WARN: relocation R_RISCV_GOT32_PCREL out of range: {{.*}} is not in [-2147483648, 2147483647]; references 'baz' // WARN: relocation R_RISCV_GOT32_PCREL out of range: {{.*}} is not in [-2147483648, 2147483647]; references 'baz' - .word baz@GOTPCREL+0xffffffff - .word baz@GOTPCREL-0xffffffff + .word %gotpcrel(baz+0xffffffff) + .word %gotpcrel(baz-0xffffffff) diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h index 300afe3d3e097..4dd45a1a7774d 100644 --- a/llvm/include/llvm/CodeGen/AsmPrinter.h +++ b/llvm/include/llvm/CodeGen/AsmPrinter.h @@ -497,7 +497,10 @@ class AsmPrinter : public MachineFunctionPass { unsigned MaxBytesToEmit = 0) const; /// Lower the specified LLVM Constant to an MCExpr. - virtual const MCExpr *lowerConstant(const Constant *CV); + /// When BaseCV is present, we are lowering the element at BaseCV plus Offset. + virtual const MCExpr *lowerConstant(const Constant *CV, + const Constant *BaseCV = nullptr, + uint64_t Offset = 0); /// Print a general LLVM constant to the .s file. /// On AIX, when an alias refers to a sub-element of a global variable, the diff --git a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h index 76571690eeda0..7c929262f6823 100644 --- a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h +++ b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h @@ -40,7 +40,6 @@ class TargetLoweringObjectFileELF : public TargetLoweringObjectFile { uint8_t PLTRelativeSpecifier = 0; public: - TargetLoweringObjectFileELF(); ~TargetLoweringObjectFileELF() override = default; void Initialize(MCContext &Ctx, const TargetMachine &TM) override; @@ -112,11 +111,22 @@ class TargetLoweringObjectFileELF : public TargetLoweringObjectFile { MCSection *getStaticDtorSection(unsigned Priority, const MCSymbol *KeySym) const override; + virtual const MCExpr *createTargetMCExpr(const MCExpr *Expr, + uint8_t Specifier) const { + return nullptr; + } + const MCExpr * + lowerSymbolDifference(const MCSymbol *LHS, const MCSymbol *RHS, + int64_t Addend, + std::optional PCRelativeOffset) const; const MCExpr *lowerRelativeReference(const GlobalValue *LHS, - const GlobalValue *RHS, + const GlobalValue *RHS, int64_t Addend, + std::optional PCRelativeOffset, const TargetMachine &TM) const override; - const MCExpr *lowerDSOLocalEquivalent(const DSOLocalEquivalent *Equiv, + const MCExpr *lowerDSOLocalEquivalent(const MCSymbol *LHS, + const MCSymbol *RHS, int64_t Addend, + std::optional PCRelativeOffset, const TargetMachine &TM) const override; MCSection *getSectionForCommandLines() const override; @@ -206,7 +216,8 @@ class TargetLoweringObjectFileCOFF : public TargetLoweringObjectFile { const MCSymbol *KeySym) const override; const MCExpr *lowerRelativeReference(const GlobalValue *LHS, - const GlobalValue *RHS, + const GlobalValue *RHS, int64_t Addend, + std::optional PCRelativeOffset, const TargetMachine &TM) const override; /// Given a mergeable constant with the specified size and relocation diff --git a/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h b/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h index 59cee18bfdf42..c7f098be70945 100644 --- a/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h +++ b/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h @@ -396,6 +396,12 @@ class MCTargetAsmParser : public MCAsmParserExtension { virtual bool parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { return getParser().parsePrimaryExpr(Res, EndLoc, nullptr); } + // Parse an expression in a data directive, possibly with a relocation + // specifier. + virtual bool parseDataExpr(const MCExpr *&Res) { + SMLoc EndLoc; + return getParser().parseExpression(Res, EndLoc); + } virtual bool parseRegister(MCRegister &Reg, SMLoc &StartLoc, SMLoc &EndLoc) = 0; diff --git a/llvm/include/llvm/Target/TargetLoweringObjectFile.h b/llvm/include/llvm/Target/TargetLoweringObjectFile.h index a5ed1b29dc1bc..9fc09bb7db6c2 100644 --- a/llvm/include/llvm/Target/TargetLoweringObjectFile.h +++ b/llvm/include/llvm/Target/TargetLoweringObjectFile.h @@ -51,7 +51,7 @@ class TargetLoweringObjectFile : public MCObjectFileInfo { bool SupportIndirectSymViaGOTPCRel = false; bool SupportGOTPCRelWithOffset = true; bool SupportDebugThreadLocalLocation = true; - bool SupportDSOLocalEquivalentLowering = false; + uint32_t PLTPCRelativeSpecifier = 0; /// PersonalityEncoding, LSDAEncoding, TTypeEncoding - Some encoding values /// for EH. @@ -196,20 +196,19 @@ class TargetLoweringObjectFile : public MCObjectFileInfo { /// emitting the address in debug info. virtual const MCExpr *getDebugThreadLocalSymbol(const MCSymbol *Sym) const; - virtual const MCExpr *lowerRelativeReference(const GlobalValue *LHS, - const GlobalValue *RHS, - const TargetMachine &TM) const { + virtual const MCExpr *lowerRelativeReference( + const GlobalValue *LHS, const GlobalValue *RHS, int64_t Addend, + std::optional PCRelativeOffset, const TargetMachine &TM) const { return nullptr; } - /// Target supports a native lowering of a dso_local_equivalent constant - /// without needing to replace it with equivalent IR. - bool supportDSOLocalEquivalentLowering() const { - return SupportDSOLocalEquivalentLowering; - } + /// Target supports a PC-relative relocation that references the PLT of a + /// function. + bool hasPLTPCRelative() const { return PLTPCRelativeSpecifier; } - virtual const MCExpr *lowerDSOLocalEquivalent(const DSOLocalEquivalent *Equiv, - const TargetMachine &TM) const { + virtual const MCExpr *lowerDSOLocalEquivalent( + const MCSymbol *LHS, const MCSymbol *RHS, int64_t Addend, + std::optional PCRelativeOffset, const TargetMachine &TM) const { return nullptr; } diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 40abe28c31763..c626202753824 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(CV)) @@ -3382,7 +3384,8 @@ const MCExpr *AsmPrinter::lowerConstant(const Constant *CV) { return lowerBlockAddressConstant(*BA); if (const auto *Equiv = dyn_cast(CV)) - return getObjFileLowering().lowerDSOLocalEquivalent(Equiv, TM); + return getObjFileLowering().lowerDSOLocalEquivalent( + getSymbol(Equiv->getGlobalValue()), nullptr, 0, std::nullopt, TM); if (const NoCFIValue *NC = dyn_cast(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 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 0e44acdd1dccc..dd6d85e3662db 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 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 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 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 PCRelativeOffset, const TargetMachine &TM) const { const Triple &T = TM.getTargetTriple(); if (T.isOSCygMing()) return nullptr; @@ -2069,9 +2091,12 @@ const MCExpr *TargetLoweringObjectFileCOFF::lowerRelativeReference( cast(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 6ae99ecc3a746..1c79af412a4d7 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 9448e7b301e28..65a38009a8488 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(Value)) { diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index e3ad085bc5a29..ff1aee9bda6e5 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -254,7 +254,9 @@ class AArch64AsmPrinter : public AsmPrinter { 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(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 2c959d7dbbd07..4183bb6a76b6e 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.h +++ b/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.h @@ -107,7 +107,8 @@ class AMDGPUAsmPrinter final : public AsmPrinter { /// 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 895d1e77bf1c4..6fa97d82a668b 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(CV)) { if (std::optional 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 552d01f81b66c..936fe9bcc288b 100644 --- a/llvm/lib/Target/AMDGPU/R600AsmPrinter.h +++ b/llvm/lib/Target/AMDGPU/R600AsmPrinter.h @@ -30,7 +30,8 @@ class R600AsmPrinter final : public AsmPrinter { /// 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 6da545659a57b..6d7e834ca3d5d 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 a63aa54211824..a8621abdb5ffb 100644 --- a/llvm/lib/Target/AVR/AVRAsmPrinter.cpp +++ b/llvm/lib/Target/AVR/AVRAsmPrinter.cpp @@ -59,7 +59,8 @@ class AVRAsmPrinter : public AsmPrinter { 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(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 b4365cd99cb58..861ccde22c5c3 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(Res)) == RISCVMCExpr::VK_PLT) + getSpecifier(cast(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 f8841dd657568..5faeb98f0abf5 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(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(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(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 c327f9d5f0f1e..7e9b312d3c25e 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 f333ffe36cbf7..b27f13e6b95ba 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 b73496beba7e0..e7c0f9501c1b0 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 af178ffabce13..604d2ebc66d1c 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h @@ -38,7 +38,7 @@ class RISCVMCExpr : public MCTargetExpr { 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 e546815b70935..57c0af7ce5dca 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 ff7e3e4c752c3..b6da3f4721f4b 100644 --- a/llvm/lib/Target/RISCV/RISCVTargetObjectFile.h +++ b/llvm/lib/Target/RISCV/RISCVTargetObjectFile.h @@ -48,6 +48,9 @@ class RISCVELFTargetObjectFile : public TargetLoweringObjectFileELF { 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, diff --git a/llvm/test/CodeGen/RISCV/dso_local_equivalent.ll b/llvm/test/CodeGen/RISCV/dso_local_equivalent.ll index 0979967614b8a..1ee8b1f78110b 100644 --- a/llvm/test/CodeGen/RISCV/dso_local_equivalent.ll +++ b/llvm/test/CodeGen/RISCV/dso_local_equivalent.ll @@ -4,9 +4,40 @@ declare void @extern_func() ; CHECK-LABEL: const: -; CHECK-NEXT: .word extern_func@PLT-const +; CHECK-NEXT: .word %pltpcrel(extern_func) ;; Note that for riscv32, the ptrtoint will actually upcast the ptr it to an ;; oversized 64-bit pointer that eventually gets truncated. This isn't needed ;; for riscv32, but this unifies the RV64 and RV32 test cases. @const = dso_local constant i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @extern_func to i64), i64 ptrtoint (ptr @const to i64)) to i32) + +@_ZTV1B = dso_local constant { [7 x i32] } { [7 x i32] [ + i32 0, + i32 0, + i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @f0 to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [7 x i32] }, ptr @_ZTV1B, i32 0, i32 0, i32 2) to i64)) to i32), + i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @f1 to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [7 x i32] }, ptr @_ZTV1B, i32 0, i32 0, i32 2) to i64)) to i32), + i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @f2 to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [7 x i32] }, ptr @_ZTV1B, i32 0, i32 0, i32 2) to i64)) to i32), + i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @f3 to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [7 x i32] }, ptr @_ZTV1B, i32 0, i32 0, i32 2) to i64)) to i32), + i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @f4 to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [7 x i32] }, ptr @_ZTV1B, i32 0, i32 0, i32 2) to i64)) to i32) +] }, align 4 + +; CHECK-LABEL: _ZTV1B: +; CHECK-NEXT: .word 0 # 0x0 +; CHECK-NEXT: .word 0 # 0x0 +; CHECK-NEXT: .word %pltpcrel(f0) +; CHECK-NEXT: .word %pltpcrel(f1+4) +; CHECK-NEXT: .word (f2-_ZTV1B)-8 +; CHECK-NEXT: .word %pltpcrel(f3+12) +; CHECK-NEXT: .word (f4-_ZTV1B)-8 +; CHECK-NEXT: .size _ZTV1B, 28 +declare void @f0() +declare void @f1() +define dso_local void @f2() { + ret void +} +define void @f3() { + ret void +} +define hidden void @f4() { + ret void +} diff --git a/llvm/test/CodeGen/RISCV/plt-relative-reloc.ll b/llvm/test/CodeGen/RISCV/plt-relative-reloc.ll new file mode 100644 index 0000000000000..a432fc5e7e530 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/plt-relative-reloc.ll @@ -0,0 +1,21 @@ +; RUN: llc -mtriple=riscv64 < %s | FileCheck %s + +@vtable = constant [5 x i32] [i32 0, + i32 trunc (i64 sub (i64 ptrtoint (ptr @fn1 to i64), i64 ptrtoint (ptr getelementptr ([5 x i32], ptr @vtable, i32 0, i32 1) to i64)) to i32), + i32 trunc (i64 sub (i64 ptrtoint (ptr @fn2 to i64), i64 ptrtoint (ptr getelementptr ([5 x i32], ptr @vtable, i32 0, i32 1) to i64)) to i32), + i32 trunc (i64 sub (i64 ptrtoint (ptr @fn3 to i64), i64 ptrtoint (ptr getelementptr ([5 x i32], ptr @vtable, i32 0, i32 1) to i64)) to i32), + i32 trunc (i64 sub (i64 ptrtoint (ptr @global4 to i64), i64 ptrtoint (ptr getelementptr ([5 x i32], ptr @vtable, i32 0, i32 1) to i64)) to i32) +] + +declare void @fn1() unnamed_addr +declare void @fn2() unnamed_addr +declare void @fn3() +@global4 = external unnamed_addr global i8 + +; CHECK: vtable: +; CHECK-NEXT: .word 0 # 0x0 +; CHECK-NEXT: .word %pltpcrel(fn1) +; CHECK-NEXT: .word %pltpcrel(fn2+4) +; CHECK-NEXT: .word (fn3-vtable)-4 +; CHECK-NEXT: .word (global4-vtable)-4 +; CHECK-NEXT: .size vtable, 20 diff --git a/llvm/test/MC/ELF/rtti-proxy-gotpcrel.ll b/llvm/test/MC/ELF/rtti-proxy-gotpcrel.ll index 9f47469ff5e7e..478d24556f892 100644 --- a/llvm/test/MC/ELF/rtti-proxy-gotpcrel.ll +++ b/llvm/test/MC/ELF/rtti-proxy-gotpcrel.ll @@ -1,7 +1,7 @@ ; REQUIRES: x86-registered-target && aarch64-registered-target && riscv-registered-target ; RUN: llc %s -mtriple=x86_64 -o - | FileCheck %s ; RUN: llc %s -mtriple=aarch64 -o - | FileCheck %s -; RUN: llc %s -mtriple=riscv64 -o - | FileCheck %s +; RUN: llc %s -mtriple=riscv64 -o - | FileCheck %s --check-prefix=RISCV @vtable = dso_local unnamed_addr constant i32 trunc (i64 sub (i64 ptrtoint (ptr @rtti.proxy to i64), i64 ptrtoint (ptr @vtable to i64)) to i32), align 4 @vtable_with_offset = dso_local unnamed_addr constant [2 x i32] [i32 0, i32 trunc (i64 sub (i64 ptrtoint (ptr @rtti.proxy to i64), i64 ptrtoint (ptr @vtable_with_offset to i64)) to i32)], align 4 @@ -28,3 +28,12 @@ ; CHECK-LABEL: vtable_with_negative_offset: ; CHECK-NEXT: .{{word|long}} rtti@GOTPCREL-4{{$}} ; CHECK-NEXT: .{{word|long}} 0 + +; RISCV-LABEL: vtable: +; RISCV-NEXT: .word %gotpcrel(rtti+0) +; RISCV-LABEL: vtable_with_offset: +; RISCV-NEXT: .word 0 +; RISCV-NEXT: .word %gotpcrel(rtti+4) +; RISCV-LABEL: vtable_with_negative_offset: +; RISCV-NEXT: .word %gotpcrel(rtti-4) +; RISCV-NEXT: .word 0 diff --git a/llvm/test/MC/RISCV/data-directive-specifier.s b/llvm/test/MC/RISCV/data-directive-specifier.s index a578f9720eccd..24fbccdb8abdb 100644 --- a/llvm/test/MC/RISCV/data-directive-specifier.s +++ b/llvm/test/MC/RISCV/data-directive-specifier.s @@ -9,18 +9,12 @@ l: # CHECK: Section ({{.*}}) .rela.data { # CHECK-NEXT: 0x0 R_RISCV_PLT32 l 0x0 -# CHECK-NEXT: 0x4 R_RISCV_PLT32 l 0x4 -# CHECK-NEXT: 0x8 R_RISCV_PLT32 extern 0x4 -# CHECK-NEXT: 0xC R_RISCV_PLT32 g 0x8 -# CHECK-NEXT: 0x10 R_RISCV_PLT32 g 0x18 +# CHECK-NEXT: 0x4 R_RISCV_PLT32 extern 0x4 +# CHECK-NEXT: 0x8 R_RISCV_PLT32 g 0x8 # CHECK-NEXT: } .data -.word l@plt - . -.word l@plt - .data - -.word extern@plt - . + 4 -.word g@plt - . + 8 -.word g@plt - .data + 8 +.word %pltpcrel(l) +.word %pltpcrel(extern + 4), %pltpcrel(g + 8) # CHECK: Section ({{.*}}) .rela.data1 { # CHECK-NEXT: 0x0 R_RISCV_GOT32_PCREL data1 0x0 @@ -30,14 +24,25 @@ l: # CHECK-NEXT: } .section .data1,"aw" data1: -.word data1@GOTPCREL -.word extern@gotpcrel+4 -.word extern@GOTPCREL-5 +.word %gotpcrel(data1) +.word %gotpcrel(extern+4), %gotpcrel(extern-5) .ifdef ERR -# ERR: [[#@LINE+1]]:7: error: symbol 'und' can not be undefined in a subtraction expression -.word extern@plt - und +# ERR: [[#@LINE+1]]:7: error: %pltpcrel can only be used in a .word directive +.quad %pltpcrel(g) + +# ERR: [[#@LINE+1]]:7: error: expected relocatable expression +.word %pltpcrel(g-.) + +# ERR: [[#@LINE+1]]:7: error: expected relocatable expression +.word %pltpcrel(extern - und) + +# ERR: [[#@LINE+1]]:7: error: %gotpcrel can only be used in a .word directive +.quad %gotpcrel(g) + +# ERR: [[#@LINE+1]]:7: error: expected relocatable expression +.word %gotpcrel(extern - .) -# ERR: [[#@LINE+1]]:7: error: symbol 'und' can not be undefined in a subtraction expression -.word extern@gotpcrel - und +# ERR: [[#@LINE+1]]:7: error: expected relocatable expression +.word %gotpcrel(extern - und) .endif diff --git a/llvm/test/MC/RISCV/pseudo-jump-invalid.s b/llvm/test/MC/RISCV/pseudo-jump-invalid.s index 222fdb43a4ec9..834b5a186b007 100644 --- a/llvm/test/MC/RISCV/pseudo-jump-invalid.s +++ b/llvm/test/MC/RISCV/pseudo-jump-invalid.s @@ -1,5 +1,5 @@ # RUN: not llvm-mc -triple riscv32 < %s 2>&1 | FileCheck %s jump 1234, x31 # CHECK: :[[@LINE]]:6: error: operand must be a valid jump target -jump foo@plt, x31 # CHECK: :[[@LINE]]:6: error: operand must be a valid jump target +jump foo@plt, x31 # CHECK: :[[@LINE]]:10: error: invalid variant 'plt' jump %pcrel_lo(1234), x31 # CHECK: :[[@LINE]]:6: error: unknown token in expression diff --git a/llvm/test/MC/RISCV/rv32i-invalid.s b/llvm/test/MC/RISCV/rv32i-invalid.s index b2ecbb2dbd508..15622cd9554ce 100644 --- a/llvm/test/MC/RISCV/rv32i-invalid.s +++ b/llvm/test/MC/RISCV/rv32i-invalid.s @@ -150,6 +150,7 @@ add a0, tp, a0, %tprel_add(foo) # CHECK: :[[@LINE]]:13: error: the second input # Unrecognized operand modifier addi t0, sp, %modifer(255) # CHECK: :[[@LINE]]:15: error: invalid relocation specifier +addi t0, sp, %pltpcrel(255) # CHECK: :[[@LINE]]:14: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo specifier or an integer in the range [-2048, 2047] # Use of operand modifier on register name addi t1, %lo(t2), 1 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction