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/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp --- a/llvm/lib/MC/ELFObjectWriter.cpp +++ b/llvm/lib/MC/ELFObjectWriter.cpp @@ -1516,6 +1516,11 @@ SymA.getType() == ELF::STT_GNU_IFUNC) return false; } + // RISC-V requires the relocation to be split up to handle the ADD_SUB split + // relocation. These are required to ensure that symbolic differences are + // emitted as paired ADD/SUB relocations. + if (!InSet && TargetObjectWriter->getEMachine() == ELF::EM_RISCV) + return !Asm.getRelaxAll(); return MCObjectWriter::isSymbolRefDifferenceFullyResolvedImpl(Asm, SymA, FB, InSet, IsPCRel); } 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,7 +140,7 @@ void MCObjectStreamer::emitAbsoluteSymbolDiff(const MCSymbol *Hi, const MCSymbol *Lo, unsigned Size) { - if (Optional Diff = absoluteSymbolDiff(getAssembler(), Hi, Lo)) { + if (Optional Diff = absoluteSymbolDiff(Hi, Lo)) { emitIntValue(*Diff, Size); return; } @@ -152,7 +149,7 @@ void MCObjectStreamer::emitAbsoluteSymbolDiffAsULEB128(const MCSymbol *Hi, const MCSymbol *Lo) { - if (Optional Diff = absoluteSymbolDiff(getAssembler(), Hi, Lo)) { + if (Optional Diff = absoluteSymbolDiff(Hi, Lo)) { emitULEB128IntValue(*Diff); return; } 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: @@ -388,8 +409,10 @@ MCFixupKind Kind = Fixup.getKind(); if (Kind >= FirstLiteralRelocationKind) return; + MCContext &Ctx = Asm.getContext(); MCFixupKindInfo Info = getFixupKindInfo(Kind); + if (!Value) return; // Doesn't change encoding. // Apply any target-specific value adjustments. 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 { @@ -50,18 +52,27 @@ const MCFixup &Fixup, bool IsPCRel) const { const MCExpr *Expr = Fixup.getValue(); + // Determine the type of the relocation unsigned Kind = Fixup.getTargetKind(); if (Kind >= FirstLiteralRelocationKind) return Kind - FirstLiteralRelocationKind; + if (IsPCRel) { switch (Kind) { default: Ctx.reportError(Fixup.getLoc(), "Unsupported relocation type"); return ELF::R_RISCV_NONE; + case FK_Data_8: + Ctx.reportError(Fixup.getLoc(), "Unsupported relocation type"); + return ELF::R_RISCV_NONE; case FK_Data_4: case FK_PCRel_4: return ELF::R_RISCV_32_PCREL; + case FK_Data_2: + break; + case FK_Data_1: + break; case RISCV::fixup_riscv_pcrel_hi20: return ELF::R_RISCV_PCREL_HI20; case RISCV::fixup_riscv_pcrel_lo12_i: @@ -86,6 +97,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 +133,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 +151,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" @@ -58,6 +61,7 @@ } MCA.setELFHeaderEFlags(EFlags); + MCA.setRelaxAll(STI.getFeatureBits()[RISCV::FeatureRelax]); } MCELFStreamer &RISCVTargetELFStreamer::getStreamer() { @@ -71,11 +75,11 @@ void RISCVTargetELFStreamer::emitDirectiveOptionRVC() {} void RISCVTargetELFStreamer::emitDirectiveOptionNoRVC() {} void RISCVTargetELFStreamer::emitDirectiveOptionRelax() { - MCAssembler &MCA = getStreamer().getAssembler(); - auto &MAB = static_cast(MCA.getBackend()); - MAB.setForceRelocs(); + getStreamer().getAssembler().setRelaxAll(true); +} +void RISCVTargetELFStreamer::emitDirectiveOptionNoRelax() { + getStreamer().getAssembler().setRelaxAll(false); } -void RISCVTargetELFStreamer::emitDirectiveOptionNoRelax() {} void RISCVTargetELFStreamer::emitAttribute(unsigned Attribute, unsigned Value) { setAttributeItem(Attribute, Value, /*OverwriteExisting=*/true); @@ -171,3 +175,92 @@ } return Result; } + +namespace { +class RISCVELFStreamer : public MCELFStreamer { +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 auto *MBE = dyn_cast(Value); + if (!MBE) + return MCELFStreamer::emitValueImpl(Value, Size, Loc); + + // Handle binary expressions manually so that we can create multiple fixups + // for the riscv_add_sub_n relocations. + + MCStreamer::emitValueImpl(Value, Size, Loc); + + MCDataFragment *DF = getOrCreateDataFragment(); + flushPendingLabels(DF, DF->getContents().size()); + MCDwarfLineEntry::make(this, getCurrentSectionOnly()); + + int64_t Absolute; + const auto *Asm = getAssemblerPtr(); + if ((Asm ? Asm->getRelaxAll() : true) && + Value->evaluateAsAbsolute(Absolute, Asm)) { + if (!isUIntN(8 * Size, Absolute) && !isIntN(8 * Size, Absolute)) + return getContext().reportError( + Loc, "value evaluated as " + Twine(Absolute) + " is out of range"); + return emitIntValue(Absolute, Size); + } + + // Create a pair of fixups; if we find that relaxation is not enabled, we + // can drop the fixup during the finalization phase. + unsigned add; + unsigned sub; + switch (Size) { + default: + llvm_unreachable("unsupported fixup size"); + case 1: + add = RISCV::fixup_riscv_add_8; + sub = RISCV::fixup_riscv_sub_8; + break; + case 2: + add = RISCV::fixup_riscv_add_16; + sub = RISCV::fixup_riscv_sub_16; + break; + case 4: + add = RISCV::fixup_riscv_add_32; + sub = RISCV::fixup_riscv_sub_32; + break; + case 8: + add = RISCV::fixup_riscv_add_64; + sub = RISCV::fixup_riscv_sub_64; + break; + } + + const auto *LHSSymRef = dyn_cast(MBE->getLHS()); + const auto *RHSSymRef = dyn_cast(MBE->getRHS()); + if (LHSSymRef || RHSSymRef) { + DF->getFixups().push_back( + MCFixup::create(DF->getContents().size(), MBE->getLHS(), + static_cast(add), Loc)); + DF->getFixups().push_back( + MCFixup::create(DF->getContents().size(), MBE->getRHS(), + static_cast(sub), Loc)); + } else { + DF->getFixups().push_back( + MCFixup::create(DF->getContents().size(), Value, + MCFixup::getKindForSize(Size, false), 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/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-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/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/rv64-relax-all.s b/llvm/test/MC/RISCV/rv64-relax-all.s --- a/llvm/test/MC/RISCV/rv64-relax-all.s +++ b/llvm/test/MC/RISCV/rv64-relax-all.s @@ -1,9 +1,11 @@ # RUN: llvm-mc -filetype=obj -triple riscv64 -mattr=+c %s | llvm-objdump -d -M no-aliases --no-show-raw-insn - | FileCheck %s --check-prefix=INSTR -# RUN: llvm-mc -filetype=obj -triple riscv64 -mattr=+c %s --mc-relax-all | llvm-objdump -d -M no-aliases --no-show-raw-insn - | FileCheck %s --check-prefix=RELAX-INSTR +# RUN: llvm-mc -filetype=obj -triple riscv64 -mattr=+c %s --mc-relax-all | llvm-objdump -d -M no-aliases --no-show-raw-insn - | FileCheck %s --check-prefix=INSTR ## Check the instructions are relaxed correctly +# NOTE: did not match gas' behaviour, matches now. + NEAR: # INSTR: c.beqz a0, 0x0