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