[llvm] r323655 - [dsymutil] Generate Apple accelerator tables

Jonas Devlieghere via llvm-commits llvm-commits at lists.llvm.org
Mon Jan 29 06:52:50 PST 2018


Author: jdevlieghere
Date: Mon Jan 29 06:52:50 2018
New Revision: 323655

URL: http://llvm.org/viewvc/llvm-project?rev=323655&view=rev
Log:
[dsymutil] Generate Apple accelerator tables

This patch adds support for generating accelerator tables in dsymutil.
This feature was already present in our internal repository but not yet
upstreamed because it requires changes to the Apple accelerator table
implementation.

Differential revision: https://reviews.llvm.org/D42501

Added:
    llvm/trunk/test/tools/dsymutil/Inputs/objc.macho.x86_64   (with props)
    llvm/trunk/test/tools/dsymutil/Inputs/objc.macho.x86_64.o
    llvm/trunk/test/tools/dsymutil/X86/objc.test
Modified:
    llvm/trunk/include/llvm/CodeGen/AccelTable.h
    llvm/trunk/lib/CodeGen/AsmPrinter/AccelTable.cpp
    llvm/trunk/test/tools/dsymutil/X86/basic-lto-linking-x86.test
    llvm/trunk/tools/dsymutil/DwarfLinker.cpp
    llvm/trunk/tools/dsymutil/dsymutil.h

Modified: llvm/trunk/include/llvm/CodeGen/AccelTable.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/AccelTable.h?rev=323655&r1=323654&r2=323655&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/AccelTable.h (original)
+++ llvm/trunk/include/llvm/CodeGen/AccelTable.h Mon Jan 29 06:52:50 2018
@@ -406,6 +406,68 @@ public:
 #endif
 };
 
+/// Accelerator table data implementation for simple accelerator tables with
+/// a DIE offset but no actual DIE pointer.
+class AppleAccelTableStaticOffsetData : public AppleAccelTableData {
+public:
+  AppleAccelTableStaticOffsetData(uint32_t Offset) : Offset(Offset) {}
+
+  void emit(AsmPrinter *Asm) const override;
+
+  static constexpr AppleAccelTableHeader::Atom Atoms[] = {
+      AppleAccelTableHeader::Atom(dwarf::DW_ATOM_die_offset,
+                                  dwarf::DW_FORM_data4)};
+
+#ifndef NDEBUG
+  void print(raw_ostream &OS) const override {
+    OS << "  Static Offset: " << Offset << "\n";
+  }
+
+#endif
+protected:
+  uint64_t order() const override { return Offset; }
+
+  uint32_t Offset;
+};
+
+/// Accelerator table data implementation for type accelerator tables with
+/// a DIE offset but no actual DIE pointer.
+class AppleAccelTableStaticTypeData : public AppleAccelTableStaticOffsetData {
+public:
+  AppleAccelTableStaticTypeData(uint32_t Offset, uint16_t Tag,
+                                bool ObjCClassIsImplementation,
+                                uint32_t QualifiedNameHash)
+      : AppleAccelTableStaticOffsetData(Offset),
+        QualifiedNameHash(QualifiedNameHash), Tag(Tag),
+        ObjCClassIsImplementation(ObjCClassIsImplementation) {}
+
+  void emit(AsmPrinter *Asm) const override;
+
+  static constexpr AppleAccelTableHeader::Atom Atoms[] = {
+      AppleAccelTableHeader::Atom(dwarf::DW_ATOM_die_offset,
+                                  dwarf::DW_FORM_data4),
+      AppleAccelTableHeader::Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2),
+      AppleAccelTableHeader::Atom(5, dwarf::DW_FORM_data1),
+      AppleAccelTableHeader::Atom(6, dwarf::DW_FORM_data4)};
+
+#ifndef NDEBUG
+  void print(raw_ostream &OS) const override {
+    OS << "  Static Offset: " << Offset << "\n";
+    OS << "  QualifiedNameHash: " << format("%x\n", QualifiedNameHash) << "\n";
+    OS << "  Tag: " << dwarf::TagString(Tag) << "\n";
+    OS << "  ObjCClassIsImplementation: "
+       << (ObjCClassIsImplementation ? "true" : "false");
+    OS << "\n";
+  }
+#endif
+protected:
+  uint64_t order() const override { return Offset; }
+
+  uint32_t QualifiedNameHash;
+  uint16_t Tag;
+  bool ObjCClassIsImplementation;
+};
+
 } // end namespace llvm
 
 #endif // LLVM_LIB_CODEGEN_ASMPRINTER_DWARFACCELTABLE_H

Modified: llvm/trunk/lib/CodeGen/AsmPrinter/AccelTable.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/AccelTable.cpp?rev=323655&r1=323654&r2=323655&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/AccelTable.cpp (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/AccelTable.cpp Mon Jan 29 06:52:50 2018
@@ -72,6 +72,8 @@ void AppleAccelTableHeader::setBucketAnd
 
 constexpr AppleAccelTableHeader::Atom AppleAccelTableTypeData::Atoms[];
 constexpr AppleAccelTableHeader::Atom AppleAccelTableOffsetData::Atoms[];
+constexpr AppleAccelTableHeader::Atom AppleAccelTableStaticOffsetData::Atoms[];
+constexpr AppleAccelTableHeader::Atom AppleAccelTableStaticTypeData::Atoms[];
 
 void AppleAccelTableBase::emitHeader(AsmPrinter *Asm) { Header.emit(Asm); }
 
@@ -219,3 +221,15 @@ void AppleAccelTableTypeData::emit(AsmPr
   Asm->EmitInt16(Die->getTag());
   Asm->EmitInt8(0);
 }
+
+void AppleAccelTableStaticOffsetData::emit(AsmPrinter *Asm) const {
+  Asm->EmitInt32(Offset);
+}
+
+void AppleAccelTableStaticTypeData::emit(AsmPrinter *Asm) const {
+  Asm->EmitInt32(Offset);
+  Asm->EmitInt16(Tag);
+  Asm->EmitInt8(ObjCClassIsImplementation ? dwarf::DW_FLAG_type_implementation
+                                          : 0);
+  Asm->EmitInt32(QualifiedNameHash);
+}

Added: llvm/trunk/test/tools/dsymutil/Inputs/objc.macho.x86_64
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/objc.macho.x86_64?rev=323655&view=auto
==============================================================================
Binary files llvm/trunk/test/tools/dsymutil/Inputs/objc.macho.x86_64 (added) and llvm/trunk/test/tools/dsymutil/Inputs/objc.macho.x86_64 Mon Jan 29 06:52:50 2018 differ

Propchange: llvm/trunk/test/tools/dsymutil/Inputs/objc.macho.x86_64
------------------------------------------------------------------------------
    svn:executable = *

Added: llvm/trunk/test/tools/dsymutil/Inputs/objc.macho.x86_64.o
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/objc.macho.x86_64.o?rev=323655&view=auto
==============================================================================
Binary files llvm/trunk/test/tools/dsymutil/Inputs/objc.macho.x86_64.o (added) and llvm/trunk/test/tools/dsymutil/Inputs/objc.macho.x86_64.o Mon Jan 29 06:52:50 2018 differ

Modified: llvm/trunk/test/tools/dsymutil/X86/basic-lto-linking-x86.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/X86/basic-lto-linking-x86.test?rev=323655&r1=323654&r2=323655&view=diff
==============================================================================
--- llvm/trunk/test/tools/dsymutil/X86/basic-lto-linking-x86.test (original)
+++ llvm/trunk/test/tools/dsymutil/X86/basic-lto-linking-x86.test Mon Jan 29 06:52:50 2018
@@ -78,7 +78,7 @@ CHECK:        DW_AT_name ("arg")
 CHECK:        DW_AT_type (0x0000000000000063
 CHECK:        DW_AT_location (0x00000000
 CHECK:          [0x0000000000000000, 0x000000000000000e): DW_OP_reg5 RDI, DW_OP_piece 0x4)
-CHECK:      DW_TAG_inlined_subroutine
+CHECK:[[INC1:0x[0-9a-f]*]]{{.*}}DW_TAG_inlined_subroutine
 CHECK:        DW_AT_abstract_origin (cu + 0x00a7 "inc")
 CHECK:        DW_AT_low_pc (0x0000000100000f63)
 CHECK:        DW_AT_high_pc (0x0000000100000f72)
@@ -120,7 +120,7 @@ CHECK:          [0x0000000000000019, 0x0
 CHECK:      DW_TAG_lexical_block
 CHECK:        DW_AT_low_pc (0x0000000100000f94)
 CHECK:        DW_AT_high_pc (0x0000000100000fa7)
-CHECK:        DW_TAG_inlined_subroutine
+CHECK:[[INC2:0x[0-9a-f]*]]{{.*}}DW_TAG_inlined_subroutine
 CHECK:          DW_AT_abstract_origin (cu + 0x009a "inc")
 CHECK:          DW_AT_ranges (0x00000000
 CHECK:             [0x0000000100000f94, 0x0000000100000f9a)
@@ -197,3 +197,194 @@ CHECK-NEXT: length = 0x0000001f version
 CHECK-NEXT: Offset     Name
 CHECK-NEXT: 0x00000063 "int"
 CHECK-NEXT: 0x00000079 "char"
+
+CHECK: .apple_names contents:
+CHECK-NEXT: Header {
+CHECK-NEXT:   Magic: 0x48415348
+CHECK-NEXT:   Version: 0x1
+CHECK-NEXT:   Hash function: 0x0
+CHECK-NEXT:   Bucket count: 7
+CHECK-NEXT:   Hashes count: 7
+CHECK-NEXT:   HeaderData length: 12
+CHECK-NEXT: }
+CHECK-NEXT: DIE offset base: 0
+CHECK-NEXT: Number of atoms: 1
+CHECK-NEXT: Atoms [
+CHECK-NEXT:   Atom 0 {
+CHECK-NEXT:     Type: DW_ATOM_die_offset
+CHECK-NEXT:     Form: DW_FORM_data4
+CHECK-NEXT:   }
+CHECK-NEXT: ]
+CHECK-NEXT: Bucket 0 [
+CHECK-NEXT:   Hash 0xb8860c2 [
+CHECK-NEXT:     Name at 0x74 {
+CHECK-NEXT:       String: 0x0000007e "baz"
+CHECK-NEXT:       Data 0 [
+CHECK-NEXT:         Atom[0]: 0x000000c0
+CHECK-NEXT:       ]
+CHECK-NEXT:     }
+CHECK-NEXT:   ]
+CHECK-NEXT:   Hash 0xb88801f [
+CHECK-NEXT:     Name at 0x84 {
+CHECK-NEXT:       String: 0x0000008a "inc"
+CHECK-NEXT:       Data 0 [
+CHECK-NEXT:         Atom[0]: 0x00000110
+CHECK-NEXT:       ]
+CHECK-NEXT:       Data 1 [
+CHECK-NEXT:         Atom[0]: 0x000001c7
+CHECK-NEXT:       ]
+CHECK-NEXT:     }
+CHECK-NEXT:   ]
+CHECK-NEXT: ]
+CHECK-NEXT: Bucket 1 [
+CHECK-NEXT:   EMPTY
+CHECK-NEXT: ]
+CHECK-NEXT: Bucket 2 [
+CHECK-NEXT:   Hash 0xfed12c6a [
+CHECK-NEXT:     Name at 0x98 {
+CHECK-NEXT:       String: 0x00000072 "private_int"
+CHECK-NEXT:       Data 0 [
+CHECK-NEXT:         Atom[0]: 0x000000a7
+CHECK-NEXT:       ]
+CHECK-NEXT:     }
+CHECK-NEXT:   ]
+CHECK-NEXT: ]
+CHECK-NEXT: Bucket 3 [
+CHECK-NEXT:   Hash 0xb88b5c8 [
+CHECK-NEXT:     Name at 0xa8 {
+CHECK-NEXT:       String: 0x00000097 "val"
+CHECK-NEXT:       Data 0 [
+CHECK-NEXT:         Atom[0]: 0x00000160
+CHECK-NEXT:       ]
+CHECK-NEXT:     }
+CHECK-NEXT:   ]
+CHECK-NEXT:   Hash 0x7c9a7f6a [
+CHECK-NEXT:     Name at 0xb8 {
+CHECK-NEXT:       String: 0x00000051 "main"
+CHECK-NEXT:       Data 0 [
+CHECK-NEXT:         Atom[0]: 0x00000026
+CHECK-NEXT:       ]
+CHECK-NEXT:     }
+CHECK-NEXT:   ]
+CHECK-NEXT: ]
+CHECK-NEXT: Bucket 4 [
+CHECK-NEXT:   EMPTY
+CHECK-NEXT: ]
+CHECK-NEXT: Bucket 5 [
+CHECK-NEXT:   Hash 0xb887389 [
+CHECK-NEXT:     Name at 0xc8 {
+CHECK-NEXT:       String: 0x00000082 "foo"
+CHECK-NEXT:       Data 0 [
+CHECK-NEXT:         Atom[0]: 0x000000d9
+CHECK-NEXT:       ]
+CHECK-NEXT:     }
+CHECK-NEXT:   ]
+CHECK-NEXT: ]
+CHECK-NEXT: Bucket 6 [
+CHECK-NEXT:   Hash 0xb8860ba [
+CHECK-NEXT:     Name at 0xd8 {
+CHECK-NEXT:       String: 0x0000009b "bar"
+CHECK-NEXT:       Data 0 [
+CHECK-NEXT:         Atom[0]: 0x0000017f
+CHECK-NEXT:       ]
+CHECK-NEXT:     }
+CHECK-NEXT:   ]
+CHECK-NEXT: ]
+
+CHECK: apple_types contents:
+CHECK-NEXT: Header {
+CHECK-NEXT:   Magic: 0x48415348
+CHECK-NEXT:   Version: 0x1
+CHECK-NEXT:   Hash function: 0x0
+CHECK-NEXT:   Bucket count: 2
+CHECK-NEXT:   Hashes count: 2
+CHECK-NEXT:   HeaderData length: 24
+CHECK-NEXT: }
+CHECK-NEXT: DIE offset base: 0
+CHECK-NEXT: Number of atoms: 4
+CHECK-NEXT: Atoms [
+CHECK-NEXT:   Atom 0 {
+CHECK-NEXT:     Type: DW_ATOM_die_offset
+CHECK-NEXT:     Form: DW_FORM_data4
+CHECK-NEXT:   }
+CHECK-NEXT:   Atom 1 {
+CHECK-NEXT:     Type: DW_ATOM_die_tag
+CHECK-NEXT:     Form: DW_FORM_data2
+CHECK-NEXT:   }
+CHECK-NEXT:   Atom 2 {
+CHECK-NEXT:     Type: DW_ATOM_type_flags
+CHECK-NEXT:     Form: DW_FORM_data1
+CHECK-NEXT:   }
+CHECK-NEXT:   Atom 3 {
+CHECK-NEXT:     Type: DW_ATOM_qual_name_hash
+CHECK-NEXT:     Form: DW_FORM_data4
+CHECK-NEXT:   }
+CHECK-NEXT: ]
+CHECK-NEXT: Bucket 0 [
+CHECK-NEXT:   Hash 0xb888030 [
+CHECK-NEXT:     Name at 0x44 {
+CHECK-NEXT:       String: 0x00000060 "int"
+CHECK-NEXT:       Data 0 [
+CHECK-NEXT:         Atom[0]: 0x00000063
+CHECK-NEXT:         Atom[1]: 0x0024
+CHECK-NEXT:         Atom[2]: 0x00
+CHECK-NEXT:         Atom[3]: 0x0c3a28a4
+CHECK-NEXT:       ]
+CHECK-NEXT:     }
+CHECK-NEXT:   ]
+CHECK-NEXT: ]
+CHECK-NEXT: Bucket 1 [
+CHECK-NEXT:   Hash 0x7c952063 [
+CHECK-NEXT:     Name at 0x5b {
+CHECK-NEXT:       String: 0x00000064 "char"
+CHECK-NEXT:       Data 0 [
+CHECK-NEXT:         Atom[0]: 0x00000079
+CHECK-NEXT:         Atom[1]: 0x0024
+CHECK-NEXT:         Atom[2]: 0x00
+CHECK-NEXT:         Atom[3]: 0x937bd757
+CHECK-NEXT:       ]
+CHECK-NEXT:     }
+CHECK-NEXT:   ]
+CHECK-NEXT: ]
+
+CHECK: .apple_namespaces contents:
+CHECK-NEXT: Header {
+CHECK-NEXT:   Magic: 0x48415348
+CHECK-NEXT:   Version: 0x1
+CHECK-NEXT:   Hash function: 0x0
+CHECK-NEXT:   Bucket count: 1
+CHECK-NEXT:   Hashes count: 0
+CHECK-NEXT:   HeaderData length: 12
+CHECK-NEXT: }
+CHECK-NEXT: DIE offset base: 0
+CHECK-NEXT: Number of atoms: 1
+CHECK-NEXT: Atoms [
+CHECK-NEXT:   Atom 0 {
+CHECK-NEXT:     Type: DW_ATOM_die_offset
+CHECK-NEXT:     Form: DW_FORM_data4
+CHECK-NEXT:   }
+CHECK-NEXT: ]
+CHECK-NEXT: Bucket 0 [
+CHECK-NEXT:   EMPTY
+CHECK-NEXT: ]
+
+CHECK: .apple_objc contents:
+CHECK-NEXT: Header {
+CHECK-NEXT:   Magic: 0x48415348
+CHECK-NEXT:   Version: 0x1
+CHECK-NEXT:   Hash function: 0x0
+CHECK-NEXT:   Bucket count: 1
+CHECK-NEXT:   Hashes count: 0
+CHECK-NEXT:   HeaderData length: 12
+CHECK-NEXT: }
+CHECK-NEXT: DIE offset base: 0
+CHECK-NEXT: Number of atoms: 1
+CHECK-NEXT: Atoms [
+CHECK-NEXT:   Atom 0 {
+CHECK-NEXT:     Type: DW_ATOM_die_offset
+CHECK-NEXT:     Form: DW_FORM_data4
+CHECK-NEXT:   }
+CHECK-NEXT: ]
+CHECK-NEXT: Bucket 0 [
+CHECK-NEXT:   EMPTY
+CHECK-NEXT: ]

Added: llvm/trunk/test/tools/dsymutil/X86/objc.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/X86/objc.test?rev=323655&view=auto
==============================================================================
--- llvm/trunk/test/tools/dsymutil/X86/objc.test (added)
+++ llvm/trunk/test/tools/dsymutil/X86/objc.test Mon Jan 29 06:52:50 2018
@@ -0,0 +1,52 @@
+RUN: llvm-dsymutil -f -oso-prepend-path=%p/.. %p/../Inputs/objc.macho.x86_64 -o - \
+RUN:   | llvm-dwarfdump -apple-types -apple-objc - | FileCheck %s
+
+CHECK: .apple_types contents:
+CHECK: String: 0x00000066 "A"
+CHECK-NEXT: Data 0 [
+CHECK-NEXT:   Atom[0]: 0x0000012d
+CHECK-NEXT:   Atom[1]: 0x0013
+CHECK-NEXT:   Atom[2]: 0x02
+CHECK-NEXT:   Atom[3]: 0x0b87b15a
+CHECK-NEXT: ]
+
+CHECK: .apple_objc contents:
+CHECK-NEXT: Header {
+CHECK-NEXT:   Magic: 0x48415348
+CHECK-NEXT:   Version: 0x1
+CHECK-NEXT:   Hash function: 0x0
+CHECK-NEXT:   Bucket count: 2
+CHECK-NEXT:   Hashes count: 2
+CHECK-NEXT:   HeaderData length: 12
+CHECK-NEXT: }
+CHECK-NEXT: DIE offset base: 0
+CHECK-NEXT: Number of atoms: 1
+CHECK-NEXT: Atoms [
+CHECK-NEXT:   Atom 0 {
+CHECK-NEXT:     Type: DW_ATOM_die_offset
+CHECK-NEXT:     Form: DW_FORM_data4
+CHECK-NEXT:   }
+CHECK-NEXT: ]
+CHECK-NEXT: Bucket 0 [
+CHECK-NEXT:   Hash 0x2b5e6 [
+CHECK-NEXT:     Name at 0x38 {
+CHECK-NEXT:       String: 0x00000066 "A"
+CHECK-NEXT:       Data 0 [
+CHECK-NEXT:         Atom[0]: 0x00000027
+CHECK-NEXT:       ]
+CHECK-NEXT:       Data 1 [
+CHECK-NEXT:         Atom[0]: 0x0000007a
+CHECK-NEXT:       ]
+CHECK-NEXT:     }
+CHECK-NEXT:   ]
+CHECK-NEXT: ]
+CHECK-NEXT: Bucket 1 [
+CHECK-NEXT:   Hash 0x3fa0f4b5 [
+CHECK-NEXT:     Name at 0x4c {
+CHECK-NEXT:       String: 0x0000009d "A(Category)"
+CHECK-NEXT:       Data 0 [
+CHECK-NEXT:         Atom[0]: 0x0000007a
+CHECK-NEXT:       ]
+CHECK-NEXT:     }
+CHECK-NEXT:   ]
+CHECK-NEXT: ]

Modified: llvm/trunk/tools/dsymutil/DwarfLinker.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/DwarfLinker.cpp?rev=323655&r1=323654&r2=323655&view=diff
==============================================================================
--- llvm/trunk/tools/dsymutil/DwarfLinker.cpp (original)
+++ llvm/trunk/tools/dsymutil/DwarfLinker.cpp Mon Jan 29 06:52:50 2018
@@ -30,6 +30,7 @@
 #include "llvm/ADT/Twine.h"
 #include "llvm/BinaryFormat/Dwarf.h"
 #include "llvm/BinaryFormat/MachO.h"
+#include "llvm/CodeGen/AccelTable.h"
 #include "llvm/CodeGen/AsmPrinter.h"
 #include "llvm/CodeGen/DIE.h"
 #include "llvm/Config/config.h"
@@ -62,6 +63,7 @@
 #include "llvm/Support/Allocator.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/Compiler.h"
+#include "llvm/Support/DJB.h"
 #include "llvm/Support/DataExtractor.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -357,29 +359,56 @@ public:
   /// debug_loc section.
   void noteLocationAttribute(PatchLocation Attr, int64_t PcOffset);
 
-  /// Add a name accelerator entry for \p Die with \p Name which is stored in
-  /// the string table at \p Offset.
-  void addNameAccelerator(const DIE *Die, const char *Name, uint32_t Offset,
+  /// Add a name accelerator entry for \a Die with \a Name.
+  void addNamespaceAccelerator(const DIE *Die, DwarfStringPoolEntryRef Name);
+
+  /// Add a name accelerator entry for \a Die with \a Name.
+  void addNameAccelerator(const DIE *Die, DwarfStringPoolEntryRef Name,
+                          bool SkipPubnamesSection = false);
+
+  /// Add various accelerator entries for \p Die with \p Name which is stored
+  /// in the string table at \p Offset. \p Name must be an Objective-C
+  /// selector.
+  void addObjCAccelerator(const DIE *Die, DwarfStringPoolEntryRef Name,
                           bool SkipPubnamesSection = false);
 
   /// Add a type accelerator entry for \p Die with \p Name which is stored in
   /// the string table at \p Offset.
-  void addTypeAccelerator(const DIE *Die, const char *Name, uint32_t Offset);
+  void addTypeAccelerator(const DIE *Die, DwarfStringPoolEntryRef Name,
+                          bool ObjcClassImplementation,
+                          uint32_t QualifiedNameHash);
 
   struct AccelInfo {
-    StringRef Name;      ///< Name of the entry.
-    const DIE *Die;      ///< DIE this entry describes.
-    uint32_t NameOffset; ///< Offset of Name in the string pool.
-    bool SkipPubSection; ///< Emit this entry only in the apple_* sections.
+    /// Name of the entry.
+    DwarfStringPoolEntryRef Name;
+
+    /// DIE this entry describes.
+    const DIE *Die;
+
+    /// Hash of the fully qualified name.
+    uint32_t QualifiedNameHash;
+
+    /// Emit this entry only in the apple_* sections.
+    bool SkipPubSection;
 
-    AccelInfo(StringRef Name, const DIE *Die, uint32_t NameOffset,
+    /// Is this an ObjC class implem?
+    bool ObjcClassImplementation;
+
+    AccelInfo(DwarfStringPoolEntryRef Name, const DIE *Die,
               bool SkipPubSection = false)
-        : Name(Name), Die(Die), NameOffset(NameOffset),
-          SkipPubSection(SkipPubSection) {}
+        : Name(Name), Die(Die), SkipPubSection(SkipPubSection) {}
+
+    AccelInfo(DwarfStringPoolEntryRef Name, const DIE *Die,
+              uint32_t QualifiedNameHash, bool ObjCClassIsImplementation)
+        : Name(Name), Die(Die), QualifiedNameHash(QualifiedNameHash),
+          SkipPubSection(false),
+          ObjcClassImplementation(ObjCClassIsImplementation) {}
   };
 
   const std::vector<AccelInfo> &getPubnames() const { return Pubnames; }
   const std::vector<AccelInfo> &getPubtypes() const { return Pubtypes; }
+  const std::vector<AccelInfo> &getNamespaces() const { return Namespaces; }
+  const std::vector<AccelInfo> &getObjC() const { return ObjC; }
 
   /// Get the full path for file \a FileNum in the line table
   StringRef getResolvedPath(unsigned FileNum) {
@@ -442,6 +471,8 @@ private:
   /// @{
   std::vector<AccelInfo> Pubnames;
   std::vector<AccelInfo> Pubtypes;
+  std::vector<AccelInfo> Namespaces;
+  std::vector<AccelInfo> ObjC;
   /// @}
 
   /// Cached resolved paths from the line table.
@@ -518,18 +549,28 @@ void CompileUnit::noteLocationAttribute(
   LocationAttributes.emplace_back(Attr, PcOffset);
 }
 
-/// Add a name accelerator entry for \p Die with \p Name
-/// which is stored in the string table at \p Offset.
-void CompileUnit::addNameAccelerator(const DIE *Die, const char *Name,
-                                     uint32_t Offset, bool SkipPubSection) {
-  Pubnames.emplace_back(Name, Die, Offset, SkipPubSection);
+void CompileUnit::addNamespaceAccelerator(const DIE *Die,
+                                          DwarfStringPoolEntryRef Name) {
+  Namespaces.emplace_back(Name, Die);
+}
+
+void CompileUnit::addObjCAccelerator(const DIE *Die,
+                                     DwarfStringPoolEntryRef Name,
+                                     bool SkipPubSection) {
+  ObjC.emplace_back(Name, Die, SkipPubSection);
 }
 
-/// Add a type accelerator entry for \p Die with \p Name
-/// which is stored in the string table at \p Offset.
-void CompileUnit::addTypeAccelerator(const DIE *Die, const char *Name,
-                                     uint32_t Offset) {
-  Pubtypes.emplace_back(Name, Die, Offset, false);
+void CompileUnit::addNameAccelerator(const DIE *Die,
+                                     DwarfStringPoolEntryRef Name,
+                                     bool SkipPubSection) {
+  Pubnames.emplace_back(Name, Die, SkipPubSection);
+}
+
+void CompileUnit::addTypeAccelerator(const DIE *Die,
+                                     DwarfStringPoolEntryRef Name,
+                                     bool ObjcClassImplementation,
+                                     uint32_t QualifiedNameHash) {
+  Pubtypes.emplace_back(Name, Die, QualifiedNameHash, ObjcClassImplementation);
 }
 
 namespace {
@@ -642,6 +683,19 @@ public:
   void emitFDE(uint32_t CIEOffset, uint32_t AddreSize, uint32_t Address,
                StringRef Bytes);
 
+  /// Emit Apple namespaces accelerator table.
+  void
+  emitAppleNamespaces(AppleAccelTable<AppleAccelTableStaticOffsetData> &Table);
+
+  /// Emit Apple names accelerator table.
+  void emitAppleNames(AppleAccelTable<AppleAccelTableStaticOffsetData> &Table);
+
+  /// Emit Apple Objective-C accelerator table.
+  void emitAppleObjc(AppleAccelTable<AppleAccelTableStaticOffsetData> &Table);
+
+  /// Emit Apple type accelerator table.
+  void emitAppleTypes(AppleAccelTable<AppleAccelTableStaticTypeData> &Table);
+
   uint32_t getFrameSectionSize() const { return FrameSectionSize; }
 };
 
@@ -779,11 +833,49 @@ void DwarfStreamer::emitStrings(const No
   for (auto Entry : Entries) {
     if (Entry.getIndex() == -1U)
       break;
-    Asm->OutStreamer->EmitBytes(
-        StringRef(Entry.getString().data(), Entry.getString().size() + 1));
+    // Emit the string itself.
+    Asm->OutStreamer->EmitBytes(Entry.getString());
+    // Emit a null terminator.
+    Asm->EmitInt8(0);
   }
 }
 
+void DwarfStreamer::emitAppleNamespaces(
+    AppleAccelTable<AppleAccelTableStaticOffsetData> &Table) {
+  Asm->OutStreamer->SwitchSection(MOFI->getDwarfAccelNamespaceSection());
+  Table.finalizeTable(Asm.get(), "namespac");
+  auto *SectionBegin = Asm->createTempSymbol("namespac_begin");
+  Asm->OutStreamer->EmitLabel(SectionBegin);
+  Table.emit(Asm.get(), SectionBegin);
+}
+
+void DwarfStreamer::emitAppleNames(
+    AppleAccelTable<AppleAccelTableStaticOffsetData> &Table) {
+  Asm->OutStreamer->SwitchSection(MOFI->getDwarfAccelNamesSection());
+  Table.finalizeTable(Asm.get(), "names");
+  auto *SectionBegin = Asm->createTempSymbol("names_begin");
+  Asm->OutStreamer->EmitLabel(SectionBegin);
+  Table.emit(Asm.get(), SectionBegin);
+}
+
+void DwarfStreamer::emitAppleObjc(
+    AppleAccelTable<AppleAccelTableStaticOffsetData> &Table) {
+  Asm->OutStreamer->SwitchSection(MOFI->getDwarfAccelObjCSection());
+  Table.finalizeTable(Asm.get(), "objc");
+  auto *SectionBegin = Asm->createTempSymbol("objc_begin");
+  Asm->OutStreamer->EmitLabel(SectionBegin);
+  Table.emit(Asm.get(), SectionBegin);
+}
+
+void DwarfStreamer::emitAppleTypes(
+    AppleAccelTable<AppleAccelTableStaticTypeData> &Table) {
+  Asm->OutStreamer->SwitchSection(MOFI->getDwarfAccelTypesSection());
+  Table.finalizeTable(Asm.get(), "types");
+  auto *SectionBegin = Asm->createTempSymbol("types_begin");
+  Asm->OutStreamer->EmitLabel(SectionBegin);
+  Table.emit(Asm.get(), SectionBegin);
+}
+
 /// Emit the swift_ast section stored in \p Buffers.
 void DwarfStreamer::emitSwiftAST(StringRef Buffer) {
   MCSection *SwiftASTSection = MOFI->getDwarfSwiftASTSection();
@@ -1137,8 +1229,11 @@ void DwarfStreamer::emitPubSectionForUni
       HeaderEmitted = true;
     }
     Asm->EmitInt32(Name.Die->getOffset());
-    Asm->OutStreamer->EmitBytes(
-        StringRef(Name.Name.data(), Name.Name.size() + 1));
+
+    // Emit the string itself.
+    Asm->OutStreamer->EmitBytes(Name.Name.getString());
+    // Emit a null terminator.
+    Asm->EmitInt8(0);
   }
 
   if (!HeaderEmitted)
@@ -1396,8 +1491,7 @@ private:
     /// clone*Attributes helpers about the attributes of a particular DIE.
     struct AttributesInfo {
       /// Names.
-      const char *Name = nullptr;
-      const char *MangledName = nullptr;
+      DwarfStringPoolEntryRef Name, MangledName, NameWithoutTemplate;
 
       /// Offsets in the string pool.
       uint32_t NameOffset = 0;
@@ -1415,6 +1509,9 @@ private:
       /// Does the DIE have a low_pc attribute?
       bool HasLowPc = false;
 
+      /// Does the DIE have a ranges attribute?
+      bool HasRanges = false;
+
       /// Is this DIE only a declaration?
       bool IsDeclaration = false;
 
@@ -1470,10 +1567,18 @@ private:
     /// described by \p Die and store them in \Info if they are not
     /// already there.
     /// \returns is a name was found.
-    bool getDIENames(const DWARFDie &Die, AttributesInfo &Info);
+    bool getDIENames(const DWARFDie &Die, AttributesInfo &Info,
+                     bool StripTemplate = false);
 
     /// Create a copy of abbreviation Abbrev.
     void copyAbbrev(const DWARFAbbreviationDeclaration &Abbrev, bool hasODR);
+
+    uint32_t hashFullyQualifiedName(DWARFDie DIE, CompileUnit &U,
+                                    int RecurseDepth = 0);
+
+    /// Helper for cloneDIE.
+    void addObjCAccelerator(CompileUnit &Unit, const DIE *Die,
+                            DwarfStringPoolEntryRef Name, bool SkipPubSection);
   };
 
   /// Assign an abbreviation number to \p Abbrev
@@ -1569,6 +1674,12 @@ private:
   /// debug_frame section.
   uint32_t LastCIEOffset = 0;
 
+  /// Apple accelerator tables.
+  AppleAccelTable<AppleAccelTableStaticOffsetData> AppleNames;
+  AppleAccelTable<AppleAccelTableStaticOffsetData> AppleNamespaces;
+  AppleAccelTable<AppleAccelTableStaticOffsetData> AppleObjc;
+  AppleAccelTable<AppleAccelTableStaticTypeData> AppleTypes;
+
   /// Mapping the PCM filename to the DwoId.
   StringMap<uint64_t> ClangModules;
 
@@ -1829,16 +1940,30 @@ PointerIntPair<DeclContext *, 1> DeclCon
 }
 
 bool DwarfLinker::DIECloner::getDIENames(const DWARFDie &Die,
-                                         AttributesInfo &Info) {
+                                         AttributesInfo &Info,
+                                         bool StripTemplate) {
+  // This function will be called on DIEs having low_pcs and
+  // ranges. As getting the name might be more expansive, filter out
+  // blocks directly.
+  if (Die.getTag() == dwarf::DW_TAG_lexical_block)
+    return false;
+
   // FIXME: a bit wasteful as the first getName might return the
   // short name.
-  if (!Info.MangledName &&
-      (Info.MangledName = Die.getName(DINameKind::LinkageName)))
-    Info.MangledNameOffset =
-        Linker.StringPool.getStringOffset(Info.MangledName);
-
-  if (!Info.Name && (Info.Name = Die.getName(DINameKind::ShortName)))
-    Info.NameOffset = Linker.StringPool.getStringOffset(Info.Name);
+  if (!Info.MangledName)
+    if (const char *MangledName = Die.getName(DINameKind::LinkageName))
+      Info.MangledName = Linker.StringPool.getEntry(MangledName);
+
+  if (!Info.Name)
+    if (const char *Name = Die.getName(DINameKind::ShortName))
+      Info.Name = Linker.StringPool.getEntry(Name);
+
+  if (StripTemplate && Info.Name && Info.MangledName != Info.Name) {
+    // FIXME: dsymutil compatibility. This is wrong for operator<
+    auto Split = Info.Name.getString().split('<');
+    if (!Split.second.empty())
+      Info.NameWithoutTemplate = Linker.StringPool.getEntry(Split.first);
+  }
 
   return Info.Name || Info.MangledName;
 }
@@ -2623,6 +2748,7 @@ unsigned DwarfLinker::DIECloner::cloneAd
     DIE &Die, AttributeSpec AttrSpec, const DWARFFormValue &Val,
     const CompileUnit &Unit, AttributesInfo &Info) {
   uint64_t Addr = *Val.getAsAddress();
+
   if (AttrSpec.Attr == dwarf::DW_AT_low_pc) {
     if (Die.getTag() == dwarf::DW_TAG_inlined_subroutine ||
         Die.getTag() == dwarf::DW_TAG_lexical_block)
@@ -2684,8 +2810,10 @@ unsigned DwarfLinker::DIECloner::cloneSc
   PatchLocation Patch =
       Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),
                    dwarf::Form(AttrSpec.Form), DIEInteger(Value));
-  if (AttrSpec.Attr == dwarf::DW_AT_ranges)
+  if (AttrSpec.Attr == dwarf::DW_AT_ranges) {
     Unit.noteRangeAttribute(Die, Patch);
+    Info.HasRanges = true;
+  }
 
   // A more generic way to check for location attributes would be
   // nice, but it's very unlikely that any other attribute needs a
@@ -2825,6 +2953,55 @@ static bool isTypeTag(uint16_t Tag) {
   return false;
 }
 
+static bool isObjCSelector(StringRef Name) {
+  return Name.size() > 2 && (Name[0] == '-' || Name[0] == '+') &&
+         (Name[1] == '[');
+}
+
+void DwarfLinker::DIECloner::addObjCAccelerator(CompileUnit &Unit,
+                                                const DIE *Die,
+                                                DwarfStringPoolEntryRef Name,
+                                                bool SkipPubSection) {
+  assert(isObjCSelector(Name.getString()) && "not an objc selector");
+  // Objective C method or class function.
+  // "- [Class(Category) selector :withArg ...]"
+  StringRef ClassNameStart(Name.getString().drop_front(2));
+  size_t FirstSpace = ClassNameStart.find(' ');
+  if (FirstSpace == StringRef::npos)
+    return;
+
+  StringRef SelectorStart(ClassNameStart.data() + FirstSpace + 1);
+  if (!SelectorStart.size())
+    return;
+
+  StringRef Selector(SelectorStart.data(), SelectorStart.size() - 1);
+  Unit.addNameAccelerator(Die, Linker.StringPool.getEntry(Selector),
+                          SkipPubSection);
+
+  // Add an entry for the class name that points to this
+  // method/class function.
+  StringRef ClassName(ClassNameStart.data(), FirstSpace);
+  Unit.addObjCAccelerator(Die, Linker.StringPool.getEntry(ClassName),
+                          SkipPubSection);
+
+  if (ClassName[ClassName.size() - 1] == ')') {
+    size_t OpenParens = ClassName.find('(');
+    if (OpenParens != StringRef::npos) {
+      StringRef ClassNameNoCategory(ClassName.data(), OpenParens);
+      Unit.addObjCAccelerator(
+          Die, Linker.StringPool.getEntry(ClassNameNoCategory), SkipPubSection);
+
+      std::string MethodNameNoCategory(Name.getString().data(), OpenParens + 2);
+      // FIXME: The missing space here may be a bug, but
+      //        dsymutil-classic also does it this way.
+      MethodNameNoCategory.append(SelectorStart);
+      Unit.addNameAccelerator(Die,
+                              Linker.StringPool.getEntry(MethodNameNoCategory),
+                              SkipPubSection);
+    }
+  }
+}
+
 static bool
 shouldSkipAttribute(DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,
                     uint16_t Tag, bool InDebugMap, bool SkipPC,
@@ -2965,25 +3142,46 @@ DIE *DwarfLinker::DIECloner::cloneDIE(
   // FIXME: This is slightly wrong. An inline_subroutine without a
   // low_pc, but with AT_ranges might be interesting to get into the
   // accelerator tables too. For now stick with dsymutil's behavior.
-  if ((Info.InDebugMap || AttrInfo.HasLowPc) &&
+  if ((Info.InDebugMap || AttrInfo.HasLowPc || AttrInfo.HasRanges) &&
       Tag != dwarf::DW_TAG_compile_unit &&
-      getDIENames(InputDIE, AttrInfo)) {
+      getDIENames(InputDIE, AttrInfo,
+                  Tag != dwarf::DW_TAG_inlined_subroutine)) {
     if (AttrInfo.MangledName && AttrInfo.MangledName != AttrInfo.Name)
       Unit.addNameAccelerator(Die, AttrInfo.MangledName,
-                              AttrInfo.MangledNameOffset,
                               Tag == dwarf::DW_TAG_inlined_subroutine);
-    if (AttrInfo.Name)
-      Unit.addNameAccelerator(Die, AttrInfo.Name, AttrInfo.NameOffset,
+    if (AttrInfo.Name) {
+      if (AttrInfo.NameWithoutTemplate)
+        Unit.addNameAccelerator(Die, AttrInfo.NameWithoutTemplate,
+                                /* SkipPubSection */ true);
+      Unit.addNameAccelerator(Die, AttrInfo.Name,
                               Tag == dwarf::DW_TAG_inlined_subroutine);
+    }
+    if (AttrInfo.Name && isObjCSelector(AttrInfo.Name.getString()))
+      addObjCAccelerator(Unit, Die, AttrInfo.Name, /* SkipPubSection =*/true);
+
+  } else if (Tag == dwarf::DW_TAG_namespace) {
+    if (!AttrInfo.Name)
+      AttrInfo.Name = Linker.StringPool.getEntry("(anonymous namespace)");
+    Unit.addNamespaceAccelerator(Die, AttrInfo.Name);
   } else if (isTypeTag(Tag) && !AttrInfo.IsDeclaration &&
-             getDIENames(InputDIE, AttrInfo)) {
-    if (AttrInfo.Name)
-      Unit.addTypeAccelerator(Die, AttrInfo.Name, AttrInfo.NameOffset);
+             getDIENames(InputDIE, AttrInfo) && AttrInfo.Name &&
+             AttrInfo.Name.getString()[0]) {
+    uint32_t Hash = hashFullyQualifiedName(InputDIE, Unit);
+    uint64_t RuntimeLang =
+        dwarf::toUnsigned(InputDIE.find(dwarf::DW_AT_APPLE_runtime_class))
+            .getValueOr(0);
+    bool ObjCClassIsImplementation =
+        (RuntimeLang == dwarf::DW_LANG_ObjC ||
+         RuntimeLang == dwarf::DW_LANG_ObjC_plus_plus) &&
+        dwarf::toUnsigned(InputDIE.find(dwarf::DW_AT_APPLE_objc_complete_type))
+            .getValueOr(0);
+    Unit.addTypeAccelerator(Die, AttrInfo.Name, ObjCClassIsImplementation,
+                            Hash);
   }
 
   // Determine whether there are any children that we want to keep.
   bool HasChildren = false;
-  for (auto Child: InputDIE.children()) {
+  for (auto Child : InputDIE.children()) {
     unsigned Idx = U.getDIEIndex(Child);
     if (Unit.getInfo(Idx).Keep) {
       HasChildren = true;
@@ -3263,8 +3461,32 @@ void DwarfLinker::patchLineTableForUnit(
 }
 
 void DwarfLinker::emitAcceleratorEntriesForUnit(CompileUnit &Unit) {
-  Streamer->emitPubNamesForUnit(Unit);
-  Streamer->emitPubTypesForUnit(Unit);
+  // Add namespaces.
+  for (const auto &Namespace : Unit.getNamespaces())
+    AppleNamespaces.addName(Namespace.Name,
+                            Namespace.Die->getOffset() + Unit.getStartOffset());
+
+  /// Add names.
+  if (!Options.Minimize)
+    Streamer->emitPubNamesForUnit(Unit);
+  for (const auto &Pubname : Unit.getPubnames())
+    AppleNames.addName(Pubname.Name,
+                       Pubname.Die->getOffset() + Unit.getStartOffset());
+
+  /// Add types.
+  if (!Options.Minimize)
+    Streamer->emitPubTypesForUnit(Unit);
+  for (const auto &Pubtype : Unit.getPubtypes())
+    AppleTypes.addName(
+        Pubtype.Name, Pubtype.Die->getOffset() + Unit.getStartOffset(),
+        Pubtype.Die->getTag(),
+        Pubtype.ObjcClassImplementation ? dwarf::DW_FLAG_type_implementation
+                                        : 0,
+        Pubtype.QualifiedNameHash);
+
+  /// Add ObjC names.
+  for (const auto &ObjC : Unit.getObjC())
+    AppleObjc.addName(ObjC.Name, ObjC.Die->getOffset() + Unit.getStartOffset());
 }
 
 /// Read the frame info stored in the object, and emit the
@@ -3367,6 +3589,50 @@ void DwarfLinker::DIECloner::copyAbbrev(
   Linker.AssignAbbrev(Copy);
 }
 
+uint32_t DwarfLinker::DIECloner::hashFullyQualifiedName(DWARFDie DIE,
+                                                        CompileUnit &U,
+                                                        int RecurseDepth) {
+  const char *Name = nullptr;
+  DWARFUnit *OrigUnit = &U.getOrigUnit();
+  CompileUnit *CU = &U;
+  Optional<DWARFFormValue> Ref;
+
+  while (1) {
+    if (const char *CurrentName = DIE.getName(DINameKind::ShortName))
+      Name = CurrentName;
+
+    if (!(Ref = DIE.find(dwarf::DW_AT_specification)) &&
+        !(Ref = DIE.find(dwarf::DW_AT_abstract_origin)))
+      break;
+
+    if (!Ref->isFormClass(DWARFFormValue::FC_Reference))
+      break;
+
+    CompileUnit *RefCU;
+    if (auto RefDIE = resolveDIEReference(Linker, CompileUnits, *Ref,
+                                          U.getOrigUnit(), DIE, RefCU)) {
+      CU = RefCU;
+      OrigUnit = &RefCU->getOrigUnit();
+      DIE = RefDIE;
+    }
+  }
+
+  unsigned Idx = OrigUnit->getDIEIndex(DIE);
+  if (!Name && DIE.getTag() == dwarf::DW_TAG_namespace)
+    Name = "(anonymous namespace)";
+
+  if (CU->getInfo(Idx).ParentIdx == 0 ||
+      // FIXME: dsymutil-classic compatibility. Ignore modules.
+      CU->getOrigUnit().getDIEAtIndex(CU->getInfo(Idx).ParentIdx).getTag() ==
+          dwarf::DW_TAG_module)
+    return djbHash(Name ? Name : "", djbHash(RecurseDepth ? "" : "::"));
+
+  DWARFDie Die = OrigUnit->getDIEAtIndex(CU->getInfo(Idx).ParentIdx);
+  return djbHash((Name ? Name : ""),
+                 djbHash((Name ? "::" : ""),
+                         hashFullyQualifiedName(Die, *CU, ++RecurseDepth)));
+}
+
 static uint64_t getDwoId(const DWARFDie &CUDie,
                          const DWARFUnit &Unit) {
   auto DwoId = dwarf::toUnsigned(CUDie.find({dwarf::DW_AT_dwo_id,
@@ -3565,9 +3831,9 @@ void DwarfLinker::DIECloner::cloneAllCom
     // an empty line table for the unit, even if the unit doesn't
     // actually exist in the DIE tree.
     Linker.patchLineTableForUnit(*CurrentUnit, DwarfContext);
+    Linker.emitAcceleratorEntriesForUnit(*CurrentUnit);
     Linker.patchRangesForUnit(*CurrentUnit, DwarfContext);
     Linker.Streamer->emitLocationsForUnit(*CurrentUnit, DwarfContext);
-    Linker.emitAcceleratorEntriesForUnit(*CurrentUnit);
   }
 
   if (Linker.Options.NoOutput)
@@ -3695,6 +3961,10 @@ bool DwarfLinker::link(const DebugMap &M
   if (!Options.NoOutput) {
     Streamer->emitAbbrevs(Abbreviations, MaxDwarfVersion);
     Streamer->emitStrings(StringPool);
+    Streamer->emitAppleNames(AppleNames);
+    Streamer->emitAppleNamespaces(AppleNamespaces);
+    Streamer->emitAppleTypes(AppleTypes);
+    Streamer->emitAppleObjc(AppleObjc);
   }
 
   return Options.NoOutput ? true : Streamer->finish(Map);

Modified: llvm/trunk/tools/dsymutil/dsymutil.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/dsymutil.h?rev=323655&r1=323654&r2=323655&view=diff
==============================================================================
--- llvm/trunk/tools/dsymutil/dsymutil.h (original)
+++ llvm/trunk/tools/dsymutil/dsymutil.h Mon Jan 29 06:52:50 2018
@@ -39,6 +39,9 @@ struct LinkOptions {
   /// Do not unique types according to ODR
   bool NoODR;
 
+  /// Minimize
+  bool Minimize = false;
+
   /// Do not check swiftmodule timestamp
   bool NoTimestamp = false;
 




More information about the llvm-commits mailing list