From f56e4f6d3df5fac4e7b9a4c0bfbed34f014119df Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Wed, 26 May 2021 15:41:11 +0000 Subject: [PATCH] RISCV: adjust handling of relocation emission for RISCV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This re-architects the RISCV relocation handling to bring the implementation closer in line with the implementation in binutils. We would previously aggressively resolve the relocation. With this restructuring, we always will emit a paired relocation for any symbolic difference of the type of S±T[±C] where S and T are labels and C is a constant. GAS has a special target hook controlled by `RELOC_EXPANSION_POSSIBLE` which indicates that a fixup may be expanded into multiple relocations. This is used by the RISCV backend to always emit a paired relocation - either ADD[WIDTH] + SUB[WIDTH] for text relocations or SET[WIDTH] + SUB[WIDTH] for a debug info relocation. Irrespective of whether linker relaxation support is enabled, symbolic difference is always emitted as a paired relocation. This change also sinks the target specific behaviour down into the target specific area rather than exposing it to the shared relocation handling. In the process, we also sink the "special" handling for debug information down into the RISCV target. Although this improves the path for the other targets, this is not necessarily entirely ideal either. The changes in the debug info emission could be done through another type of hook as this functionality would be required by any other target which wishes to do linker relaxation. However, as there are no other targets in LLVM which currently do this, this is a reasonable thing to do until such time as the code needs to be shared. Improve the handling of the relocation (and add a reduced test case from the Linux kernel) to ensure that we handle complex expressions for symbolic difference. This ensures that we correct relocate symbols with the adddends normalized and associated with the addition portion of the paired relocation. This change also addresses some review comments from Alex Bradbury about the relocations meant for use in the DWARF CFA being named incorrectly (using ADD6 instead of SET6) in the original change which introduced the relocation type. This resolves the issues with the symbolic difference emission sufficiently to enable building the Linux kernel with clang+IAS+lld (without linker relaxation). Resolves PR50153, PR50156! Fixes: ClangBuiltLinux/linux#1023, ClangBuiltLinux/linux#1143 Reviewed By: nickdesaulniers, maskray Differential Revision: https://reviews.llvm.org/D103539 --- include/llvm/MC/MCAsmBackend.h | 14 +- include/llvm/MC/MCDwarf.h | 10 +- include/llvm/MC/MCFixup.h | 58 ------ lib/MC/MCAsmBackend.cpp | 11 +- lib/MC/MCAssembler.cpp | 73 ++------ lib/MC/MCDwarf.cpp | 94 ++-------- lib/MC/MCExpr.cpp | 25 +-- lib/MC/MCObjectStreamer.cpp | 21 +-- .../RISCV/MCTargetDesc/RISCVAsmBackend.cpp | 166 +++++++++++++++++- .../RISCV/MCTargetDesc/RISCVAsmBackend.h | 19 +- .../MCTargetDesc/RISCVELFObjectWriter.cpp | 62 ++++--- .../RISCV/MCTargetDesc/RISCVELFStreamer.cpp | 93 ++++++++++ .../RISCV/MCTargetDesc/RISCVELFStreamer.h | 6 + .../RISCV/MCTargetDesc/RISCVFixupKinds.h | 36 ++++ lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp | 16 +- .../RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp | 15 ++ test/CodeGen/RISCV/fixups-diff.ll | 23 ++- test/CodeGen/RISCV/fixups-relax-diff.ll | 10 +- test/MC/RISCV/fde-reloc.s | 21 ++- test/MC/RISCV/fixups-expr.s | 12 +- test/MC/RISCV/hilo-constaddr-expr.s | 22 +-- test/MC/RISCV/reloc-addend.s | 11 ++ test/MC/RISCV/scoped-relaxation.s | 34 ++++ 23 files changed, 502 insertions(+), 350 deletions(-) create mode 100644 test/MC/RISCV/reloc-addend.s create mode 100644 test/MC/RISCV/scoped-relaxation.s diff --git a/include/llvm/MC/MCAsmBackend.h b/include/llvm/MC/MCAsmBackend.h index 94ed3d27e78..08739d51f75 100644 --- a/include/llvm/MC/MCAsmBackend.h +++ b/include/llvm/MC/MCAsmBackend.h @@ -129,10 +129,6 @@ public: 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 @@ -169,6 +165,16 @@ public: virtual void relaxInstruction(MCInst &Inst, const MCSubtargetInfo &STI) const {}; + virtual bool relaxDwarfLineAddr(MCDwarfLineAddrFragment &DF, + MCAsmLayout &Layout, bool &WasRelaxed) const { + return false; + } + + virtual bool relaxDwarfCFA(MCDwarfCallFrameFragment &DF, MCAsmLayout &Layout, + bool &WasRelaxed) const { + return false; + } + /// @} /// Returns the minimum size of a nop in bytes on this target. The assembler diff --git a/include/llvm/MC/MCDwarf.h b/include/llvm/MC/MCDwarf.h index fd94d6758f2..23efdc70609 100644 --- a/include/llvm/MC/MCDwarf.h +++ b/include/llvm/MC/MCDwarf.h @@ -387,13 +387,6 @@ public: static void Encode(MCContext &Context, MCDwarfLineTableParams Params, int64_t LineDelta, uint64_t AddrDelta, raw_ostream &OS); - /// Utility function to encode a Dwarf pair of LineDelta and AddrDeltas using - /// fixed length operands. Returns (Offset, Size, SetDelta). - static std::tuple fixedEncode(MCContext &Context, - int64_t LineDelta, - uint64_t AddrDelta, - raw_ostream &OS); - /// Utility function to emit the encoding to a streamer. static void Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params, int64_t LineDelta, uint64_t AddrDelta); @@ -667,8 +660,7 @@ public: static void Emit(MCObjectStreamer &streamer, MCAsmBackend *MAB, bool isEH); static void EmitAdvanceLoc(MCObjectStreamer &Streamer, uint64_t AddrDelta); static void EncodeAdvanceLoc(MCContext &Context, uint64_t AddrDelta, - raw_ostream &OS, uint32_t *Offset = nullptr, - uint32_t *Size = nullptr); + raw_ostream &OS); }; } // end namespace llvm diff --git a/include/llvm/MC/MCFixup.h b/include/llvm/MC/MCFixup.h index b3a23911d63..069ca058310 100644 --- a/include/llvm/MC/MCFixup.h +++ b/include/llvm/MC/MCFixup.h @@ -41,16 +41,6 @@ enum MCFixupKind { 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 @@ public: 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 @@ public: } } - /// 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/lib/MC/MCAsmBackend.cpp b/lib/MC/MCAsmBackend.cpp index 0d32e71c2d8..7989dd57907 100644 --- a/lib/MC/MCAsmBackend.cpp +++ b/lib/MC/MCAsmBackend.cpp @@ -95,16 +95,7 @@ const MCFixupKindInfo &MCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { {"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/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index ce296d7faa4..9ed8d1083a4 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -792,26 +792,7 @@ MCAssembler::handleFixup(const MCAsmLayout &Layout, MCFragment &F, // 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); } @@ -1100,6 +1081,11 @@ bool MCAssembler::relaxBoundaryAlign(MCAsmLayout &Layout, bool MCAssembler::relaxDwarfLineAddr(MCAsmLayout &Layout, MCDwarfLineAddrFragment &DF) { + + bool WasRelaxed; + if (getBackend().relaxDwarfLineAddr(DF, Layout, WasRelaxed)) + return WasRelaxed; + MCContext &Context = Layout.getAssembler().getContext(); uint64_t OldSize = DF.getContents().size(); int64_t AddrDelta; @@ -1113,33 +1099,17 @@ bool MCAssembler::relaxDwarfLineAddr(MCAsmLayout &Layout, 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(); } bool MCAssembler::relaxDwarfCallFrameFragment(MCAsmLayout &Layout, MCDwarfCallFrameFragment &DF) { + bool WasRelaxed; + if (getBackend().relaxDwarfCFA(DF, Layout, WasRelaxed)) + return WasRelaxed; + MCContext &Context = Layout.getAssembler().getContext(); uint64_t OldSize = DF.getContents().size(); int64_t AddrDelta; @@ -1151,20 +1121,7 @@ bool MCAssembler::relaxDwarfCallFrameFragment(MCAsmLayout &Layout, 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 +1151,6 @@ bool MCAssembler::relaxPseudoProbeAddr(MCAsmLayout &Layout, 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/lib/MC/MCDwarf.cpp b/lib/MC/MCDwarf.cpp index 217584edece..27bb7a10316 100644 --- a/lib/MC/MCDwarf.cpp +++ b/lib/MC/MCDwarf.cpp @@ -734,54 +734,6 @@ void MCDwarfLineAddr::Encode(MCContext &Context, MCDwarfLineTableParams Params, } } -std::tuple -MCDwarfLineAddr::fixedEncode(MCContext &Context, int64_t LineDelta, - uint64_t AddrDelta, raw_ostream &OS) { - uint32_t Offset, Size; - if (LineDelta != INT64_MAX) { - OS << char(dwarf::DW_LNS_advance_line); - encodeSLEB128(LineDelta, OS); - } - - // Use address delta to adjust address or use absolute address to adjust - // address. - bool SetDelta; - // According to DWARF spec., the DW_LNS_fixed_advance_pc opcode takes a - // single uhalf (unencoded) operand. So, the maximum value of AddrDelta - // is 65535. We set a conservative upper bound for it for relaxation. - if (AddrDelta > 60000) { - const MCAsmInfo *asmInfo = Context.getAsmInfo(); - unsigned AddrSize = asmInfo->getCodePointerSize(); - - OS << char(dwarf::DW_LNS_extended_op); - encodeULEB128(1 + AddrSize, OS); - OS << char(dwarf::DW_LNE_set_address); - // Generate fixup for the address. - Offset = OS.tell(); - Size = AddrSize; - SetDelta = false; - OS.write_zeros(AddrSize); - } else { - OS << char(dwarf::DW_LNS_fixed_advance_pc); - // Generate fixup for 2-bytes address delta. - Offset = OS.tell(); - Size = 2; - SetDelta = true; - OS << char(0); - OS << char(0); - } - - if (LineDelta == INT64_MAX) { - OS << char(dwarf::DW_LNS_extended_op); - OS << char(1); - OS << char(dwarf::DW_LNE_end_sequence); - } else { - OS << char(dwarf::DW_LNS_copy); - } - - return std::make_tuple(Offset, Size, SetDelta); -} - // Utility function to write a tuple for .debug_abbrev. static void EmitAbbrev(MCStreamer *MCOS, uint64_t Name, uint64_t Form) { MCOS->emitULEB128IntValue(Name); @@ -1940,54 +1892,28 @@ void MCDwarfFrameEmitter::EmitAdvanceLoc(MCObjectStreamer &Streamer, } void MCDwarfFrameEmitter::EncodeAdvanceLoc(MCContext &Context, - uint64_t AddrDelta, raw_ostream &OS, - uint32_t *Offset, uint32_t *Size) { + uint64_t AddrDelta, + raw_ostream &OS) { // Scale the address delta by the minimum instruction length. AddrDelta = ScaleAddrDelta(Context, AddrDelta); - - bool WithFixups = false; - if (Offset && Size) - WithFixups = true; + if (AddrDelta == 0) + return; support::endianness E = Context.getAsmInfo()->isLittleEndian() ? support::little : support::big; - if (AddrDelta == 0) { - if (WithFixups) { - *Offset = 0; - *Size = 0; - } - } else if (isUIntN(6, AddrDelta)) { + + if (isUIntN(6, AddrDelta)) { uint8_t Opcode = dwarf::DW_CFA_advance_loc | AddrDelta; - if (WithFixups) { - *Offset = OS.tell(); - *Size = 6; - OS << uint8_t(dwarf::DW_CFA_advance_loc); - } else - OS << Opcode; + OS << Opcode; } else if (isUInt<8>(AddrDelta)) { OS << uint8_t(dwarf::DW_CFA_advance_loc1); - if (WithFixups) { - *Offset = OS.tell(); - *Size = 8; - OS.write_zeros(1); - } else - OS << uint8_t(AddrDelta); + OS << uint8_t(AddrDelta); } else if (isUInt<16>(AddrDelta)) { OS << uint8_t(dwarf::DW_CFA_advance_loc2); - if (WithFixups) { - *Offset = OS.tell(); - *Size = 16; - OS.write_zeros(2); - } else - support::endian::write(OS, AddrDelta, E); + support::endian::write(OS, AddrDelta, E); } else { assert(isUInt<32>(AddrDelta)); OS << uint8_t(dwarf::DW_CFA_advance_loc4); - if (WithFixups) { - *Offset = OS.tell(); - *Size = 32; - OS.write_zeros(4); - } else - support::endian::write(OS, AddrDelta, E); + support::endian::write(OS, AddrDelta, E); } } diff --git a/lib/MC/MCExpr.cpp b/lib/MC/MCExpr.cpp index 55b20a37f65..84ec0f6bb57 100644 --- a/lib/MC/MCExpr.cpp +++ b/lib/MC/MCExpr.cpp @@ -671,24 +671,6 @@ static void AttemptToFoldSymbolOffsetDifference( } } -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 @@ EvaluateSymbolicAdd(const MCAssembler *Asm, const MCAsmLayout *Layout, 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/lib/MC/MCObjectStreamer.cpp b/lib/MC/MCObjectStreamer.cpp index 299f2a719fb..4dae2f41fc4 100644 --- a/lib/MC/MCObjectStreamer.cpp +++ b/lib/MC/MCObjectStreamer.cpp @@ -127,12 +127,9 @@ void MCObjectStreamer::resolvePendingFixups() { // 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) { +static Optional 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 @@ absoluteSymbolDiff(MCAssembler &Asm, const MCSymbol *Hi, const MCSymbol *Lo) { 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/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp index 69f6ee46029..70b02b428b1 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ b/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -9,6 +9,7 @@ #include "RISCVAsmBackend.h" #include "RISCVMCExpr.h" #include "llvm/ADT/APInt.h" +#include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" @@ -18,7 +19,10 @@ #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCValue.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/EndianStream.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/LEB128.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -70,7 +74,26 @@ RISCVAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { {"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_set_8", 0, 8, 0}, + {"fixup_riscv_add_8", 0, 8, 0}, + {"fixup_riscv_sub_8", 0, 8, 0}, + + {"fixup_riscv_set_16", 0, 16, 0}, + {"fixup_riscv_add_16", 0, 16, 0}, + {"fixup_riscv_sub_16", 0, 16, 0}, + + {"fixup_riscv_set_32", 0, 32, 0}, + {"fixup_riscv_add_32", 0, 32, 0}, + {"fixup_riscv_sub_32", 0, 32, 0}, + + {"fixup_riscv_add_64", 0, 64, 0}, + {"fixup_riscv_sub_64", 0, 64, 0}, + + {"fixup_riscv_set_6b", 2, 6, 0}, + {"fixup_riscv_sub_6b", 2, 6, 0}, + }; static_assert((array_lengthof(Infos)) == RISCV::NumTargetFixupKinds, "Not all fixup kinds added to Infos array"); @@ -179,6 +202,134 @@ void RISCVAsmBackend::relaxInstruction(MCInst &Inst, Inst = std::move(Res); } +bool RISCVAsmBackend::relaxDwarfLineAddr(MCDwarfLineAddrFragment &DF, + MCAsmLayout &Layout, + bool &WasRelaxed) const { + MCContext &C = Layout.getAssembler().getContext(); + + int64_t LineDelta = DF.getLineDelta(); + const MCExpr &AddrDelta = DF.getAddrDelta(); + SmallVectorImpl &Data = DF.getContents(); + SmallVectorImpl &Fixups = DF.getFixups(); + size_t OldSize = Data.size(); + + int64_t Value; + bool IsAbsolute = AddrDelta.evaluateKnownAbsolute(Value, Layout); + assert(IsAbsolute && "CFA with invalid expression"); + (void)IsAbsolute; + + Data.clear(); + Fixups.clear(); + raw_svector_ostream OS(Data); + + // INT64_MAX is a signal that this is actually a DW_LNE_end_sequence. + if (LineDelta != INT64_MAX) { + OS << uint8_t(dwarf::DW_LNS_advance_line); + encodeSLEB128(LineDelta, OS); + } + + unsigned Offset; + std::pair Fixup; + + // According to the DWARF specification, the `DW_LNS_fixed_advance_pc` opcode + // takes a single unsigned half (unencoded) operand. The maximum encodable + // value is therefore 65535. Set a conservative upper bound for relaxation. + if (Value > 60000) { + unsigned PtrSize = C.getAsmInfo()->getCodePointerSize(); + + OS << uint8_t(dwarf::DW_LNS_extended_op); + encodeULEB128(PtrSize + 1, OS); + + OS << uint8_t(dwarf::DW_LNE_set_address); + Offset = OS.tell(); + Fixup = PtrSize == 4 ? std::make_pair(RISCV::fixup_riscv_add_32, + RISCV::fixup_riscv_sub_32) + : std::make_pair(RISCV::fixup_riscv_add_64, + RISCV::fixup_riscv_sub_64); + OS.write_zeros(PtrSize); + } else { + OS << uint8_t(dwarf::DW_LNS_fixed_advance_pc); + Offset = OS.tell(); + Fixup = {RISCV::fixup_riscv_add_16, RISCV::fixup_riscv_sub_16}; + support::endian::write(OS, 0, support::little); + } + + const MCBinaryExpr &MBE = cast(AddrDelta); + Fixups.push_back(MCFixup::create( + Offset, MBE.getLHS(), static_cast(std::get<0>(Fixup)))); + Fixups.push_back(MCFixup::create( + Offset, MBE.getRHS(), static_cast(std::get<1>(Fixup)))); + + if (LineDelta == INT64_MAX) { + OS << uint8_t(dwarf::DW_LNS_extended_op); + OS << uint8_t(1); + OS << uint8_t(dwarf::DW_LNE_end_sequence); + } else { + OS << uint8_t(dwarf::DW_LNS_copy); + } + + WasRelaxed = OldSize != Data.size(); + return true; +} + +bool RISCVAsmBackend::relaxDwarfCFA(MCDwarfCallFrameFragment &DF, + MCAsmLayout &Layout, + bool &WasRelaxed) const { + MCContext &C = Layout.getAssembler().getContext(); + + const MCExpr &AddrDelta = DF.getAddrDelta(); + SmallVectorImpl &Data = DF.getContents(); + SmallVectorImpl &Fixups = DF.getFixups(); + size_t OldSize = Data.size(); + + int64_t Value; + bool IsAbsolute = AddrDelta.evaluateKnownAbsolute(Value, Layout); + assert(IsAbsolute && "CFA with invalid expression"); + (void)IsAbsolute; + + Data.clear(); + Fixups.clear(); + raw_svector_ostream OS(Data); + + assert(C.getAsmInfo()->getMinInstAlignment() == 1 && + "expected 1-byte alignment"); + if (Value == 0) { + WasRelaxed = OldSize != Data.size(); + return true; + } + + auto AddFixups = [&Fixups, &AddrDelta](unsigned Offset, + std::pair Fixup) { + const MCBinaryExpr &MBE = cast(AddrDelta); + Fixups.push_back(MCFixup::create( + Offset, MBE.getLHS(), static_cast(std::get<0>(Fixup)))); + Fixups.push_back(MCFixup::create( + Offset, MBE.getRHS(), static_cast(std::get<1>(Fixup)))); + }; + + if (isUIntN(6, Value)) { + OS << uint8_t(dwarf::DW_CFA_advance_loc); + AddFixups(0, {RISCV::fixup_riscv_set_6b, RISCV::fixup_riscv_sub_6b}); + } else if (isUInt<8>(Value)) { + OS << uint8_t(dwarf::DW_CFA_advance_loc1); + support::endian::write(OS, 0, support::little); + AddFixups(1, {RISCV::fixup_riscv_set_8, RISCV::fixup_riscv_sub_8}); + } else if (isUInt<16>(Value)) { + OS << uint8_t(dwarf::DW_CFA_advance_loc2); + support::endian::write(OS, 0, support::little); + AddFixups(1, {RISCV::fixup_riscv_set_16, RISCV::fixup_riscv_sub_16}); + } else if (isUInt<32>(Value)) { + OS << uint8_t(dwarf::DW_CFA_advance_loc4); + support::endian::write(OS, 0, support::little); + AddFixups(1, {RISCV::fixup_riscv_set_32, RISCV::fixup_riscv_sub_32}); + } else { + llvm_unreachable("unsupported CFA encoding"); + } + + WasRelaxed = OldSize != Data.size(); + return true; +} + // Given a compressed control flow instruction this function returns // the expanded instruction. unsigned RISCVAsmBackend::getRelaxedOpcode(unsigned Op) const { @@ -227,12 +378,25 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, 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_set_8: + case RISCV::fixup_riscv_add_8: + case RISCV::fixup_riscv_sub_8: + case RISCV::fixup_riscv_set_16: + case RISCV::fixup_riscv_add_16: + case RISCV::fixup_riscv_sub_16: + case RISCV::fixup_riscv_set_32: + 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: case FK_Data_8: case FK_Data_6b: return Value; + case RISCV::fixup_riscv_set_6b: + return Value & 0x03; case RISCV::fixup_riscv_lo12_i: case RISCV::fixup_riscv_pcrel_lo12_i: case RISCV::fixup_riscv_tprel_lo12_i: diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h b/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h index 56991ccf010..e1628673419 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h +++ b/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h @@ -42,20 +42,6 @@ public: 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; @@ -108,6 +94,11 @@ public: void relaxInstruction(MCInst &Inst, const MCSubtargetInfo &STI) const override; + bool relaxDwarfLineAddr(MCDwarfLineAddrFragment &DF, MCAsmLayout &Layout, + bool &WasRelaxed) const override; + bool relaxDwarfCFA(MCDwarfCallFrameFragment &DF, MCAsmLayout &Layout, + bool &WasRelaxed) const override; + bool writeNopData(raw_ostream &OS, uint64_t Count) const override; const MCTargetOptions &getTargetOptions() const { return TargetOptions; } diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp b/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp index b38ba2bff58..fb1ce19d73b 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp +++ b/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp @@ -86,6 +86,22 @@ unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx, 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 +122,6 @@ unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx, 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 +140,32 @@ unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx, return ELF::R_RISCV_RELAX; case RISCV::fixup_riscv_align: return ELF::R_RISCV_ALIGN; + case RISCV::fixup_riscv_set_6b: + return ELF::R_RISCV_SET6; + case RISCV::fixup_riscv_sub_6b: + return ELF::R_RISCV_SUB6; + case RISCV::fixup_riscv_add_8: + return ELF::R_RISCV_ADD8; + case RISCV::fixup_riscv_set_8: + return ELF::R_RISCV_SET8; + case RISCV::fixup_riscv_sub_8: + return ELF::R_RISCV_SUB8; + case RISCV::fixup_riscv_set_16: + return ELF::R_RISCV_SET16; + 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_set_32: + return ELF::R_RISCV_SET32; + 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/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp b/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp index 7df454be872..d88ba9e4ac7 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp +++ b/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp @@ -15,9 +15,13 @@ #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/MC/MCValue.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/RISCVAttributes.h" @@ -167,3 +171,92 @@ size_t RISCVTargetELFStreamer::calculateContentSize() const { } 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 requiresFixups(MCContext &C, const MCExpr *Value, + const MCExpr *&LHS, const MCExpr *&RHS) { + const auto *MBE = dyn_cast(Value); + if (MBE == nullptr) + return false; + + MCValue E; + if (!Value->evaluateAsRelocatable(E, nullptr, nullptr)) + return false; + if (E.getSymA() == nullptr || E.getSymB() == nullptr) + return false; + + const auto &A = E.getSymA()->getSymbol(); + const auto &B = E.getSymB()->getSymbol(); + + LHS = + MCBinaryExpr::create(MCBinaryExpr::Add, MCSymbolRefExpr::create(&A, C), + MCConstantExpr::create(E.getConstant(), C), C); + RHS = E.getSymB(); + + return (A.isInSection() ? A.getSection().hasInstructions() + : !A.getName().empty()) || + (B.isInSection() ? B.getSection().hasInstructions() + : !B.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 MCExpr *A, *B; + if (!requiresFixups(getContext(), 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 + +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; +} +} // namespace llvm diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h b/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h index 392c87054d4..59d8bb009d1 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h +++ b/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h @@ -104,5 +104,11 @@ public: 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/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h b/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h index faa88716043..7953b6036f3 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h +++ b/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h @@ -68,6 +68,42 @@ enum Fixups { // Used to generate an R_RISCV_ALIGN relocation, which indicates the linker // should fixup the alignment after linker relaxation. fixup_riscv_align, + // 8-bit fixup corresponding to R_RISCV_SET8 for local label assignment. + fixup_riscv_set_8, + // 8-bit fixup corresponding to R_RISCV_ADD8 for 8-bit symbolic difference + // paired relocations. + fixup_riscv_add_8, + // 8-bit fixup corresponding to R_RISCV_SUB8 for 8-bit symbolic difference + // paired relocations. + fixup_riscv_sub_8, + // 16-bit fixup corresponding to R_RISCV_SET16 for local label assignment. + fixup_riscv_set_16, + // 16-bit fixup corresponding to R_RISCV_ADD16 for 16-bit symbolic difference + // paired reloctions. + fixup_riscv_add_16, + // 16-bit fixup corresponding to R_RISCV_SUB16 for 16-bit symbolic difference + // paired reloctions. + fixup_riscv_sub_16, + // 32-bit fixup corresponding to R_RISCV_SET32 for local label assignment. + fixup_riscv_set_32, + // 32-bit fixup corresponding to R_RISCV_ADD32 for 32-bit symbolic difference + // paired relocations. + fixup_riscv_add_32, + // 32-bit fixup corresponding to R_RISCV_SUB32 for 32-bit symbolic difference + // paired relocations. + fixup_riscv_sub_32, + // 64-bit fixup corresponding to R_RISCV_ADD64 for 64-bit symbolic difference + // paired relocations. + fixup_riscv_add_64, + // 64-bit fixup corresponding to R_RISCV_SUB64 for 64-bit symbolic difference + // paired relocations. + fixup_riscv_sub_64, + // 6-bit fixup corresponding to R_RISCV_SET6 for local label assignment in + // DWARF CFA. + fixup_riscv_set_6b, + // 6-bit fixup corresponding to R_RISCV_SUB6 for local label assignment in + // DWARF CFA. + fixup_riscv_sub_6b, // Used as a sentinel, must be the last fixup_riscv_invalid, diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp b/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp index 120c6d95bfc..7bbf9be7fd9 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp +++ b/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp @@ -92,14 +92,19 @@ const MCFixup *RISCVMCExpr::getPCRelHiFixup(const MCFragment **DFOut) const { 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; + break; case VK_RISCV_LO: case VK_RISCV_HI: case VK_RISCV_PCREL_LO: @@ -113,8 +118,7 @@ bool RISCVMCExpr::evaluateAsRelocatableImpl(MCValue &Res, return false; } } - - return true; + return getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup); } void RISCVMCExpr::visitUsedExpr(MCStreamer &Streamer) const { diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp b/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp index 084b750790d..38c32539833 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp +++ b/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp @@ -18,9 +18,12 @@ #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/MCObjectWriter.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" @@ -138,6 +141,17 @@ static MCInstrAnalysis *createRISCVInstrAnalysis(const MCInstrInfo *Info) { 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); +} +} // end anonymous namespace + extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTargetMC() { for (Target *T : {&getTheRISCV32Target(), &getTheRISCV64Target()}) { TargetRegistry::RegisterMCAsmInfo(*T, createRISCVMCAsmInfo); @@ -147,6 +161,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTargetMC() { 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/test/CodeGen/RISCV/fixups-diff.ll b/test/CodeGen/RISCV/fixups-diff.ll index 8b2273ddaa3..22b2dca2bee 100644 --- a/test/CodeGen/RISCV/fixups-diff.ll +++ b/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 @@ entry: 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-NEXT: 0x22 R_RISCV_SUB32 - 0x0 +; CHECK: 0x2B R_RISCV_ADD32 - 0x0 +; CHECK-NEXT: 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-NEXT: 0x20 R_RISCV_SUB32 - 0x0 +; CHECK: } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5} diff --git a/test/CodeGen/RISCV/fixups-relax-diff.ll b/test/CodeGen/RISCV/fixups-relax-diff.ll index 2ac335b74d6..cf431d95ae4 100644 --- a/test/CodeGen/RISCV/fixups-relax-diff.ll +++ b/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 @@ entry: 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/test/MC/RISCV/fde-reloc.s b/test/MC/RISCV/fde-reloc.s index 98793f1552d..d7c3f5c2bb7 100644 --- a/test/MC/RISCV/fde-reloc.s +++ b/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/test/MC/RISCV/fixups-expr.s b/test/MC/RISCV/fixups-expr.s index 3d025fdd343..10db3a3c563 100644 --- a/test/MC/RISCV/fixups-expr.s +++ b/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 @@ G2: # 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/test/MC/RISCV/hilo-constaddr-expr.s b/test/MC/RISCV/hilo-constaddr-expr.s index 6731ddd2b89..af47985cde7 100644 --- a/test/MC/RISCV/hilo-constaddr-expr.s +++ b/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 @@ tmp1: # 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]]:[[#]]: error: expected relocatable expression lui t0, %hi(tmp3-tmp1) -# CHECK-RELAX: :[[@LINE+1]]:{{[0-9]+}}: error: expected relocatable expression +# CHECK: :[[#@LINE+1]]:[[#]]: 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]]:[[#]]: error: expected relocatable expression lui t1, %hi(tmp2-tmp3) -# CHECK-RELAX: :[[@LINE+1]]:{{[0-9]+}}: error: expected relocatable expression +# CHECK: :[[#@LINE+1]]:[[#]]: 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/test/MC/RISCV/reloc-addend.s b/test/MC/RISCV/reloc-addend.s new file mode 100644 index 00000000000..96e7c51e83b --- /dev/null +++ b/test/MC/RISCV/reloc-addend.s @@ -0,0 +1,11 @@ +# RUN: llvm-mc -triple riscv64 -filetype obj -o - %s | llvm-readobj -r - | FileCheck %s + + .section __jump_table,"aw",@progbits + .p2align 3 +.Ltmp0: + .quad (function+128)-.Ltmp0 + +# CHECK: .rela__jump_table { +# CHECK: 0x0 R_RISCV_ADD64 function 0x80 +# CHECK-NEXT: 0x0 R_RISCV_SUB64 .Ltmp0 0x0 +# CHECK: } diff --git a/test/MC/RISCV/scoped-relaxation.s b/test/MC/RISCV/scoped-relaxation.s new file mode 100644 index 00000000000..6cb82536fcd --- /dev/null +++ b/test/MC/RISCV/scoped-relaxation.s @@ -0,0 +1,34 @@ +# RUN: llvm-mc -mattr -relax -triple riscv64 -filetype obj %s -o - | llvm-readobj -d -r - | FileCheck %s + +.global function + +# CHECK: .rela.text { + +# 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-NEXT: 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-NEXT: 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-NEXT: 0x10 R_RISCV_SUB64 - 0x0 + +# CHECK: }