diff --git a/llvm/include/llvm/MC/MCAsmBackend.h b/llvm/include/llvm/MC/MCAsmBackend.h --- a/llvm/include/llvm/MC/MCAsmBackend.h +++ b/llvm/include/llvm/MC/MCAsmBackend.h @@ -129,10 +129,6 @@ uint64_t Value, bool IsResolved, const MCSubtargetInfo *STI) const = 0; - /// Check whether the given target requires emitting differences of two - /// symbols as a set of relocations. - virtual bool requiresDiffExpressionRelocations() const { return false; } - /// @} /// \name Target Relaxation Interfaces diff --git a/llvm/include/llvm/MC/MCFixup.h b/llvm/include/llvm/MC/MCFixup.h --- a/llvm/include/llvm/MC/MCFixup.h +++ b/llvm/include/llvm/MC/MCFixup.h @@ -41,16 +41,6 @@ FK_SecRel_2, ///< A two-byte section relative fixup. FK_SecRel_4, ///< A four-byte section relative fixup. FK_SecRel_8, ///< A eight-byte section relative fixup. - FK_Data_Add_1, ///< A one-byte add fixup. - FK_Data_Add_2, ///< A two-byte add fixup. - FK_Data_Add_4, ///< A four-byte add fixup. - FK_Data_Add_8, ///< A eight-byte add fixup. - FK_Data_Add_6b, ///< A six-bits add fixup. - FK_Data_Sub_1, ///< A one-byte sub fixup. - FK_Data_Sub_2, ///< A two-byte sub fixup. - FK_Data_Sub_4, ///< A four-byte sub fixup. - FK_Data_Sub_8, ///< A eight-byte sub fixup. - FK_Data_Sub_6b, ///< A six-bits sub fixup. FirstTargetFixupKind = 128, @@ -105,28 +95,6 @@ return FI; } - /// Return a fixup corresponding to the add half of a add/sub fixup pair for - /// the given Fixup. - static MCFixup createAddFor(const MCFixup &Fixup) { - MCFixup FI; - FI.Value = Fixup.getValue(); - FI.Offset = Fixup.getOffset(); - FI.Kind = getAddKindForKind(Fixup.getKind()); - FI.Loc = Fixup.getLoc(); - return FI; - } - - /// Return a fixup corresponding to the sub half of a add/sub fixup pair for - /// the given Fixup. - static MCFixup createSubFor(const MCFixup &Fixup) { - MCFixup FI; - FI.Value = Fixup.getValue(); - FI.Offset = Fixup.getOffset(); - FI.Kind = getSubKindForKind(Fixup.getKind()); - FI.Loc = Fixup.getLoc(); - return FI; - } - MCFixupKind getKind() const { return Kind; } unsigned getTargetKind() const { return Kind; } @@ -172,32 +140,6 @@ } } - /// Return the generic fixup kind for an addition with a given size. It - /// is an error to pass an unsupported size. - static MCFixupKind getAddKindForKind(MCFixupKind Kind) { - switch (Kind) { - default: llvm_unreachable("Unknown type to convert!"); - case FK_Data_1: return FK_Data_Add_1; - case FK_Data_2: return FK_Data_Add_2; - case FK_Data_4: return FK_Data_Add_4; - case FK_Data_8: return FK_Data_Add_8; - case FK_Data_6b: return FK_Data_Add_6b; - } - } - - /// Return the generic fixup kind for an subtraction with a given size. It - /// is an error to pass an unsupported size. - static MCFixupKind getSubKindForKind(MCFixupKind Kind) { - switch (Kind) { - default: llvm_unreachable("Unknown type to convert!"); - case FK_Data_1: return FK_Data_Sub_1; - case FK_Data_2: return FK_Data_Sub_2; - case FK_Data_4: return FK_Data_Sub_4; - case FK_Data_8: return FK_Data_Sub_8; - case FK_Data_6b: return FK_Data_Sub_6b; - } - } - SMLoc getLoc() const { return Loc; } }; diff --git a/llvm/lib/MC/MCAsmBackend.cpp b/llvm/lib/MC/MCAsmBackend.cpp --- a/llvm/lib/MC/MCAsmBackend.cpp +++ b/llvm/lib/MC/MCAsmBackend.cpp @@ -95,16 +95,7 @@ {"FK_SecRel_2", 0, 16, 0}, {"FK_SecRel_4", 0, 32, 0}, {"FK_SecRel_8", 0, 64, 0}, - {"FK_Data_Add_1", 0, 8, 0}, - {"FK_Data_Add_2", 0, 16, 0}, - {"FK_Data_Add_4", 0, 32, 0}, - {"FK_Data_Add_8", 0, 64, 0}, - {"FK_Data_Add_6b", 0, 6, 0}, - {"FK_Data_Sub_1", 0, 8, 0}, - {"FK_Data_Sub_2", 0, 16, 0}, - {"FK_Data_Sub_4", 0, 32, 0}, - {"FK_Data_Sub_8", 0, 64, 0}, - {"FK_Data_Sub_6b", 0, 6, 0}}; + }; assert((size_t)Kind <= array_lengthof(Builtins) && "Unknown fixup kind"); return Builtins[Kind]; diff --git a/llvm/lib/MC/MCAssembler.cpp b/llvm/lib/MC/MCAssembler.cpp --- a/llvm/lib/MC/MCAssembler.cpp +++ b/llvm/lib/MC/MCAssembler.cpp @@ -792,26 +792,7 @@ // The fixup was unresolved, we need a relocation. Inform the object // writer of the relocation, and give it an opportunity to adjust the // fixup value if need be. - if (Target.getSymA() && Target.getSymB() && - getBackend().requiresDiffExpressionRelocations()) { - // The fixup represents the difference between two symbols, which the - // backend has indicated must be resolved at link time. Split up the fixup - // into two relocations, one for the add, and one for the sub, and emit - // both of these. The constant will be associated with the add half of the - // expression. - MCFixup FixupAdd = MCFixup::createAddFor(Fixup); - MCValue TargetAdd = - MCValue::get(Target.getSymA(), nullptr, Target.getConstant()); - getWriter().recordRelocation(*this, Layout, &F, FixupAdd, TargetAdd, - FixedValue); - MCFixup FixupSub = MCFixup::createSubFor(Fixup); - MCValue TargetSub = MCValue::get(Target.getSymB()); - getWriter().recordRelocation(*this, Layout, &F, FixupSub, TargetSub, - FixedValue); - } else { - getWriter().recordRelocation(*this, Layout, &F, Fixup, Target, - FixedValue); - } + getWriter().recordRelocation(*this, Layout, &F, Fixup, Target, FixedValue); } return std::make_tuple(Target, FixedValue, IsResolved); } @@ -1113,28 +1094,8 @@ raw_svector_ostream OSE(Data); DF.getFixups().clear(); - if (!getBackend().requiresDiffExpressionRelocations()) { - MCDwarfLineAddr::Encode(Context, getDWARFLinetableParams(), LineDelta, - AddrDelta, OSE); - } else { - uint32_t Offset; - uint32_t Size; - bool SetDelta; - std::tie(Offset, Size, SetDelta) = - MCDwarfLineAddr::fixedEncode(Context, LineDelta, AddrDelta, OSE); - // Add Fixups for address delta or new address. - const MCExpr *FixupExpr; - if (SetDelta) { - FixupExpr = &DF.getAddrDelta(); - } else { - const MCBinaryExpr *ABE = cast(&DF.getAddrDelta()); - FixupExpr = ABE->getLHS(); - } - DF.getFixups().push_back( - MCFixup::create(Offset, FixupExpr, - MCFixup::getKindForSize(Size, false /*isPCRel*/))); - } - + MCDwarfLineAddr::Encode(Context, getDWARFLinetableParams(), LineDelta, + AddrDelta, OSE); return OldSize != Data.size(); } @@ -1151,20 +1112,7 @@ raw_svector_ostream OSE(Data); DF.getFixups().clear(); - if (getBackend().requiresDiffExpressionRelocations()) { - uint32_t Offset; - uint32_t Size; - MCDwarfFrameEmitter::EncodeAdvanceLoc(Context, AddrDelta, OSE, &Offset, - &Size); - if (Size) { - DF.getFixups().push_back(MCFixup::create( - Offset, &DF.getAddrDelta(), - MCFixup::getKindForSizeInBits(Size /*In bits.*/, false /*isPCRel*/))); - } - } else { - MCDwarfFrameEmitter::EncodeAdvanceLoc(Context, AddrDelta, OSE); - } - + MCDwarfFrameEmitter::EncodeAdvanceLoc(Context, AddrDelta, OSE); return OldSize != Data.size(); } @@ -1194,10 +1142,6 @@ raw_svector_ostream OSE(Data); PF.getFixups().clear(); - // Relocations should not be needed in general except on RISC-V which we are - // not targeted for now. - assert(!getBackend().requiresDiffExpressionRelocations() && - "cannot relax relocations"); // AddrDelta is a signed integer encodeSLEB128(AddrDelta, OSE, OldSize); return OldSize != Data.size(); diff --git a/llvm/lib/MC/MCExpr.cpp b/llvm/lib/MC/MCExpr.cpp --- a/llvm/lib/MC/MCExpr.cpp +++ b/llvm/lib/MC/MCExpr.cpp @@ -671,24 +671,6 @@ } } -static bool canFold(const MCAssembler *Asm, const MCSymbolRefExpr *A, - const MCSymbolRefExpr *B, bool InSet) { - if (InSet) - return true; - - if (!Asm->getBackend().requiresDiffExpressionRelocations()) - return true; - - const MCSymbol &CheckSym = A ? A->getSymbol() : B->getSymbol(); - if (!CheckSym.isInSection()) - return true; - - if (!CheckSym.getSection().hasInstructions()) - return true; - - return false; -} - /// Evaluate the result of an add between (conceptually) two MCValues. /// /// This routine conceptually attempts to construct an MCValue: @@ -725,11 +707,8 @@ assert((!Layout || Asm) && "Must have an assembler object if layout is given!"); - // If we have a layout, we can fold resolved differences. Do not do this if - // the backend requires this to be emitted as individual relocations, unless - // the InSet flag is set to get the current difference anyway (used for - // example to calculate symbol sizes). - if (Asm && canFold(Asm, LHS_A, LHS_B, InSet)) { + // If we have a layout, we can fold resolved differences. + if (Asm) { // First, fold out any differences which are fully resolved. By // reassociating terms in // Result = (LHS_A - LHS_B + LHS_Cst) + (RHS_A - RHS_B + RHS_Cst). diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp --- a/llvm/lib/MC/MCObjectStreamer.cpp +++ b/llvm/lib/MC/MCObjectStreamer.cpp @@ -128,11 +128,8 @@ // As a compile-time optimization, avoid allocating and evaluating an MCExpr // tree for (Hi - Lo) when Hi and Lo are offsets into the same fragment. static Optional -absoluteSymbolDiff(MCAssembler &Asm, const MCSymbol *Hi, const MCSymbol *Lo) { +absoluteSymbolDiff(const MCSymbol *Hi, const MCSymbol *Lo) { assert(Hi && Lo); - if (Asm.getBackendPtr()->requiresDiffExpressionRelocations()) - return None; - if (!Hi->getFragment() || Hi->getFragment() != Lo->getFragment() || Hi->isVariable() || Lo->isVariable()) return None; @@ -143,19 +140,17 @@ void MCObjectStreamer::emitAbsoluteSymbolDiff(const MCSymbol *Hi, const MCSymbol *Lo, unsigned Size) { - if (Optional Diff = absoluteSymbolDiff(getAssembler(), Hi, Lo)) { - emitIntValue(*Diff, Size); - return; - } + if (!getAssembler().getContext().getTargetTriple().isRISCV()) + if (Optional Diff = absoluteSymbolDiff(Hi, Lo)) + return emitIntValue(*Diff, Size); MCStreamer::emitAbsoluteSymbolDiff(Hi, Lo, Size); } void MCObjectStreamer::emitAbsoluteSymbolDiffAsULEB128(const MCSymbol *Hi, const MCSymbol *Lo) { - if (Optional Diff = absoluteSymbolDiff(getAssembler(), Hi, Lo)) { - emitULEB128IntValue(*Diff); - return; - } + if (!getAssembler().getContext().getTargetTriple().isRISCV()) + if (Optional Diff = absoluteSymbolDiff(Hi, Lo)) + return emitULEB128IntValue(*Diff); MCStreamer::emitAbsoluteSymbolDiffAsULEB128(Hi, Lo); } diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h @@ -42,20 +42,6 @@ void setForceRelocs() { ForceRelocs = true; } - // Returns true if relocations will be forced for shouldForceRelocation by - // default. This will be true if relaxation is enabled or had previously - // been enabled. - bool willForceRelocations() const { - return ForceRelocs || STI.getFeatureBits()[RISCV::FeatureRelax]; - } - - // Generate diff expression relocations if the relax feature is enabled or had - // previously been enabled, otherwise it is safe for the assembler to - // calculate these internally. - bool requiresDiffExpressionRelocations() const override { - return willForceRelocations(); - } - // Return Size with extra Nop Bytes for alignment directive in code section. bool shouldInsertExtraNopBytesForCodeAlign(const MCAlignFragment &AF, unsigned &Size) override; diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -70,7 +70,20 @@ {"fixup_riscv_call", 0, 64, MCFixupKindInfo::FKF_IsPCRel}, {"fixup_riscv_call_plt", 0, 64, MCFixupKindInfo::FKF_IsPCRel}, {"fixup_riscv_relax", 0, 0, 0}, - {"fixup_riscv_align", 0, 0, 0}}; + {"fixup_riscv_align", 0, 0, 0}, + + {"fixup_riscv_add_8", 0, 0, 0}, + {"fixup_riscv_sub_8", 0, 0, 0}, + + {"fixup_riscv_add_16", 0, 0, 0}, + {"fixup_riscv_sub_16", 0, 0, 0}, + + {"fixup_riscv_add_32", 0, 0, 0}, + {"fixup_riscv_sub_32", 0, 0, 0}, + + {"fixup_riscv_add_64", 0, 0, 0}, + {"fixup_riscv_sub_64", 0, 0, 0}, + }; static_assert((array_lengthof(Infos)) == RISCV::NumTargetFixupKinds, "Not all fixup kinds added to Infos array"); @@ -227,6 +240,14 @@ case RISCV::fixup_riscv_tls_got_hi20: case RISCV::fixup_riscv_tls_gd_hi20: llvm_unreachable("Relocation should be unconditionally forced\n"); + case RISCV::fixup_riscv_add_8: + case RISCV::fixup_riscv_sub_8: + case RISCV::fixup_riscv_add_16: + case RISCV::fixup_riscv_sub_16: + case RISCV::fixup_riscv_add_32: + case RISCV::fixup_riscv_sub_32: + case RISCV::fixup_riscv_add_64: + case RISCV::fixup_riscv_sub_64: case FK_Data_1: case FK_Data_2: case FK_Data_4: diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp @@ -15,6 +15,8 @@ #include "llvm/MC/MCObjectWriter.h" #include "llvm/Support/ErrorHandling.h" +#include + using namespace llvm; namespace { @@ -86,6 +88,22 @@ return ELF::R_RISCV_CALL; case RISCV::fixup_riscv_call_plt: return ELF::R_RISCV_CALL_PLT; + case RISCV::fixup_riscv_add_8: + return ELF::R_RISCV_ADD8; + case RISCV::fixup_riscv_sub_8: + return ELF::R_RISCV_SUB8; + case RISCV::fixup_riscv_add_16: + return ELF::R_RISCV_ADD16; + case RISCV::fixup_riscv_sub_16: + return ELF::R_RISCV_SUB16; + case RISCV::fixup_riscv_add_32: + return ELF::R_RISCV_ADD32; + case RISCV::fixup_riscv_sub_32: + return ELF::R_RISCV_SUB32; + case RISCV::fixup_riscv_add_64: + return ELF::R_RISCV_ADD64; + case RISCV::fixup_riscv_sub_64: + return ELF::R_RISCV_SUB64; } } @@ -106,26 +124,6 @@ return ELF::R_RISCV_32; case FK_Data_8: return ELF::R_RISCV_64; - case FK_Data_Add_1: - return ELF::R_RISCV_ADD8; - case FK_Data_Add_2: - return ELF::R_RISCV_ADD16; - case FK_Data_Add_4: - return ELF::R_RISCV_ADD32; - case FK_Data_Add_8: - return ELF::R_RISCV_ADD64; - case FK_Data_Add_6b: - return ELF::R_RISCV_SET6; - case FK_Data_Sub_1: - return ELF::R_RISCV_SUB8; - case FK_Data_Sub_2: - return ELF::R_RISCV_SUB16; - case FK_Data_Sub_4: - return ELF::R_RISCV_SUB32; - case FK_Data_Sub_8: - return ELF::R_RISCV_SUB64; - case FK_Data_Sub_6b: - return ELF::R_RISCV_SUB6; case RISCV::fixup_riscv_hi20: return ELF::R_RISCV_HI20; case RISCV::fixup_riscv_lo12_i: @@ -144,6 +142,22 @@ return ELF::R_RISCV_RELAX; case RISCV::fixup_riscv_align: return ELF::R_RISCV_ALIGN; + case RISCV::fixup_riscv_add_8: + return ELF::R_RISCV_ADD8; + case RISCV::fixup_riscv_sub_8: + return ELF::R_RISCV_SUB8; + case RISCV::fixup_riscv_add_16: + return ELF::R_RISCV_ADD16; + case RISCV::fixup_riscv_sub_16: + return ELF::R_RISCV_SUB16; + case RISCV::fixup_riscv_add_32: + return ELF::R_RISCV_ADD32; + case RISCV::fixup_riscv_sub_32: + return ELF::R_RISCV_SUB32; + case RISCV::fixup_riscv_add_64: + return ELF::R_RISCV_ADD64; + case RISCV::fixup_riscv_sub_64: + return ELF::R_RISCV_SUB64; } } diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h @@ -104,5 +104,11 @@ void emitDirectiveOptionRelax() override; void emitDirectiveOptionNoRelax() override; }; + +MCELFStreamer *createRISCVELFStreamer(MCContext &C, + std::unique_ptr MAB, + std::unique_ptr MOW, + std::unique_ptr MCE, + bool RelaxAll); } #endif diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp @@ -15,7 +15,10 @@ #include "RISCVBaseInfo.h" #include "RISCVMCTargetDesc.h" #include "llvm/BinaryFormat/ELF.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/LEB128.h" @@ -167,3 +170,94 @@ } return Result; } + +namespace { +class RISCVELFStreamer : public MCELFStreamer { + static std::pair getRelocPairForSize(unsigned Size) { + switch (Size) { + default: llvm_unreachable("unsupported fixup size"); + case 1: + return std::make_pair(RISCV::fixup_riscv_add_8, RISCV::fixup_riscv_sub_8); + case 2: + return std::make_pair(RISCV::fixup_riscv_add_16, + RISCV::fixup_riscv_sub_16); + case 4: + return std::make_pair(RISCV::fixup_riscv_add_32, + RISCV::fixup_riscv_sub_32); + case 8: + return std::make_pair(RISCV::fixup_riscv_add_64, + RISCV::fixup_riscv_sub_64); + } + } + + static bool UseLinkerRelaxation(const MCExpr *Value, + const MCSymbolRefExpr *&LHS, + const MCSymbolRefExpr *&RHS) { + const auto *MBE = dyn_cast(Value); + if (MBE == nullptr) + return false; + + LHS = dyn_cast(MBE->getLHS()); + RHS = dyn_cast(MBE->getRHS()); + + // Unwrap A ± B ± C + if (RHS == nullptr && isa(MBE->getRHS())) { + if (const auto *E = dyn_cast(MBE->getLHS())) { + LHS = dyn_cast(E->getLHS()); + RHS = dyn_cast(E->getRHS()); + } + } + + if (LHS == nullptr || RHS == nullptr) + return false; + + const auto &S = LHS->getSymbol(); + const auto &T = RHS->getSymbol(); + return (S.isInSection() ? S.getSection().hasInstructions() + : !S.getName().empty()) || + (T.isInSection() ? T.getSection().hasInstructions() + : !T.getName().empty()); + } + +public: + RISCVELFStreamer(MCContext &C, std::unique_ptr MAB, + std::unique_ptr MOW, + std::unique_ptr MCE) + : MCELFStreamer(C, std::move(MAB), std::move(MOW), std::move(MCE)) {} + + void emitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc) override { + const MCSymbolRefExpr *A, *B; + if (!UseLinkerRelaxation(Value, A, B)) + return MCELFStreamer::emitValueImpl(Value, Size, Loc); + + MCStreamer::emitValueImpl(Value, Size, Loc); + + MCDataFragment *DF = getOrCreateDataFragment(); + flushPendingLabels(DF, DF->getContents().size()); + MCDwarfLineEntry::make(this, getCurrentSectionOnly()); + + unsigned add, sub; + std::tie(add, sub) = getRelocPairForSize(Size); + + DF->getFixups().push_back(MCFixup::create( + DF->getContents().size(), A, static_cast(add), Loc)); + DF->getFixups().push_back(MCFixup::create( + DF->getContents().size(), B, static_cast(sub), Loc)); + + DF->getContents().resize(DF->getContents().size() + Size, 0); + } +}; +} + +namespace llvm { +MCELFStreamer *createRISCVELFStreamer(MCContext &C, + std::unique_ptr MAB, + std::unique_ptr MOW, + std::unique_ptr MCE, + bool RelaxAll) { + RISCVELFStreamer *S = + new RISCVELFStreamer(C, std::move(MAB), std::move(MOW), std::move(MCE)); + S->getAssembler().setRelaxAll(RelaxAll); + return S; +} +} diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h @@ -82,6 +82,18 @@ // relaxation. fixup_riscv_align, + fixup_riscv_add_8, + fixup_riscv_sub_8, + + fixup_riscv_add_16, + fixup_riscv_sub_16, + + fixup_riscv_add_32, + fixup_riscv_sub_32, + + fixup_riscv_add_64, + fixup_riscv_sub_64, + // fixup_riscv_invalid - used as a sentinel and a marker, must be last fixup fixup_riscv_invalid, NumTargetFixupKinds = fixup_riscv_invalid - FirstTargetFixupKind diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp @@ -92,14 +92,18 @@ bool RISCVMCExpr::evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout, const MCFixup *Fixup) const { - if (!getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup)) - return false; + bool IsSymbolicDifference = false; + if (const auto *MBE = dyn_cast(getSubExpr())) { + if (isa(MBE->getLHS()) && isa(MBE->getRHS())) + MBE = cast(MBE->getLHS()); + IsSymbolicDifference = isa(MBE->getLHS()) && + isa(MBE->getRHS()); + } // Some custom fixup types are not valid with symbol difference expressions - if (Res.getSymA() && Res.getSymB()) { + if (IsSymbolicDifference) { switch (getKind()) { - default: - return true; + default: break; case VK_RISCV_LO: case VK_RISCV_HI: case VK_RISCV_PCREL_LO: @@ -113,8 +117,7 @@ return false; } } - - return true; + return getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup); } void RISCVMCExpr::visitUsedExpr(MCStreamer &Streamer) const { diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp @@ -18,10 +18,13 @@ #include "RISCVTargetStreamer.h" #include "TargetInfo/RISCVTargetInfo.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCInstrAnalysis.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/ErrorHandling.h" @@ -138,6 +141,17 @@ return new RISCVMCInstrAnalysis(Info); } +namespace { +MCStreamer *createRISCVELFStreamer(const Triple &T, MCContext &Context, + std::unique_ptr &&MAB, + std::unique_ptr &&MOW, + std::unique_ptr &&MCE, + bool RelaxAll) { + return createRISCVELFStreamer(Context, std::move(MAB), std::move(MOW), + std::move(MCE), RelaxAll); +} +} + extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTargetMC() { for (Target *T : {&getTheRISCV32Target(), &getTheRISCV64Target()}) { TargetRegistry::RegisterMCAsmInfo(*T, createRISCVMCAsmInfo); @@ -147,6 +161,7 @@ TargetRegistry::RegisterMCCodeEmitter(*T, createRISCVMCCodeEmitter); TargetRegistry::RegisterMCInstPrinter(*T, createRISCVMCInstPrinter); TargetRegistry::RegisterMCSubtargetInfo(*T, createRISCVMCSubtargetInfo); + TargetRegistry::RegisterELFStreamer(*T, createRISCVELFStreamer); TargetRegistry::RegisterObjectTargetStreamer( *T, createRISCVObjectTargetStreamer); TargetRegistry::RegisterMCInstrAnalysis(*T, createRISCVInstrAnalysis); diff --git a/llvm/test/CodeGen/RISCV/fixups-diff.ll b/llvm/test/CodeGen/RISCV/fixups-diff.ll --- a/llvm/test/CodeGen/RISCV/fixups-diff.ll +++ b/llvm/test/CodeGen/RISCV/fixups-diff.ll @@ -1,10 +1,10 @@ ; RUN: llc -filetype=obj -mtriple=riscv32 -mattr=+relax %s -o - \ -; RUN: | llvm-readobj -r - | FileCheck -check-prefix=RELAX %s +; RUN: | llvm-readobj -r - | FileCheck %s ; RUN: llc -filetype=obj -mtriple=riscv32 -mattr=-relax %s -o - \ -; RUN: | llvm-readobj -r - | FileCheck -check-prefix=NORELAX %s +; RUN: | llvm-readobj -r - | FileCheck %s ; Check that a difference between two symbols in the same fragment -; causes relocations to be emitted if and only if relaxation is enabled. +; causes relocations to be emitted. ; ; This specific test is checking that the size of the function in ; the debug information is represented by a relocation. This isn't @@ -22,11 +22,18 @@ ret i32 0 } -; RELAX: 0x22 R_RISCV_ADD32 - 0x0 -; RELAX: 0x22 R_RISCV_SUB32 - 0x0 -; RELAX: 0x2B R_RISCV_ADD32 - 0x0 -; RELAX: 0x2B R_RISCV_SUB32 - 0x0 -; NORELAX-NOT: R_RISCV_ADD32 +; CHECK: Section {{.*}} .rela.debug_info { +; CHECK: 0x22 R_RISCV_ADD32 - 0x0 +; CHECK: 0x22 R_RISCV_SUB32 - 0x0 +; CHECK: 0x2B R_RISCV_ADD32 - 0x0 +; CHECK: 0x2B R_RISCV_SUB32 - 0x0 +; CHECK: } + +; CHECK: Section {{.*}} .rela.eh_frame { +; CHECK: 0x1C R_RISCV_32_PCREL - 0x0 +; CHECK: 0x20 R_RISCV_ADD32 - 0x0 +; CHECK: 0x20 R_RISCV_SUB32 - 0x0 +; CHECK: } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5} diff --git a/llvm/test/CodeGen/RISCV/fixups-relax-diff.ll b/llvm/test/CodeGen/RISCV/fixups-relax-diff.ll --- a/llvm/test/CodeGen/RISCV/fixups-relax-diff.ll +++ b/llvm/test/CodeGen/RISCV/fixups-relax-diff.ll @@ -1,12 +1,11 @@ ; RUN: llc -filetype=obj -mtriple=riscv32 -mattr=+relax %s -o - \ ; RUN: | llvm-readobj -r - | FileCheck -check-prefix=RELAX %s ; RUN: llc -filetype=obj -mtriple=riscv32 -mattr=-relax %s -o - \ -; RUN: | llvm-readobj -r - | FileCheck -check-prefix=NORELAX %s +; RUN: | llvm-readobj -r - | FileCheck -check-prefix=RELAX %s -; This test checks that a diff inserted via inline assembly only causes -; relocations when relaxation is enabled. This isn't an assembly test -; as the assembler takes a different path through LLVM, which is -; already covered by the fixups-expr.s test. +; This test checks that a diff inserted via inline assembly always causes +; relocations. This isn't an assembly test as the assembler takes a different +; path through LLVM, which is already covered by the fixups-expr.s test. define i32 @main() nounwind { entry: @@ -14,7 +13,6 @@ store i32 0, i32* %retval, align 4 ; RELAX: R_RISCV_ADD64 b ; RELAX: R_RISCV_SUB64 a - ; NORELAX-NOT: R_RISCV_ADD call void asm sideeffect "a:\0Ab:\0A.dword b-a", ""() ret i32 0 } diff --git a/llvm/test/MC/RISCV/fde-reloc.s b/llvm/test/MC/RISCV/fde-reloc.s --- a/llvm/test/MC/RISCV/fde-reloc.s +++ b/llvm/test/MC/RISCV/fde-reloc.s @@ -1,19 +1,18 @@ # RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+relax < %s \ -# RUN: | llvm-readobj -r - | FileCheck -check-prefix=RELAX-RELOC %s +# RUN: | llvm-readobj -r - | FileCheck %s # RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=-relax < %s \ -# RUN: | llvm-readobj -r - | FileCheck -check-prefix=NORELAX-RELOC %s +# RUN: | llvm-readobj -r - | FileCheck %s + +# Ensure that the eh_frame records the symbolic difference with the paired +# relocations always. func: .cfi_startproc ret .cfi_endproc -# RELAX-RELOC: Section (4) .rela.eh_frame { -# RELAX-RELOC-NEXT: 0x1C R_RISCV_32_PCREL - 0x0 -# RELAX-RELOC-NEXT: 0x20 R_RISCV_ADD32 - 0x0 -# RELAX-RELOC-NEXT: 0x20 R_RISCV_SUB32 - 0x0 -# RELAX-RELOC-NEXT: } - -# NORELAX-RELOC: Section (4) .rela.eh_frame { -# NORELAX-RELOC-NEXT: 0x1C R_RISCV_32_PCREL - 0x0 -# NORELAX-RELOC-NEXT: } +# CHECK: Section (4) .rela.eh_frame { +# CHECK-NEXT: 0x1C R_RISCV_32_PCREL - 0x0 +# CHECK-NEXT: 0x20 R_RISCV_ADD32 - 0x0 +# CHECK-NEXT: 0x20 R_RISCV_SUB32 - 0x0 +# CHECK-NEXT: } diff --git a/llvm/test/MC/RISCV/fixups-expr.s b/llvm/test/MC/RISCV/fixups-expr.s --- a/llvm/test/MC/RISCV/fixups-expr.s +++ b/llvm/test/MC/RISCV/fixups-expr.s @@ -1,15 +1,14 @@ # RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax %s \ -# RUN: | llvm-readobj -r - | FileCheck -check-prefix=RELAX %s +# RUN: | llvm-readobj -r - | FileCheck -check-prefix RELAX %s # RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=-relax %s \ -# RUN: | llvm-readobj -r - | FileCheck -check-prefix=NORELAX %s +# RUN: | llvm-readobj -r - | FileCheck -check-prefix RELAX %s # RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax %s \ -# RUN: | llvm-readobj -r - | FileCheck -check-prefix=RELAX %s +# RUN: | llvm-readobj -r - | FileCheck -check-prefix RELAX %s # RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=-relax %s \ -# RUN: | llvm-readobj -r - | FileCheck -check-prefix=NORELAX %s +# RUN: | llvm-readobj -r - | FileCheck -check-prefix RELAX %s -# Check that subtraction expressions are emitted as two relocations -# only when relaxation is enabled +# Check that subtraction expressions are emitted as two relocations always. .globl G1 .globl G2 @@ -44,4 +43,3 @@ # RELAX: 0x1C R_RISCV_SUB8 .L1 0x0 # RELAX: 0x1D R_RISCV_ADD8 G2 0x0 # RELAX: 0x1D R_RISCV_SUB8 G1 0x0 -# NORELAX-NOT: R_RISCV diff --git a/llvm/test/MC/RISCV/hilo-constaddr-expr.s b/llvm/test/MC/RISCV/hilo-constaddr-expr.s --- a/llvm/test/MC/RISCV/hilo-constaddr-expr.s +++ b/llvm/test/MC/RISCV/hilo-constaddr-expr.s @@ -1,9 +1,5 @@ -# RUN: not llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax %s 2>&1 \ -# RUN: | FileCheck %s -check-prefix=CHECK-RELAX -# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=-relax %s 2>&1 \ -# RUN: | llvm-objdump -d - | FileCheck %s --check-prefix=CHECK-INSTR -# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=-relax %s 2>&1 \ -# RUN: | llvm-objdump -r - | FileCheck %s --check-prefix=CHECK-REL +# RUN: not llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax %s 2>&1 | FileCheck %s +# RUN: not llvm-mc -filetype=obj -triple=riscv32 -mattr=-relax %s 2>&1 | FileCheck %s # Check the assembler rejects hi and lo expressions with constant expressions # involving labels when diff expressions are emitted as relocation pairs. @@ -13,19 +9,13 @@ # Emit zeros so that difference between tmp1 and tmp3 is 0x30124 bytes. .fill 0x30124-8 tmp2: -# CHECK-RELAX: :[[@LINE+1]]:{{[0-9]+}}: error: expected relocatable expression +# CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: expected relocatable expression lui t0, %hi(tmp3-tmp1) -# CHECK-RELAX: :[[@LINE+1]]:{{[0-9]+}}: error: expected relocatable expression +# CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: expected relocatable expression lw ra, %lo(tmp3-tmp1)(t0) -# CHECK-INSTR: lui t0, 48 -# CHECK-INSTR: lw ra, 292(t0) tmp3: -# CHECK-RELAX: :[[@LINE+1]]:{{[0-9]+}}: error: expected relocatable expression +# CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: expected relocatable expression lui t1, %hi(tmp2-tmp3) -# CHECK-RELAX: :[[@LINE+1]]:{{[0-9]+}}: error: expected relocatable expression +# CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: expected relocatable expression lw sp, %lo(tmp2-tmp3)(t1) -# CHECK-INSTR: lui t1, 0 -# CHECK-INSTR: lw sp, -8(t1) - -# CHECK-REL-NOT: R_RISCV \ No newline at end of file diff --git a/llvm/test/MC/RISCV/scoped-relaxation.s b/llvm/test/MC/RISCV/scoped-relaxation.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/scoped-relaxation.s @@ -0,0 +1,30 @@ +# RUN: llvm-mc -mattr -relax -triple riscv64-unknown-none-elf -filetype obj %s -o - | llvm-readobj -d -r - | FileCheck %s + +.global function + +# Unrelaxed reference, this would normally fail, but the subsequent scoped +# relaxation forces relaxation on the file. +.dword function - . + +# CHECK: 0x0 R_RISCV_ADD64 function 0x0 +# CHECK: 0x0 R_RISCV_SUB64 - 0x0 + +# Relaxed reference, this will resolve to a pair of `RISCV_ADD64` and +# `RISCV_SUB64` relocation. +.option push +.option relax +.dword function - . +.option pop + +# CHECK: 0x8 R_RISCV_ADD64 function 0x0 +# CHECK: 0x8 R_RISCV_SUB64 - 0x0 + +# Unrelaxed reference, this will resolve to a pair of `RISCV_ADD64` and +# `RISCV_SUB64` relocation due to relaxation being sticky to the file. +.option push +.option norelax +.dword function - . +.option pop + +# CHECK: 0x10 R_RISCV_ADD64 function 0x0 +# CHECK: 0x10 R_RISCV_SUB64 - 0x0