[llvm] r275125 - Add a libLTO API to query a memory buffer and check if it contains ObjC categories

Sean Silva via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 11 16:25:57 PDT 2016


On Mon, Jul 11, 2016 at 4:10 PM, Mehdi Amini via llvm-commits <
llvm-commits at lists.llvm.org> wrote:

> Author: mehdi_amini
> Date: Mon Jul 11 18:10:18 2016
> New Revision: 275125
>
> URL: http://llvm.org/viewvc/llvm-project?rev=275125&view=rev
> Log:
> Add a libLTO API to query a memory buffer and check if it contains ObjC
> categories
>
> The linker supports a feature to force load an object from a static
> archive if it defines an Objective-C category.
> This API supports this feature by looking at every section in the
> module to find if a category is defined in the module.
>
> Added:
>     llvm/trunk/test/LTO/X86/objc-detection-i386.ll
>     llvm/trunk/test/LTO/X86/objc-detection.ll
> Modified:
>     llvm/trunk/include/llvm-c/lto.h
>     llvm/trunk/include/llvm/Bitcode/ReaderWriter.h
>     llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp
>     llvm/trunk/tools/llvm-lto/llvm-lto.cpp
>     llvm/trunk/tools/lto/lto.cpp
>     llvm/trunk/tools/lto/lto.exports
>
> Modified: llvm/trunk/include/llvm-c/lto.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm-c/lto.h?rev=275125&r1=275124&r2=275125&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm-c/lto.h (original)
> +++ llvm/trunk/include/llvm-c/lto.h Mon Jul 11 18:10:18 2016
> @@ -44,7 +44,7 @@ typedef bool lto_bool_t;
>   * @{
>   */
>
> -#define LTO_API_VERSION 19
> +#define LTO_API_VERSION 20
>
>  /**
>   * \since prior to LTO_API_VERSION=3
> @@ -136,12 +136,20 @@ lto_module_is_object_file_for_target(con
>                                       const char* target_triple_prefix);
>
>  /**
> - * Checks if a buffer is a loadable object file.
> + * Return true if \p Buffer contains a bitcode file with ObjC code
> (category
> + * or class) in it.
>   *
> - * \since prior to LTO_API_VERSION=3
> + * \since LTO_API_VERSION=20
>   */
> -extern lto_bool_t
> -lto_module_is_object_file_in_memory(const void* mem, size_t length);
> +bool lto_module_has_objc_category(const void *mem, size_t length);
> +
> +/**
> +* Checks if a buffer is a loadable object file.
> +*
> +* \since prior to LTO_API_VERSION=3
> +*/
> +extern lto_bool_t lto_module_is_object_file_in_memory(const void *mem,
> +                                                      size_t length);
>
>  /**
>   * Checks if a buffer is a loadable object compiled for requested target.
>
> Modified: llvm/trunk/include/llvm/Bitcode/ReaderWriter.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Bitcode/ReaderWriter.h?rev=275125&r1=275124&r2=275125&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/Bitcode/ReaderWriter.h (original)
> +++ llvm/trunk/include/llvm/Bitcode/ReaderWriter.h Mon Jul 11 18:10:18 2016
> @@ -60,6 +60,11 @@ namespace llvm {
>    std::string getBitcodeTargetTriple(MemoryBufferRef Buffer,
>                                       LLVMContext &Context);
>
> +  /// Return true if \p Buffer contains a bitcode file with ObjC code
> (category
> +  /// or class) in it.
> +  bool isBitcodeContainingObjCCategory(MemoryBufferRef Buffer,
> +                                       LLVMContext &Context);
> +
>    /// Read the header of the specified bitcode buffer and extract just the
>    /// producer string information. If successful, this returns a string.
> On
>    /// error, this returns "".
>
> Modified: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp?rev=275125&r1=275124&r2=275125&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp (original)
> +++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp Mon Jul 11 18:10:18
> 2016
> @@ -313,6 +313,10 @@ public:
>    /// Cheap mechanism to just extract the identification block out of
> bitcode.
>    ErrorOr<std::string> parseIdentificationBlock();
>
> +  /// Peak at the module content and return true if any ObjC category or
> class
> +  /// is found.
> +  ErrorOr<bool> hasObjCCategory();
> +
>    static uint64_t decodeSignRotatedValue(uint64_t V);
>
>    /// Materialize any deferred Metadata block.
> @@ -450,6 +454,7 @@ private:
>                                ArrayRef<uint64_t> Record);
>    std::error_code parseMetadataAttachment(Function &F);
>    ErrorOr<std::string> parseModuleTriple();
> +  ErrorOr<bool> hasObjCCategoryInModule();
>    std::error_code parseUseLists();
>    std::error_code initStream(std::unique_ptr<DataStreamer> Streamer);
>    std::error_code initStreamFromBuffer();
> @@ -4195,6 +4200,81 @@ std::error_code BitcodeReader::parseGlob
>    return std::error_code();
>  }
>
> +ErrorOr<bool> BitcodeReader::hasObjCCategory() {
> +  if (std::error_code EC = initStream(nullptr))
> +    return EC;
> +
> +  // Sniff for the signature.
> +  if (!hasValidBitcodeHeader(Stream))
> +    return error("Invalid bitcode signature");
> +
> +  // We expect a number of well-defined blocks, though we don't
> necessarily
> +  // need to understand them all.
> +  while (1) {
> +    BitstreamEntry Entry = Stream.advance();
> +
> +    switch (Entry.Kind) {
> +    case BitstreamEntry::Error:
> +      return error("Malformed block");
> +    case BitstreamEntry::EndBlock:
> +      return std::error_code();
>

What does it mean to return a success error_code into an ErrorOr? Would it
be the same as doing `return false;` here?

-- Sean Silva


> +
> +    case BitstreamEntry::SubBlock:
> +      if (Entry.ID == bitc::MODULE_BLOCK_ID)
> +        return hasObjCCategoryInModule();
> +
> +      // Ignore other sub-blocks.
> +      if (Stream.SkipBlock())
> +        return error("Malformed block");
> +      continue;
> +
> +    case BitstreamEntry::Record:
> +      Stream.skipRecord(Entry.ID);
> +      continue;
> +    }
> +  }
> +}
> +
> +ErrorOr<bool> BitcodeReader::hasObjCCategoryInModule() {
> +  if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID))
> +    return error("Invalid record");
> +
> +  SmallVector<uint64_t, 64> Record;
> +  // Read all the records for this module.
> +  while (1) {
> +    BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
> +
> +    switch (Entry.Kind) {
> +    case BitstreamEntry::SubBlock: // Handled for us already.
> +    case BitstreamEntry::Error:
> +      return error("Malformed block");
> +    case BitstreamEntry::EndBlock:
> +      return false;
> +    case BitstreamEntry::Record:
> +      // The interesting case.
> +      break;
> +    }
> +
> +    // Read a record.
> +    switch (Stream.readRecord(Entry.ID, Record)) {
> +    default:
> +      break; // Default behavior, ignore unknown content.
> +    case bitc::MODULE_CODE_SECTIONNAME: { // SECTIONNAME: [strchr x N]
> +      std::string S;
> +      if (convertToString(Record, 0, S))
> +        return error("Invalid record");
> +      // Check for the i386 and other (x86_64, ARM) conventions
> +      if (S.find("__DATA, __objc_catlist") != std::string::npos ||
> +          S.find("__OBJC,__category") != std::string::npos)
> +        return true;
> +      break;
> +    }
> +    }
> +    Record.clear();
> +  }
> +  llvm_unreachable("Exit infinite loop");
> +}
> +
>  /// Parse metadata attachments.
>  std::error_code BitcodeReader::parseMetadataAttachment(Function &F) {
>    if (Stream.EnterSubBlock(bitc::METADATA_ATTACHMENT_ID))
> @@ -6548,6 +6628,16 @@ std::string llvm::getBitcodeTargetTriple
>    return Triple.get();
>  }
>
> +bool llvm::isBitcodeContainingObjCCategory(MemoryBufferRef Buffer,
> +                                           LLVMContext &Context) {
> +  std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Buffer,
> false);
> +  auto R = llvm::make_unique<BitcodeReader>(Buf.release(), Context);
> +  ErrorOr<bool> hasObjCCategory = R->hasObjCCategory();
> +  if (hasObjCCategory.getError())
> +    return false;
> +  return hasObjCCategory.get();
> +}
> +
>  std::string llvm::getBitcodeProducerString(MemoryBufferRef Buffer,
>                                             LLVMContext &Context) {
>    std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Buffer,
> false);
>
> Added: llvm/trunk/test/LTO/X86/objc-detection-i386.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/LTO/X86/objc-detection-i386.ll?rev=275125&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/LTO/X86/objc-detection-i386.ll (added)
> +++ llvm/trunk/test/LTO/X86/objc-detection-i386.ll Mon Jul 11 18:10:18 2016
> @@ -0,0 +1,59 @@
> +; RUN: llvm-as < %s -o %t
> +; RUN: llvm-lto -check-for-objc %t | FileCheck %s
> +
> +; CHECK: contains ObjC
> +
> +
> +target datalayout = "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128"
> +target triple = "i386-apple-macosx10.12.0"
> +
> +module asm "\09.lazy_reference .objc_class_name_A"
> +module asm "\09.objc_category_name_A_foo=0"
> +module asm "\09.globl .objc_category_name_A_foo"
> +
> +%0 = type opaque
> +%struct._objc_method = type { i8*, i8*, i8* }
> +%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* }
> +%struct._objc_method_list = type opaque
> +%struct._objc_protocol_list = type { %struct._objc_protocol_list*, i32,
> [0 x %struct._objc_protocol] }
> +%struct._objc_protocol = type { %struct._objc_protocol_extension*, i8*,
> %struct._objc_protocol_list*, %struct._objc_method_description_list*,
> %struct._objc_method_description_list* }
> +%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* }
> +%struct._objc_method_description_list = type { i32, [0 x
> %struct._objc_method_description] }
> +%struct._objc_method_description = type { i8*, i8* }
> +%struct._prop_list_t = type { i32, i32, [0 x %struct._prop_t] }
> +%struct._prop_t = type { i8*, i8* }
> +%struct._objc_module = type { i32, i32, i8*, %struct._objc_symtab* }
> +%struct._objc_symtab = type { i32, i8*, i16, i16, [0 x i8*] }
> +
> + at OBJC_METH_VAR_NAME_ = private global [12 x i8] c"foo_myStuff\00",
> section "__TEXT,__cstring,cstring_literals", align 1
> + at OBJC_METH_VAR_TYPE_ = private global [7 x i8] c"v8 at 0:4\00", section
> "__TEXT,__cstring,cstring_literals", align 1
> + at OBJC_CLASS_NAME_ = private global [4 x i8] c"foo\00", section
> "__TEXT,__cstring,cstring_literals", align 1
> + at OBJC_CLASS_NAME_.1 = private global [2 x i8] c"A\00", section
> "__TEXT,__cstring,cstring_literals", align 1
> + at 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
> + at 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
> + at OBJC_CLASS_NAME_.2 = private global [1 x i8] zeroinitializer, section
> "__TEXT,__cstring,cstring_literals", align 1
> + at 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
> + at 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
> + at 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"
> +
> +; Function Attrs: nounwind ssp
> +define internal void @"\01-[A(foo) foo_myStuff]"(%0*, i8*) #0 {
> +  %3 = alloca %0*, align 4
> +  %4 = alloca i8*, align 4
> +  store %0* %0, %0** %3, align 4
> +  store i8* %1, i8** %4, align 4
> +  ret void
> +}
> +
> +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" }
> +
> +!llvm.module.flags = !{!0, !1, !2, !3, !4, !5}
> +!llvm.ident = !{!6}
> +
> +!0 = !{i32 1, !"Objective-C Version", i32 1}
> +!1 = !{i32 1, !"Objective-C Image Info Version", i32 0}
> +!2 = !{i32 1, !"Objective-C Image Info Section", !"__OBJC,
> __image_info,regular"}
> +!3 = !{i32 4, !"Objective-C Garbage Collection", i32 0}
> +!4 = !{i32 1, !"Objective-C Class Properties", i32 64}
> +!5 = !{i32 1, !"PIC Level", i32 2}
> +!6 = !{!"Apple LLVM version 8.0.0 (clang-800.0.24.1)"}
>
> Added: llvm/trunk/test/LTO/X86/objc-detection.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/LTO/X86/objc-detection.ll?rev=275125&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/LTO/X86/objc-detection.ll (added)
> +++ llvm/trunk/test/LTO/X86/objc-detection.ll Mon Jul 11 18:10:18 2016
> @@ -0,0 +1,52 @@
> +; RUN: llvm-as < %s -o %t
> +; RUN: llvm-lto -check-for-objc %t | FileCheck %s
> +
> +; CHECK: contains ObjC
> +
> +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
> +target triple = "x86_64-apple-macosx10.12.0"
> +
> +%0 = type opaque
> +%struct._class_t = type { %struct._class_t*, %struct._class_t*,
> %struct._objc_cache*, i8* (i8*, i8*)**, %struct._class_ro_t* }
> +%struct._objc_cache = type opaque
> +%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* }
> +%struct.__method_list_t = type { i32, i32, [0 x %struct._objc_method] }
> +%struct._objc_method = type { i8*, i8*, i8* }
> +%struct._objc_protocol_list = type { i64, [0 x %struct._protocol_t*] }
> +%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* }
> +%struct._ivar_list_t = type { i32, i32, [0 x %struct._ivar_t] }
> +%struct._ivar_t = type { i64*, i8*, i8*, i32, i32 }
> +%struct._prop_list_t = type { i32, i32, [0 x %struct._prop_t] }
> +%struct._prop_t = type { i8*, i8* }
> +%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 }
> +
> + at OBJC_CLASS_NAME_ = private global [4 x i8] c"foo\00", section
> "__TEXT,__objc_classname,cstring_literals", align 1
> +@"OBJC_CLASS_$_A" = external global %struct._class_t
> + at OBJC_METH_VAR_NAME_ = private global [12 x i8] c"foo_myStuff\00",
> section "__TEXT,__objc_methname,cstring_literals", align 1
> + at OBJC_METH_VAR_TYPE_ = private global [8 x i8] c"v16 at 0:8\00", section
> "__TEXT,__objc_methtype,cstring_literals", align 1
> +@"\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
> +@"\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
> +@"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
> + at 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"
> +
> +; Function Attrs: ssp uwtable
> +define internal void @"\01-[A(foo) foo_myStuff]"(%0*, i8*) #0 {
> +  %3 = alloca %0*, align 8
> +  %4 = alloca i8*, align 8
> +  store %0* %0, %0** %3, align 8
> +  store i8* %1, i8** %4, align 8
> +  ret void
> +}
> +
> +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" }
> +
> +!llvm.module.flags = !{!0, !1, !2, !3, !4, !5}
> +!llvm.ident = !{!6}
> +
> +!0 = !{i32 1, !"Objective-C Version", i32 2}
> +!1 = !{i32 1, !"Objective-C Image Info Version", i32 0}
> +!2 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,
> __objc_imageinfo, regular, no_dead_strip"}
> +!3 = !{i32 4, !"Objective-C Garbage Collection", i32 0}
> +!4 = !{i32 1, !"Objective-C Class Properties", i32 64}
> +!5 = !{i32 1, !"PIC Level", i32 2}
> +!6 = !{!"Apple LLVM version 8.0.0 (clang-800.0.24.1)"}
>
> Modified: llvm/trunk/tools/llvm-lto/llvm-lto.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-lto/llvm-lto.cpp?rev=275125&r1=275124&r2=275125&view=diff
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-lto/llvm-lto.cpp (original)
> +++ llvm/trunk/tools/llvm-lto/llvm-lto.cpp Mon Jul 11 18:10:18 2016
> @@ -156,6 +156,10 @@ static cl::opt<bool> RestoreGlobalsLinka
>      "restore-linkage", cl::init(false),
>      cl::desc("Restore original linkage of globals prior to CodeGen"));
>
> +static cl::opt<bool> CheckHasObjC(
> +    "check-for-objc", cl::init(false),
> +    cl::desc("Only check if the module has objective-C defined in it"));
> +
>  namespace {
>  struct ModuleInfo {
>    std::vector<bool> CanBeHidden;
> @@ -714,6 +718,21 @@ int main(int argc, char **argv) {
>      return 0;
>    }
>
> +  if (CheckHasObjC) {
> +    for (auto &Filename : InputFilenames) {
> +      ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
> +          MemoryBuffer::getFile(Filename);
> +      error(BufferOrErr, "error loading file '" + Filename + "'");
> +      auto Buffer = std::move(BufferOrErr.get());
> +      LLVMContext Ctx;
> +      if (llvm::isBitcodeContainingObjCCategory(*Buffer, Ctx))
> +        outs() << "Bitcode " << Filename << " contains ObjC\n";
> +      else
> +        outs() << "Bitcode " << Filename << " does not contain ObjC\n";
> +    }
> +    return 0;
> +  }
> +
>    if (ThinLTOMode.getNumOccurrences()) {
>      if (ThinLTOMode.getNumOccurrences() > 1)
>        report_fatal_error("You can't specify more than one
> -thinlto-action");
>
> Modified: llvm/trunk/tools/lto/lto.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lto/lto.cpp?rev=275125&r1=275124&r2=275125&view=diff
>
> ==============================================================================
> --- llvm/trunk/tools/lto/lto.cpp (original)
> +++ llvm/trunk/tools/lto/lto.cpp Mon Jul 11 18:10:18 2016
> @@ -14,6 +14,7 @@
>
>  #include "llvm-c/lto.h"
>  #include "llvm/ADT/STLExtras.h"
> +#include "llvm/Bitcode/ReaderWriter.h"
>  #include "llvm/CodeGen/CommandFlags.h"
>  #include "llvm/IR/DiagnosticInfo.h"
>  #include "llvm/IR/DiagnosticPrinter.h"
> @@ -180,6 +181,14 @@ bool lto_module_is_object_file_for_targe
>    return LTOModule::isBitcodeForTarget(Buffer->get(),
> target_triplet_prefix);
>  }
>
> +bool lto_module_has_objc_category(const void *mem, size_t length) {
> +  std::unique_ptr<MemoryBuffer> Buffer(LTOModule::makeBuffer(mem,
> length));
> +  if (!Buffer)
> +    return false;
> +  LLVMContext Ctx;
> +  return llvm::isBitcodeContainingObjCCategory(*Buffer, Ctx);
> +}
> +
>  bool lto_module_is_object_file_in_memory(const void* mem, size_t length) {
>    return LTOModule::isBitcodeFile(mem, length);
>  }
>
> Modified: llvm/trunk/tools/lto/lto.exports
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lto/lto.exports?rev=275125&r1=275124&r2=275125&view=diff
>
> ==============================================================================
> --- llvm/trunk/tools/lto/lto.exports (original)
> +++ llvm/trunk/tools/lto/lto.exports Mon Jul 11 18:10:18 2016
> @@ -18,6 +18,7 @@ lto_module_is_object_file
>  lto_module_is_object_file_for_target
>  lto_module_is_object_file_in_memory
>  lto_module_is_object_file_in_memory_for_target
> +lto_module_has_objc_category
>  lto_module_dispose
>  lto_api_version
>  lto_codegen_set_diagnostic_handler
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20160711/c6c4e91a/attachment.html>


More information about the llvm-commits mailing list