[llvm] bbea642 - RISCV: adjust handling of relocation emission for RISCV

Saleem Abdulrasool via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 17 08:53:23 PDT 2021


Author: Saleem Abdulrasool
Date: 2021-06-17T08:20:02-07:00
New Revision: bbea64250f65480d787e1c5ff45c4de3ec2dcda8

URL: https://github.com/llvm/llvm-project/commit/bbea64250f65480d787e1c5ff45c4de3ec2dcda8
DIFF: https://github.com/llvm/llvm-project/commit/bbea64250f65480d787e1c5ff45c4de3ec2dcda8.diff

LOG: RISCV: adjust handling of relocation emission for RISCV

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

Added: 
    llvm/test/MC/RISCV/reloc-addend.s
    llvm/test/MC/RISCV/scoped-relaxation.s

Modified: 
    llvm/include/llvm/MC/MCAsmBackend.h
    llvm/include/llvm/MC/MCDwarf.h
    llvm/include/llvm/MC/MCFixup.h
    llvm/lib/MC/MCAsmBackend.cpp
    llvm/lib/MC/MCAssembler.cpp
    llvm/lib/MC/MCDwarf.cpp
    llvm/lib/MC/MCExpr.cpp
    llvm/lib/MC/MCObjectStreamer.cpp
    llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
    llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h
    llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
    llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
    llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h
    llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
    llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
    llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
    llvm/test/CodeGen/RISCV/fixups-diff.ll
    llvm/test/CodeGen/RISCV/fixups-relax-diff.ll
    llvm/test/MC/RISCV/fde-reloc.s
    llvm/test/MC/RISCV/fixups-expr.s
    llvm/test/MC/RISCV/hilo-constaddr-expr.s

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/MC/MCAsmBackend.h b/llvm/include/llvm/MC/MCAsmBackend.h
index 94ed3d27e7859..08739d51f751e 100644
--- a/llvm/include/llvm/MC/MCAsmBackend.h
+++ b/llvm/include/llvm/MC/MCAsmBackend.h
@@ -129,10 +129,6 @@ class MCAsmBackend {
                           uint64_t Value, bool IsResolved,
                           const MCSubtargetInfo *STI) const = 0;
 
-  /// Check whether the given target requires emitting 
diff erences of two
-  /// symbols as a set of relocations.
-  virtual bool requiresDiffExpressionRelocations() const { return false; }
-
   /// @}
 
   /// \name Target Relaxation Interfaces
@@ -169,6 +165,16 @@ class MCAsmBackend {
   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
index fd94d6758f22d..23efdc70609b6 100644
--- a/llvm/include/llvm/MC/MCDwarf.h
+++ b/llvm/include/llvm/MC/MCDwarf.h
@@ -387,13 +387,6 @@ class MCDwarfLineAddr {
   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<uint32_t, uint32_t, bool> 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 @@ class MCDwarfFrameEmitter {
   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
index b3a23911d636e..069ca058310fc 100644
--- a/llvm/include/llvm/MC/MCFixup.h
+++ b/llvm/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 @@ class MCFixup {
     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 @@ class MCFixup {
     }
   }
 
-  /// 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
index 0d32e71c2d8f3..7989dd57907ca 100644
--- a/llvm/lib/MC/MCAsmBackend.cpp
+++ b/llvm/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/llvm/lib/MC/MCAssembler.cpp b/llvm/lib/MC/MCAssembler.cpp
index ce296d7faa458..9ed8d1083a403 100644
--- a/llvm/lib/MC/MCAssembler.cpp
+++ b/llvm/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 
diff erence 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<MCBinaryExpr>(&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/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp
index 217584edecec6..27bb7a1031652 100644
--- a/llvm/lib/MC/MCDwarf.cpp
+++ b/llvm/lib/MC/MCDwarf.cpp
@@ -734,54 +734,6 @@ void MCDwarfLineAddr::Encode(MCContext &Context, MCDwarfLineTableParams Params,
   }
 }
 
-std::tuple<uint32_t, uint32_t, bool>
-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<uint16_t>(OS, AddrDelta, E);
+    support::endian::write<uint16_t>(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<uint32_t>(OS, AddrDelta, E);
+    support::endian::write<uint32_t>(OS, AddrDelta, E);
   }
 }

diff  --git a/llvm/lib/MC/MCExpr.cpp b/llvm/lib/MC/MCExpr.cpp
index 55b20a37f6520..84ec0f6bb57ba 100644
--- a/llvm/lib/MC/MCExpr.cpp
+++ b/llvm/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 
diff erences. 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 
diff erence 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 
diff erences.
+  if (Asm) {
     // First, fold out any 
diff erences 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
index 299f2a719fb96..4dae2f41fc454 100644
--- a/llvm/lib/MC/MCObjectStreamer.cpp
+++ b/llvm/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<uint64_t>
-absoluteSymbolDiff(MCAssembler &Asm, const MCSymbol *Hi, const MCSymbol *Lo) {
+static Optional<uint64_t> 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<uint64_t> Diff = absoluteSymbolDiff(getAssembler(), Hi, Lo)) {
-    emitIntValue(*Diff, Size);
-    return;
-  }
+  if (!getAssembler().getContext().getTargetTriple().isRISCV())
+    if (Optional<uint64_t> Diff = absoluteSymbolDiff(Hi, Lo))
+      return emitIntValue(*Diff, Size);
   MCStreamer::emitAbsoluteSymbolDiff(Hi, Lo, Size);
 }
 
 void MCObjectStreamer::emitAbsoluteSymbolDiffAsULEB128(const MCSymbol *Hi,
                                                        const MCSymbol *Lo) {
-  if (Optional<uint64_t> Diff = absoluteSymbolDiff(getAssembler(), Hi, Lo)) {
-    emitULEB128IntValue(*Diff);
-    return;
-  }
+  if (!getAssembler().getContext().getTargetTriple().isRISCV())
+    if (Optional<uint64_t> Diff = absoluteSymbolDiff(Hi, Lo))
+      return emitULEB128IntValue(*Diff);
   MCStreamer::emitAbsoluteSymbolDiffAsULEB128(Hi, Lo);
 }
 

diff  --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
index 69f6ee4602983..70b02b428b13c 100644
--- 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 @@ 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<char> &Data = DF.getContents();
+  SmallVectorImpl<MCFixup> &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<unsigned, unsigned> 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<uint16_t>(OS, 0, support::little);
+  }
+
+  const MCBinaryExpr &MBE = cast<MCBinaryExpr>(AddrDelta);
+  Fixups.push_back(MCFixup::create(
+      Offset, MBE.getLHS(), static_cast<MCFixupKind>(std::get<0>(Fixup))));
+  Fixups.push_back(MCFixup::create(
+      Offset, MBE.getRHS(), static_cast<MCFixupKind>(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<char> &Data = DF.getContents();
+  SmallVectorImpl<MCFixup> &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<unsigned, unsigned> Fixup) {
+    const MCBinaryExpr &MBE = cast<MCBinaryExpr>(AddrDelta);
+    Fixups.push_back(MCFixup::create(
+        Offset, MBE.getLHS(), static_cast<MCFixupKind>(std::get<0>(Fixup))));
+    Fixups.push_back(MCFixup::create(
+        Offset, MBE.getRHS(), static_cast<MCFixupKind>(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<uint8_t>(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<uint16_t>(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<uint32_t>(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/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h
index 56991ccf010a1..e1628673419a8 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h
@@ -42,20 +42,6 @@ class RISCVAsmBackend : public MCAsmBackend {
 
   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 @@ class RISCVAsmBackend : public MCAsmBackend {
   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/RISCVELFObjectWriter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
index b38ba2bff582c..fb1ce19d73bc3 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
+++ b/llvm/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/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
index 7df454be87292..d88ba9e4ac726 100644
--- 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 @@ size_t RISCVTargetELFStreamer::calculateContentSize() const {
   }
   return Result;
 }
+
+namespace {
+class RISCVELFStreamer : public MCELFStreamer {
+  static std::pair<unsigned, unsigned> 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<MCBinaryExpr>(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<MCAsmBackend> MAB,
+                   std::unique_ptr<MCObjectWriter> MOW,
+                   std::unique_ptr<MCCodeEmitter> 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<MCFixupKind>(Add), Loc));
+    DF->getFixups().push_back(MCFixup::create(
+        DF->getContents().size(), B, static_cast<MCFixupKind>(Sub), Loc));
+
+    DF->getContents().resize(DF->getContents().size() + Size, 0);
+  }
+};
+} // namespace
+
+namespace llvm {
+MCELFStreamer *createRISCVELFStreamer(MCContext &C,
+                                      std::unique_ptr<MCAsmBackend> MAB,
+                                      std::unique_ptr<MCObjectWriter> MOW,
+                                      std::unique_ptr<MCCodeEmitter> 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/RISCVELFStreamer.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h
index 392c87054d431..59d8bb009d1ce 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h
@@ -104,5 +104,11 @@ class RISCVTargetELFStreamer : public RISCVTargetStreamer {
   void emitDirectiveOptionRelax() override;
   void emitDirectiveOptionNoRelax() override;
 };
+
+MCELFStreamer *createRISCVELFStreamer(MCContext &C,
+                                      std::unique_ptr<MCAsmBackend> MAB,
+                                      std::unique_ptr<MCObjectWriter> MOW,
+                                      std::unique_ptr<MCCodeEmitter> MCE,
+                                      bool RelaxAll);
 }
 #endif

diff  --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
index faa8871604353..7953b6036f3bf 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
+++ b/llvm/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 
diff erence
+  // paired relocations.
+  fixup_riscv_add_8,
+  // 8-bit fixup corresponding to R_RISCV_SUB8 for 8-bit symbolic 
diff erence
+  // 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 
diff erence
+  // paired reloctions.
+  fixup_riscv_add_16,
+  // 16-bit fixup corresponding to R_RISCV_SUB16 for 16-bit symbolic 
diff erence
+  // 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 
diff erence
+  // paired relocations.
+  fixup_riscv_add_32,
+  // 32-bit fixup corresponding to R_RISCV_SUB32 for 32-bit symbolic 
diff erence
+  // paired relocations.
+  fixup_riscv_sub_32,
+  // 64-bit fixup corresponding to R_RISCV_ADD64 for 64-bit symbolic 
diff erence
+  // paired relocations.
+  fixup_riscv_add_64,
+  // 64-bit fixup corresponding to R_RISCV_SUB64 for 64-bit symbolic 
diff erence
+  // 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
index 120c6d95bfc06..7bbf9be7fd9e6 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
+++ b/llvm/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<MCBinaryExpr>(getSubExpr())) {
+    if (isa<MCBinaryExpr>(MBE->getLHS()) && isa<MCConstantExpr>(MBE->getRHS()))
+      MBE = cast<MCBinaryExpr>(MBE->getLHS());
+    IsSymbolicDifference = isa<MCSymbolRefExpr>(MBE->getLHS()) &&
+                           isa<MCSymbolRefExpr>(MBE->getRHS());
+  }
 
   // Some custom fixup types are not valid with symbol 
diff erence 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/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
index 084b750790d0d..38c32539833c1 100644
--- 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 @@ static MCInstrAnalysis *createRISCVInstrAnalysis(const MCInstrInfo *Info) {
   return new RISCVMCInstrAnalysis(Info);
 }
 
+namespace {
+MCStreamer *createRISCVELFStreamer(const Triple &T, MCContext &Context,
+                                   std::unique_ptr<MCAsmBackend> &&MAB,
+                                   std::unique_ptr<MCObjectWriter> &&MOW,
+                                   std::unique_ptr<MCCodeEmitter> &&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/llvm/test/CodeGen/RISCV/fixups-
diff .ll b/llvm/test/CodeGen/RISCV/fixups-
diff .ll
index 8b2273ddaa388..22b2dca2bee77 100644
--- 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 
diff erence 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/llvm/test/CodeGen/RISCV/fixups-relax-
diff .ll b/llvm/test/CodeGen/RISCV/fixups-relax-
diff .ll
index 2ac335b74d65c..cf431d95ae459 100644
--- 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 
diff erent 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 
diff erent
+; 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/llvm/test/MC/RISCV/fde-reloc.s b/llvm/test/MC/RISCV/fde-reloc.s
index 98793f1552da2..d7c3f5c2bb72e 100644
--- 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 
diff erence 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
index 3d025fdd34362..10db3a3c563b9 100644
--- 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 @@ 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/llvm/test/MC/RISCV/hilo-constaddr-expr.s b/llvm/test/MC/RISCV/hilo-constaddr-expr.s
index 6731ddd2b895a..af47985cde7c1 100644
--- 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 @@ tmp1:
   # Emit zeros so that 
diff erence 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
index 0000000000000..96e7c51e83b28
--- /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", at 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
index 0000000000000..6cb82536fcda8
--- /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: }


        


More information about the llvm-commits mailing list