diff --git a/llvm/docs/LinkTimeOptimization.rst b/llvm/docs/LinkTimeOptimization.rst --- a/llvm/docs/LinkTimeOptimization.rst +++ b/llvm/docs/LinkTimeOptimization.rst @@ -249,6 +249,12 @@ The attributes of a symbol include the alignment, visibility, and kind. +Tools working with object files on Darwin (e.g. lipo) may need to know properties like the CPU type: + +.. code-block:: c + + lto_module_get_macho_cputype(lto_module_t mod, unsigned int *out_cputype, unsigned int *out_cpusubtype) + ``lto_code_gen_t`` ------------------ diff --git a/llvm/include/llvm-c/lto.h b/llvm/include/llvm-c/lto.h --- a/llvm/include/llvm-c/lto.h +++ b/llvm/include/llvm-c/lto.h @@ -46,7 +46,7 @@ * @{ */ -#define LTO_API_VERSION 26 +#define LTO_API_VERSION 27 /** * \since prior to LTO_API_VERSION=3 @@ -298,6 +298,21 @@ lto_module_get_linkeropts(lto_module_t mod); /** + * If targeting mach-o on darwin, this function gets the CPU type and subtype + * that will end up being encoded in the mach-o header. These are the values + * that can be found in mach/machine.h. + * + * \p out_cputype and \p out_cpusubtype must be non-NULL. + * + * Returns true on error (check lto_get_error_message() for details). + * + * \since LTO_API_VERSION=27 + */ +extern lto_bool_t lto_module_get_macho_cputype(lto_module_t mod, + unsigned int *out_cputype, + unsigned int *out_cpusubtype); + +/** * Diagnostic severity. * * \since LTO_API_VERSION=7 diff --git a/llvm/include/llvm/LTO/legacy/LTOModule.h b/llvm/include/llvm/LTO/legacy/LTOModule.h --- a/llvm/include/llvm/LTO/legacy/LTOModule.h +++ b/llvm/include/llvm/LTO/legacy/LTOModule.h @@ -165,6 +165,10 @@ static const char *getDependentLibrary(lto::InputFile *input, size_t index, size_t *size); + Expected getMachOCPUType() const; + + Expected getMachOCPUSubType() const; + private: /// Parse metadata from the module // FIXME: it only parses "llvm.linker.options" metadata at the moment diff --git a/llvm/lib/LTO/LTOModule.cpp b/llvm/lib/LTO/LTOModule.cpp --- a/llvm/lib/LTO/LTOModule.cpp +++ b/llvm/lib/LTO/LTOModule.cpp @@ -28,6 +28,7 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/MC/SubtargetFeature.h" #include "llvm/Object/IRObjectFile.h" +#include "llvm/Object/MachO.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" @@ -676,3 +677,11 @@ *size = S.size(); return S.data(); } + +Expected LTOModule::getMachOCPUType() const { + return MachO::getCPUType(Triple(Mod->getTargetTriple())); +} + +Expected LTOModule::getMachOCPUSubType() const { + return MachO::getCPUSubType(Triple(Mod->getTargetTriple())); +} diff --git a/llvm/test/LTO/X86/print-macho-cpu.ll b/llvm/test/LTO/X86/print-macho-cpu.ll new file mode 100644 --- /dev/null +++ b/llvm/test/LTO/X86/print-macho-cpu.ll @@ -0,0 +1,8 @@ +; RUN: rm -rf %t && mkdir -p %t +; RUN: llvm-as -o %t/1.bc %s +; RUN: llvm-lto -print-macho-cpu-only %t/1.bc | FileCheck %s + +target triple = "x86_64-apple-darwin" +; CHECK: 1.bc: +; CHECK-NEXT: cputype: 16777223 +; CHECK-NEXT: cpusubtype: 3 diff --git a/llvm/test/tools/llvm-lto/error.ll b/llvm/test/tools/llvm-lto/error.ll --- a/llvm/test/tools/llvm-lto/error.ll +++ b/llvm/test/tools/llvm-lto/error.ll @@ -7,5 +7,8 @@ ; RUN: not llvm-lto --list-dependent-libraries-only %S/Inputs/empty.bc 2>&1 | FileCheck %s --check-prefix=CHECK-LIBS ; CHECK-LIBS: llvm-lto: {{.*}}/Inputs/empty.bc: Could not read LTO input file: The file was not recognized as a valid object file +; RUN: not llvm-lto --print-macho-cpu-only %S/Inputs/empty.bc 2>&1 | FileCheck %s --check-prefix=CHECK-MACHO +; CHECK-MACHO: llvm-lto: error: The file was not recognized as a valid object file + ; RUN: not llvm-lto --thinlto %S/Inputs/empty.bc 2>&1 | FileCheck %s --check-prefix=CHECK-THIN ; CHECK-THIN: llvm-lto: error loading file '{{.*}}/Inputs/empty.bc': file too small to contain bitcode header diff --git a/llvm/tools/llvm-lto/llvm-lto.cpp b/llvm/tools/llvm-lto/llvm-lto.cpp --- a/llvm/tools/llvm-lto/llvm-lto.cpp +++ b/llvm/tools/llvm-lto/llvm-lto.cpp @@ -223,6 +223,10 @@ "check-for-objc", cl::init(false), cl::desc("Only check if the module has objective-C defined in it")); +static cl::opt PrintMachOCPUOnly( + "print-macho-cpu-only", cl::init(false), + cl::desc("Instead of running LTO, print the mach-o cpu in each IR file")); + namespace { struct ModuleInfo { @@ -404,6 +408,30 @@ } } +static void printMachOCPUOnly() { + LLVMContext Context; + Context.setDiagnosticHandler(std::make_unique(), + true); + TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); + for (auto &Filename : InputFilenames) { + ErrorOr> ModuleOrErr = + LTOModule::createFromFile(Context, Filename, Options); + if (!ModuleOrErr) + error(ModuleOrErr, "llvm-lto: "); + + Expected CPUType = (*ModuleOrErr)->getMachOCPUType(); + Expected CPUSubType = (*ModuleOrErr)->getMachOCPUSubType(); + if (!CPUType) + error("Error while printing mach-o cputype: " + + toString(CPUType.takeError())); + if (!CPUSubType) + error("Error while printing mach-o cpusubtype: " + + toString(CPUSubType.takeError())); + outs() << llvm::format("%s:\ncputype: %u\ncpusubtype: %u\n", + Filename.c_str(), *CPUType, *CPUSubType); + } +} + /// Create a combined index file from the input IR files and write it. /// /// This is meant to enable testing of ThinLTO combined index generation, @@ -905,6 +933,11 @@ return 0; } + if (PrintMachOCPUOnly) { + printMachOCPUOnly(); + return 0; + } + if (ThinLTOMode.getNumOccurrences()) { if (ThinLTOMode.getNumOccurrences() > 1) report_fatal_error("You can't specify more than one -thinlto-action"); diff --git a/llvm/tools/lto/lto.cpp b/llvm/tools/lto/lto.cpp --- a/llvm/tools/lto/lto.cpp +++ b/llvm/tools/lto/lto.cpp @@ -327,6 +327,27 @@ return unwrap(mod)->getLinkerOpts().data(); } +lto_bool_t lto_module_get_macho_cputype(lto_module_t mod, + unsigned int *out_cputype, + unsigned int *out_cpusubtype) { + LTOModule *M = unwrap(mod); + Expected CPUType = M->getMachOCPUType(); + if (!CPUType) { + sLastErrorString = toString(CPUType.takeError()); + return true; + } + *out_cputype = *CPUType; + + Expected CPUSubType = M->getMachOCPUSubType(); + if (!CPUSubType) { + sLastErrorString = toString(CPUSubType.takeError()); + return true; + } + *out_cpusubtype = *CPUSubType; + + return false; +} + void lto_codegen_set_diagnostic_handler(lto_code_gen_t cg, lto_diagnostic_handler_t diag_handler, void *ctxt) { diff --git a/llvm/tools/lto/lto.exports b/llvm/tools/lto/lto.exports --- a/llvm/tools/lto/lto.exports +++ b/llvm/tools/lto/lto.exports @@ -9,6 +9,7 @@ lto_module_create_in_local_context lto_module_create_in_codegen_context lto_module_get_linkeropts +lto_module_get_macho_cputype lto_module_get_num_symbols lto_module_get_symbol_attribute lto_module_get_symbol_name