|  | //===- ObjCARCAPElim.cpp - ObjC ARC Optimization --------------------------===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | /// \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. | 
|  | /// | 
|  | /// This specific file implements optimizations which remove extraneous | 
|  | /// autorelease pools. | 
|  | /// | 
|  | /// WARNING: This file knows about certain library functions. It recognizes them | 
|  | /// by name, and hardwires knowledge of their semantics. | 
|  | /// | 
|  | /// WARNING: This file knows about how certain Objective-C library functions are | 
|  | /// used. Naive LLVM IR transformations which would otherwise be | 
|  | /// behavior-preserving may break these assumptions. | 
|  | /// | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "ObjCARC.h" | 
|  | #include "llvm/ADT/STLExtras.h" | 
|  | #include "llvm/IR/Constants.h" | 
|  | #include "llvm/Support/Debug.h" | 
|  | #include "llvm/Support/raw_ostream.h" | 
|  |  | 
|  | using namespace llvm; | 
|  | using namespace llvm::objcarc; | 
|  |  | 
|  | #define DEBUG_TYPE "objc-arc-ap-elim" | 
|  |  | 
|  | namespace { | 
|  | /// \brief Autorelease pool elimination. | 
|  | class ObjCARCAPElim : public ModulePass { | 
|  | void getAnalysisUsage(AnalysisUsage &AU) const override; | 
|  | bool runOnModule(Module &M) override; | 
|  |  | 
|  | static bool MayAutorelease(ImmutableCallSite CS, unsigned Depth = 0); | 
|  | static bool OptimizeBB(BasicBlock *BB); | 
|  |  | 
|  | public: | 
|  | static char ID; | 
|  | ObjCARCAPElim() : ModulePass(ID) { | 
|  | initializeObjCARCAPElimPass(*PassRegistry::getPassRegistry()); | 
|  | } | 
|  | }; | 
|  | } | 
|  |  | 
|  | char ObjCARCAPElim::ID = 0; | 
|  | INITIALIZE_PASS(ObjCARCAPElim, | 
|  | "objc-arc-apelim", | 
|  | "ObjC ARC autorelease pool elimination", | 
|  | false, false) | 
|  |  | 
|  | Pass *llvm::createObjCARCAPElimPass() { | 
|  | return new ObjCARCAPElim(); | 
|  | } | 
|  |  | 
|  | void ObjCARCAPElim::getAnalysisUsage(AnalysisUsage &AU) const { | 
|  | AU.setPreservesCFG(); | 
|  | } | 
|  |  | 
|  | /// Interprocedurally determine if calls made by the given call site can | 
|  | /// possibly produce autoreleases. | 
|  | bool ObjCARCAPElim::MayAutorelease(ImmutableCallSite CS, unsigned Depth) { | 
|  | if (const Function *Callee = CS.getCalledFunction()) { | 
|  | if (Callee->isDeclaration() || Callee->mayBeOverridden()) | 
|  | return true; | 
|  | for (const BasicBlock &BB : *Callee) { | 
|  | for (const Instruction &I : BB) | 
|  | if (ImmutableCallSite JCS = ImmutableCallSite(&I)) | 
|  | // This recursion depth limit is arbitrary. It's just great | 
|  | // enough to cover known interesting testcases. | 
|  | if (Depth < 3 && | 
|  | !JCS.onlyReadsMemory() && | 
|  | MayAutorelease(JCS, Depth + 1)) | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool ObjCARCAPElim::OptimizeBB(BasicBlock *BB) { | 
|  | bool Changed = false; | 
|  |  | 
|  | Instruction *Push = nullptr; | 
|  | for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) { | 
|  | Instruction *Inst = &*I++; | 
|  | switch (GetBasicARCInstKind(Inst)) { | 
|  | case ARCInstKind::AutoreleasepoolPush: | 
|  | Push = Inst; | 
|  | break; | 
|  | case ARCInstKind::AutoreleasepoolPop: | 
|  | // If this pop matches a push and nothing in between can autorelease, | 
|  | // zap the pair. | 
|  | if (Push && cast<CallInst>(Inst)->getArgOperand(0) == Push) { | 
|  | Changed = true; | 
|  | DEBUG(dbgs() << "ObjCARCAPElim::OptimizeBB: Zapping push pop " | 
|  | "autorelease pair:\n" | 
|  | "                           Pop: " << *Inst << "\n" | 
|  | << "                           Push: " << *Push << "\n"); | 
|  | Inst->eraseFromParent(); | 
|  | Push->eraseFromParent(); | 
|  | } | 
|  | Push = nullptr; | 
|  | break; | 
|  | case ARCInstKind::CallOrUser: | 
|  | if (MayAutorelease(ImmutableCallSite(Inst))) | 
|  | Push = nullptr; | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | return Changed; | 
|  | } | 
|  |  | 
|  | bool ObjCARCAPElim::runOnModule(Module &M) { | 
|  | if (!EnableARCOpts) | 
|  | return false; | 
|  |  | 
|  | // If nothing in the Module uses ARC, don't do anything. | 
|  | if (!ModuleHasARC(M)) | 
|  | return false; | 
|  |  | 
|  | // Find the llvm.global_ctors variable, as the first step in | 
|  | // identifying the global constructors. In theory, unnecessary autorelease | 
|  | // pools could occur anywhere, but in practice it's pretty rare. Global | 
|  | // ctors are a place where autorelease pools get inserted automatically, | 
|  | // so it's pretty common for them to be unnecessary, and it's pretty | 
|  | // profitable to eliminate them. | 
|  | GlobalVariable *GV = M.getGlobalVariable("llvm.global_ctors"); | 
|  | if (!GV) | 
|  | return false; | 
|  |  | 
|  | assert(GV->hasDefinitiveInitializer() && | 
|  | "llvm.global_ctors is uncooperative!"); | 
|  |  | 
|  | bool Changed = false; | 
|  |  | 
|  | // Dig the constructor functions out of GV's initializer. | 
|  | ConstantArray *Init = cast<ConstantArray>(GV->getInitializer()); | 
|  | for (User::op_iterator OI = Init->op_begin(), OE = Init->op_end(); | 
|  | OI != OE; ++OI) { | 
|  | Value *Op = *OI; | 
|  | // llvm.global_ctors is an array of three-field structs where the second | 
|  | // members are constructor functions. | 
|  | Function *F = dyn_cast<Function>(cast<ConstantStruct>(Op)->getOperand(1)); | 
|  | // If the user used a constructor function with the wrong signature and | 
|  | // it got bitcasted or whatever, look the other way. | 
|  | if (!F) | 
|  | continue; | 
|  | // Only look at function definitions. | 
|  | if (F->isDeclaration()) | 
|  | continue; | 
|  | // Only look at functions with one basic block. | 
|  | if (std::next(F->begin()) != F->end()) | 
|  | continue; | 
|  | // Ok, a single-block constructor function definition. Try to optimize it. | 
|  | Changed |= OptimizeBB(&F->front()); | 
|  | } | 
|  |  | 
|  | return Changed; | 
|  | } |