| Michael Gottesman | 6f729fa | 2015-02-19 19:51:32 +0000 | [diff] [blame] | 1 | //===- ARCInstKind.cpp - ObjC ARC Optimization ----------------------------===// | 
|  | 2 | // | 
| Chandler Carruth | 2946cd7 | 2019-01-19 08:50:56 +0000 | [diff] [blame] | 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 | 
| Michael Gottesman | 6f729fa | 2015-02-19 19:51:32 +0000 | [diff] [blame] | 6 | // | 
|  | 7 | //===----------------------------------------------------------------------===// | 
|  | 8 | /// \file | 
|  | 9 | /// This file defines several utility functions used by various ARC | 
|  | 10 | /// optimizations which are IMHO too big to be in a header file. | 
|  | 11 | /// | 
|  | 12 | /// WARNING: This file knows about certain library functions. It recognizes them | 
|  | 13 | /// by name, and hardwires knowledge of their semantics. | 
|  | 14 | /// | 
|  | 15 | /// WARNING: This file knows about how certain Objective-C library functions are | 
|  | 16 | /// used. Naive LLVM IR transformations which would otherwise be | 
|  | 17 | /// behavior-preserving may break these assumptions. | 
|  | 18 | /// | 
|  | 19 | //===----------------------------------------------------------------------===// | 
|  | 20 |  | 
| Chandler Carruth | 0f79218 | 2015-08-20 08:06:03 +0000 | [diff] [blame] | 21 | #include "llvm/Analysis/ObjCARCInstKind.h" | 
| Chandler Carruth | 0f79218 | 2015-08-20 08:06:03 +0000 | [diff] [blame] | 22 | #include "llvm/ADT/StringSwitch.h" | 
| Chandler Carruth | 6bda14b | 2017-06-06 11:49:48 +0000 | [diff] [blame] | 23 | #include "llvm/Analysis/ObjCARCAnalysisUtils.h" | 
| Michael Gottesman | 6f729fa | 2015-02-19 19:51:32 +0000 | [diff] [blame] | 24 | #include "llvm/IR/Intrinsics.h" | 
|  | 25 |  | 
|  | 26 | using namespace llvm; | 
|  | 27 | using namespace llvm::objcarc; | 
|  | 28 |  | 
|  | 29 | raw_ostream &llvm::objcarc::operator<<(raw_ostream &OS, | 
|  | 30 | const ARCInstKind Class) { | 
|  | 31 | switch (Class) { | 
|  | 32 | case ARCInstKind::Retain: | 
|  | 33 | return OS << "ARCInstKind::Retain"; | 
|  | 34 | case ARCInstKind::RetainRV: | 
|  | 35 | return OS << "ARCInstKind::RetainRV"; | 
| John McCall | 3fe604f | 2016-01-27 19:05:08 +0000 | [diff] [blame] | 36 | case ARCInstKind::ClaimRV: | 
|  | 37 | return OS << "ARCInstKind::ClaimRV"; | 
| Michael Gottesman | 6f729fa | 2015-02-19 19:51:32 +0000 | [diff] [blame] | 38 | case ARCInstKind::RetainBlock: | 
|  | 39 | return OS << "ARCInstKind::RetainBlock"; | 
|  | 40 | case ARCInstKind::Release: | 
|  | 41 | return OS << "ARCInstKind::Release"; | 
|  | 42 | case ARCInstKind::Autorelease: | 
|  | 43 | return OS << "ARCInstKind::Autorelease"; | 
|  | 44 | case ARCInstKind::AutoreleaseRV: | 
|  | 45 | return OS << "ARCInstKind::AutoreleaseRV"; | 
|  | 46 | case ARCInstKind::AutoreleasepoolPush: | 
|  | 47 | return OS << "ARCInstKind::AutoreleasepoolPush"; | 
|  | 48 | case ARCInstKind::AutoreleasepoolPop: | 
|  | 49 | return OS << "ARCInstKind::AutoreleasepoolPop"; | 
|  | 50 | case ARCInstKind::NoopCast: | 
|  | 51 | return OS << "ARCInstKind::NoopCast"; | 
|  | 52 | case ARCInstKind::FusedRetainAutorelease: | 
|  | 53 | return OS << "ARCInstKind::FusedRetainAutorelease"; | 
|  | 54 | case ARCInstKind::FusedRetainAutoreleaseRV: | 
|  | 55 | return OS << "ARCInstKind::FusedRetainAutoreleaseRV"; | 
|  | 56 | case ARCInstKind::LoadWeakRetained: | 
|  | 57 | return OS << "ARCInstKind::LoadWeakRetained"; | 
|  | 58 | case ARCInstKind::StoreWeak: | 
|  | 59 | return OS << "ARCInstKind::StoreWeak"; | 
|  | 60 | case ARCInstKind::InitWeak: | 
|  | 61 | return OS << "ARCInstKind::InitWeak"; | 
|  | 62 | case ARCInstKind::LoadWeak: | 
|  | 63 | return OS << "ARCInstKind::LoadWeak"; | 
|  | 64 | case ARCInstKind::MoveWeak: | 
|  | 65 | return OS << "ARCInstKind::MoveWeak"; | 
|  | 66 | case ARCInstKind::CopyWeak: | 
|  | 67 | return OS << "ARCInstKind::CopyWeak"; | 
|  | 68 | case ARCInstKind::DestroyWeak: | 
|  | 69 | return OS << "ARCInstKind::DestroyWeak"; | 
|  | 70 | case ARCInstKind::StoreStrong: | 
|  | 71 | return OS << "ARCInstKind::StoreStrong"; | 
|  | 72 | case ARCInstKind::CallOrUser: | 
|  | 73 | return OS << "ARCInstKind::CallOrUser"; | 
|  | 74 | case ARCInstKind::Call: | 
|  | 75 | return OS << "ARCInstKind::Call"; | 
|  | 76 | case ARCInstKind::User: | 
|  | 77 | return OS << "ARCInstKind::User"; | 
|  | 78 | case ARCInstKind::IntrinsicUser: | 
|  | 79 | return OS << "ARCInstKind::IntrinsicUser"; | 
|  | 80 | case ARCInstKind::None: | 
|  | 81 | return OS << "ARCInstKind::None"; | 
|  | 82 | } | 
|  | 83 | llvm_unreachable("Unknown instruction class!"); | 
|  | 84 | } | 
|  | 85 |  | 
|  | 86 | ARCInstKind llvm::objcarc::GetFunctionClass(const Function *F) { | 
| Michael Gottesman | 6f729fa | 2015-02-19 19:51:32 +0000 | [diff] [blame] | 87 |  | 
| Pete Cooper | be4f571 | 2018-12-18 20:32:49 +0000 | [diff] [blame] | 88 | Intrinsic::ID ID = F->getIntrinsicID(); | 
|  | 89 | switch (ID) { | 
|  | 90 | default: | 
| Duncan P. N. Exon Smith | 6331dc1 | 2016-08-17 01:02:18 +0000 | [diff] [blame] | 91 | return ARCInstKind::CallOrUser; | 
| Pete Cooper | be4f571 | 2018-12-18 20:32:49 +0000 | [diff] [blame] | 92 | case Intrinsic::objc_autorelease: | 
|  | 93 | return ARCInstKind::Autorelease; | 
|  | 94 | case Intrinsic::objc_autoreleasePoolPop: | 
|  | 95 | return ARCInstKind::AutoreleasepoolPop; | 
|  | 96 | case Intrinsic::objc_autoreleasePoolPush: | 
|  | 97 | return ARCInstKind::AutoreleasepoolPush; | 
|  | 98 | case Intrinsic::objc_autoreleaseReturnValue: | 
|  | 99 | return ARCInstKind::AutoreleaseRV; | 
|  | 100 | case Intrinsic::objc_copyWeak: | 
|  | 101 | return ARCInstKind::CopyWeak; | 
|  | 102 | case Intrinsic::objc_destroyWeak: | 
|  | 103 | return ARCInstKind::DestroyWeak; | 
|  | 104 | case Intrinsic::objc_initWeak: | 
|  | 105 | return ARCInstKind::InitWeak; | 
|  | 106 | case Intrinsic::objc_loadWeak: | 
|  | 107 | return ARCInstKind::LoadWeak; | 
|  | 108 | case Intrinsic::objc_loadWeakRetained: | 
|  | 109 | return ARCInstKind::LoadWeakRetained; | 
|  | 110 | case Intrinsic::objc_moveWeak: | 
|  | 111 | return ARCInstKind::MoveWeak; | 
|  | 112 | case Intrinsic::objc_release: | 
|  | 113 | return ARCInstKind::Release; | 
|  | 114 | case Intrinsic::objc_retain: | 
|  | 115 | return ARCInstKind::Retain; | 
|  | 116 | case Intrinsic::objc_retainAutorelease: | 
|  | 117 | return ARCInstKind::FusedRetainAutorelease; | 
|  | 118 | case Intrinsic::objc_retainAutoreleaseReturnValue: | 
|  | 119 | return ARCInstKind::FusedRetainAutoreleaseRV; | 
|  | 120 | case Intrinsic::objc_retainAutoreleasedReturnValue: | 
|  | 121 | return ARCInstKind::RetainRV; | 
|  | 122 | case Intrinsic::objc_retainBlock: | 
|  | 123 | return ARCInstKind::RetainBlock; | 
|  | 124 | case Intrinsic::objc_storeStrong: | 
|  | 125 | return ARCInstKind::StoreStrong; | 
|  | 126 | case Intrinsic::objc_storeWeak: | 
|  | 127 | return ARCInstKind::StoreWeak; | 
|  | 128 | case Intrinsic::objc_clang_arc_use: | 
|  | 129 | return ARCInstKind::IntrinsicUser; | 
|  | 130 | case Intrinsic::objc_unsafeClaimAutoreleasedReturnValue: | 
|  | 131 | return ARCInstKind::ClaimRV; | 
|  | 132 | case Intrinsic::objc_retainedObject: | 
|  | 133 | return ARCInstKind::NoopCast; | 
|  | 134 | case Intrinsic::objc_unretainedObject: | 
|  | 135 | return ARCInstKind::NoopCast; | 
|  | 136 | case Intrinsic::objc_unretainedPointer: | 
|  | 137 | return ARCInstKind::NoopCast; | 
|  | 138 | case Intrinsic::objc_retain_autorelease: | 
|  | 139 | return ARCInstKind::FusedRetainAutorelease; | 
|  | 140 | case Intrinsic::objc_sync_enter: | 
|  | 141 | return ARCInstKind::User; | 
|  | 142 | case Intrinsic::objc_sync_exit: | 
|  | 143 | return ARCInstKind::User; | 
|  | 144 | case Intrinsic::objc_arc_annotation_topdown_bbstart: | 
|  | 145 | case Intrinsic::objc_arc_annotation_topdown_bbend: | 
|  | 146 | case Intrinsic::objc_arc_annotation_bottomup_bbstart: | 
|  | 147 | case Intrinsic::objc_arc_annotation_bottomup_bbend: | 
|  | 148 | // Ignore annotation calls. This is important to stop the | 
|  | 149 | // optimizer from treating annotations as uses which would | 
|  | 150 | // make the state of the pointers they are attempting to | 
|  | 151 | // elucidate to be incorrect. | 
|  | 152 | return ARCInstKind::None; | 
| Duncan P. N. Exon Smith | 6331dc1 | 2016-08-17 01:02:18 +0000 | [diff] [blame] | 153 | } | 
| Michael Gottesman | 6f729fa | 2015-02-19 19:51:32 +0000 | [diff] [blame] | 154 | } | 
|  | 155 |  | 
| Michael Gottesman | 7a26d8f | 2015-03-16 07:02:32 +0000 | [diff] [blame] | 156 | // A whitelist of intrinsics that we know do not use objc pointers or decrement | 
|  | 157 | // ref counts. | 
|  | 158 | static bool isInertIntrinsic(unsigned ID) { | 
|  | 159 | // TODO: Make this into a covered switch. | 
|  | 160 | switch (ID) { | 
|  | 161 | case Intrinsic::returnaddress: | 
| Albert Gutowski | 795d7d6 | 2016-10-12 22:13:19 +0000 | [diff] [blame] | 162 | case Intrinsic::addressofreturnaddress: | 
| Michael Gottesman | 7a26d8f | 2015-03-16 07:02:32 +0000 | [diff] [blame] | 163 | case Intrinsic::frameaddress: | 
|  | 164 | case Intrinsic::stacksave: | 
|  | 165 | case Intrinsic::stackrestore: | 
|  | 166 | case Intrinsic::vastart: | 
|  | 167 | case Intrinsic::vacopy: | 
|  | 168 | case Intrinsic::vaend: | 
|  | 169 | case Intrinsic::objectsize: | 
|  | 170 | case Intrinsic::prefetch: | 
|  | 171 | case Intrinsic::stackprotector: | 
|  | 172 | case Intrinsic::eh_return_i32: | 
|  | 173 | case Intrinsic::eh_return_i64: | 
|  | 174 | case Intrinsic::eh_typeid_for: | 
|  | 175 | case Intrinsic::eh_dwarf_cfa: | 
|  | 176 | case Intrinsic::eh_sjlj_lsda: | 
|  | 177 | case Intrinsic::eh_sjlj_functioncontext: | 
|  | 178 | case Intrinsic::init_trampoline: | 
|  | 179 | case Intrinsic::adjust_trampoline: | 
|  | 180 | case Intrinsic::lifetime_start: | 
|  | 181 | case Intrinsic::lifetime_end: | 
|  | 182 | case Intrinsic::invariant_start: | 
|  | 183 | case Intrinsic::invariant_end: | 
|  | 184 | // Don't let dbg info affect our results. | 
|  | 185 | case Intrinsic::dbg_declare: | 
|  | 186 | case Intrinsic::dbg_value: | 
| Shiva Chen | 2c86455 | 2018-05-09 02:40:45 +0000 | [diff] [blame] | 187 | case Intrinsic::dbg_label: | 
| Michael Gottesman | 7a26d8f | 2015-03-16 07:02:32 +0000 | [diff] [blame] | 188 | // Short cut: Some intrinsics obviously don't use ObjC pointers. | 
|  | 189 | return true; | 
|  | 190 | default: | 
|  | 191 | return false; | 
|  | 192 | } | 
|  | 193 | } | 
|  | 194 |  | 
|  | 195 | // A whitelist of intrinsics that we know do not use objc pointers or decrement | 
|  | 196 | // ref counts. | 
|  | 197 | static bool isUseOnlyIntrinsic(unsigned ID) { | 
|  | 198 | // We are conservative and even though intrinsics are unlikely to touch | 
|  | 199 | // reference counts, we white list them for safety. | 
|  | 200 | // | 
|  | 201 | // TODO: Expand this into a covered switch. There is a lot more here. | 
|  | 202 | switch (ID) { | 
|  | 203 | case Intrinsic::memcpy: | 
|  | 204 | case Intrinsic::memmove: | 
|  | 205 | case Intrinsic::memset: | 
|  | 206 | return true; | 
|  | 207 | default: | 
|  | 208 | return false; | 
|  | 209 | } | 
|  | 210 | } | 
|  | 211 |  | 
| Adrian Prantl | 5f8f34e4 | 2018-05-01 15:54:18 +0000 | [diff] [blame] | 212 | /// Determine what kind of construct V is. | 
| Michael Gottesman | 6f729fa | 2015-02-19 19:51:32 +0000 | [diff] [blame] | 213 | ARCInstKind llvm::objcarc::GetARCInstKind(const Value *V) { | 
|  | 214 | if (const Instruction *I = dyn_cast<Instruction>(V)) { | 
|  | 215 | // Any instruction other than bitcast and gep with a pointer operand have a | 
|  | 216 | // use of an objc pointer. Bitcasts, GEPs, Selects, PHIs transfer a pointer | 
|  | 217 | // to a subsequent use, rather than using it themselves, in this sense. | 
|  | 218 | // As a short cut, several other opcodes are known to have no pointer | 
|  | 219 | // operands of interest. And ret is never followed by a release, so it's | 
|  | 220 | // not interesting to examine. | 
|  | 221 | switch (I->getOpcode()) { | 
|  | 222 | case Instruction::Call: { | 
|  | 223 | const CallInst *CI = cast<CallInst>(I); | 
| Michael Gottesman | 7a26d8f | 2015-03-16 07:02:32 +0000 | [diff] [blame] | 224 | // See if we have a function that we know something about. | 
| Michael Gottesman | 6f729fa | 2015-02-19 19:51:32 +0000 | [diff] [blame] | 225 | if (const Function *F = CI->getCalledFunction()) { | 
|  | 226 | ARCInstKind Class = GetFunctionClass(F); | 
|  | 227 | if (Class != ARCInstKind::CallOrUser) | 
|  | 228 | return Class; | 
| Pete Cooper | 9e1d335 | 2015-05-20 17:16:39 +0000 | [diff] [blame] | 229 | Intrinsic::ID ID = F->getIntrinsicID(); | 
| Michael Gottesman | 7a26d8f | 2015-03-16 07:02:32 +0000 | [diff] [blame] | 230 | if (isInertIntrinsic(ID)) | 
| Michael Gottesman | 6f729fa | 2015-02-19 19:51:32 +0000 | [diff] [blame] | 231 | return ARCInstKind::None; | 
| Michael Gottesman | 7a26d8f | 2015-03-16 07:02:32 +0000 | [diff] [blame] | 232 | if (isUseOnlyIntrinsic(ID)) | 
|  | 233 | return ARCInstKind::User; | 
| Michael Gottesman | 6f729fa | 2015-02-19 19:51:32 +0000 | [diff] [blame] | 234 | } | 
| Michael Gottesman | 7a26d8f | 2015-03-16 07:02:32 +0000 | [diff] [blame] | 235 |  | 
|  | 236 | // Otherwise, be conservative. | 
| Michael Gottesman | 6f729fa | 2015-02-19 19:51:32 +0000 | [diff] [blame] | 237 | return GetCallSiteClass(CI); | 
|  | 238 | } | 
|  | 239 | case Instruction::Invoke: | 
| Michael Gottesman | 7a26d8f | 2015-03-16 07:02:32 +0000 | [diff] [blame] | 240 | // Otherwise, be conservative. | 
| Michael Gottesman | 6f729fa | 2015-02-19 19:51:32 +0000 | [diff] [blame] | 241 | return GetCallSiteClass(cast<InvokeInst>(I)); | 
|  | 242 | case Instruction::BitCast: | 
|  | 243 | case Instruction::GetElementPtr: | 
|  | 244 | case Instruction::Select: | 
|  | 245 | case Instruction::PHI: | 
|  | 246 | case Instruction::Ret: | 
|  | 247 | case Instruction::Br: | 
|  | 248 | case Instruction::Switch: | 
|  | 249 | case Instruction::IndirectBr: | 
|  | 250 | case Instruction::Alloca: | 
|  | 251 | case Instruction::VAArg: | 
|  | 252 | case Instruction::Add: | 
|  | 253 | case Instruction::FAdd: | 
|  | 254 | case Instruction::Sub: | 
|  | 255 | case Instruction::FSub: | 
|  | 256 | case Instruction::Mul: | 
|  | 257 | case Instruction::FMul: | 
|  | 258 | case Instruction::SDiv: | 
|  | 259 | case Instruction::UDiv: | 
|  | 260 | case Instruction::FDiv: | 
|  | 261 | case Instruction::SRem: | 
|  | 262 | case Instruction::URem: | 
|  | 263 | case Instruction::FRem: | 
|  | 264 | case Instruction::Shl: | 
|  | 265 | case Instruction::LShr: | 
|  | 266 | case Instruction::AShr: | 
|  | 267 | case Instruction::And: | 
|  | 268 | case Instruction::Or: | 
|  | 269 | case Instruction::Xor: | 
|  | 270 | case Instruction::SExt: | 
|  | 271 | case Instruction::ZExt: | 
|  | 272 | case Instruction::Trunc: | 
|  | 273 | case Instruction::IntToPtr: | 
|  | 274 | case Instruction::FCmp: | 
|  | 275 | case Instruction::FPTrunc: | 
|  | 276 | case Instruction::FPExt: | 
|  | 277 | case Instruction::FPToUI: | 
|  | 278 | case Instruction::FPToSI: | 
|  | 279 | case Instruction::UIToFP: | 
|  | 280 | case Instruction::SIToFP: | 
|  | 281 | case Instruction::InsertElement: | 
|  | 282 | case Instruction::ExtractElement: | 
|  | 283 | case Instruction::ShuffleVector: | 
|  | 284 | case Instruction::ExtractValue: | 
|  | 285 | break; | 
|  | 286 | case Instruction::ICmp: | 
|  | 287 | // Comparing a pointer with null, or any other constant, isn't an | 
|  | 288 | // interesting use, because we don't care what the pointer points to, or | 
|  | 289 | // about the values of any other dynamic reference-counted pointers. | 
|  | 290 | if (IsPotentialRetainableObjPtr(I->getOperand(1))) | 
|  | 291 | return ARCInstKind::User; | 
|  | 292 | break; | 
|  | 293 | default: | 
|  | 294 | // For anything else, check all the operands. | 
|  | 295 | // Note that this includes both operands of a Store: while the first | 
|  | 296 | // operand isn't actually being dereferenced, it is being stored to | 
|  | 297 | // memory where we can no longer track who might read it and dereference | 
|  | 298 | // it, so we have to consider it potentially used. | 
|  | 299 | for (User::const_op_iterator OI = I->op_begin(), OE = I->op_end(); | 
|  | 300 | OI != OE; ++OI) | 
|  | 301 | if (IsPotentialRetainableObjPtr(*OI)) | 
|  | 302 | return ARCInstKind::User; | 
|  | 303 | } | 
|  | 304 | } | 
|  | 305 |  | 
|  | 306 | // Otherwise, it's totally inert for ARC purposes. | 
|  | 307 | return ARCInstKind::None; | 
|  | 308 | } | 
| Michael Gottesman | 2e0e4e0 | 2015-02-19 19:51:36 +0000 | [diff] [blame] | 309 |  | 
| Adrian Prantl | 5f8f34e4 | 2018-05-01 15:54:18 +0000 | [diff] [blame] | 310 | /// Test if the given class is a kind of user. | 
| Michael Gottesman | 2e0e4e0 | 2015-02-19 19:51:36 +0000 | [diff] [blame] | 311 | bool llvm::objcarc::IsUser(ARCInstKind Class) { | 
|  | 312 | switch (Class) { | 
|  | 313 | case ARCInstKind::User: | 
|  | 314 | case ARCInstKind::CallOrUser: | 
|  | 315 | case ARCInstKind::IntrinsicUser: | 
|  | 316 | return true; | 
|  | 317 | case ARCInstKind::Retain: | 
|  | 318 | case ARCInstKind::RetainRV: | 
|  | 319 | case ARCInstKind::RetainBlock: | 
|  | 320 | case ARCInstKind::Release: | 
|  | 321 | case ARCInstKind::Autorelease: | 
|  | 322 | case ARCInstKind::AutoreleaseRV: | 
|  | 323 | case ARCInstKind::AutoreleasepoolPush: | 
|  | 324 | case ARCInstKind::AutoreleasepoolPop: | 
|  | 325 | case ARCInstKind::NoopCast: | 
|  | 326 | case ARCInstKind::FusedRetainAutorelease: | 
|  | 327 | case ARCInstKind::FusedRetainAutoreleaseRV: | 
|  | 328 | case ARCInstKind::LoadWeakRetained: | 
|  | 329 | case ARCInstKind::StoreWeak: | 
|  | 330 | case ARCInstKind::InitWeak: | 
|  | 331 | case ARCInstKind::LoadWeak: | 
|  | 332 | case ARCInstKind::MoveWeak: | 
|  | 333 | case ARCInstKind::CopyWeak: | 
|  | 334 | case ARCInstKind::DestroyWeak: | 
|  | 335 | case ARCInstKind::StoreStrong: | 
|  | 336 | case ARCInstKind::Call: | 
|  | 337 | case ARCInstKind::None: | 
| John McCall | 3fe604f | 2016-01-27 19:05:08 +0000 | [diff] [blame] | 338 | case ARCInstKind::ClaimRV: | 
| Michael Gottesman | 2e0e4e0 | 2015-02-19 19:51:36 +0000 | [diff] [blame] | 339 | return false; | 
|  | 340 | } | 
|  | 341 | llvm_unreachable("covered switch isn't covered?"); | 
|  | 342 | } | 
|  | 343 |  | 
| Adrian Prantl | 5f8f34e4 | 2018-05-01 15:54:18 +0000 | [diff] [blame] | 344 | /// Test if the given class is objc_retain or equivalent. | 
| Michael Gottesman | 2e0e4e0 | 2015-02-19 19:51:36 +0000 | [diff] [blame] | 345 | bool llvm::objcarc::IsRetain(ARCInstKind Class) { | 
|  | 346 | switch (Class) { | 
|  | 347 | case ARCInstKind::Retain: | 
|  | 348 | case ARCInstKind::RetainRV: | 
|  | 349 | return true; | 
|  | 350 | // I believe we treat retain block as not a retain since it can copy its | 
|  | 351 | // block. | 
|  | 352 | case ARCInstKind::RetainBlock: | 
|  | 353 | case ARCInstKind::Release: | 
|  | 354 | case ARCInstKind::Autorelease: | 
|  | 355 | case ARCInstKind::AutoreleaseRV: | 
|  | 356 | case ARCInstKind::AutoreleasepoolPush: | 
|  | 357 | case ARCInstKind::AutoreleasepoolPop: | 
|  | 358 | case ARCInstKind::NoopCast: | 
|  | 359 | case ARCInstKind::FusedRetainAutorelease: | 
|  | 360 | case ARCInstKind::FusedRetainAutoreleaseRV: | 
|  | 361 | case ARCInstKind::LoadWeakRetained: | 
|  | 362 | case ARCInstKind::StoreWeak: | 
|  | 363 | case ARCInstKind::InitWeak: | 
|  | 364 | case ARCInstKind::LoadWeak: | 
|  | 365 | case ARCInstKind::MoveWeak: | 
|  | 366 | case ARCInstKind::CopyWeak: | 
|  | 367 | case ARCInstKind::DestroyWeak: | 
|  | 368 | case ARCInstKind::StoreStrong: | 
|  | 369 | case ARCInstKind::IntrinsicUser: | 
|  | 370 | case ARCInstKind::CallOrUser: | 
|  | 371 | case ARCInstKind::Call: | 
|  | 372 | case ARCInstKind::User: | 
|  | 373 | case ARCInstKind::None: | 
| John McCall | 3fe604f | 2016-01-27 19:05:08 +0000 | [diff] [blame] | 374 | case ARCInstKind::ClaimRV: | 
| Michael Gottesman | 2e0e4e0 | 2015-02-19 19:51:36 +0000 | [diff] [blame] | 375 | return false; | 
|  | 376 | } | 
|  | 377 | llvm_unreachable("covered switch isn't covered?"); | 
|  | 378 | } | 
|  | 379 |  | 
| Adrian Prantl | 5f8f34e4 | 2018-05-01 15:54:18 +0000 | [diff] [blame] | 380 | /// Test if the given class is objc_autorelease or equivalent. | 
| Michael Gottesman | 2e0e4e0 | 2015-02-19 19:51:36 +0000 | [diff] [blame] | 381 | bool llvm::objcarc::IsAutorelease(ARCInstKind Class) { | 
|  | 382 | switch (Class) { | 
|  | 383 | case ARCInstKind::Autorelease: | 
|  | 384 | case ARCInstKind::AutoreleaseRV: | 
|  | 385 | return true; | 
|  | 386 | case ARCInstKind::Retain: | 
|  | 387 | case ARCInstKind::RetainRV: | 
| John McCall | 3fe604f | 2016-01-27 19:05:08 +0000 | [diff] [blame] | 388 | case ARCInstKind::ClaimRV: | 
| Michael Gottesman | 2e0e4e0 | 2015-02-19 19:51:36 +0000 | [diff] [blame] | 389 | case ARCInstKind::RetainBlock: | 
|  | 390 | case ARCInstKind::Release: | 
|  | 391 | case ARCInstKind::AutoreleasepoolPush: | 
|  | 392 | case ARCInstKind::AutoreleasepoolPop: | 
|  | 393 | case ARCInstKind::NoopCast: | 
|  | 394 | case ARCInstKind::FusedRetainAutorelease: | 
|  | 395 | case ARCInstKind::FusedRetainAutoreleaseRV: | 
|  | 396 | case ARCInstKind::LoadWeakRetained: | 
|  | 397 | case ARCInstKind::StoreWeak: | 
|  | 398 | case ARCInstKind::InitWeak: | 
|  | 399 | case ARCInstKind::LoadWeak: | 
|  | 400 | case ARCInstKind::MoveWeak: | 
|  | 401 | case ARCInstKind::CopyWeak: | 
|  | 402 | case ARCInstKind::DestroyWeak: | 
|  | 403 | case ARCInstKind::StoreStrong: | 
|  | 404 | case ARCInstKind::IntrinsicUser: | 
|  | 405 | case ARCInstKind::CallOrUser: | 
|  | 406 | case ARCInstKind::Call: | 
|  | 407 | case ARCInstKind::User: | 
|  | 408 | case ARCInstKind::None: | 
|  | 409 | return false; | 
|  | 410 | } | 
|  | 411 | llvm_unreachable("covered switch isn't covered?"); | 
|  | 412 | } | 
|  | 413 |  | 
| Adrian Prantl | 5f8f34e4 | 2018-05-01 15:54:18 +0000 | [diff] [blame] | 414 | /// Test if the given class represents instructions which return their | 
| Michael Gottesman | 2e0e4e0 | 2015-02-19 19:51:36 +0000 | [diff] [blame] | 415 | /// argument verbatim. | 
|  | 416 | bool llvm::objcarc::IsForwarding(ARCInstKind Class) { | 
|  | 417 | switch (Class) { | 
|  | 418 | case ARCInstKind::Retain: | 
|  | 419 | case ARCInstKind::RetainRV: | 
| John McCall | 3fe604f | 2016-01-27 19:05:08 +0000 | [diff] [blame] | 420 | case ARCInstKind::ClaimRV: | 
| Michael Gottesman | 2e0e4e0 | 2015-02-19 19:51:36 +0000 | [diff] [blame] | 421 | case ARCInstKind::Autorelease: | 
|  | 422 | case ARCInstKind::AutoreleaseRV: | 
|  | 423 | case ARCInstKind::NoopCast: | 
|  | 424 | return true; | 
|  | 425 | case ARCInstKind::RetainBlock: | 
|  | 426 | case ARCInstKind::Release: | 
|  | 427 | case ARCInstKind::AutoreleasepoolPush: | 
|  | 428 | case ARCInstKind::AutoreleasepoolPop: | 
|  | 429 | case ARCInstKind::FusedRetainAutorelease: | 
|  | 430 | case ARCInstKind::FusedRetainAutoreleaseRV: | 
|  | 431 | case ARCInstKind::LoadWeakRetained: | 
|  | 432 | case ARCInstKind::StoreWeak: | 
|  | 433 | case ARCInstKind::InitWeak: | 
|  | 434 | case ARCInstKind::LoadWeak: | 
|  | 435 | case ARCInstKind::MoveWeak: | 
|  | 436 | case ARCInstKind::CopyWeak: | 
|  | 437 | case ARCInstKind::DestroyWeak: | 
|  | 438 | case ARCInstKind::StoreStrong: | 
|  | 439 | case ARCInstKind::IntrinsicUser: | 
|  | 440 | case ARCInstKind::CallOrUser: | 
|  | 441 | case ARCInstKind::Call: | 
|  | 442 | case ARCInstKind::User: | 
|  | 443 | case ARCInstKind::None: | 
|  | 444 | return false; | 
|  | 445 | } | 
|  | 446 | llvm_unreachable("covered switch isn't covered?"); | 
|  | 447 | } | 
|  | 448 |  | 
| Adrian Prantl | 5f8f34e4 | 2018-05-01 15:54:18 +0000 | [diff] [blame] | 449 | /// Test if the given class represents instructions which do nothing if | 
| Michael Gottesman | 2e0e4e0 | 2015-02-19 19:51:36 +0000 | [diff] [blame] | 450 | /// passed a null pointer. | 
|  | 451 | bool llvm::objcarc::IsNoopOnNull(ARCInstKind Class) { | 
|  | 452 | switch (Class) { | 
|  | 453 | case ARCInstKind::Retain: | 
|  | 454 | case ARCInstKind::RetainRV: | 
| John McCall | 3fe604f | 2016-01-27 19:05:08 +0000 | [diff] [blame] | 455 | case ARCInstKind::ClaimRV: | 
| Michael Gottesman | 2e0e4e0 | 2015-02-19 19:51:36 +0000 | [diff] [blame] | 456 | case ARCInstKind::Release: | 
|  | 457 | case ARCInstKind::Autorelease: | 
|  | 458 | case ARCInstKind::AutoreleaseRV: | 
|  | 459 | case ARCInstKind::RetainBlock: | 
|  | 460 | return true; | 
|  | 461 | case ARCInstKind::AutoreleasepoolPush: | 
|  | 462 | case ARCInstKind::AutoreleasepoolPop: | 
|  | 463 | case ARCInstKind::FusedRetainAutorelease: | 
|  | 464 | case ARCInstKind::FusedRetainAutoreleaseRV: | 
|  | 465 | case ARCInstKind::LoadWeakRetained: | 
|  | 466 | case ARCInstKind::StoreWeak: | 
|  | 467 | case ARCInstKind::InitWeak: | 
|  | 468 | case ARCInstKind::LoadWeak: | 
|  | 469 | case ARCInstKind::MoveWeak: | 
|  | 470 | case ARCInstKind::CopyWeak: | 
|  | 471 | case ARCInstKind::DestroyWeak: | 
|  | 472 | case ARCInstKind::StoreStrong: | 
|  | 473 | case ARCInstKind::IntrinsicUser: | 
|  | 474 | case ARCInstKind::CallOrUser: | 
|  | 475 | case ARCInstKind::Call: | 
|  | 476 | case ARCInstKind::User: | 
|  | 477 | case ARCInstKind::None: | 
|  | 478 | case ARCInstKind::NoopCast: | 
|  | 479 | return false; | 
|  | 480 | } | 
|  | 481 | llvm_unreachable("covered switch isn't covered?"); | 
|  | 482 | } | 
|  | 483 |  | 
| Adrian Prantl | 5f8f34e4 | 2018-05-01 15:54:18 +0000 | [diff] [blame] | 484 | /// Test if the given class represents instructions which are always safe | 
| Michael Gottesman | 2e0e4e0 | 2015-02-19 19:51:36 +0000 | [diff] [blame] | 485 | /// to mark with the "tail" keyword. | 
|  | 486 | bool llvm::objcarc::IsAlwaysTail(ARCInstKind Class) { | 
|  | 487 | // ARCInstKind::RetainBlock may be given a stack argument. | 
|  | 488 | switch (Class) { | 
|  | 489 | case ARCInstKind::Retain: | 
|  | 490 | case ARCInstKind::RetainRV: | 
| John McCall | 3fe604f | 2016-01-27 19:05:08 +0000 | [diff] [blame] | 491 | case ARCInstKind::ClaimRV: | 
| Michael Gottesman | 2e0e4e0 | 2015-02-19 19:51:36 +0000 | [diff] [blame] | 492 | case ARCInstKind::AutoreleaseRV: | 
|  | 493 | return true; | 
|  | 494 | case ARCInstKind::Release: | 
|  | 495 | case ARCInstKind::Autorelease: | 
|  | 496 | case ARCInstKind::RetainBlock: | 
|  | 497 | case ARCInstKind::AutoreleasepoolPush: | 
|  | 498 | case ARCInstKind::AutoreleasepoolPop: | 
|  | 499 | case ARCInstKind::FusedRetainAutorelease: | 
|  | 500 | case ARCInstKind::FusedRetainAutoreleaseRV: | 
|  | 501 | case ARCInstKind::LoadWeakRetained: | 
|  | 502 | case ARCInstKind::StoreWeak: | 
|  | 503 | case ARCInstKind::InitWeak: | 
|  | 504 | case ARCInstKind::LoadWeak: | 
|  | 505 | case ARCInstKind::MoveWeak: | 
|  | 506 | case ARCInstKind::CopyWeak: | 
|  | 507 | case ARCInstKind::DestroyWeak: | 
|  | 508 | case ARCInstKind::StoreStrong: | 
|  | 509 | case ARCInstKind::IntrinsicUser: | 
|  | 510 | case ARCInstKind::CallOrUser: | 
|  | 511 | case ARCInstKind::Call: | 
|  | 512 | case ARCInstKind::User: | 
|  | 513 | case ARCInstKind::None: | 
|  | 514 | case ARCInstKind::NoopCast: | 
|  | 515 | return false; | 
|  | 516 | } | 
|  | 517 | llvm_unreachable("covered switch isn't covered?"); | 
|  | 518 | } | 
|  | 519 |  | 
| Adrian Prantl | 5f8f34e4 | 2018-05-01 15:54:18 +0000 | [diff] [blame] | 520 | /// Test if the given class represents instructions which are never safe | 
| Michael Gottesman | 2e0e4e0 | 2015-02-19 19:51:36 +0000 | [diff] [blame] | 521 | /// to mark with the "tail" keyword. | 
|  | 522 | bool llvm::objcarc::IsNeverTail(ARCInstKind Class) { | 
|  | 523 | /// It is never safe to tail call objc_autorelease since by tail calling | 
|  | 524 | /// objc_autorelease: fast autoreleasing causing our object to be potentially | 
|  | 525 | /// reclaimed from the autorelease pool which violates the semantics of | 
|  | 526 | /// __autoreleasing types in ARC. | 
|  | 527 | switch (Class) { | 
|  | 528 | case ARCInstKind::Autorelease: | 
|  | 529 | return true; | 
|  | 530 | case ARCInstKind::Retain: | 
|  | 531 | case ARCInstKind::RetainRV: | 
| John McCall | 3fe604f | 2016-01-27 19:05:08 +0000 | [diff] [blame] | 532 | case ARCInstKind::ClaimRV: | 
| Michael Gottesman | 2e0e4e0 | 2015-02-19 19:51:36 +0000 | [diff] [blame] | 533 | case ARCInstKind::AutoreleaseRV: | 
|  | 534 | case ARCInstKind::Release: | 
|  | 535 | case ARCInstKind::RetainBlock: | 
|  | 536 | case ARCInstKind::AutoreleasepoolPush: | 
|  | 537 | case ARCInstKind::AutoreleasepoolPop: | 
|  | 538 | case ARCInstKind::FusedRetainAutorelease: | 
|  | 539 | case ARCInstKind::FusedRetainAutoreleaseRV: | 
|  | 540 | case ARCInstKind::LoadWeakRetained: | 
|  | 541 | case ARCInstKind::StoreWeak: | 
|  | 542 | case ARCInstKind::InitWeak: | 
|  | 543 | case ARCInstKind::LoadWeak: | 
|  | 544 | case ARCInstKind::MoveWeak: | 
|  | 545 | case ARCInstKind::CopyWeak: | 
|  | 546 | case ARCInstKind::DestroyWeak: | 
|  | 547 | case ARCInstKind::StoreStrong: | 
|  | 548 | case ARCInstKind::IntrinsicUser: | 
|  | 549 | case ARCInstKind::CallOrUser: | 
|  | 550 | case ARCInstKind::Call: | 
|  | 551 | case ARCInstKind::User: | 
|  | 552 | case ARCInstKind::None: | 
|  | 553 | case ARCInstKind::NoopCast: | 
|  | 554 | return false; | 
|  | 555 | } | 
|  | 556 | llvm_unreachable("covered switch isn't covered?"); | 
|  | 557 | } | 
|  | 558 |  | 
| Adrian Prantl | 5f8f34e4 | 2018-05-01 15:54:18 +0000 | [diff] [blame] | 559 | /// Test if the given class represents instructions which are always safe | 
| Michael Gottesman | 2e0e4e0 | 2015-02-19 19:51:36 +0000 | [diff] [blame] | 560 | /// to mark with the nounwind attribute. | 
|  | 561 | bool llvm::objcarc::IsNoThrow(ARCInstKind Class) { | 
|  | 562 | // objc_retainBlock is not nounwind because it calls user copy constructors | 
|  | 563 | // which could theoretically throw. | 
|  | 564 | switch (Class) { | 
|  | 565 | case ARCInstKind::Retain: | 
|  | 566 | case ARCInstKind::RetainRV: | 
| John McCall | 3fe604f | 2016-01-27 19:05:08 +0000 | [diff] [blame] | 567 | case ARCInstKind::ClaimRV: | 
| Michael Gottesman | 2e0e4e0 | 2015-02-19 19:51:36 +0000 | [diff] [blame] | 568 | case ARCInstKind::Release: | 
|  | 569 | case ARCInstKind::Autorelease: | 
|  | 570 | case ARCInstKind::AutoreleaseRV: | 
|  | 571 | case ARCInstKind::AutoreleasepoolPush: | 
|  | 572 | case ARCInstKind::AutoreleasepoolPop: | 
|  | 573 | return true; | 
|  | 574 | case ARCInstKind::RetainBlock: | 
|  | 575 | case ARCInstKind::FusedRetainAutorelease: | 
|  | 576 | case ARCInstKind::FusedRetainAutoreleaseRV: | 
|  | 577 | case ARCInstKind::LoadWeakRetained: | 
|  | 578 | case ARCInstKind::StoreWeak: | 
|  | 579 | case ARCInstKind::InitWeak: | 
|  | 580 | case ARCInstKind::LoadWeak: | 
|  | 581 | case ARCInstKind::MoveWeak: | 
|  | 582 | case ARCInstKind::CopyWeak: | 
|  | 583 | case ARCInstKind::DestroyWeak: | 
|  | 584 | case ARCInstKind::StoreStrong: | 
|  | 585 | case ARCInstKind::IntrinsicUser: | 
|  | 586 | case ARCInstKind::CallOrUser: | 
|  | 587 | case ARCInstKind::Call: | 
|  | 588 | case ARCInstKind::User: | 
|  | 589 | case ARCInstKind::None: | 
|  | 590 | case ARCInstKind::NoopCast: | 
|  | 591 | return false; | 
|  | 592 | } | 
|  | 593 | llvm_unreachable("covered switch isn't covered?"); | 
|  | 594 | } | 
|  | 595 |  | 
|  | 596 | /// Test whether the given instruction can autorelease any pointer or cause an | 
|  | 597 | /// autoreleasepool pop. | 
|  | 598 | /// | 
|  | 599 | /// This means that it *could* interrupt the RV optimization. | 
|  | 600 | bool llvm::objcarc::CanInterruptRV(ARCInstKind Class) { | 
|  | 601 | switch (Class) { | 
|  | 602 | case ARCInstKind::AutoreleasepoolPop: | 
|  | 603 | case ARCInstKind::CallOrUser: | 
|  | 604 | case ARCInstKind::Call: | 
|  | 605 | case ARCInstKind::Autorelease: | 
|  | 606 | case ARCInstKind::AutoreleaseRV: | 
|  | 607 | case ARCInstKind::FusedRetainAutorelease: | 
|  | 608 | case ARCInstKind::FusedRetainAutoreleaseRV: | 
|  | 609 | return true; | 
|  | 610 | case ARCInstKind::Retain: | 
|  | 611 | case ARCInstKind::RetainRV: | 
| John McCall | 3fe604f | 2016-01-27 19:05:08 +0000 | [diff] [blame] | 612 | case ARCInstKind::ClaimRV: | 
| Michael Gottesman | 2e0e4e0 | 2015-02-19 19:51:36 +0000 | [diff] [blame] | 613 | case ARCInstKind::Release: | 
|  | 614 | case ARCInstKind::AutoreleasepoolPush: | 
|  | 615 | case ARCInstKind::RetainBlock: | 
|  | 616 | case ARCInstKind::LoadWeakRetained: | 
|  | 617 | case ARCInstKind::StoreWeak: | 
|  | 618 | case ARCInstKind::InitWeak: | 
|  | 619 | case ARCInstKind::LoadWeak: | 
|  | 620 | case ARCInstKind::MoveWeak: | 
|  | 621 | case ARCInstKind::CopyWeak: | 
|  | 622 | case ARCInstKind::DestroyWeak: | 
|  | 623 | case ARCInstKind::StoreStrong: | 
|  | 624 | case ARCInstKind::IntrinsicUser: | 
|  | 625 | case ARCInstKind::User: | 
|  | 626 | case ARCInstKind::None: | 
|  | 627 | case ARCInstKind::NoopCast: | 
|  | 628 | return false; | 
|  | 629 | } | 
|  | 630 | llvm_unreachable("covered switch isn't covered?"); | 
|  | 631 | } | 
| Michael Gottesman | 5ab64de | 2015-02-20 00:02:45 +0000 | [diff] [blame] | 632 |  | 
|  | 633 | bool llvm::objcarc::CanDecrementRefCount(ARCInstKind Kind) { | 
|  | 634 | switch (Kind) { | 
|  | 635 | case ARCInstKind::Retain: | 
|  | 636 | case ARCInstKind::RetainRV: | 
|  | 637 | case ARCInstKind::Autorelease: | 
|  | 638 | case ARCInstKind::AutoreleaseRV: | 
|  | 639 | case ARCInstKind::NoopCast: | 
|  | 640 | case ARCInstKind::FusedRetainAutorelease: | 
|  | 641 | case ARCInstKind::FusedRetainAutoreleaseRV: | 
|  | 642 | case ARCInstKind::IntrinsicUser: | 
|  | 643 | case ARCInstKind::User: | 
|  | 644 | case ARCInstKind::None: | 
|  | 645 | return false; | 
|  | 646 |  | 
|  | 647 | // The cases below are conservative. | 
|  | 648 |  | 
|  | 649 | // RetainBlock can result in user defined copy constructors being called | 
|  | 650 | // implying releases may occur. | 
|  | 651 | case ARCInstKind::RetainBlock: | 
|  | 652 | case ARCInstKind::Release: | 
|  | 653 | case ARCInstKind::AutoreleasepoolPush: | 
|  | 654 | case ARCInstKind::AutoreleasepoolPop: | 
|  | 655 | case ARCInstKind::LoadWeakRetained: | 
|  | 656 | case ARCInstKind::StoreWeak: | 
|  | 657 | case ARCInstKind::InitWeak: | 
|  | 658 | case ARCInstKind::LoadWeak: | 
|  | 659 | case ARCInstKind::MoveWeak: | 
|  | 660 | case ARCInstKind::CopyWeak: | 
|  | 661 | case ARCInstKind::DestroyWeak: | 
|  | 662 | case ARCInstKind::StoreStrong: | 
|  | 663 | case ARCInstKind::CallOrUser: | 
|  | 664 | case ARCInstKind::Call: | 
| John McCall | 3fe604f | 2016-01-27 19:05:08 +0000 | [diff] [blame] | 665 | case ARCInstKind::ClaimRV: | 
| Michael Gottesman | 5ab64de | 2015-02-20 00:02:45 +0000 | [diff] [blame] | 666 | return true; | 
|  | 667 | } | 
|  | 668 |  | 
|  | 669 | llvm_unreachable("covered switch isn't covered?"); | 
|  | 670 | } |