diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h --- a/lld/MachO/Config.h +++ b/lld/MachO/Config.h @@ -47,6 +47,7 @@ bool implicitDylibs = false; bool isPic = false; bool headerPadMaxInstallNames = false; + bool ltoNewPassManager = LLVM_ENABLE_NEW_PASS_MANAGER; bool printEachFile = false; bool printWhyLoad = false; bool searchDylibsFirst = false; diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -735,6 +735,9 @@ config->printWhyLoad = args.hasArg(OPT_why_load); config->outputType = getOutputType(args); config->ltoObjPath = args.getLastArgValue(OPT_object_path_lto); + config->ltoNewPassManager = + args.hasFlag(OPT_no_lto_legacy_pass_manager, OPT_lto_legacy_pass_manager, + LLVM_ENABLE_NEW_PASS_MANAGER); config->runtimePaths = args::getStrings(args, OPT_rpath); config->allLoad = args.hasArg(OPT_all_load); config->forceLoadObjC = args.hasArg(OPT_ObjC); diff --git a/lld/MachO/LTO.cpp b/lld/MachO/LTO.cpp --- a/lld/MachO/LTO.cpp +++ b/lld/MachO/LTO.cpp @@ -31,6 +31,7 @@ c.CodeModel = getCodeModelFromCMModel(); c.CPU = getCPUStr(); c.MAttrs = getMAttrs(); + c.UseNewPM = config->ltoNewPassManager; return c; } diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td --- a/lld/MachO/Options.td +++ b/lld/MachO/Options.td @@ -29,6 +29,12 @@ def version: Flag<["--"], "version">, HelpText<"Display the version number and exit">, Group; +def lto_legacy_pass_manager: Flag<["--"], "lto-legacy-pass-manager">, + HelpText<"Use the legacy pass manager in LLVM">, + Group; +def no_lto_legacy_pass_manager : Flag<["--"], "no-lto-legacy-pass-manager">, + HelpText<"Use the new pass manager in LLVM">, + Group; // This is a complete Options.td compiled from Apple's ld(1) manpage diff --git a/lld/test/MachO/objc-arc-contract.ll b/lld/test/MachO/objc-arc-contract.ll new file mode 100644 --- /dev/null +++ b/lld/test/MachO/objc-arc-contract.ll @@ -0,0 +1,30 @@ +; REQUIRES: x86 + +;; Verify that we run the ObjCARCContractPass during LTO. Without that, the +;; objc.clang.arc.use intrinsic will get passed to the instruction selector, +;; which doesn't know how to handle it. + +; RUN: llvm-as %s -o %t.o +; RUN: %lld -dylib -lSystem %t.o -o %t --lto-legacy-pass-manager +; RUN: llvm-objdump -d %t | FileCheck %s +; RUN: %lld -dylib -lSystem %t.o -o %t --no-lto-legacy-pass-manager +; RUN: llvm-objdump -d %t | FileCheck %s + +; RUN: opt -module-summary %s -o %t.o +; RUN: %lld -dylib -lSystem %t.o -o %t --lto-legacy-pass-manager +; RUN: llvm-objdump -d %t | FileCheck %s +; RUN: %lld -dylib -lSystem %t.o -o %t --no-lto-legacy-pass-manager +; RUN: llvm-objdump -d %t | FileCheck %s + +; CHECK: <_foo>: +; CHECK-NEXT: retq + +target triple = "x86_64-apple-darwin" +target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + +define void @foo(i8* %a, i8* %b) { + call void (...) @llvm.objc.clang.arc.use(i8* %a, i8* %b) nounwind + ret void +} + +declare void @llvm.objc.clang.arc.use(...) nounwind diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -43,6 +43,7 @@ #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" +#include "llvm/Transforms/ObjCARC.h" #include "llvm/Transforms/Scalar/LoopPassManager.h" #include "llvm/Transforms/Utils/FunctionImportUtils.h" #include "llvm/Transforms/Utils/SplitModule.h" @@ -281,6 +282,7 @@ if (!Conf.DisableVerify) MPM.addPass(VerifierPass()); + MPM.addPass(createModuleToFunctionPassAdaptor(ObjCARCContractPass())); MPM.run(Mod, MAM); } @@ -357,6 +359,8 @@ PMB.populateThinLTOPassManager(passes); else PMB.populateLTOPassManager(passes); + + passes.add(createObjCARCContractPass()); passes.run(Mod); }