|
12 | 12 |
|
13 | 13 | #include "swift/SIL/OwnershipUtils.h"
|
14 | 14 | #include "swift/Basic/Defer.h"
|
| 15 | +#include "swift/SIL/InstructionUtils.h" |
15 | 16 | #include "swift/SIL/LinearLifetimeChecker.h"
|
16 | 17 | #include "swift/SIL/Projection.h"
|
17 | 18 | #include "swift/SIL/SILArgument.h"
|
@@ -266,6 +267,48 @@ void BorrowingOperand::visitUserResultConsumingUses(
|
266 | 267 | }
|
267 | 268 | }
|
268 | 269 |
|
| 270 | +bool BorrowingOperand::getImplicitUses( |
| 271 | + SmallVectorImpl<Operand *> &foundUses, |
| 272 | + std::function<void(Operand *)> *errorFunction) const { |
| 273 | + if (!areAnyUserResultsBorrowIntroducers()) { |
| 274 | + visitEndScopeInstructions([&](Operand *op) { foundUses.push_back(op); }); |
| 275 | + return false; |
| 276 | + } |
| 277 | + |
| 278 | + // Ok, we have an instruction that introduces a new borrow scope and its |
| 279 | + // result is that borrow scope. In such a case, we need to not just add the |
| 280 | + // end scope instructions of this scoped operand, but also look through any |
| 281 | + // guaranteed phis and add their end_borrow to this list as well. |
| 282 | + SmallVector<BorrowingOperand, 8> worklist; |
| 283 | + SmallPtrSet<Operand *, 8> visitedValue; |
| 284 | + worklist.push_back(*this); |
| 285 | + visitedValue.insert(op); |
| 286 | + bool foundError = false; |
| 287 | + while (!worklist.empty()) { |
| 288 | + auto scopedOperand = worklist.pop_back_val(); |
| 289 | + scopedOperand.visitConsumingUsesOfBorrowIntroducingUserResults( |
| 290 | + [&](Operand *op) { |
| 291 | + if (auto subSub = BorrowingOperand::get(op)) { |
| 292 | + if (!visitedValue.insert(op).second) { |
| 293 | + if (errorFunction) { |
| 294 | + (*errorFunction)(op); |
| 295 | + } |
| 296 | + foundError = true; |
| 297 | + return; |
| 298 | + } |
| 299 | + |
| 300 | + worklist.push_back(*subSub); |
| 301 | + visitedValue.insert(subSub->op); |
| 302 | + return; |
| 303 | + } |
| 304 | + |
| 305 | + foundUses.push_back(op); |
| 306 | + }); |
| 307 | + } |
| 308 | + |
| 309 | + return foundError; |
| 310 | +} |
| 311 | + |
269 | 312 | //===----------------------------------------------------------------------===//
|
270 | 313 | // Borrow Introducers
|
271 | 314 | //===----------------------------------------------------------------------===//
|
@@ -459,6 +502,113 @@ bool BorrowedValue::visitInteriorPointerOperands(
|
459 | 502 | return true;
|
460 | 503 | }
|
461 | 504 |
|
| 505 | +//===----------------------------------------------------------------------===// |
| 506 | +// InteriorPointerOperand |
| 507 | +//===----------------------------------------------------------------------===// |
| 508 | + |
| 509 | +bool InteriorPointerOperand::getImplicitUses( |
| 510 | + SmallVectorImpl<Operand *> &foundUses, |
| 511 | + std::function<void(Operand *)> *onError) { |
| 512 | + SILValue projectedAddress = getProjectedAddress(); |
| 513 | + SmallVector<Operand *, 8> worklist(projectedAddress->getUses()); |
| 514 | + |
| 515 | + bool foundError = false; |
| 516 | + |
| 517 | + while (!worklist.empty()) { |
| 518 | + auto *op = worklist.pop_back_val(); |
| 519 | + |
| 520 | + // Skip type dependent operands. |
| 521 | + if (op->isTypeDependent()) |
| 522 | + continue; |
| 523 | + |
| 524 | + // Before we do anything, add this operand to our implicit regular user |
| 525 | + // list. |
| 526 | + foundUses.push_back(op); |
| 527 | + |
| 528 | + // Then update the worklist with new things to find if we recognize this |
| 529 | + // inst and then continue. If we fail, we emit an error at the bottom of the |
| 530 | + // loop that we didn't recognize the user. |
| 531 | + auto *user = op->getUser(); |
| 532 | + |
| 533 | + // First, eliminate "end point uses" that we just need to check liveness at |
| 534 | + // and do not need to check transitive uses of. |
| 535 | + if (isa<LoadInst>(user) || isa<CopyAddrInst>(user) || |
| 536 | + isIncidentalUse(user) || isa<StoreInst>(user) || |
| 537 | + isa<StoreBorrowInst>(user) || isa<PartialApplyInst>(user) || |
| 538 | + isa<DestroyAddrInst>(user) || isa<AssignInst>(user) || |
| 539 | + isa<AddressToPointerInst>(user) || isa<YieldInst>(user) || |
| 540 | + isa<LoadUnownedInst>(user) || isa<StoreUnownedInst>(user) || |
| 541 | + isa<EndApplyInst>(user) || isa<LoadWeakInst>(user) || |
| 542 | + isa<StoreWeakInst>(user) || isa<AssignByWrapperInst>(user) || |
| 543 | + isa<BeginUnpairedAccessInst>(user) || |
| 544 | + isa<EndUnpairedAccessInst>(user) || isa<WitnessMethodInst>(user) || |
| 545 | + isa<SwitchEnumAddrInst>(user) || isa<CheckedCastAddrBranchInst>(user) || |
| 546 | + isa<SelectEnumAddrInst>(user)) { |
| 547 | + continue; |
| 548 | + } |
| 549 | + |
| 550 | + // Then handle users that we need to look at transitive uses of. |
| 551 | + if (Projection::isAddressProjection(user) || |
| 552 | + isa<ProjectBlockStorageInst>(user) || |
| 553 | + isa<OpenExistentialAddrInst>(user) || |
| 554 | + isa<InitExistentialAddrInst>(user) || isa<BeginAccessInst>(user) || |
| 555 | + isa<TailAddrInst>(user) || isa<IndexAddrInst>(user)) { |
| 556 | + for (SILValue r : user->getResults()) { |
| 557 | + llvm::copy(r->getUses(), std::back_inserter(worklist)); |
| 558 | + } |
| 559 | + continue; |
| 560 | + } |
| 561 | + |
| 562 | + if (auto *builtin = dyn_cast<BuiltinInst>(user)) { |
| 563 | + if (auto kind = builtin->getBuiltinKind()) { |
| 564 | + if (*kind == BuiltinValueKind::TSanInoutAccess) { |
| 565 | + continue; |
| 566 | + } |
| 567 | + } |
| 568 | + } |
| 569 | + |
| 570 | + // If we have a load_borrow, add it's end scope to the liveness requirement. |
| 571 | + if (auto *lbi = dyn_cast<LoadBorrowInst>(user)) { |
| 572 | + transform(lbi->getEndBorrows(), std::back_inserter(foundUses), |
| 573 | + [](EndBorrowInst *ebi) { return &ebi->getAllOperands()[0]; }); |
| 574 | + continue; |
| 575 | + } |
| 576 | + |
| 577 | + // TODO: Merge this into the full apply site code below. |
| 578 | + if (auto *beginApply = dyn_cast<BeginApplyInst>(user)) { |
| 579 | + // TODO: Just add this to implicit regular user list? |
| 580 | + llvm::copy(beginApply->getTokenResult()->getUses(), |
| 581 | + std::back_inserter(foundUses)); |
| 582 | + continue; |
| 583 | + } |
| 584 | + |
| 585 | + if (auto fas = FullApplySite::isa(user)) { |
| 586 | + continue; |
| 587 | + } |
| 588 | + |
| 589 | + if (auto *mdi = dyn_cast<MarkDependenceInst>(user)) { |
| 590 | + // If this is the base, just treat it as a liveness use. |
| 591 | + if (op->get() == mdi->getBase()) { |
| 592 | + continue; |
| 593 | + } |
| 594 | + |
| 595 | + // If we are the value use, look through it. |
| 596 | + llvm::copy(mdi->getValue()->getUses(), std::back_inserter(worklist)); |
| 597 | + continue; |
| 598 | + } |
| 599 | + |
| 600 | + // We were unable to recognize this user, so return true that we failed. |
| 601 | + if (onError) { |
| 602 | + (*onError)(op); |
| 603 | + } |
| 604 | + foundError = true; |
| 605 | + } |
| 606 | + |
| 607 | + // We were able to recognize all of the uses of the address, so return false |
| 608 | + // that we did not find any errors. |
| 609 | + return foundError; |
| 610 | +} |
| 611 | + |
462 | 612 | //===----------------------------------------------------------------------===//
|
463 | 613 | // Owned Value Introducers
|
464 | 614 | //===----------------------------------------------------------------------===//
|
|
0 commit comments