|
24 | 24 | #include "swift/SIL/BasicBlockUtils.h"
|
25 | 25 | #include "swift/SIL/Dominance.h"
|
26 | 26 | #include "swift/SIL/DynamicCasts.h"
|
| 27 | +#include "swift/SIL/InstructionUtils.h" |
27 | 28 | #include "swift/SIL/LinearLifetimeChecker.h"
|
28 | 29 | #include "swift/SIL/OwnershipUtils.h"
|
29 | 30 | #include "swift/SIL/PrettyStackTrace.h"
|
@@ -164,10 +165,12 @@ class SILValueOwnershipChecker {
|
164 | 165 | bool isSubobjectProjectionWithLifetimeEndingUses(
|
165 | 166 | SILValue value,
|
166 | 167 | const SmallVectorImpl<Operand *> &lifetimeEndingUsers) const;
|
167 |
| - bool |
168 |
| - discoverImplicitRegularUsers(const BorrowScopeOperand &initialScopedOperand, |
169 |
| - SmallVectorImpl<Operand *> &implicitRegularUsers, |
170 |
| - bool isGuaranteed); |
| 168 | + bool discoverBorrowOperandImplicitRegularUsers( |
| 169 | + const BorrowScopeOperand &initialScopedOperand, |
| 170 | + SmallVectorImpl<Operand *> &implicitRegularUsers, bool isGuaranteed); |
| 171 | + bool discoverInteriorPointerOperandImplicitRegularUsers( |
| 172 | + const InteriorPointerOperand &interiorPointerOperand, |
| 173 | + SmallVectorImpl<Operand *> &implicitRegularUsers); |
171 | 174 | };
|
172 | 175 |
|
173 | 176 | } // end anonymous namespace
|
@@ -240,7 +243,7 @@ bool SILValueOwnershipChecker::isCompatibleDefUse(
|
240 | 243 | }
|
241 | 244 |
|
242 | 245 | /// Returns true if an error was found.
|
243 |
| -bool SILValueOwnershipChecker::discoverImplicitRegularUsers( |
| 246 | +bool SILValueOwnershipChecker::discoverBorrowOperandImplicitRegularUsers( |
244 | 247 | const BorrowScopeOperand &initialScopedOperand,
|
245 | 248 | SmallVectorImpl<Operand *> &implicitRegularUsers, bool isGuaranteed) {
|
246 | 249 | if (!initialScopedOperand.areAnyUserResultsBorrowIntroducers()) {
|
@@ -288,6 +291,115 @@ bool SILValueOwnershipChecker::discoverImplicitRegularUsers(
|
288 | 291 | return foundError;
|
289 | 292 | }
|
290 | 293 |
|
| 294 | +bool SILValueOwnershipChecker:: |
| 295 | + discoverInteriorPointerOperandImplicitRegularUsers( |
| 296 | + const InteriorPointerOperand &interiorPointerOperand, |
| 297 | + SmallVectorImpl<Operand *> &implicitRegularUsers) { |
| 298 | + SILValue projectedAddress = interiorPointerOperand.getProjectedAddress(); |
| 299 | + SmallVector<Operand *, 8> worklist(projectedAddress->getUses()); |
| 300 | + |
| 301 | + bool foundError = false; |
| 302 | + |
| 303 | + while (!worklist.empty()) { |
| 304 | + auto *op = worklist.pop_back_val(); |
| 305 | + |
| 306 | + // Skip type dependent operands. |
| 307 | + if (op->isTypeDependent()) |
| 308 | + continue; |
| 309 | + |
| 310 | + // Before we do anything, add this operand to our implicit regular user |
| 311 | + // list. |
| 312 | + implicitRegularUsers.push_back(op); |
| 313 | + |
| 314 | + // Then update the worklist with new things to find if we recognize this |
| 315 | + // inst and then continue. If we fail, we emit an error at the bottom of the |
| 316 | + // loop that we didn't recognize the user. |
| 317 | + auto *user = op->getUser(); |
| 318 | + |
| 319 | + // First, eliminate "end point uses" that we just need to check liveness at |
| 320 | + // and do not need to check transitive uses of. |
| 321 | + if (isa<LoadInst>(user) || isa<CopyAddrInst>(user) || |
| 322 | + isIncidentalUse(user) || isa<StoreInst>(user) || |
| 323 | + isa<StoreBorrowInst>(user) || isa<PartialApplyInst>(user) || |
| 324 | + isa<DestroyAddrInst>(user) || isa<AssignInst>(user) || |
| 325 | + isa<AddressToPointerInst>(user) || isa<YieldInst>(user) || |
| 326 | + isa<LoadUnownedInst>(user) || isa<StoreUnownedInst>(user) || |
| 327 | + isa<EndApplyInst>(user) || isa<LoadWeakInst>(user) || |
| 328 | + isa<StoreWeakInst>(user) || isa<AssignByWrapperInst>(user) || |
| 329 | + isa<BeginUnpairedAccessInst>(user) || |
| 330 | + isa<EndUnpairedAccessInst>(user) || isa<WitnessMethodInst>(user) || |
| 331 | + isa<SwitchEnumAddrInst>(user) || isa<CheckedCastAddrBranchInst>(user) || |
| 332 | + isa<SelectEnumAddrInst>(user)) { |
| 333 | + continue; |
| 334 | + } |
| 335 | + |
| 336 | + // Then handle users that we need to look at transitive uses of. |
| 337 | + if (Projection::isAddressProjection(user) || |
| 338 | + isa<ProjectBlockStorageInst>(user) || |
| 339 | + isa<OpenExistentialAddrInst>(user) || |
| 340 | + isa<InitExistentialAddrInst>(user) || isa<BeginAccessInst>(user) || |
| 341 | + isa<TailAddrInst>(user) || isa<IndexAddrInst>(user)) { |
| 342 | + for (SILValue r : user->getResults()) { |
| 343 | + llvm::copy(r->getUses(), std::back_inserter(worklist)); |
| 344 | + } |
| 345 | + continue; |
| 346 | + } |
| 347 | + |
| 348 | + if (auto *builtin = dyn_cast<BuiltinInst>(user)) { |
| 349 | + if (auto kind = builtin->getBuiltinKind()) { |
| 350 | + if (*kind == BuiltinValueKind::TSanInoutAccess) { |
| 351 | + continue; |
| 352 | + } |
| 353 | + } |
| 354 | + } |
| 355 | + |
| 356 | + // If we have a load_borrow, add it's end scope to the liveness requirement. |
| 357 | + if (auto *lbi = dyn_cast<LoadBorrowInst>(user)) { |
| 358 | + transform(lbi->getEndBorrows(), std::back_inserter(implicitRegularUsers), |
| 359 | + [](EndBorrowInst *ebi) { return &ebi->getAllOperands()[0]; }); |
| 360 | + continue; |
| 361 | + } |
| 362 | + |
| 363 | + // TODO: Merge this into the full apply site code below. |
| 364 | + if (auto *beginApply = dyn_cast<BeginApplyInst>(user)) { |
| 365 | + // TODO: Just add this to implicit regular user list? |
| 366 | + llvm::copy(beginApply->getTokenResult()->getUses(), |
| 367 | + std::back_inserter(implicitRegularUsers)); |
| 368 | + continue; |
| 369 | + } |
| 370 | + |
| 371 | + if (auto fas = FullApplySite::isa(user)) { |
| 372 | + continue; |
| 373 | + } |
| 374 | + |
| 375 | + if (auto *mdi = dyn_cast<MarkDependenceInst>(user)) { |
| 376 | + // If this is the base, just treat it as a liveness use. |
| 377 | + if (op->get() == mdi->getBase()) { |
| 378 | + continue; |
| 379 | + } |
| 380 | + |
| 381 | + // If we are the value use, look through it. |
| 382 | + llvm::copy(mdi->getValue()->getUses(), std::back_inserter(worklist)); |
| 383 | + continue; |
| 384 | + } |
| 385 | + |
| 386 | + // We were unable to recognize this user, so return true that we failed. |
| 387 | + handleError([&] { |
| 388 | + llvm::errs() |
| 389 | + << "Function: " << op->getUser()->getFunction()->getName() << "\n" |
| 390 | + << "Could not recognize address user of interior pointer operand!\n" |
| 391 | + << "Interior Pointer Operand: " |
| 392 | + << *interiorPointerOperand.operand->getUser() |
| 393 | + << "Address User: " << *op->getUser(); |
| 394 | + }); |
| 395 | + foundError = true; |
| 396 | + } |
| 397 | + |
| 398 | + // We were able to recognize all of the uses of the address, so return false |
| 399 | + // that we did not find any errors. |
| 400 | + return foundError; |
| 401 | +} |
| 402 | + |
291 | 403 | bool SILValueOwnershipChecker::gatherNonGuaranteedUsers(
|
292 | 404 | SmallVectorImpl<Operand *> &lifetimeEndingUsers,
|
293 | 405 | SmallVectorImpl<Operand *> &nonLifetimeEndingUsers,
|
@@ -348,8 +460,8 @@ bool SILValueOwnershipChecker::gatherNonGuaranteedUsers(
|
348 | 460 | // initial end scope instructions without any further work.
|
349 | 461 | //
|
350 | 462 | // Maybe: Is borrow scope non-local?
|
351 |
| - foundError |= discoverImplicitRegularUsers(*initialScopedOperand, |
352 |
| - implicitRegularUsers, false); |
| 463 | + foundError |= discoverBorrowOperandImplicitRegularUsers( |
| 464 | + *initialScopedOperand, implicitRegularUsers, false); |
353 | 465 | }
|
354 | 466 |
|
355 | 467 | return foundError;
|
@@ -441,11 +553,19 @@ bool SILValueOwnershipChecker::gatherUsers(
|
441 | 553 | if (auto scopedOperand = BorrowScopeOperand::get(op)) {
|
442 | 554 | assert(!scopedOperand->consumesGuaranteedValues());
|
443 | 555 |
|
444 |
| - foundError |= discoverImplicitRegularUsers(*scopedOperand, |
445 |
| - implicitRegularUsers, true); |
| 556 | + foundError |= discoverBorrowOperandImplicitRegularUsers( |
| 557 | + *scopedOperand, implicitRegularUsers, true); |
| 558 | + } |
| 559 | + |
| 560 | + // Next see if our use is an interior pointer operand. If we have an |
| 561 | + // interior pointer, we need to add all of its address uses as "implicit |
| 562 | + // regular users" of our consumed value. |
| 563 | + if (auto interiorPointerOperand = InteriorPointerOperand::get(op)) { |
| 564 | + foundError |= discoverInteriorPointerOperandImplicitRegularUsers( |
| 565 | + *interiorPointerOperand, implicitRegularUsers); |
446 | 566 | }
|
447 | 567 |
|
448 |
| - // And then add the op to the non lifetime ending user list. |
| 568 | + // Finally add the op to the non lifetime ending user list. |
449 | 569 | LLVM_DEBUG(llvm::dbgs() << " Regular User: " << *user);
|
450 | 570 | nonLifetimeEndingUsers.push_back(op);
|
451 | 571 | continue;
|
|
0 commit comments