1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
|
//===- ObjCARCUtil.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 several utility functions used by various ARC
/// optimizations which are IMHO too big to be in a header file.
///
/// 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/IR/Intrinsics.h"
using namespace llvm;
using namespace llvm::objcarc;
raw_ostream &llvm::objcarc::operator<<(raw_ostream &OS,
const InstructionClass Class) {
switch (Class) {
case IC_Retain:
return OS << "IC_Retain";
case IC_RetainRV:
return OS << "IC_RetainRV";
case IC_RetainBlock:
return OS << "IC_RetainBlock";
case IC_Release:
return OS << "IC_Release";
case IC_Autorelease:
return OS << "IC_Autorelease";
case IC_AutoreleaseRV:
return OS << "IC_AutoreleaseRV";
case IC_AutoreleasepoolPush:
return OS << "IC_AutoreleasepoolPush";
case IC_AutoreleasepoolPop:
return OS << "IC_AutoreleasepoolPop";
case IC_NoopCast:
return OS << "IC_NoopCast";
case IC_FusedRetainAutorelease:
return OS << "IC_FusedRetainAutorelease";
case IC_FusedRetainAutoreleaseRV:
return OS << "IC_FusedRetainAutoreleaseRV";
case IC_LoadWeakRetained:
return OS << "IC_LoadWeakRetained";
case IC_StoreWeak:
return OS << "IC_StoreWeak";
case IC_InitWeak:
return OS << "IC_InitWeak";
case IC_LoadWeak:
return OS << "IC_LoadWeak";
case IC_MoveWeak:
return OS << "IC_MoveWeak";
case IC_CopyWeak:
return OS << "IC_CopyWeak";
case IC_DestroyWeak:
return OS << "IC_DestroyWeak";
case IC_StoreStrong:
return OS << "IC_StoreStrong";
case IC_CallOrUser:
return OS << "IC_CallOrUser";
case IC_Call:
return OS << "IC_Call";
case IC_User:
return OS << "IC_User";
case IC_IntrinsicUser:
return OS << "IC_IntrinsicUser";
case IC_None:
return OS << "IC_None";
}
llvm_unreachable("Unknown instruction class!");
}
InstructionClass llvm::objcarc::GetFunctionClass(const Function *F) {
Function::const_arg_iterator AI = F->arg_begin(), AE = F->arg_end();
// No (mandatory) arguments.
if (AI == AE)
return StringSwitch<InstructionClass>(F->getName())
.Case("objc_autoreleasePoolPush", IC_AutoreleasepoolPush)
.Case("clang.arc.use", IC_IntrinsicUser)
.Default(IC_CallOrUser);
// One argument.
const Argument *A0 = AI++;
if (AI == AE)
// Argument is a pointer.
if (PointerType *PTy = dyn_cast<PointerType>(A0->getType())) {
Type *ETy = PTy->getElementType();
// Argument is i8*.
if (ETy->isIntegerTy(8))
return StringSwitch<InstructionClass>(F->getName())
.Case("objc_retain", IC_Retain)
.Case("objc_retainAutoreleasedReturnValue", IC_RetainRV)
.Case("objc_retainBlock", IC_RetainBlock)
.Case("objc_release", IC_Release)
.Case("objc_autorelease", IC_Autorelease)
.Case("objc_autoreleaseReturnValue", IC_AutoreleaseRV)
.Case("objc_autoreleasePoolPop", IC_AutoreleasepoolPop)
.Case("objc_retainedObject", IC_NoopCast)
.Case("objc_unretainedObject", IC_NoopCast)
.Case("objc_unretainedPointer", IC_NoopCast)
.Case("objc_retain_autorelease", IC_FusedRetainAutorelease)
.Case("objc_retainAutorelease", IC_FusedRetainAutorelease)
.Case("objc_retainAutoreleaseReturnValue",IC_FusedRetainAutoreleaseRV)
.Case("objc_sync_enter", IC_User)
.Case("objc_sync_exit", IC_User)
.Default(IC_CallOrUser);
// Argument is i8**
if (PointerType *Pte = dyn_cast<PointerType>(ETy))
if (Pte->getElementType()->isIntegerTy(8))
return StringSwitch<InstructionClass>(F->getName())
.Case("objc_loadWeakRetained", IC_LoadWeakRetained)
.Case("objc_loadWeak", IC_LoadWeak)
.Case("objc_destroyWeak", IC_DestroyWeak)
.Default(IC_CallOrUser);
}
// Two arguments, first is i8**.
const Argument *A1 = AI++;
if (AI == AE)
if (PointerType *PTy = dyn_cast<PointerType>(A0->getType()))
if (PointerType *Pte = dyn_cast<PointerType>(PTy->getElementType()))
if (Pte->getElementType()->isIntegerTy(8))
if (PointerType *PTy1 = dyn_cast<PointerType>(A1->getType())) {
Type *ETy1 = PTy1->getElementType();
// Second argument is i8*
if (ETy1->isIntegerTy(8))
return StringSwitch<InstructionClass>(F->getName())
.Case("objc_storeWeak", IC_StoreWeak)
.Case("objc_initWeak", IC_InitWeak)
.Case("objc_storeStrong", IC_StoreStrong)
.Default(IC_CallOrUser);
// Second argument is i8**.
if (PointerType *Pte1 = dyn_cast<PointerType>(ETy1))
if (Pte1->getElementType()->isIntegerTy(8))
return StringSwitch<InstructionClass>(F->getName())
.Case("objc_moveWeak", IC_MoveWeak)
.Case("objc_copyWeak", IC_CopyWeak)
// Ignore annotation calls. This is important to stop the
// optimizer from treating annotations as uses which would
// make the state of the pointers they are attempting to
// elucidate to be incorrect.
.Case("llvm.arc.annotation.topdown.bbstart", IC_None)
.Case("llvm.arc.annotation.topdown.bbend", IC_None)
.Case("llvm.arc.annotation.bottomup.bbstart", IC_None)
.Case("llvm.arc.annotation.bottomup.bbend", IC_None)
.Default(IC_CallOrUser);
}
// Anything else.
return IC_CallOrUser;
}
/// \brief Determine what kind of construct V is.
InstructionClass
llvm::objcarc::GetInstructionClass(const Value *V) {
if (const Instruction *I = dyn_cast<Instruction>(V)) {
// Any instruction other than bitcast and gep with a pointer operand have a
// use of an objc pointer. Bitcasts, GEPs, Selects, PHIs transfer a pointer
// to a subsequent use, rather than using it themselves, in this sense.
// As a short cut, several other opcodes are known to have no pointer
// operands of interest. And ret is never followed by a release, so it's
// not interesting to examine.
switch (I->getOpcode()) {
case Instruction::Call: {
const CallInst *CI = cast<CallInst>(I);
// Check for calls to special functions.
if (const Function *F = CI->getCalledFunction()) {
InstructionClass Class = GetFunctionClass(F);
if (Class != IC_CallOrUser)
return Class;
// None of the intrinsic functions do objc_release. For intrinsics, the
// only question is whether or not they may be users.
switch (F->getIntrinsicID()) {
case Intrinsic::returnaddress: case Intrinsic::frameaddress:
case Intrinsic::stacksave: case Intrinsic::stackrestore:
case Intrinsic::vastart: case Intrinsic::vacopy: case Intrinsic::vaend:
case Intrinsic::objectsize: case Intrinsic::prefetch:
case Intrinsic::stackprotector:
case Intrinsic::eh_return_i32: case Intrinsic::eh_return_i64:
case Intrinsic::eh_typeid_for: case Intrinsic::eh_dwarf_cfa:
case Intrinsic::eh_sjlj_lsda: case Intrinsic::eh_sjlj_functioncontext:
case Intrinsic::init_trampoline: case Intrinsic::adjust_trampoline:
case Intrinsic::lifetime_start: case Intrinsic::lifetime_end:
case Intrinsic::invariant_start: case Intrinsic::invariant_end:
// Don't let dbg info affect our results.
case Intrinsic::dbg_declare: case Intrinsic::dbg_value:
// Short cut: Some intrinsics obviously don't use ObjC pointers.
return IC_None;
default:
break;
}
}
return GetCallSiteClass(CI);
}
case Instruction::Invoke:
return GetCallSiteClass(cast<InvokeInst>(I));
case Instruction::BitCast:
case Instruction::GetElementPtr:
case Instruction::Select: case Instruction::PHI:
case Instruction::Ret: case Instruction::Br:
case Instruction::Switch: case Instruction::IndirectBr:
case Instruction::Alloca: case Instruction::VAArg:
case Instruction::Add: case Instruction::FAdd:
case Instruction::Sub: case Instruction::FSub:
case Instruction::Mul: case Instruction::FMul:
case Instruction::SDiv: case Instruction::UDiv: case Instruction::FDiv:
case Instruction::SRem: case Instruction::URem: case Instruction::FRem:
case Instruction::Shl: case Instruction::LShr: case Instruction::AShr:
case Instruction::And: case Instruction::Or: case Instruction::Xor:
case Instruction::SExt: case Instruction::ZExt: case Instruction::Trunc:
case Instruction::IntToPtr: case Instruction::FCmp:
case Instruction::FPTrunc: case Instruction::FPExt:
case Instruction::FPToUI: case Instruction::FPToSI:
case Instruction::UIToFP: case Instruction::SIToFP:
case Instruction::InsertElement: case Instruction::ExtractElement:
case Instruction::ShuffleVector:
case Instruction::ExtractValue:
break;
case Instruction::ICmp:
// Comparing a pointer with null, or any other constant, isn't an
// interesting use, because we don't care what the pointer points to, or
// about the values of any other dynamic reference-counted pointers.
if (IsPotentialRetainableObjPtr(I->getOperand(1)))
return IC_User;
break;
default:
// For anything else, check all the operands.
// Note that this includes both operands of a Store: while the first
// operand isn't actually being dereferenced, it is being stored to
// memory where we can no longer track who might read it and dereference
// it, so we have to consider it potentially used.
for (User::const_op_iterator OI = I->op_begin(), OE = I->op_end();
OI != OE; ++OI)
if (IsPotentialRetainableObjPtr(*OI))
return IC_User;
}
}
// Otherwise, it's totally inert for ARC purposes.
return IC_None;
}
|