[llvm] r205084 - MachO: Add linker-optimisation hint framework to MC.

Tim Northover tnorthover at apple.com
Sat Mar 29 00:35:00 PDT 2014


Author: tnorthover
Date: Sat Mar 29 02:34:53 2014
New Revision: 205084

URL: http://llvm.org/viewvc/llvm-project?rev=205084&view=rev
Log:
MachO: Add linker-optimisation hint framework to MC.

Another part of the ARM64 backend (so tests will be following soon).
This is currently used by the linker to relax adrp/ldr pairs into nops
where possible, though could well be more broadly applicable.

Added:
    llvm/trunk/include/llvm/MC/MCLinkerOptimizationHint.h
    llvm/trunk/lib/MC/MCLinkerOptimizationHint.cpp
Modified:
    llvm/trunk/include/llvm/MC/MCAssembler.h
    llvm/trunk/include/llvm/MC/MCStreamer.h
    llvm/trunk/include/llvm/Support/MachO.h
    llvm/trunk/lib/MC/CMakeLists.txt
    llvm/trunk/lib/MC/MCAsmStreamer.cpp
    llvm/trunk/lib/MC/MCAssembler.cpp
    llvm/trunk/lib/MC/MCMachOStreamer.cpp
    llvm/trunk/lib/MC/MachObjectWriter.cpp

Modified: llvm/trunk/include/llvm/MC/MCAssembler.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCAssembler.h?rev=205084&r1=205083&r2=205084&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MC/MCAssembler.h (original)
+++ llvm/trunk/include/llvm/MC/MCAssembler.h Sat Mar 29 02:34:53 2014
@@ -18,6 +18,7 @@
 #include "llvm/MC/MCDirectives.h"
 #include "llvm/MC/MCFixup.h"
 #include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCLinkerOptimizationHint.h"
 #include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/DataTypes.h"
@@ -932,6 +933,10 @@ private:
   // which flags to be set.
   unsigned ELFHeaderEFlags;
 
+  /// Used to communicate Linker Optimization Hint information between
+  /// the Streamer and the .o writer
+  MCLOHContainer LOHContainer;
+
   VersionMinInfoType VersionMinInfo;
 private:
   /// Evaluate a fixup to a relocatable expression and the value which should be
@@ -1175,6 +1180,19 @@ public:
   size_t data_region_size() const { return DataRegions.size(); }
 
   /// @}
+  /// @name Data Region List Access
+  /// @{
+
+  // FIXME: This is a total hack, this should not be here. Once things are
+  // factored so that the streamer has direct access to the .o writer, it can
+  // disappear.
+  MCLOHContainer & getLOHContainer() {
+    return LOHContainer;
+  }
+  const MCLOHContainer & getLOHContainer() const {
+    return const_cast<MCAssembler *>(this)->getLOHContainer();
+  }
+  /// @}
   /// @name Backend Data Access
   /// @{
 

Added: llvm/trunk/include/llvm/MC/MCLinkerOptimizationHint.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCLinkerOptimizationHint.h?rev=205084&view=auto
==============================================================================
--- llvm/trunk/include/llvm/MC/MCLinkerOptimizationHint.h (added)
+++ llvm/trunk/include/llvm/MC/MCLinkerOptimizationHint.h Sat Mar 29 02:34:53 2014
@@ -0,0 +1,214 @@
+//===- MCLinkerOptimizationHint.h - LOH interface ---------------*- C++ -*-===//
+//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares some helpers classes to handle Linker Optimization Hint
+// (LOH).
+//
+// FIXME: LOH interface supports only MachO format at the moment.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_MC_MCLINKEROPTIMIZATIONHINT_H
+#define LLVM_MC_MCLINKEROPTIMIZATIONHINT_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/MC/MCMachObjectWriter.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+
+// Forward declarations.
+class MCAsmLayout;
+class MCSymbol;
+
+/// Linker Optimization Hint Type.
+enum MCLOHType {
+  MCLOH_AdrpAdrp = 0x1u,      ///< Adrp xY, _v1 at PAGE -> Adrp xY, _v2 at PAGE.
+  MCLOH_AdrpLdr = 0x2u,       ///< Adrp _v at PAGE -> Ldr _v at PAGEOFF.
+  MCLOH_AdrpAddLdr = 0x3u,    ///< Adrp _v at PAGE -> Add _v at PAGEOFF -> Ldr.
+  MCLOH_AdrpLdrGotLdr = 0x4u, ///< Adrp _v at GOTPAGE -> Ldr _v at GOTPAGEOFF -> Ldr.
+  MCLOH_AdrpAddStr = 0x5u,    ///< Adrp _v at PAGE -> Add _v at PAGEOFF -> Str.
+  MCLOH_AdrpLdrGotStr = 0x6u, ///< Adrp _v at GOTPAGE -> Ldr _v at GOTPAGEOFF -> Str.
+  MCLOH_AdrpAdd = 0x7u,       ///< Adrp _v at PAGE -> Add _v at PAGEOFF.
+  MCLOH_AdrpLdrGot = 0x8u     ///< Adrp _v at GOTPAGE -> Ldr _v at GOTPAGEOFF.
+};
+
+static inline StringRef MCLOHDirectiveName() {
+  return StringRef(".loh");
+}
+
+static inline bool isValidMCLOHType(MCLOHType Kind) {
+  return Kind >= MCLOH_AdrpAdrp && Kind <= MCLOH_AdrpLdrGot;
+}
+
+static inline int MCLOHNameToId(StringRef Name) {
+#define MCLOHCaseNameToId(Name)     .Case(#Name, MCLOH_ ## Name)
+  return StringSwitch<int>(Name)
+    MCLOHCaseNameToId(AdrpAdrp)
+    MCLOHCaseNameToId(AdrpLdr)
+    MCLOHCaseNameToId(AdrpAddLdr)
+    MCLOHCaseNameToId(AdrpLdrGotLdr)
+    MCLOHCaseNameToId(AdrpAddStr)
+    MCLOHCaseNameToId(AdrpLdrGotStr)
+    MCLOHCaseNameToId(AdrpAdd)
+    MCLOHCaseNameToId(AdrpLdrGot)
+    .Default(-1);
+}
+
+static inline StringRef MCLOHIdToName(MCLOHType Kind) {
+#define MCLOHCaseIdToName(Name)      case MCLOH_ ## Name: return StringRef(#Name);
+  switch (Kind) {
+    MCLOHCaseIdToName(AdrpAdrp);
+    MCLOHCaseIdToName(AdrpLdr);
+    MCLOHCaseIdToName(AdrpAddLdr);
+    MCLOHCaseIdToName(AdrpLdrGotLdr);
+    MCLOHCaseIdToName(AdrpAddStr);
+    MCLOHCaseIdToName(AdrpLdrGotStr);
+    MCLOHCaseIdToName(AdrpAdd);
+    MCLOHCaseIdToName(AdrpLdrGot);
+  }
+  return StringRef();
+}
+
+static inline int MCLOHIdToNbArgs(MCLOHType Kind) {
+  switch (Kind) {
+    // LOH with two arguments
+  case MCLOH_AdrpAdrp:
+  case MCLOH_AdrpLdr:
+  case MCLOH_AdrpAdd:
+  case MCLOH_AdrpLdrGot:
+    return 2;
+    // LOH with three arguments
+  case MCLOH_AdrpAddLdr:
+  case MCLOH_AdrpLdrGotLdr:
+  case MCLOH_AdrpAddStr:
+  case MCLOH_AdrpLdrGotStr:
+    return 3;
+  }
+  return -1;
+}
+
+/// Store Linker Optimization Hint information (LOH).
+template<typename T>
+class LOHDirective {
+private:
+  MCLOHType Kind;
+
+  /// Arguments of this directive. Order matters.
+  SmallVector<T *, 3> Args;
+
+  /// Emit this directive in @p OutStream using the information available
+  /// in the given @p ObjWriter and @p Layout to get the address of the
+  /// arguments within the object file.
+  /// This function is currently specialized for T = MCSymbol.
+  void Emit_impl(raw_ostream &OutStream, const MachObjectWriter &ObjWriter,
+                 const MCAsmLayout &Layout) const {  }
+
+public:
+  typedef SmallVectorImpl<T *> LOHArgs;
+
+  LOHDirective(MCLOHType Kind, const LOHArgs &Args)
+  : Kind(Kind), Args(Args.begin(), Args.end()) {};
+
+  MCLOHType getKind() const { return Kind; }
+
+  const LOHArgs & getArgs() const { return Args; }
+
+  /// Emit this directive as:
+  /// <kind, numArgs, addr1, ..., addrN>
+  void Emit(MachObjectWriter &ObjWriter, const MCAsmLayout &Layout) const {
+    raw_ostream &OutStream = ObjWriter.getStream();
+    Emit_impl(OutStream, ObjWriter, Layout);
+  }
+
+  /// Get the size in bytes of this directive if emitted in @p ObjWriter with
+  /// the given @p Layout.
+  uint64_t getEmitSize(const MachObjectWriter &ObjWriter,
+                       const MCAsmLayout &Layout) const {
+    std::string Buffer;
+    raw_string_ostream OutStream(Buffer);
+    Emit_impl(OutStream, ObjWriter, Layout);
+    return OutStream.tell();
+  }
+};
+
+template<typename T>
+class LOHContainer {
+public:
+  typedef SmallVectorImpl<LOHDirective<T> > LOHDirectives;
+
+private:
+  /// Keep track of the emit size of all the LOHs.
+  mutable uint64_t EmitSize;
+
+  /// Keep track of all LOH directives.
+  SmallVector<LOHDirective<T>, 32> Directives;
+
+  /// Accessor to the directives.
+  LOHDirectives &getDirectives() { return Directives; }
+
+public:
+  LOHContainer() : EmitSize(0) {};
+
+  /// Const accessor to the directives.
+  const LOHDirectives &getDirectives() const {
+    return const_cast<LOHContainer *>(this)->getDirectives();
+  }
+
+  /// Add the directive of the given kind @p Kind with the given arguments
+  /// @p Args to the container.
+  void addDirective(MCLOHType Kind,
+                    const typename LOHDirective<T>::LOHArgs &Args) {
+    assert(isValidMCLOHType(Kind) && "Invalid LOH directive type!");
+    getDirectives().push_back(LOHDirective<T>(Kind, Args));
+  }
+
+  /// Get the size of the directives if emitted.
+  uint64_t getEmitSize(const MachObjectWriter &ObjWriter,
+                       const MCAsmLayout &Layout) const {
+    if (!EmitSize) {
+      for (typename LOHDirectives::const_iterator It = getDirectives().begin(),
+             EndIt = getDirectives().end(); It != EndIt; ++It)
+        EmitSize += It->getEmitSize(ObjWriter, Layout);
+    }
+    return EmitSize;
+  }
+
+  /// Emit all Linker Optimization Hint in one big table.
+  /// Each line of the table is emitted by LOHDirective::Emit.
+  void Emit(MachObjectWriter &ObjWriter, const MCAsmLayout &Layout) const {
+    for (typename LOHDirectives::const_iterator It = getDirectives().begin(),
+           EndIt = getDirectives().end(); It != EndIt; ++It)
+      It->Emit(ObjWriter, Layout);
+  }
+
+  void reset() {
+    getDirectives().clear();
+    EmitSize = 0;
+  }
+};
+
+// Add types for specialized template using MCSymbol.
+typedef LOHDirective<MCSymbol> MCLOHDirective;
+typedef LOHDirective<MCSymbol>::LOHArgs MCLOHArgs;
+
+typedef LOHContainer<MCLOHDirective>::LOHDirectives MCLOHDirectives;
+
+typedef LOHContainer<MCSymbol> MCLOHContainer;
+
+// Declare the specialization for MCSymbol.
+template<>
+void MCLOHDirective::Emit_impl(raw_ostream &OutStream,
+                               const MachObjectWriter &ObjWriter,
+                               const MCAsmLayout &Layout) const;
+} // end namespace llvm
+
+#endif

Modified: llvm/trunk/include/llvm/MC/MCStreamer.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCStreamer.h?rev=205084&r1=205083&r2=205084&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MC/MCStreamer.h (original)
+++ llvm/trunk/include/llvm/MC/MCStreamer.h Sat Mar 29 02:34:53 2014
@@ -19,6 +19,7 @@
 #include "llvm/MC/MCAssembler.h"
 #include "llvm/MC/MCDirectives.h"
 #include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCLinkerOptimizationHint.h"
 #include "llvm/MC/MCWin64EH.h"
 #include "llvm/Support/DataTypes.h"
 #include <string>
@@ -466,6 +467,10 @@ public:
   ///
   virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) = 0;
 
+  /// \brief Emit a Linker Optimization Hint (LOH) directive.
+  /// \param Args - Arguments of the LOH.
+  virtual void EmitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) {}
+
   /// EmitCommonSymbol - Emit a common symbol.
   ///
   /// @param Symbol - The common symbol to emit.

Modified: llvm/trunk/include/llvm/Support/MachO.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/MachO.h?rev=205084&r1=205083&r2=205084&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/MachO.h (original)
+++ llvm/trunk/include/llvm/Support/MachO.h Sat Mar 29 02:34:53 2014
@@ -128,7 +128,8 @@ namespace llvm {
       LC_SOURCE_VERSION       = 0x0000002Au,
       LC_DYLIB_CODE_SIGN_DRS  = 0x0000002Bu,
       //                        0x0000002Cu,
-      LC_LINKER_OPTIONS       = 0x0000002Du
+      LC_LINKER_OPTIONS       = 0x0000002Du,
+      LC_LINKER_OPTIMIZATION_HINT = 0x0000002Eu
     };
 
     enum : uint32_t {

Modified: llvm/trunk/lib/MC/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/CMakeLists.txt?rev=205084&r1=205083&r2=205084&view=diff
==============================================================================
--- llvm/trunk/lib/MC/CMakeLists.txt (original)
+++ llvm/trunk/lib/MC/CMakeLists.txt Sat Mar 29 02:34:53 2014
@@ -24,6 +24,7 @@ add_llvm_library(LLVMMC
   MCInstPrinter.cpp
   MCInstrAnalysis.cpp
   MCLabel.cpp
+  MCLinkerOptimizationHint.cpp
   MCMachOStreamer.cpp
   MCMachObjectTargetWriter.cpp
   MCModule.cpp

Modified: llvm/trunk/lib/MC/MCAsmStreamer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCAsmStreamer.cpp?rev=205084&r1=205083&r2=205084&view=diff
==============================================================================
--- llvm/trunk/lib/MC/MCAsmStreamer.cpp (original)
+++ llvm/trunk/lib/MC/MCAsmStreamer.cpp Sat Mar 29 02:34:53 2014
@@ -126,6 +126,7 @@ public:
   void ChangeSection(const MCSection *Section,
                      const MCExpr *Subsection) override;
 
+  void EmitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) override;
   void EmitLabel(MCSymbol *Symbol) override;
   void EmitDebugLabel(MCSymbol *Symbol) override;
 
@@ -342,6 +343,27 @@ void MCAsmStreamer::EmitLabel(MCSymbol *
   EmitEOL();
 }
 
+void MCAsmStreamer::EmitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) {
+  StringRef str = MCLOHIdToName(Kind);
+
+#ifndef NDEBUG
+  int NbArgs = MCLOHIdToNbArgs(Kind);
+  assert(NbArgs != -1 && ((size_t)NbArgs) == Args.size() && "Malformed LOH!");
+  assert(str != "" && "Invalid LOH name");
+#endif
+
+  OS << "\t" << MCLOHDirectiveName() << " " << str << "\t";
+  bool IsFirst = true;
+  for (MCLOHArgs::const_iterator It = Args.begin(), EndIt = Args.end();
+       It != EndIt; ++It) {
+    if (!IsFirst)
+      OS << ", ";
+    IsFirst = false;
+    OS << **It;
+  }
+  EmitEOL();
+}
+
 void MCAsmStreamer::EmitDebugLabel(MCSymbol *Symbol) {
   assert(Symbol->isUndefined() && "Cannot define a symbol twice!");
   MCStreamer::EmitDebugLabel(Symbol);

Modified: llvm/trunk/lib/MC/MCAssembler.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCAssembler.cpp?rev=205084&r1=205083&r2=205084&view=diff
==============================================================================
--- llvm/trunk/lib/MC/MCAssembler.cpp (original)
+++ llvm/trunk/lib/MC/MCAssembler.cpp Sat Mar 29 02:34:53 2014
@@ -355,6 +355,7 @@ void MCAssembler::reset() {
   getBackend().reset();
   getEmitter().reset();
   getWriter().reset();
+  getLOHContainer().reset();
 }
 
 bool MCAssembler::isSymbolLinkerVisible(const MCSymbol &Symbol) const {

Added: llvm/trunk/lib/MC/MCLinkerOptimizationHint.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCLinkerOptimizationHint.cpp?rev=205084&view=auto
==============================================================================
--- llvm/trunk/lib/MC/MCLinkerOptimizationHint.cpp (added)
+++ llvm/trunk/lib/MC/MCLinkerOptimizationHint.cpp Sat Mar 29 02:34:53 2014
@@ -0,0 +1,30 @@
+//===-- llvm/MC/MCLinkerOptimizationHint.cpp ----- LOH handling -*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCLinkerOptimizationHint.h"
+#include "llvm/MC/MCAsmLayout.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/MC/MCStreamer.h"
+
+using namespace llvm;
+
+namespace llvm {
+template<>
+void MCLOHDirective::Emit_impl(raw_ostream &OutStream,
+                               const MachObjectWriter &ObjWriter,
+                               const MCAsmLayout &Layout) const {
+  const MCAssembler &Asm = Layout.getAssembler();
+  encodeULEB128(Kind, OutStream);
+  encodeULEB128(Args.size(), OutStream);
+  for (LOHArgs::const_iterator It = Args.begin(), EndIt = Args.end();
+       It != EndIt; ++It)
+    encodeULEB128(ObjWriter.getSymbolAddress(&Asm.getSymbolData(**It), Layout),
+                  OutStream);
+}
+} // end namespace llvm

Modified: llvm/trunk/lib/MC/MCMachOStreamer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCMachOStreamer.cpp?rev=205084&r1=205083&r2=205084&view=diff
==============================================================================
--- llvm/trunk/lib/MC/MCMachOStreamer.cpp (original)
+++ llvm/trunk/lib/MC/MCMachOStreamer.cpp Sat Mar 29 02:34:53 2014
@@ -17,6 +17,7 @@
 #include "llvm/MC/MCDwarf.h"
 #include "llvm/MC/MCExpr.h"
 #include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCLinkerOptimizationHint.h"
 #include "llvm/MC/MCMachOSymbolFlags.h"
 #include "llvm/MC/MCObjectFileInfo.h"
 #include "llvm/MC/MCObjectStreamer.h"
@@ -104,6 +105,10 @@ public:
     llvm_unreachable("macho doesn't support this directive");
   }
 
+  void EmitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) override {
+    getAssembler().getLOHContainer().addDirective(Kind, Args);
+  }
+
   void FinishImpl() override;
 };
 

Modified: llvm/trunk/lib/MC/MachObjectWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MachObjectWriter.cpp?rev=205084&r1=205083&r2=205084&view=diff
==============================================================================
--- llvm/trunk/lib/MC/MachObjectWriter.cpp (original)
+++ llvm/trunk/lib/MC/MachObjectWriter.cpp Sat Mar 29 02:34:53 2014
@@ -761,6 +761,14 @@ void MachObjectWriter::WriteObject(MCAss
     LoadCommandsSize += sizeof(MachO::linkedit_data_command);
   }
 
+  // Add the loh load command size, if used.
+  uint64_t LOHRawSize = Asm.getLOHContainer().getEmitSize(*this, Layout);
+  uint64_t LOHSize = RoundUpToAlignment(LOHRawSize, is64Bit() ? 8 : 4);
+  if (LOHSize) {
+    ++NumLoadCommands;
+    LoadCommandsSize += sizeof(MachO::linkedit_data_command);
+  }
+
   // Add the symbol table load command sizes, if used.
   unsigned NumSymbols = LocalSymbolData.size() + ExternalSymbolData.size() +
     UndefinedSymbolData.size();
@@ -849,6 +857,12 @@ void MachObjectWriter::WriteObject(MCAss
                              DataRegionsSize);
   }
 
+  // Write the loh load command, if used.
+  uint64_t LOHTableEnd = DataInCodeTableEnd + LOHSize;
+  if (LOHSize)
+    WriteLinkeditLoadCommand(MachO::LC_LINKER_OPTIMIZATION_HINT,
+                             DataInCodeTableEnd, LOHSize);
+
   // Write the symbol table load command, if used.
   if (NumSymbols) {
     unsigned FirstLocalSymbol = 0;
@@ -865,10 +879,10 @@ void MachObjectWriter::WriteObject(MCAss
 
     // If used, the indirect symbols are written after the section data.
     if (NumIndirectSymbols)
-      IndirectSymbolOffset = DataInCodeTableEnd;
+      IndirectSymbolOffset = LOHTableEnd;
 
     // The symbol table is written after the indirect symbol data.
-    uint64_t SymbolTableOffset = DataInCodeTableEnd + IndirectSymbolSize;
+    uint64_t SymbolTableOffset = LOHTableEnd + IndirectSymbolSize;
 
     // The string table is written after symbol table.
     uint64_t StringTableOffset =
@@ -935,6 +949,17 @@ void MachObjectWriter::WriteObject(MCAss
     Write16(Data->Kind);
   }
 
+  // Write out the loh commands, if there is one.
+  if (LOHSize) {
+#ifndef NDEBUG
+    unsigned Start = OS.tell();
+#endif
+    Asm.getLOHContainer().Emit(*this, Layout);
+    // Pad to a multiple of the pointer size.
+    WriteBytes("", OffsetToAlignment(LOHRawSize, is64Bit() ? 8 : 4));
+    assert(OS.tell() - Start == LOHSize);
+  }
+
   // Write the symbol table data, if used.
   if (NumSymbols) {
     // Write the indirect symbol entries.





More information about the llvm-commits mailing list