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 @@ -316,7 +316,7 @@ void initializeObjCARCAPElimPass(PassRegistry&); void initializeObjCARCContractPass(PassRegistry&); void initializeObjCARCExpandPass(PassRegistry&); -void initializeObjCARCOptPass(PassRegistry&); +void initializeObjCARCOptLegacyPassPass(PassRegistry &); void initializeOptimizationRemarkEmitterWrapperPassPass(PassRegistry&); void initializeOptimizePHIsPass(PassRegistry&); void initializePAEvalPass(PassRegistry&); diff --git a/llvm/include/llvm/Transforms/ObjCARC/ObjCARCOpts.h b/llvm/include/llvm/Transforms/ObjCARC/ObjCARCOpts.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Transforms/ObjCARC/ObjCARCOpts.h @@ -0,0 +1,34 @@ +//===- ObjCARCOpts.h - ObjC ARC Optimization ------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +/// \file +/// This file defines ObjC ARC optimizations. ARC stands for Automatic +/// Reference Counting and is a system for managing reference counts for objects +/// in Objective C. +/// +/// The optimizations performed include elimination of redundant, partially +/// redundant, and inconsequential reference count operations, elimination of +/// redundant weak pointer operations, and numerous minor simplifications. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_OBJCARC_OBJCARCOPTS_H +#define LLVM_TRANSFORMS_OBJCARC_OBJCARCOPTS_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { +class ObjCARCOptPass : public PassInfoMixin { +public: + ObjCARCOptPass() {} + + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); +}; +} // namespace llvm + +#endif // LLVM_TRANSFORMS_OBJCARC_OBJCARCOPTS_H diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -116,6 +116,7 @@ #include "llvm/Transforms/Instrumentation/PoisonChecking.h" #include "llvm/Transforms/Instrumentation/SanitizerCoverage.h" #include "llvm/Transforms/Instrumentation/ThreadSanitizer.h" +#include "llvm/Transforms/ObjCARC/ObjCARCOpts.h" #include "llvm/Transforms/Scalar/ADCE.h" #include "llvm/Transforms/Scalar/AlignmentFromAssumptions.h" #include "llvm/Transforms/Scalar/BDCE.h" 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 @@ -69,6 +69,7 @@ MODULE_PASS("mergefunc", MergeFunctionsPass()) MODULE_PASS("name-anon-globals", NameAnonGlobalPass()) MODULE_PASS("no-op-module", NoOpModulePass()) +MODULE_PASS("objc-arc", ObjCARCOptPass()) 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 @@ -30,7 +30,7 @@ initializeObjCARCAPElimPass(Registry); initializeObjCARCExpandPass(Registry); initializeObjCARCContractPass(Registry); - initializeObjCARCOptPass(Registry); + initializeObjCARCOptLegacyPassPass(Registry); initializePAEvalPass(Registry); } diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp --- a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp +++ b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp @@ -24,6 +24,8 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Transforms/ObjCARC/ObjCARCOpts.h" + #include "ARCRuntimeEntryPoints.h" #include "BlotMapVector.h" #include "DependencyAnalysis.h" @@ -480,123 +482,133 @@ namespace { /// The main ARC optimization pass. - class ObjCARCOpt : public FunctionPass { - bool Changed; - ProvenanceAnalysis PA; - - /// A cache of references to runtime entry point constants. - ARCRuntimeEntryPoints EP; - - /// A cache of MDKinds that can be passed into other functions to propagate - /// MDKind identifiers. - ARCMDKindCache MDKindCache; - - /// A flag indicating whether this optimization pass should run. - bool Run; - - /// A flag indicating whether the optimization that removes or moves - /// retain/release pairs should be performed. - bool DisableRetainReleasePairing = false; - - /// Flags which determine whether each of the interesting runtime functions - /// is in fact used in the current function. - unsigned UsedInThisFunction; - - bool OptimizeRetainRVCall(Function &F, Instruction *RetainRV); - void OptimizeAutoreleaseRVCall(Function &F, Instruction *AutoreleaseRV, - ARCInstKind &Class); - void OptimizeIndividualCalls(Function &F); - - /// Optimize an individual call, optionally passing the - /// GetArgRCIdentityRoot if it has already been computed. - void OptimizeIndividualCallImpl( - Function &F, DenseMap &BlockColors, - Instruction *Inst, ARCInstKind Class, const Value *Arg); - - /// Try to optimize an AutoreleaseRV with a RetainRV or ClaimRV. If the - /// optimization occurs, returns true to indicate that the caller should - /// assume the instructions are dead. - bool OptimizeInlinedAutoreleaseRVCall( - Function &F, DenseMap &BlockColors, - Instruction *Inst, const Value *&Arg, ARCInstKind Class, - Instruction *AutoreleaseRV, const Value *&AutoreleaseRVArg); - - void CheckForCFGHazards(const BasicBlock *BB, - DenseMap &BBStates, - BBState &MyStates) const; - bool VisitInstructionBottomUp(Instruction *Inst, BasicBlock *BB, - BlotMapVector &Retains, - BBState &MyStates); - bool VisitBottomUp(BasicBlock *BB, - DenseMap &BBStates, - BlotMapVector &Retains); - bool VisitInstructionTopDown(Instruction *Inst, - DenseMap &Releases, - BBState &MyStates); - bool VisitTopDown(BasicBlock *BB, - DenseMap &BBStates, - DenseMap &Releases); - bool Visit(Function &F, DenseMap &BBStates, - BlotMapVector &Retains, - DenseMap &Releases); - - void MoveCalls(Value *Arg, RRInfo &RetainsToMove, RRInfo &ReleasesToMove, - BlotMapVector &Retains, - DenseMap &Releases, - SmallVectorImpl &DeadInsts, Module *M); - - bool - PairUpRetainsAndReleases(DenseMap &BBStates, - BlotMapVector &Retains, - DenseMap &Releases, Module *M, - Instruction * Retain, - SmallVectorImpl &DeadInsts, - RRInfo &RetainsToMove, RRInfo &ReleasesToMove, - Value *Arg, bool KnownSafe, - bool &AnyPairsCompletelyEliminated); - - bool PerformCodePlacement(DenseMap &BBStates, - BlotMapVector &Retains, - DenseMap &Releases, Module *M); - - void OptimizeWeakCalls(Function &F); - - bool OptimizeSequences(Function &F); - - void OptimizeReturns(Function &F); +class ObjCARCOpt { + bool Changed; + ProvenanceAnalysis PA; + + /// A cache of references to runtime entry point constants. + ARCRuntimeEntryPoints EP; + + /// A cache of MDKinds that can be passed into other functions to propagate + /// MDKind identifiers. + ARCMDKindCache MDKindCache; + + /// A flag indicating whether this optimization pass should run. + bool Run; + + /// A flag indicating whether the optimization that removes or moves + /// retain/release pairs should be performed. + bool DisableRetainReleasePairing = false; + + /// Flags which determine whether each of the interesting runtime functions + /// is in fact used in the current function. + unsigned UsedInThisFunction; + + bool OptimizeRetainRVCall(Function &F, Instruction *RetainRV); + void OptimizeAutoreleaseRVCall(Function &F, Instruction *AutoreleaseRV, + ARCInstKind &Class); + void OptimizeIndividualCalls(Function &F); + + /// Optimize an individual call, optionally passing the + /// GetArgRCIdentityRoot if it has already been computed. + void OptimizeIndividualCallImpl( + Function &F, DenseMap &BlockColors, + Instruction *Inst, ARCInstKind Class, const Value *Arg); + + /// Try to optimize an AutoreleaseRV with a RetainRV or ClaimRV. If the + /// optimization occurs, returns true to indicate that the caller should + /// assume the instructions are dead. + bool OptimizeInlinedAutoreleaseRVCall( + Function &F, DenseMap &BlockColors, + Instruction *Inst, const Value *&Arg, ARCInstKind Class, + Instruction *AutoreleaseRV, const Value *&AutoreleaseRVArg); + + void CheckForCFGHazards(const BasicBlock *BB, + DenseMap &BBStates, + BBState &MyStates) const; + bool VisitInstructionBottomUp(Instruction *Inst, BasicBlock *BB, + BlotMapVector &Retains, + BBState &MyStates); + bool VisitBottomUp(BasicBlock *BB, + DenseMap &BBStates, + BlotMapVector &Retains); + bool VisitInstructionTopDown(Instruction *Inst, + DenseMap &Releases, + BBState &MyStates); + bool VisitTopDown(BasicBlock *BB, + DenseMap &BBStates, + DenseMap &Releases); + bool Visit(Function &F, DenseMap &BBStates, + BlotMapVector &Retains, + DenseMap &Releases); + + void MoveCalls(Value *Arg, RRInfo &RetainsToMove, RRInfo &ReleasesToMove, + BlotMapVector &Retains, + DenseMap &Releases, + SmallVectorImpl &DeadInsts, Module *M); + + bool PairUpRetainsAndReleases(DenseMap &BBStates, + BlotMapVector &Retains, + DenseMap &Releases, Module *M, + Instruction *Retain, + SmallVectorImpl &DeadInsts, + RRInfo &RetainsToMove, RRInfo &ReleasesToMove, + Value *Arg, bool KnownSafe, + bool &AnyPairsCompletelyEliminated); + + bool PerformCodePlacement(DenseMap &BBStates, + BlotMapVector &Retains, + DenseMap &Releases, Module *M); + + void OptimizeWeakCalls(Function &F); + + bool OptimizeSequences(Function &F); + + void OptimizeReturns(Function &F); #ifndef NDEBUG - void GatherStatistics(Function &F, bool AfterOptimization = false); + void GatherStatistics(Function &F, bool AfterOptimization = false); #endif - void getAnalysisUsage(AnalysisUsage &AU) const override; - bool doInitialization(Module &M) override; - bool runOnFunction(Function &F) override; - void releaseMemory() override; - public: - static char ID; - - ObjCARCOpt() : FunctionPass(ID) { - initializeObjCARCOptPass(*PassRegistry::getPassRegistry()); - } - }; + void init(Module &M); + bool run(Function &F, AAResults &AA); + void releaseMemory(); +}; + +/// The main ARC optimization pass. +class ObjCARCOptLegacyPass : public FunctionPass { +public: + ObjCARCOptLegacyPass() : FunctionPass(ID) { + initializeObjCARCOptLegacyPassPass(*PassRegistry::getPassRegistry()); + } + void getAnalysisUsage(AnalysisUsage &AU) const override; + bool doInitialization(Module &M) override { + OCAO.init(M); + return false; + } + bool runOnFunction(Function &F) override { + return OCAO.run(F, getAnalysis().getAAResults()); + } + void releaseMemory() override { OCAO.releaseMemory(); } + static char ID; +private: + ObjCARCOpt OCAO; +}; } // end anonymous namespace -char ObjCARCOpt::ID = 0; +char ObjCARCOptLegacyPass::ID = 0; -INITIALIZE_PASS_BEGIN(ObjCARCOpt, - "objc-arc", "ObjC ARC optimization", false, false) +INITIALIZE_PASS_BEGIN(ObjCARCOptLegacyPass, "objc-arc", "ObjC ARC optimization", + false, false) INITIALIZE_PASS_DEPENDENCY(ObjCARCAAWrapperPass) -INITIALIZE_PASS_END(ObjCARCOpt, - "objc-arc", "ObjC ARC optimization", false, false) +INITIALIZE_PASS_END(ObjCARCOptLegacyPass, "objc-arc", "ObjC ARC optimization", + false, false) -Pass *llvm::createObjCARCOptPass() { - return new ObjCARCOpt(); -} +Pass *llvm::createObjCARCOptPass() { return new ObjCARCOptLegacyPass(); } -void ObjCARCOpt::getAnalysisUsage(AnalysisUsage &AU) const { +void ObjCARCOptLegacyPass::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); AU.addRequired(); // ARC optimization doesn't currently split critical edges. @@ -2393,14 +2405,14 @@ } #endif -bool ObjCARCOpt::doInitialization(Module &M) { +void ObjCARCOpt::init(Module &M) { if (!EnableARCOpts) - return false; + return; // If nothing in the Module uses ARC, don't do anything. Run = ModuleHasARC(M); if (!Run) - return false; + return; // Intuitively, objc_retain and others are nocapture, however in practice // they are not, because they return their argument value. And objc_release @@ -2409,11 +2421,9 @@ // Initialize our runtime entry point cache. EP.init(&M); - - return false; } -bool ObjCARCOpt::runOnFunction(Function &F) { +bool ObjCARCOpt::run(Function &F, AAResults &AA) { if (!EnableARCOpts) return false; @@ -2427,7 +2437,7 @@ << " >>>" "\n"); - PA.setAA(&getAnalysis().getAAResults()); + PA.setAA(&AA); #ifndef NDEBUG if (AreStatisticsEnabled()) { @@ -2484,3 +2494,17 @@ /// @} /// + +PreservedAnalyses ObjCARCOptPass::run(Module &M, ModuleAnalysisManager &AM) { + ObjCARCOpt OCAO; + OCAO.init(M); + + auto &FAM = AM.getResult(M).getManager(); + bool Changed = false; + for (Function &F : M) { + if (F.isDeclaration()) + continue; + Changed |= OCAO.run(F, FAM.getResult(F)); + } + return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all(); +} diff --git a/llvm/test/Transforms/ObjCARC/basic.ll b/llvm/test/Transforms/ObjCARC/basic.ll --- a/llvm/test/Transforms/ObjCARC/basic.ll +++ b/llvm/test/Transforms/ObjCARC/basic.ll @@ -1,4 +1,5 @@ ; RUN: opt -basic-aa -objc-arc -S < %s | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes=objc-arc -S < %s | FileCheck %s target datalayout = "e-p:64:64:64"