1 //===- PtrState.cpp -------------------------------------------------------===// 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 9 #include "PtrState.h" 10 #include "DependencyAnalysis.h" 11 #include "ObjCARC.h" 12 #include "llvm/Analysis/ObjCARCAnalysisUtils.h" 13 #include "llvm/Analysis/ObjCARCInstKind.h" 14 #include "llvm/IR/BasicBlock.h" 15 #include "llvm/IR/Instruction.h" 16 #include "llvm/IR/Instructions.h" 17 #include "llvm/IR/Value.h" 18 #include "llvm/Support/Casting.h" 19 #include "llvm/Support/Compiler.h" 20 #include "llvm/Support/Debug.h" 21 #include "llvm/Support/ErrorHandling.h" 22 #include "llvm/Support/raw_ostream.h" 23 #include <cassert> 24 #include <iterator> 25 #include <utility> 26 27 using namespace llvm; 28 using namespace llvm::objcarc; 29 30 #define DEBUG_TYPE "objc-arc-ptr-state" 31 32 //===----------------------------------------------------------------------===// 33 // Utility 34 //===----------------------------------------------------------------------===// 35 36 raw_ostream &llvm::objcarc::operator<<(raw_ostream &OS, const Sequence S) { 37 switch (S) { 38 case S_None: 39 return OS << "S_None"; 40 case S_Retain: 41 return OS << "S_Retain"; 42 case S_CanRelease: 43 return OS << "S_CanRelease"; 44 case S_Use: 45 return OS << "S_Use"; 46 case S_MovableRelease: 47 return OS << "S_MovableRelease"; 48 case S_Stop: 49 return OS << "S_Stop"; 50 } 51 llvm_unreachable("Unknown sequence type."); 52 } 53 54 //===----------------------------------------------------------------------===// 55 // Sequence 56 //===----------------------------------------------------------------------===// 57 58 static Sequence MergeSeqs(Sequence A, Sequence B, bool TopDown) { 59 // The easy cases. 60 if (A == B) 61 return A; 62 if (A == S_None || B == S_None) 63 return S_None; 64 65 if (A > B) 66 std::swap(A, B); 67 if (TopDown) { 68 // Choose the side which is further along in the sequence. 69 if ((A == S_Retain || A == S_CanRelease) && 70 (B == S_CanRelease || B == S_Use)) 71 return B; 72 } else { 73 // Choose the side which is further along in the sequence. 74 if ((A == S_Use || A == S_CanRelease) && 75 (B == S_Use || B == S_Stop || B == S_MovableRelease)) 76 return A; 77 // If both sides are releases, choose the more conservative one. 78 if (A == S_Stop && B == S_MovableRelease) 79 return A; 80 } 81 82 return S_None; 83 } 84 85 //===----------------------------------------------------------------------===// 86 // RRInfo 87 //===----------------------------------------------------------------------===// 88 89 void RRInfo::clear() { 90 KnownSafe = false; 91 IsTailCallRelease = false; 92 ReleaseMetadata = nullptr; 93 Calls.clear(); 94 ReverseInsertPts.clear(); 95 CFGHazardAfflicted = false; 96 } 97 98 bool RRInfo::Merge(const RRInfo &Other) { 99 // Conservatively merge the ReleaseMetadata information. 100 if (ReleaseMetadata != Other.ReleaseMetadata) 101 ReleaseMetadata = nullptr; 102 103 // Conservatively merge the boolean state. 104 KnownSafe &= Other.KnownSafe; 105 IsTailCallRelease &= Other.IsTailCallRelease; 106 CFGHazardAfflicted |= Other.CFGHazardAfflicted; 107 108 // Merge the call sets. 109 Calls.insert(Other.Calls.begin(), Other.Calls.end()); 110 111 // Merge the insert point sets. If there are any differences, 112 // that makes this a partial merge. 113 bool Partial = ReverseInsertPts.size() != Other.ReverseInsertPts.size(); 114 for (Instruction *Inst : Other.ReverseInsertPts) 115 Partial |= ReverseInsertPts.insert(Inst).second; 116 return Partial; 117 } 118 119 //===----------------------------------------------------------------------===// 120 // PtrState 121 //===----------------------------------------------------------------------===// 122 123 void PtrState::SetKnownPositiveRefCount() { 124 LLVM_DEBUG(dbgs() << " Setting Known Positive.\n"); 125 KnownPositiveRefCount = true; 126 } 127 128 void PtrState::ClearKnownPositiveRefCount() { 129 LLVM_DEBUG(dbgs() << " Clearing Known Positive.\n"); 130 KnownPositiveRefCount = false; 131 } 132 133 void PtrState::SetSeq(Sequence NewSeq) { 134 LLVM_DEBUG(dbgs() << " Old: " << GetSeq() << "; New: " << NewSeq 135 << "\n"); 136 Seq = NewSeq; 137 } 138 139 void PtrState::ResetSequenceProgress(Sequence NewSeq) { 140 LLVM_DEBUG(dbgs() << " Resetting sequence progress.\n"); 141 SetSeq(NewSeq); 142 Partial = false; 143 RRI.clear(); 144 } 145 146 void PtrState::Merge(const PtrState &Other, bool TopDown) { 147 Seq = MergeSeqs(GetSeq(), Other.GetSeq(), TopDown); 148 KnownPositiveRefCount &= Other.KnownPositiveRefCount; 149 150 // If we're not in a sequence (anymore), drop all associated state. 151 if (Seq == S_None) { 152 Partial = false; 153 RRI.clear(); 154 } else if (Partial || Other.Partial) { 155 // If we're doing a merge on a path that's previously seen a partial 156 // merge, conservatively drop the sequence, to avoid doing partial 157 // RR elimination. If the branch predicates for the two merge differ, 158 // mixing them is unsafe. 159 ClearSequenceProgress(); 160 } else { 161 // Otherwise merge the other PtrState's RRInfo into our RRInfo. At this 162 // point, we know that currently we are not partial. Stash whether or not 163 // the merge operation caused us to undergo a partial merging of reverse 164 // insertion points. 165 Partial = RRI.Merge(Other.RRI); 166 } 167 } 168 169 //===----------------------------------------------------------------------===// 170 // BottomUpPtrState 171 //===----------------------------------------------------------------------===// 172 173 bool BottomUpPtrState::InitBottomUp(ARCMDKindCache &Cache, Instruction *I) { 174 // If we see two releases in a row on the same pointer. If so, make 175 // a note, and we'll cicle back to revisit it after we've 176 // hopefully eliminated the second release, which may allow us to 177 // eliminate the first release too. 178 // Theoretically we could implement removal of nested retain+release 179 // pairs by making PtrState hold a stack of states, but this is 180 // simple and avoids adding overhead for the non-nested case. 181 bool NestingDetected = false; 182 if (GetSeq() == S_MovableRelease) { 183 LLVM_DEBUG( 184 dbgs() << " Found nested releases (i.e. a release pair)\n"); 185 NestingDetected = true; 186 } 187 188 MDNode *ReleaseMetadata = 189 I->getMetadata(Cache.get(ARCMDKindID::ImpreciseRelease)); 190 Sequence NewSeq = ReleaseMetadata ? S_MovableRelease : S_Stop; 191 ResetSequenceProgress(NewSeq); 192 if (NewSeq == S_Stop) 193 InsertReverseInsertPt(I); 194 SetReleaseMetadata(ReleaseMetadata); 195 SetKnownSafe(HasKnownPositiveRefCount()); 196 SetTailCallRelease(cast<CallInst>(I)->isTailCall()); 197 InsertCall(I); 198 SetKnownPositiveRefCount(); 199 return NestingDetected; 200 } 201 202 bool BottomUpPtrState::MatchWithRetain() { 203 SetKnownPositiveRefCount(); 204 205 Sequence OldSeq = GetSeq(); 206 switch (OldSeq) { 207 case S_Stop: 208 case S_MovableRelease: 209 case S_Use: 210 // If OldSeq is not S_Use or OldSeq is S_Use and we are tracking an 211 // imprecise release, clear our reverse insertion points. 212 if (OldSeq != S_Use || IsTrackingImpreciseReleases()) 213 ClearReverseInsertPts(); 214 LLVM_FALLTHROUGH; 215 case S_CanRelease: 216 return true; 217 case S_None: 218 return false; 219 case S_Retain: 220 llvm_unreachable("bottom-up pointer in retain state!"); 221 } 222 llvm_unreachable("Sequence unknown enum value"); 223 } 224 225 bool BottomUpPtrState::HandlePotentialAlterRefCount(Instruction *Inst, 226 const Value *Ptr, 227 ProvenanceAnalysis &PA, 228 ARCInstKind Class) { 229 Sequence S = GetSeq(); 230 231 // Check for possible releases. 232 if (!CanDecrementRefCount(Inst, Ptr, PA, Class)) 233 return false; 234 235 LLVM_DEBUG(dbgs() << " CanAlterRefCount: Seq: " << S << "; " 236 << *Ptr << "\n"); 237 switch (S) { 238 case S_Use: 239 SetSeq(S_CanRelease); 240 return true; 241 case S_CanRelease: 242 case S_MovableRelease: 243 case S_Stop: 244 case S_None: 245 return false; 246 case S_Retain: 247 llvm_unreachable("bottom-up pointer in retain state!"); 248 } 249 llvm_unreachable("Sequence unknown enum value"); 250 } 251 252 void BottomUpPtrState::HandlePotentialUse(BasicBlock *BB, Instruction *Inst, 253 const Value *Ptr, 254 ProvenanceAnalysis &PA, 255 ARCInstKind Class) { 256 auto SetSeqAndInsertReverseInsertPt = [&](Sequence NewSeq){ 257 assert(!HasReverseInsertPts()); 258 SetSeq(NewSeq); 259 // If this is an invoke instruction, we're scanning it as part of 260 // one of its successor blocks, since we can't insert code after it 261 // in its own block, and we don't want to split critical edges. 262 BasicBlock::iterator InsertAfter; 263 if (isa<InvokeInst>(Inst)) { 264 const auto IP = BB->getFirstInsertionPt(); 265 InsertAfter = IP == BB->end() ? std::prev(BB->end()) : IP; 266 if (isa<CatchSwitchInst>(InsertAfter)) 267 // A catchswitch must be the only non-phi instruction in its basic 268 // block, so attempting to insert an instruction into such a block would 269 // produce invalid IR. 270 SetCFGHazardAfflicted(true); 271 } else { 272 InsertAfter = std::next(Inst->getIterator()); 273 } 274 275 if (InsertAfter != BB->end()) 276 InsertAfter = skipDebugIntrinsics(InsertAfter); 277 278 InsertReverseInsertPt(&*InsertAfter); 279 }; 280 281 // Check for possible direct uses. 282 switch (GetSeq()) { 283 case S_MovableRelease: 284 if (CanUse(Inst, Ptr, PA, Class)) { 285 LLVM_DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; " 286 << *Ptr << "\n"); 287 SetSeqAndInsertReverseInsertPt(S_Use); 288 } else if (const auto *Call = getreturnRVOperand(*Inst, Class)) { 289 if (CanUse(Call, Ptr, PA, GetBasicARCInstKind(Call))) { 290 LLVM_DEBUG(dbgs() << " ReleaseUse: Seq: " << GetSeq() << "; " 291 << *Ptr << "\n"); 292 SetSeqAndInsertReverseInsertPt(S_Stop); 293 } 294 } 295 break; 296 case S_Stop: 297 if (CanUse(Inst, Ptr, PA, Class)) { 298 LLVM_DEBUG(dbgs() << " PreciseStopUse: Seq: " << GetSeq() 299 << "; " << *Ptr << "\n"); 300 SetSeq(S_Use); 301 } 302 break; 303 case S_CanRelease: 304 case S_Use: 305 case S_None: 306 break; 307 case S_Retain: 308 llvm_unreachable("bottom-up pointer in retain state!"); 309 } 310 } 311 312 //===----------------------------------------------------------------------===// 313 // TopDownPtrState 314 //===----------------------------------------------------------------------===// 315 316 bool TopDownPtrState::InitTopDown(ARCInstKind Kind, Instruction *I) { 317 bool NestingDetected = false; 318 // Don't do retain+release tracking for ARCInstKind::RetainRV, because 319 // it's 320 // better to let it remain as the first instruction after a call. 321 if (Kind != ARCInstKind::RetainRV) { 322 // If we see two retains in a row on the same pointer. If so, make 323 // a note, and we'll cicle back to revisit it after we've 324 // hopefully eliminated the second retain, which may allow us to 325 // eliminate the first retain too. 326 // Theoretically we could implement removal of nested retain+release 327 // pairs by making PtrState hold a stack of states, but this is 328 // simple and avoids adding overhead for the non-nested case. 329 if (GetSeq() == S_Retain) 330 NestingDetected = true; 331 332 ResetSequenceProgress(S_Retain); 333 SetKnownSafe(HasKnownPositiveRefCount()); 334 InsertCall(I); 335 } 336 337 SetKnownPositiveRefCount(); 338 return NestingDetected; 339 } 340 341 bool TopDownPtrState::MatchWithRelease(ARCMDKindCache &Cache, 342 Instruction *Release) { 343 ClearKnownPositiveRefCount(); 344 345 Sequence OldSeq = GetSeq(); 346 347 MDNode *ReleaseMetadata = 348 Release->getMetadata(Cache.get(ARCMDKindID::ImpreciseRelease)); 349 350 switch (OldSeq) { 351 case S_Retain: 352 case S_CanRelease: 353 if (OldSeq == S_Retain || ReleaseMetadata != nullptr) 354 ClearReverseInsertPts(); 355 LLVM_FALLTHROUGH; 356 case S_Use: 357 SetReleaseMetadata(ReleaseMetadata); 358 SetTailCallRelease(cast<CallInst>(Release)->isTailCall()); 359 return true; 360 case S_None: 361 return false; 362 case S_Stop: 363 case S_MovableRelease: 364 llvm_unreachable("top-down pointer in bottom up state!"); 365 } 366 llvm_unreachable("Sequence unknown enum value"); 367 } 368 369 bool TopDownPtrState::HandlePotentialAlterRefCount(Instruction *Inst, 370 const Value *Ptr, 371 ProvenanceAnalysis &PA, 372 ARCInstKind Class) { 373 // Check for possible releases. Treat clang.arc.use as a releasing instruction 374 // to prevent sinking a retain past it. 375 if (!CanDecrementRefCount(Inst, Ptr, PA, Class) && 376 Class != ARCInstKind::IntrinsicUser) 377 return false; 378 379 LLVM_DEBUG(dbgs() << " CanAlterRefCount: Seq: " << GetSeq() << "; " 380 << *Ptr << "\n"); 381 ClearKnownPositiveRefCount(); 382 switch (GetSeq()) { 383 case S_Retain: 384 SetSeq(S_CanRelease); 385 assert(!HasReverseInsertPts()); 386 InsertReverseInsertPt(Inst); 387 388 // One call can't cause a transition from S_Retain to S_CanRelease 389 // and S_CanRelease to S_Use. If we've made the first transition, 390 // we're done. 391 return true; 392 case S_Use: 393 case S_CanRelease: 394 case S_None: 395 return false; 396 case S_Stop: 397 case S_MovableRelease: 398 llvm_unreachable("top-down pointer in release state!"); 399 } 400 llvm_unreachable("covered switch is not covered!?"); 401 } 402 403 void TopDownPtrState::HandlePotentialUse(Instruction *Inst, const Value *Ptr, 404 ProvenanceAnalysis &PA, 405 ARCInstKind Class) { 406 // Check for possible direct uses. 407 switch (GetSeq()) { 408 case S_CanRelease: 409 if (!CanUse(Inst, Ptr, PA, Class)) 410 return; 411 LLVM_DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; " 412 << *Ptr << "\n"); 413 SetSeq(S_Use); 414 return; 415 case S_Retain: 416 case S_Use: 417 case S_None: 418 return; 419 case S_Stop: 420 case S_MovableRelease: 421 llvm_unreachable("top-down pointer in release state!"); 422 } 423 } 424