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 "llvm/ADT/STLExtras.h" |
27 | #include "llvm/Analysis/ObjCARCAnalysisUtils.h" |
28 | #include "llvm/Analysis/ObjCARCInstKind.h" |
29 | #include "llvm/IR/Constants.h" |
30 | #include "llvm/IR/InstrTypes.h" |
31 | #include "llvm/IR/PassManager.h" |
32 | #include "llvm/Support/Debug.h" |
33 | #include "llvm/Support/raw_ostream.h" |
34 | #include "llvm/Transforms/ObjCARC.h" |
35 | |
36 | using namespace llvm; |
37 | using namespace llvm::objcarc; |
38 | |
39 | #define DEBUG_TYPE "objc-arc-ap-elim" |
40 | |
41 | namespace { |
42 | |
43 | /// Interprocedurally determine if calls made by the given call site can |
44 | /// possibly produce autoreleases. |
45 | bool MayAutorelease(const CallBase &CB, unsigned Depth = 0) { |
46 | if (const Function *Callee = CB.getCalledFunction()) { |
47 | if (!Callee->hasExactDefinition()) |
48 | return true; |
49 | for (const BasicBlock &BB : *Callee) { |
50 | for (const Instruction &I : BB) |
51 | if (const CallBase *JCB = dyn_cast<CallBase>(Val: &I)) |
52 | // This recursion depth limit is arbitrary. It's just great |
53 | // enough to cover known interesting testcases. |
54 | if (Depth < 3 && !JCB->onlyReadsMemory() && |
55 | MayAutorelease(CB: *JCB, Depth: Depth + 1)) |
56 | return true; |
57 | } |
58 | return false; |
59 | } |
60 | |
61 | return true; |
62 | } |
63 | |
64 | bool OptimizeBB(BasicBlock *BB) { |
65 | bool Changed = false; |
66 | |
67 | Instruction *Push = nullptr; |
68 | for (Instruction &Inst : llvm::make_early_inc_range(Range&: *BB)) { |
69 | switch (GetBasicARCInstKind(V: &Inst)) { |
70 | case ARCInstKind::AutoreleasepoolPush: |
71 | Push = &Inst; |
72 | break; |
73 | case ARCInstKind::AutoreleasepoolPop: |
74 | // If this pop matches a push and nothing in between can autorelease, |
75 | // zap the pair. |
76 | if (Push && cast<CallInst>(Val: &Inst)->getArgOperand(i: 0) == Push) { |
77 | Changed = true; |
78 | LLVM_DEBUG(dbgs() << "ObjCARCAPElim::OptimizeBB: Zapping push pop " |
79 | "autorelease pair:\n" |
80 | " Pop: " |
81 | << Inst << "\n" |
82 | << " Push: " << *Push |
83 | << "\n" ); |
84 | Inst.eraseFromParent(); |
85 | Push->eraseFromParent(); |
86 | } |
87 | Push = nullptr; |
88 | break; |
89 | case ARCInstKind::CallOrUser: |
90 | if (MayAutorelease(CB: cast<CallBase>(Val&: Inst))) |
91 | Push = nullptr; |
92 | break; |
93 | default: |
94 | break; |
95 | } |
96 | } |
97 | |
98 | return Changed; |
99 | } |
100 | |
101 | bool runImpl(Module &M) { |
102 | if (!EnableARCOpts) |
103 | return false; |
104 | |
105 | // If nothing in the Module uses ARC, don't do anything. |
106 | if (!ModuleHasARC(M)) |
107 | return false; |
108 | // Find the llvm.global_ctors variable, as the first step in |
109 | // identifying the global constructors. In theory, unnecessary autorelease |
110 | // pools could occur anywhere, but in practice it's pretty rare. Global |
111 | // ctors are a place where autorelease pools get inserted automatically, |
112 | // so it's pretty common for them to be unnecessary, and it's pretty |
113 | // profitable to eliminate them. |
114 | GlobalVariable *GV = M.getGlobalVariable(Name: "llvm.global_ctors" ); |
115 | if (!GV) |
116 | return false; |
117 | |
118 | assert(GV->hasDefinitiveInitializer() && |
119 | "llvm.global_ctors is uncooperative!" ); |
120 | |
121 | bool Changed = false; |
122 | |
123 | // Dig the constructor functions out of GV's initializer. |
124 | ConstantArray *Init = cast<ConstantArray>(Val: GV->getInitializer()); |
125 | for (User::op_iterator OI = Init->op_begin(), OE = Init->op_end(); |
126 | OI != OE; ++OI) { |
127 | Value *Op = *OI; |
128 | // llvm.global_ctors is an array of three-field structs where the second |
129 | // members are constructor functions. |
130 | Function *F = dyn_cast<Function>(Val: cast<ConstantStruct>(Val: Op)->getOperand(i_nocapture: 1)); |
131 | // If the user used a constructor function with the wrong signature and |
132 | // it got bitcasted or whatever, look the other way. |
133 | if (!F) |
134 | continue; |
135 | // Only look at function definitions. |
136 | if (F->isDeclaration()) |
137 | continue; |
138 | // Only look at functions with one basic block. |
139 | if (std::next(x: F->begin()) != F->end()) |
140 | continue; |
141 | // Ok, a single-block constructor function definition. Try to optimize it. |
142 | Changed |= OptimizeBB(BB: &F->front()); |
143 | } |
144 | |
145 | return Changed; |
146 | } |
147 | |
148 | } // namespace |
149 | |
150 | PreservedAnalyses ObjCARCAPElimPass::run(Module &M, ModuleAnalysisManager &AM) { |
151 | if (!runImpl(M)) |
152 | return PreservedAnalyses::all(); |
153 | PreservedAnalyses PA; |
154 | PA.preserveSet<CFGAnalyses>(); |
155 | return PA; |
156 | } |
157 | |