diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h --- a/llvm/include/llvm/InitializePasses.h +++ b/llvm/include/llvm/InitializePasses.h @@ -317,7 +317,7 @@ void initializeNewGVNLegacyPassPass(PassRegistry&); void initializeObjCARCAAWrapperPassPass(PassRegistry&); void initializeObjCARCAPElimPass(PassRegistry&); -void initializeObjCARCContractPass(PassRegistry&); +void initializeObjCARCContractLegacyPassPass(PassRegistry &); void initializeObjCARCExpandPass(PassRegistry&); void initializeObjCARCOptLegacyPassPass(PassRegistry &); void initializeOptimizationRemarkEmitterWrapperPassPass(PassRegistry&); diff --git a/llvm/include/llvm/Transforms/ObjCARC.h b/llvm/include/llvm/Transforms/ObjCARC.h --- a/llvm/include/llvm/Transforms/ObjCARC.h +++ b/llvm/include/llvm/Transforms/ObjCARC.h @@ -44,10 +44,11 @@ // Pass *createObjCARCOptPass(); -class ObjCARCOptPass : public PassInfoMixin { -public: - ObjCARCOptPass() {} +struct ObjCARCOptPass : public PassInfoMixin { + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); +}; +struct ObjCARCContractPass : public PassInfoMixin { PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); }; diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -70,6 +70,7 @@ MODULE_PASS("name-anon-globals", NameAnonGlobalPass()) MODULE_PASS("no-op-module", NoOpModulePass()) MODULE_PASS("objc-arc", ObjCARCOptPass()) +MODULE_PASS("objc-arc-contract", ObjCARCContractPass()) MODULE_PASS("partial-inliner", PartialInlinerPass()) MODULE_PASS("pgo-icall-prom", PGOIndirectCallPromotion()) MODULE_PASS("pgo-instr-gen", PGOInstrumentationGen()) diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARC.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARC.cpp --- a/llvm/lib/Transforms/ObjCARC/ObjCARC.cpp +++ b/llvm/lib/Transforms/ObjCARC/ObjCARC.cpp @@ -29,7 +29,7 @@ initializeObjCARCAAWrapperPassPass(Registry); initializeObjCARCAPElimPass(Registry); initializeObjCARCExpandPass(Registry); - initializeObjCARCContractPass(Registry); + initializeObjCARCContractLegacyPassPass(Registry); initializeObjCARCOptLegacyPassPass(Registry); initializePAEvalPass(Registry); } diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp --- a/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp +++ b/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp @@ -35,10 +35,12 @@ #include "llvm/IR/InlineAsm.h" #include "llvm/IR/InstIterator.h" #include "llvm/IR/Operator.h" +#include "llvm/IR/PassManager.h" #include "llvm/InitializePasses.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/ObjCARC.h" using namespace llvm; using namespace llvm::objcarc; @@ -53,59 +55,66 @@ //===----------------------------------------------------------------------===// namespace { - /// Late ARC optimizations - /// - /// These change the IR in a way that makes it difficult to be analyzed by - /// ObjCARCOpt, so it's run late. - class ObjCARCContract : public FunctionPass { - bool Changed; - AliasAnalysis *AA; - DominatorTree *DT; - ProvenanceAnalysis PA; - ARCRuntimeEntryPoints EP; - - /// A flag indicating whether this optimization pass should run. - bool Run; - - /// The inline asm string to insert between calls and RetainRV calls to make - /// the optimization work on targets which need it. - const MDString *RVInstMarker; - - /// The set of inserted objc_storeStrong calls. If at the end of walking the - /// function we have found no alloca instructions, these calls can be marked - /// "tail". - SmallPtrSet StoreStrongCalls; - - /// Returns true if we eliminated Inst. - bool tryToPeepholeInstruction( - Function &F, Instruction *Inst, inst_iterator &Iter, - SmallPtrSetImpl &DepInsts, - SmallPtrSetImpl &Visited, - bool &TailOkForStoreStrong, - const DenseMap &BlockColors); - - bool optimizeRetainCall(Function &F, Instruction *Retain); - - bool - contractAutorelease(Function &F, Instruction *Autorelease, - ARCInstKind Class, - SmallPtrSetImpl &DependingInstructions, - SmallPtrSetImpl &Visited); - - void tryToContractReleaseIntoStoreStrong( - Instruction *Release, inst_iterator &Iter, - const DenseMap &BlockColors); - - void getAnalysisUsage(AnalysisUsage &AU) const override; - bool doInitialization(Module &M) override; - bool runOnFunction(Function &F) override; - - public: - static char ID; - ObjCARCContract() : FunctionPass(ID) { - initializeObjCARCContractPass(*PassRegistry::getPassRegistry()); - } - }; +/// Late ARC optimizations +/// +/// These change the IR in a way that makes it difficult to be analyzed by +/// ObjCARCOpt, so it's run late. + +class ObjCARCContract { + bool Changed; + AliasAnalysis *AA; + DominatorTree *DT; + ProvenanceAnalysis PA; + ARCRuntimeEntryPoints EP; + + /// A flag indicating whether this optimization pass should run. + bool Run; + + /// The inline asm string to insert between calls and RetainRV calls to make + /// the optimization work on targets which need it. + const MDString *RVInstMarker; + + /// The set of inserted objc_storeStrong calls. If at the end of walking the + /// function we have found no alloca instructions, these calls can be marked + /// "tail". + SmallPtrSet StoreStrongCalls; + + /// Returns true if we eliminated Inst. + bool tryToPeepholeInstruction( + Function &F, Instruction *Inst, inst_iterator &Iter, + SmallPtrSetImpl &DepInsts, + SmallPtrSetImpl &Visited, bool &TailOkForStoreStrong, + const DenseMap &BlockColors); + + bool optimizeRetainCall(Function &F, Instruction *Retain); + + bool + contractAutorelease(Function &F, Instruction *Autorelease, ARCInstKind Class, + SmallPtrSetImpl &DependingInstructions, + SmallPtrSetImpl &Visited); + + void tryToContractReleaseIntoStoreStrong( + Instruction *Release, inst_iterator &Iter, + const DenseMap &BlockColors); + +public: + bool init(Module &M); + bool run(Function &F, AAResults *AA, DominatorTree *DT); +}; + +class ObjCARCContractLegacyPass : public FunctionPass { + ObjCARCContract OCARCC; + +public: + void getAnalysisUsage(AnalysisUsage &AU) const override; + bool doInitialization(Module &M) override; + bool runOnFunction(Function &F) override; + + static char ID; + ObjCARCContractLegacyPass() : FunctionPass(ID) { + initializeObjCARCContractLegacyPassPass(*PassRegistry::getPassRegistry()); + } +}; } //===----------------------------------------------------------------------===// @@ -542,7 +551,22 @@ // Top Level Driver //===----------------------------------------------------------------------===// -bool ObjCARCContract::runOnFunction(Function &F) { +bool ObjCARCContract::init(Module &M) { + // If nothing in the Module uses ARC, don't do anything. + Run = ModuleHasARC(M); + if (!Run) + return false; + + EP.init(&M); + + // Initialize RVInstMarker. + const char *MarkerKey = "clang.arc.retainAutoreleasedReturnValueMarker"; + RVInstMarker = dyn_cast_or_null(M.getModuleFlag(MarkerKey)); + + return false; +} + +bool ObjCARCContract::run(Function &F, AAResults *A, DominatorTree *D) { if (!EnableARCOpts) return false; @@ -550,11 +574,9 @@ if (!Run) return false; - Changed = false; - AA = &getAnalysis().getAAResults(); - DT = &getAnalysis().getDomTree(); - - PA.setAA(&getAnalysis().getAAResults()); + AA = A; + DT = D; + PA.setAA(A); DenseMap BlockColors; if (F.hasPersonalityFn() && @@ -720,33 +742,51 @@ // Misc Pass Manager //===----------------------------------------------------------------------===// -char ObjCARCContract::ID = 0; -INITIALIZE_PASS_BEGIN(ObjCARCContract, "objc-arc-contract", +char ObjCARCContractLegacyPass::ID = 0; +INITIALIZE_PASS_BEGIN(ObjCARCContractLegacyPass, "objc-arc-contract", "ObjC ARC contraction", false, false) INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) -INITIALIZE_PASS_END(ObjCARCContract, "objc-arc-contract", +INITIALIZE_PASS_END(ObjCARCContractLegacyPass, "objc-arc-contract", "ObjC ARC contraction", false, false) -void ObjCARCContract::getAnalysisUsage(AnalysisUsage &AU) const { +void ObjCARCContractLegacyPass::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); AU.addRequired(); AU.setPreservesCFG(); } -Pass *llvm::createObjCARCContractPass() { return new ObjCARCContract(); } +Pass *llvm::createObjCARCContractPass() { + return new ObjCARCContractLegacyPass(); +} -bool ObjCARCContract::doInitialization(Module &M) { - // If nothing in the Module uses ARC, don't do anything. - Run = ModuleHasARC(M); - if (!Run) - return false; +bool ObjCARCContractLegacyPass::doInitialization(Module &M) { + return OCARCC.init(M); +} - EP.init(&M); +bool ObjCARCContractLegacyPass::runOnFunction(Function &F) { + auto *AA = &getAnalysis().getAAResults(); + auto *DT = &getAnalysis().getDomTree(); + return OCARCC.run(F, AA, DT); +} - // Initialize RVInstMarker. - const char *MarkerKey = "clang.arc.retainAutoreleasedReturnValueMarker"; - RVInstMarker = dyn_cast_or_null(M.getModuleFlag(MarkerKey)); +PreservedAnalyses ObjCARCContractPass::run(Module &M, + ModuleAnalysisManager &AM) { + ObjCARCContract OCAC; + OCAC.init(M); - return false; + auto &FAM = AM.getResult(M).getManager(); + bool Changed = false; + for (Function &F : M) { + if (F.isDeclaration()) + continue; + Changed |= OCAC.run(F, &FAM.getResult(F), + &FAM.getResult(F)); + } + if (Changed) { + PreservedAnalyses PA; + PA.preserveSet(); + return PA; + } + return PreservedAnalyses::all(); } diff --git a/llvm/test/Transforms/ObjCARC/contract.ll b/llvm/test/Transforms/ObjCARC/contract.ll --- a/llvm/test/Transforms/ObjCARC/contract.ll +++ b/llvm/test/Transforms/ObjCARC/contract.ll @@ -1,4 +1,5 @@ ; RUN: opt -objc-arc-contract -S < %s | FileCheck %s +; RUN: opt -passes=objc-arc-contract -S < %s | FileCheck %s target datalayout = "e-p:64:64:64"