/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- ObjCARCAPElim.cpp - ObjC ARC Optimization --------------------------===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | /// \file |
9 | | /// |
10 | | /// This file defines ObjC ARC optimizations. ARC stands for Automatic |
11 | | /// Reference Counting and is a system for managing reference counts for objects |
12 | | /// in Objective C. |
13 | | /// |
14 | | /// This specific file implements optimizations which remove extraneous |
15 | | /// autorelease pools. |
16 | | /// |
17 | | /// WARNING: This file knows about certain library functions. It recognizes them |
18 | | /// by name, and hardwires knowledge of their semantics. |
19 | | /// |
20 | | /// WARNING: This file knows about how certain Objective-C library functions are |
21 | | /// used. Naive LLVM IR transformations which would otherwise be |
22 | | /// behavior-preserving may break these assumptions. |
23 | | /// |
24 | | //===----------------------------------------------------------------------===// |
25 | | |
26 | | #include "ObjCARC.h" |
27 | | #include "llvm/ADT/STLExtras.h" |
28 | | #include "llvm/IR/Constants.h" |
29 | | #include "llvm/Support/Debug.h" |
30 | | #include "llvm/Support/raw_ostream.h" |
31 | | |
32 | | using namespace llvm; |
33 | | using namespace llvm::objcarc; |
34 | | |
35 | | #define DEBUG_TYPE "objc-arc-ap-elim" |
36 | | |
37 | | namespace { |
38 | | /// Autorelease pool elimination. |
39 | | class ObjCARCAPElim : public ModulePass { |
40 | | void getAnalysisUsage(AnalysisUsage &AU) const override; |
41 | | bool runOnModule(Module &M) override; |
42 | | |
43 | | static bool MayAutorelease(ImmutableCallSite CS, unsigned Depth = 0); |
44 | | static bool OptimizeBB(BasicBlock *BB); |
45 | | |
46 | | public: |
47 | | static char ID; |
48 | 8 | ObjCARCAPElim() : ModulePass(ID) { |
49 | 8 | initializeObjCARCAPElimPass(*PassRegistry::getPassRegistry()); |
50 | 8 | } |
51 | | }; |
52 | | } |
53 | | |
54 | | char ObjCARCAPElim::ID = 0; |
55 | | INITIALIZE_PASS(ObjCARCAPElim, |
56 | | "objc-arc-apelim", |
57 | | "ObjC ARC autorelease pool elimination", |
58 | | false, false) |
59 | | |
60 | 6 | Pass *llvm::createObjCARCAPElimPass() { |
61 | 6 | return new ObjCARCAPElim(); |
62 | 6 | } |
63 | | |
64 | 8 | void ObjCARCAPElim::getAnalysisUsage(AnalysisUsage &AU) const { |
65 | 8 | AU.setPreservesCFG(); |
66 | 8 | } |
67 | | |
68 | | /// Interprocedurally determine if calls made by the given call site can |
69 | | /// possibly produce autoreleases. |
70 | 10 | bool ObjCARCAPElim::MayAutorelease(ImmutableCallSite CS, unsigned Depth) { |
71 | 10 | if (const Function *Callee = CS.getCalledFunction()) { |
72 | 9 | if (!Callee->hasExactDefinition()) |
73 | 3 | return true; |
74 | 6 | for (const BasicBlock &BB : *Callee) { |
75 | 6 | for (const Instruction &I : BB) |
76 | 11 | if (ImmutableCallSite JCS = ImmutableCallSite(&I)) |
77 | 5 | // This recursion depth limit is arbitrary. It's just great |
78 | 5 | // enough to cover known interesting testcases. |
79 | 5 | if (Depth < 3 && |
80 | 5 | !JCS.onlyReadsMemory() && |
81 | 5 | MayAutorelease(JCS, Depth + 1)) |
82 | 4 | return true; |
83 | 6 | } |
84 | 6 | return false2 ; |
85 | 1 | } |
86 | 1 | |
87 | 1 | return true; |
88 | 1 | } |
89 | | |
90 | 5 | bool ObjCARCAPElim::OptimizeBB(BasicBlock *BB) { |
91 | 5 | bool Changed = false; |
92 | 5 | |
93 | 5 | Instruction *Push = nullptr; |
94 | 25 | for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) { |
95 | 20 | Instruction *Inst = &*I++; |
96 | 20 | switch (GetBasicARCInstKind(Inst)) { |
97 | 20 | case ARCInstKind::AutoreleasepoolPush: |
98 | 5 | Push = Inst; |
99 | 5 | break; |
100 | 20 | case ARCInstKind::AutoreleasepoolPop: |
101 | 5 | // If this pop matches a push and nothing in between can autorelease, |
102 | 5 | // zap the pair. |
103 | 5 | if (Push && cast<CallInst>(Inst)->getArgOperand(0) == Push1 ) { |
104 | 1 | Changed = true; |
105 | 1 | LLVM_DEBUG(dbgs() << "ObjCARCAPElim::OptimizeBB: Zapping push pop " |
106 | 1 | "autorelease pair:\n" |
107 | 1 | " Pop: " |
108 | 1 | << *Inst << "\n" |
109 | 1 | << " Push: " << *Push |
110 | 1 | << "\n"); |
111 | 1 | Inst->eraseFromParent(); |
112 | 1 | Push->eraseFromParent(); |
113 | 1 | } |
114 | 5 | Push = nullptr; |
115 | 5 | break; |
116 | 20 | case ARCInstKind::CallOrUser: |
117 | 5 | if (MayAutorelease(ImmutableCallSite(Inst))) |
118 | 4 | Push = nullptr; |
119 | 5 | break; |
120 | 20 | default: |
121 | 5 | break; |
122 | 20 | } |
123 | 20 | } |
124 | 5 | |
125 | 5 | return Changed; |
126 | 5 | } |
127 | | |
128 | 8 | bool ObjCARCAPElim::runOnModule(Module &M) { |
129 | 8 | if (!EnableARCOpts) |
130 | 0 | return false; |
131 | 8 | |
132 | 8 | // If nothing in the Module uses ARC, don't do anything. |
133 | 8 | if (!ModuleHasARC(M)) |
134 | 1 | return false; |
135 | 7 | |
136 | 7 | if (skipModule(M)) |
137 | 0 | return false; |
138 | 7 | |
139 | 7 | // Find the llvm.global_ctors variable, as the first step in |
140 | 7 | // identifying the global constructors. In theory, unnecessary autorelease |
141 | 7 | // pools could occur anywhere, but in practice it's pretty rare. Global |
142 | 7 | // ctors are a place where autorelease pools get inserted automatically, |
143 | 7 | // so it's pretty common for them to be unnecessary, and it's pretty |
144 | 7 | // profitable to eliminate them. |
145 | 7 | GlobalVariable *GV = M.getGlobalVariable("llvm.global_ctors"); |
146 | 7 | if (!GV) |
147 | 4 | return false; |
148 | 3 | |
149 | 3 | assert(GV->hasDefinitiveInitializer() && |
150 | 3 | "llvm.global_ctors is uncooperative!"); |
151 | 3 | |
152 | 3 | bool Changed = false; |
153 | 3 | |
154 | 3 | // Dig the constructor functions out of GV's initializer. |
155 | 3 | ConstantArray *Init = cast<ConstantArray>(GV->getInitializer()); |
156 | 3 | for (User::op_iterator OI = Init->op_begin(), OE = Init->op_end(); |
157 | 8 | OI != OE; ++OI5 ) { |
158 | 5 | Value *Op = *OI; |
159 | 5 | // llvm.global_ctors is an array of three-field structs where the second |
160 | 5 | // members are constructor functions. |
161 | 5 | Function *F = dyn_cast<Function>(cast<ConstantStruct>(Op)->getOperand(1)); |
162 | 5 | // If the user used a constructor function with the wrong signature and |
163 | 5 | // it got bitcasted or whatever, look the other way. |
164 | 5 | if (!F) |
165 | 0 | continue; |
166 | 5 | // Only look at function definitions. |
167 | 5 | if (F->isDeclaration()) |
168 | 0 | continue; |
169 | 5 | // Only look at functions with one basic block. |
170 | 5 | if (std::next(F->begin()) != F->end()) |
171 | 0 | continue; |
172 | 5 | // Ok, a single-block constructor function definition. Try to optimize it. |
173 | 5 | Changed |= OptimizeBB(&F->front()); |
174 | 5 | } |
175 | 3 | |
176 | 3 | return Changed; |
177 | 3 | } |