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 @@ -169,6 +165,16 @@ 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/llvm/include/llvm/MC/MCDwarf.h b/llvm/include/llvm/MC/MCDwarf.h --- a/llvm/include/llvm/MC/MCDwarf.h +++ b/llvm/include/llvm/MC/MCDwarf.h @@ -387,13 +387,6 @@ 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 @@ 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/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); } @@ -1100,6 +1081,11 @@ 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 @@ 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 @@ 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 @@ 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/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp --- a/llvm/lib/MC/MCDwarf.cpp +++ b/llvm/lib/MC/MCDwarf.cpp @@ -734,54 +734,6 @@ } } -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::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/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 @@ -127,12 +127,9 @@ // 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 @@ 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; @@ -108,6 +94,11 @@ 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/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 @@ -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 @@ {"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 @@ 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 @@ 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/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 @@ -86,6 +86,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 +122,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 +140,32 @@ 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/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,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 @@ } 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/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 @@ -68,6 +68,42 @@ // 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/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,19 @@ 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 @@ 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,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 @@ 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 @@ 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-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/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]]:[[#]]: 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/llvm/test/MC/RISCV/reloc-addend.s b/llvm/test/MC/RISCV/reloc-addend.s new file mode 100644 --- /dev/null +++ b/llvm/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/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,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: }