<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Jul 11, 2016 at 4:10 PM, Mehdi Amini via llvm-commits <span dir="ltr"><<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: mehdi_amini<br>
Date: Mon Jul 11 18:10:18 2016<br>
New Revision: 275125<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=275125&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=275125&view=rev</a><br>
Log:<br>
Add a libLTO API to query a memory buffer and check if it contains ObjC categories<br>
<br>
The linker supports a feature to force load an object from a static<br>
archive if it defines an Objective-C category.<br>
This API supports this feature by looking at every section in the<br>
module to find if a category is defined in the module.<br>
<br>
Added:<br>
    llvm/trunk/test/LTO/X86/objc-detection-i386.ll<br>
    llvm/trunk/test/LTO/X86/objc-detection.ll<br>
Modified:<br>
    llvm/trunk/include/llvm-c/lto.h<br>
    llvm/trunk/include/llvm/Bitcode/ReaderWriter.h<br>
    llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp<br>
    llvm/trunk/tools/llvm-lto/llvm-lto.cpp<br>
    llvm/trunk/tools/lto/lto.cpp<br>
    llvm/trunk/tools/lto/lto.exports<br>
<br>
Modified: llvm/trunk/include/llvm-c/lto.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm-c/lto.h?rev=275125&r1=275124&r2=275125&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm-c/lto.h?rev=275125&r1=275124&r2=275125&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm-c/lto.h (original)<br>
+++ llvm/trunk/include/llvm-c/lto.h Mon Jul 11 18:10:18 2016<br>
@@ -44,7 +44,7 @@ typedef bool lto_bool_t;<br>
  * @{<br>
  */<br>
<br>
-#define LTO_API_VERSION 19<br>
+#define LTO_API_VERSION 20<br>
<br>
 /**<br>
  * \since prior to LTO_API_VERSION=3<br>
@@ -136,12 +136,20 @@ lto_module_is_object_file_for_target(con<br>
                                      const char* target_triple_prefix);<br>
<br>
 /**<br>
- * Checks if a buffer is a loadable object file.<br>
+ * Return true if \p Buffer contains a bitcode file with ObjC code (category<br>
+ * or class) in it.<br>
  *<br>
- * \since prior to LTO_API_VERSION=3<br>
+ * \since LTO_API_VERSION=20<br>
  */<br>
-extern lto_bool_t<br>
-lto_module_is_object_file_in_memory(const void* mem, size_t length);<br>
+bool lto_module_has_objc_category(const void *mem, size_t length);<br>
+<br>
+/**<br>
+* Checks if a buffer is a loadable object file.<br>
+*<br>
+* \since prior to LTO_API_VERSION=3<br>
+*/<br>
+extern lto_bool_t lto_module_is_object_file_in_memory(const void *mem,<br>
+                                                      size_t length);<br>
<br>
 /**<br>
  * Checks if a buffer is a loadable object compiled for requested target.<br>
<br>
Modified: llvm/trunk/include/llvm/Bitcode/ReaderWriter.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Bitcode/ReaderWriter.h?rev=275125&r1=275124&r2=275125&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Bitcode/ReaderWriter.h?rev=275125&r1=275124&r2=275125&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/Bitcode/ReaderWriter.h (original)<br>
+++ llvm/trunk/include/llvm/Bitcode/ReaderWriter.h Mon Jul 11 18:10:18 2016<br>
@@ -60,6 +60,11 @@ namespace llvm {<br>
   std::string getBitcodeTargetTriple(MemoryBufferRef Buffer,<br>
                                      LLVMContext &Context);<br>
<br>
+  /// Return true if \p Buffer contains a bitcode file with ObjC code (category<br>
+  /// or class) in it.<br>
+  bool isBitcodeContainingObjCCategory(MemoryBufferRef Buffer,<br>
+                                       LLVMContext &Context);<br>
+<br>
   /// Read the header of the specified bitcode buffer and extract just the<br>
   /// producer string information. If successful, this returns a string. On<br>
   /// error, this returns "".<br>
<br>
Modified: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp?rev=275125&r1=275124&r2=275125&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp?rev=275125&r1=275124&r2=275125&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp (original)<br>
+++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp Mon Jul 11 18:10:18 2016<br>
@@ -313,6 +313,10 @@ public:<br>
   /// Cheap mechanism to just extract the identification block out of bitcode.<br>
   ErrorOr<std::string> parseIdentificationBlock();<br>
<br>
+  /// Peak at the module content and return true if any ObjC category or class<br>
+  /// is found.<br>
+  ErrorOr<bool> hasObjCCategory();<br>
+<br>
   static uint64_t decodeSignRotatedValue(uint64_t V);<br>
<br>
   /// Materialize any deferred Metadata block.<br>
@@ -450,6 +454,7 @@ private:<br>
                               ArrayRef<uint64_t> Record);<br>
   std::error_code parseMetadataAttachment(Function &F);<br>
   ErrorOr<std::string> parseModuleTriple();<br>
+  ErrorOr<bool> hasObjCCategoryInModule();<br>
   std::error_code parseUseLists();<br>
   std::error_code initStream(std::unique_ptr<DataStreamer> Streamer);<br>
   std::error_code initStreamFromBuffer();<br>
@@ -4195,6 +4200,81 @@ std::error_code BitcodeReader::parseGlob<br>
   return std::error_code();<br>
 }<br>
<br>
+ErrorOr<bool> BitcodeReader::hasObjCCategory() {<br>
+  if (std::error_code EC = initStream(nullptr))<br>
+    return EC;<br>
+<br>
+  // Sniff for the signature.<br>
+  if (!hasValidBitcodeHeader(Stream))<br>
+    return error("Invalid bitcode signature");<br>
+<br>
+  // We expect a number of well-defined blocks, though we don't necessarily<br>
+  // need to understand them all.<br>
+  while (1) {<br>
+    BitstreamEntry Entry = Stream.advance();<br>
+<br>
+    switch (Entry.Kind) {<br>
+    case BitstreamEntry::Error:<br>
+      return error("Malformed block");<br>
+    case BitstreamEntry::EndBlock:<br>
+      return std::error_code();<br></blockquote><div><br></div><div>What does it mean to return a success error_code into an ErrorOr? Would it be the same as doing `return false;` here?</div><div><br></div><div>-- Sean Silva</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+    case BitstreamEntry::SubBlock:<br>
+      if (Entry.ID == bitc::MODULE_BLOCK_ID)<br>
+        return hasObjCCategoryInModule();<br>
+<br>
+      // Ignore other sub-blocks.<br>
+      if (Stream.SkipBlock())<br>
+        return error("Malformed block");<br>
+      continue;<br>
+<br>
+    case BitstreamEntry::Record:<br>
+      Stream.skipRecord(Entry.ID);<br>
+      continue;<br>
+    }<br>
+  }<br>
+}<br>
+<br>
+ErrorOr<bool> BitcodeReader::hasObjCCategoryInModule() {<br>
+  if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID))<br>
+    return error("Invalid record");<br>
+<br>
+  SmallVector<uint64_t, 64> Record;<br>
+  // Read all the records for this module.<br>
+  while (1) {<br>
+    BitstreamEntry Entry = Stream.advanceSkippingSubblocks();<br>
+<br>
+    switch (Entry.Kind) {<br>
+    case BitstreamEntry::SubBlock: // Handled for us already.<br>
+    case BitstreamEntry::Error:<br>
+      return error("Malformed block");<br>
+    case BitstreamEntry::EndBlock:<br>
+      return false;<br>
+    case BitstreamEntry::Record:<br>
+      // The interesting case.<br>
+      break;<br>
+    }<br>
+<br>
+    // Read a record.<br>
+    switch (Stream.readRecord(Entry.ID, Record)) {<br>
+    default:<br>
+      break; // Default behavior, ignore unknown content.<br>
+    case bitc::MODULE_CODE_SECTIONNAME: { // SECTIONNAME: [strchr x N]<br>
+      std::string S;<br>
+      if (convertToString(Record, 0, S))<br>
+        return error("Invalid record");<br>
+      // Check for the i386 and other (x86_64, ARM) conventions<br>
+      if (S.find("__DATA, __objc_catlist") != std::string::npos ||<br>
+          S.find("__OBJC,__category") != std::string::npos)<br>
+        return true;<br>
+      break;<br>
+    }<br>
+    }<br>
+    Record.clear();<br>
+  }<br>
+  llvm_unreachable("Exit infinite loop");<br>
+}<br>
+<br>
 /// Parse metadata attachments.<br>
 std::error_code BitcodeReader::parseMetadataAttachment(Function &F) {<br>
   if (Stream.EnterSubBlock(bitc::METADATA_ATTACHMENT_ID))<br>
@@ -6548,6 +6628,16 @@ std::string llvm::getBitcodeTargetTriple<br>
   return Triple.get();<br>
 }<br>
<br>
+bool llvm::isBitcodeContainingObjCCategory(MemoryBufferRef Buffer,<br>
+                                           LLVMContext &Context) {<br>
+  std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Buffer, false);<br>
+  auto R = llvm::make_unique<BitcodeReader>(Buf.release(), Context);<br>
+  ErrorOr<bool> hasObjCCategory = R->hasObjCCategory();<br>
+  if (hasObjCCategory.getError())<br>
+    return false;<br>
+  return hasObjCCategory.get();<br>
+}<br>
+<br>
 std::string llvm::getBitcodeProducerString(MemoryBufferRef Buffer,<br>
                                            LLVMContext &Context) {<br>
   std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Buffer, false);<br>
<br>
Added: llvm/trunk/test/LTO/X86/objc-detection-i386.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/LTO/X86/objc-detection-i386.ll?rev=275125&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/LTO/X86/objc-detection-i386.ll?rev=275125&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/LTO/X86/objc-detection-i386.ll (added)<br>
+++ llvm/trunk/test/LTO/X86/objc-detection-i386.ll Mon Jul 11 18:10:18 2016<br>
@@ -0,0 +1,59 @@<br>
+; RUN: llvm-as < %s -o %t<br>
+; RUN: llvm-lto -check-for-objc %t | FileCheck %s<br>
+<br>
+; CHECK: contains ObjC<br>
+<br>
+<br>
+target datalayout = "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128"<br>
+target triple = "i386-apple-macosx10.12.0"<br>
+<br>
+module asm "\09.lazy_reference .objc_class_name_A"<br>
+module asm "\09.objc_category_name_A_foo=0"<br>
+module asm "\09.globl .objc_category_name_A_foo"<br>
+<br>
+%0 = type opaque<br>
+%struct._objc_method = type { i8*, i8*, i8* }<br>
+%struct._objc_category = type { i8*, i8*, %struct._objc_method_list*, %struct._objc_method_list*, %struct._objc_protocol_list*, i32, %struct._prop_list_t*, %struct._prop_list_t* }<br>
+%struct._objc_method_list = type opaque<br>
+%struct._objc_protocol_list = type { %struct._objc_protocol_list*, i32, [0 x %struct._objc_protocol] }<br>
+%struct._objc_protocol = type { %struct._objc_protocol_extension*, i8*, %struct._objc_protocol_list*, %struct._objc_method_description_list*, %struct._objc_method_description_list* }<br>
+%struct._objc_protocol_extension = type { i32, %struct._objc_method_description_list*, %struct._objc_method_description_list*, %struct._prop_list_t*, i8**, %struct._prop_list_t* }<br>
+%struct._objc_method_description_list = type { i32, [0 x %struct._objc_method_description] }<br>
+%struct._objc_method_description = type { i8*, i8* }<br>
+%struct._prop_list_t = type { i32, i32, [0 x %struct._prop_t] }<br>
+%struct._prop_t = type { i8*, i8* }<br>
+%struct._objc_module = type { i32, i32, i8*, %struct._objc_symtab* }<br>
+%struct._objc_symtab = type { i32, i8*, i16, i16, [0 x i8*] }<br>
+<br>
+@OBJC_METH_VAR_NAME_ = private global [12 x i8] c"foo_myStuff\00", section "__TEXT,__cstring,cstring_literals", align 1<br>
+@OBJC_METH_VAR_TYPE_ = private global [7 x i8] c"v8@0:4\00", section "__TEXT,__cstring,cstring_literals", align 1<br>
+@OBJC_CLASS_NAME_ = private global [4 x i8] c"foo\00", section "__TEXT,__cstring,cstring_literals", align 1<br>
+@OBJC_CLASS_NAME_.1 = private global [2 x i8] c"A\00", section "__TEXT,__cstring,cstring_literals", align 1<br>
+@OBJC_CATEGORY_INSTANCE_METHODS_A_foo = private global { i8*, i32, [1 x %struct._objc_method] } { i8* null, i32 1, [1 x %struct._objc_method] [%struct._objc_method { i8* getelementptr inbounds ([12 x i8], [12 x i8]* @OBJC_METH_VAR_NAME_, i32 0, i32 0), i8* getelementptr inbounds ([7 x i8], [7 x i8]* @OBJC_METH_VAR_TYPE_, i32 0, i32 0), i8* bitcast (void (%0*, i8*)* @"\01-[A(foo) foo_myStuff]" to i8*) }] }, section "__OBJC,__cat_inst_meth,regular,no_dead_strip", align 4<br>
+@OBJC_CATEGORY_A_foo = private global %struct._objc_category { i8* getelementptr inbounds ([4 x i8], [4 x i8]* @OBJC_CLASS_NAME_, i32 0, i32 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @OBJC_CLASS_NAME_.1, i32 0, i32 0), %struct._objc_method_list* bitcast ({ i8*, i32, [1 x %struct._objc_method] }* @OBJC_CATEGORY_INSTANCE_METHODS_A_foo to %struct._objc_method_list*), %struct._objc_method_list* null, %struct._objc_protocol_list* null, i32 32, %struct._prop_list_t* null, %struct._prop_list_t* null }, section "__OBJC,__category,regular,no_dead_strip", align 4<br>
+@OBJC_CLASS_NAME_.2 = private global [1 x i8] zeroinitializer, section "__TEXT,__cstring,cstring_literals", align 1<br>
+@OBJC_SYMBOLS = private global { i32, i8*, i16, i16, [1 x i8*] } { i32 0, i8* null, i16 0, i16 1, [1 x i8*] [i8* bitcast (%struct._objc_category* @OBJC_CATEGORY_A_foo to i8*)] }, section "__OBJC,__symbols,regular,no_dead_strip", align 4<br>
+@OBJC_MODULES = private global %struct._objc_module { i32 7, i32 16, i8* getelementptr inbounds ([1 x i8], [1 x i8]* @OBJC_CLASS_NAME_.2, i32 0, i32 0), %struct._objc_symtab* bitcast ({ i32, i8*, i16, i16, [1 x i8*] }* @OBJC_SYMBOLS to %struct._objc_symtab*) }, section "__OBJC,__module_info,regular,no_dead_strip", align 4<br>
+@llvm.compiler.used = appending global [9 x i8*] [i8* getelementptr inbounds ([12 x i8], [12 x i8]* @OBJC_METH_VAR_NAME_, i32 0, i32 0), i8* getelementptr inbounds ([7 x i8], [7 x i8]* @OBJC_METH_VAR_TYPE_, i32 0, i32 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @OBJC_CLASS_NAME_, i32 0, i32 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @OBJC_CLASS_NAME_.1, i32 0, i32 0), i8* bitcast ({ i8*, i32, [1 x %struct._objc_method] }* @OBJC_CATEGORY_INSTANCE_METHODS_A_foo to i8*), i8* bitcast (%struct._objc_category* @OBJC_CATEGORY_A_foo to i8*), i8* getelementptr inbounds ([1 x i8], [1 x i8]* @OBJC_CLASS_NAME_.2, i32 0, i32 0), i8* bitcast ({ i32, i8*, i16, i16, [1 x i8*] }* @OBJC_SYMBOLS to i8*), i8* bitcast (%struct._objc_module* @OBJC_MODULES to i8*)], section "llvm.metadata"<br>
+<br>
+; Function Attrs: nounwind ssp<br>
+define internal void @"\01-[A(foo) foo_myStuff]"(%0*, i8*) #0 {<br>
+  %3 = alloca %0*, align 4<br>
+  %4 = alloca i8*, align 4<br>
+  store %0* %0, %0** %3, align 4<br>
+  store i8* %1, i8** %4, align 4<br>
+  ret void<br>
+}<br>
+<br>
+attributes #0 = { nounwind ssp "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+fxsr,+mmx,+sse,+sse2,+sse3,+sse4.1,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" }<br>
+<br>
+!llvm.module.flags = !{!0, !1, !2, !3, !4, !5}<br>
+!llvm.ident = !{!6}<br>
+<br>
+!0 = !{i32 1, !"Objective-C Version", i32 1}<br>
+!1 = !{i32 1, !"Objective-C Image Info Version", i32 0}<br>
+!2 = !{i32 1, !"Objective-C Image Info Section", !"__OBJC, __image_info,regular"}<br>
+!3 = !{i32 4, !"Objective-C Garbage Collection", i32 0}<br>
+!4 = !{i32 1, !"Objective-C Class Properties", i32 64}<br>
+!5 = !{i32 1, !"PIC Level", i32 2}<br>
+!6 = !{!"Apple LLVM version 8.0.0 (clang-800.0.24.1)"}<br>
<br>
Added: llvm/trunk/test/LTO/X86/objc-detection.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/LTO/X86/objc-detection.ll?rev=275125&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/LTO/X86/objc-detection.ll?rev=275125&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/LTO/X86/objc-detection.ll (added)<br>
+++ llvm/trunk/test/LTO/X86/objc-detection.ll Mon Jul 11 18:10:18 2016<br>
@@ -0,0 +1,52 @@<br>
+; RUN: llvm-as < %s -o %t<br>
+; RUN: llvm-lto -check-for-objc %t | FileCheck %s<br>
+<br>
+; CHECK: contains ObjC<br>
+<br>
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"<br>
+target triple = "x86_64-apple-macosx10.12.0"<br>
+<br>
+%0 = type opaque<br>
+%struct._class_t = type { %struct._class_t*, %struct._class_t*, %struct._objc_cache*, i8* (i8*, i8*)**, %struct._class_ro_t* }<br>
+%struct._objc_cache = type opaque<br>
+%struct._class_ro_t = type { i32, i32, i32, i8*, i8*, %struct.__method_list_t*, %struct._objc_protocol_list*, %struct._ivar_list_t*, i8*, %struct._prop_list_t* }<br>
+%struct.__method_list_t = type { i32, i32, [0 x %struct._objc_method] }<br>
+%struct._objc_method = type { i8*, i8*, i8* }<br>
+%struct._objc_protocol_list = type { i64, [0 x %struct._protocol_t*] }<br>
+%struct._protocol_t = type { i8*, i8*, %struct._objc_protocol_list*, %struct.__method_list_t*, %struct.__method_list_t*, %struct.__method_list_t*, %struct.__method_list_t*, %struct._prop_list_t*, i32, i32, i8**, i8*, %struct._prop_list_t* }<br>
+%struct._ivar_list_t = type { i32, i32, [0 x %struct._ivar_t] }<br>
+%struct._ivar_t = type { i64*, i8*, i8*, i32, i32 }<br>
+%struct._prop_list_t = type { i32, i32, [0 x %struct._prop_t] }<br>
+%struct._prop_t = type { i8*, i8* }<br>
+%struct._category_t = type { i8*, %struct._class_t*, %struct.__method_list_t*, %struct.__method_list_t*, %struct._objc_protocol_list*, %struct._prop_list_t*, %struct._prop_list_t*, i32 }<br>
+<br>
+@OBJC_CLASS_NAME_ = private global [4 x i8] c"foo\00", section "__TEXT,__objc_classname,cstring_literals", align 1<br>
+@"OBJC_CLASS_$_A" = external global %struct._class_t<br>
+@OBJC_METH_VAR_NAME_ = private global [12 x i8] c"foo_myStuff\00", section "__TEXT,__objc_methname,cstring_literals", align 1<br>
+@OBJC_METH_VAR_TYPE_ = private global [8 x i8] c"v16@0:8\00", section "__TEXT,__objc_methtype,cstring_literals", align 1<br>
+@"\01l_OBJC_$_CATEGORY_INSTANCE_METHODS_A_$_foo" = private global { i32, i32, [1 x %struct._objc_method] } { i32 24, i32 1, [1 x %struct._objc_method] [%struct._objc_method { i8* getelementptr inbounds ([12 x i8], [12 x i8]* @OBJC_METH_VAR_NAME_, i32 0, i32 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @OBJC_METH_VAR_TYPE_, i32 0, i32 0), i8* bitcast (void (%0*, i8*)* @"\01-[A(foo) foo_myStuff]" to i8*) }] }, section "__DATA, __objc_const", align 8<br>
+@"\01l_OBJC_$_CATEGORY_A_$_foo" = private global %struct._category_t { i8* getelementptr inbounds ([4 x i8], [4 x i8]* @OBJC_CLASS_NAME_, i32 0, i32 0), %struct._class_t* @"OBJC_CLASS_$_A", %struct.__method_list_t* bitcast ({ i32, i32, [1 x %struct._objc_method] }* @"\01l_OBJC_$_CATEGORY_INSTANCE_METHODS_A_$_foo" to %struct.__method_list_t*), %struct.__method_list_t* null, %struct._objc_protocol_list* null, %struct._prop_list_t* null, %struct._prop_list_t* null, i32 64 }, section "__DATA, __objc_const", align 8<br>
+@"OBJC_LABEL_CATEGORY_$" = private global [1 x i8*] [i8* bitcast (%struct._category_t* @"\01l_OBJC_$_CATEGORY_A_$_foo" to i8*)], section "__DATA, __objc_catlist, regular, no_dead_strip", align 8<br>
+@llvm.compiler.used = appending global [6 x i8*] [i8* getelementptr inbounds ([4 x i8], [4 x i8]* @OBJC_CLASS_NAME_, i32 0, i32 0), i8* getelementptr inbounds ([12 x i8], [12 x i8]* @OBJC_METH_VAR_NAME_, i32 0, i32 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @OBJC_METH_VAR_TYPE_, i32 0, i32 0), i8* bitcast ({ i32, i32, [1 x %struct._objc_method] }* @"\01l_OBJC_$_CATEGORY_INSTANCE_METHODS_A_$_foo" to i8*), i8* bitcast (%struct._category_t* @"\01l_OBJC_$_CATEGORY_A_$_foo" to i8*), i8* bitcast ([1 x i8*]* @"OBJC_LABEL_CATEGORY_$" to i8*)], section "llvm.metadata"<br>
+<br>
+; Function Attrs: ssp uwtable<br>
+define internal void @"\01-[A(foo) foo_myStuff]"(%0*, i8*) #0 {<br>
+  %3 = alloca %0*, align 8<br>
+  %4 = alloca i8*, align 8<br>
+  store %0* %0, %0** %3, align 8<br>
+  store i8* %1, i8** %4, align 8<br>
+  ret void<br>
+}<br>
+<br>
+attributes #0 = { ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+fxsr,+mmx,+sse,+sse2,+sse3,+sse4.1,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" }<br>
+<br>
+!llvm.module.flags = !{!0, !1, !2, !3, !4, !5}<br>
+!llvm.ident = !{!6}<br>
+<br>
+!0 = !{i32 1, !"Objective-C Version", i32 2}<br>
+!1 = !{i32 1, !"Objective-C Image Info Version", i32 0}<br>
+!2 = !{i32 1, !"Objective-C Image Info Section", !"__DATA, __objc_imageinfo, regular, no_dead_strip"}<br>
+!3 = !{i32 4, !"Objective-C Garbage Collection", i32 0}<br>
+!4 = !{i32 1, !"Objective-C Class Properties", i32 64}<br>
+!5 = !{i32 1, !"PIC Level", i32 2}<br>
+!6 = !{!"Apple LLVM version 8.0.0 (clang-800.0.24.1)"}<br>
<br>
Modified: llvm/trunk/tools/llvm-lto/llvm-lto.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-lto/llvm-lto.cpp?rev=275125&r1=275124&r2=275125&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-lto/llvm-lto.cpp?rev=275125&r1=275124&r2=275125&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-lto/llvm-lto.cpp (original)<br>
+++ llvm/trunk/tools/llvm-lto/llvm-lto.cpp Mon Jul 11 18:10:18 2016<br>
@@ -156,6 +156,10 @@ static cl::opt<bool> RestoreGlobalsLinka<br>
     "restore-linkage", cl::init(false),<br>
     cl::desc("Restore original linkage of globals prior to CodeGen"));<br>
<br>
+static cl::opt<bool> CheckHasObjC(<br>
+    "check-for-objc", cl::init(false),<br>
+    cl::desc("Only check if the module has objective-C defined in it"));<br>
+<br>
 namespace {<br>
 struct ModuleInfo {<br>
   std::vector<bool> CanBeHidden;<br>
@@ -714,6 +718,21 @@ int main(int argc, char **argv) {<br>
     return 0;<br>
   }<br>
<br>
+  if (CheckHasObjC) {<br>
+    for (auto &Filename : InputFilenames) {<br>
+      ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =<br>
+          MemoryBuffer::getFile(Filename);<br>
+      error(BufferOrErr, "error loading file '" + Filename + "'");<br>
+      auto Buffer = std::move(BufferOrErr.get());<br>
+      LLVMContext Ctx;<br>
+      if (llvm::isBitcodeContainingObjCCategory(*Buffer, Ctx))<br>
+        outs() << "Bitcode " << Filename << " contains ObjC\n";<br>
+      else<br>
+        outs() << "Bitcode " << Filename << " does not contain ObjC\n";<br>
+    }<br>
+    return 0;<br>
+  }<br>
+<br>
   if (ThinLTOMode.getNumOccurrences()) {<br>
     if (ThinLTOMode.getNumOccurrences() > 1)<br>
       report_fatal_error("You can't specify more than one -thinlto-action");<br>
<br>
Modified: llvm/trunk/tools/lto/lto.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lto/lto.cpp?rev=275125&r1=275124&r2=275125&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lto/lto.cpp?rev=275125&r1=275124&r2=275125&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/lto/lto.cpp (original)<br>
+++ llvm/trunk/tools/lto/lto.cpp Mon Jul 11 18:10:18 2016<br>
@@ -14,6 +14,7 @@<br>
<br>
 #include "llvm-c/lto.h"<br>
 #include "llvm/ADT/STLExtras.h"<br>
+#include "llvm/Bitcode/ReaderWriter.h"<br>
 #include "llvm/CodeGen/CommandFlags.h"<br>
 #include "llvm/IR/DiagnosticInfo.h"<br>
 #include "llvm/IR/DiagnosticPrinter.h"<br>
@@ -180,6 +181,14 @@ bool lto_module_is_object_file_for_targe<br>
   return LTOModule::isBitcodeForTarget(Buffer->get(), target_triplet_prefix);<br>
 }<br>
<br>
+bool lto_module_has_objc_category(const void *mem, size_t length) {<br>
+  std::unique_ptr<MemoryBuffer> Buffer(LTOModule::makeBuffer(mem, length));<br>
+  if (!Buffer)<br>
+    return false;<br>
+  LLVMContext Ctx;<br>
+  return llvm::isBitcodeContainingObjCCategory(*Buffer, Ctx);<br>
+}<br>
+<br>
 bool lto_module_is_object_file_in_memory(const void* mem, size_t length) {<br>
   return LTOModule::isBitcodeFile(mem, length);<br>
 }<br>
<br>
Modified: llvm/trunk/tools/lto/lto.exports<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lto/lto.exports?rev=275125&r1=275124&r2=275125&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lto/lto.exports?rev=275125&r1=275124&r2=275125&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/lto/lto.exports (original)<br>
+++ llvm/trunk/tools/lto/lto.exports Mon Jul 11 18:10:18 2016<br>
@@ -18,6 +18,7 @@ lto_module_is_object_file<br>
 lto_module_is_object_file_for_target<br>
 lto_module_is_object_file_in_memory<br>
 lto_module_is_object_file_in_memory_for_target<br>
+lto_module_has_objc_category<br>
 lto_module_dispose<br>
 lto_api_version<br>
 lto_codegen_set_diagnostic_handler<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div></div>