146146#include " llvm/ADT/PointerUnion.h"
147147#include " llvm/ADT/SmallBitVector.h"
148148#include " llvm/ADT/SmallPtrSet.h"
149+ #include " llvm/ADT/SmallVector.h"
149150#include " llvm/Support/Debug.h"
150151#include " llvm/Support/ErrorHandling.h"
151152
@@ -204,10 +205,31 @@ struct DiagnosticEmitter {
204205 SILInstruction *violatingUse);
205206 void emitAddressDiagnosticNoCopy (MarkMustCheckInst *markedValue,
206207 SILInstruction *consumingUse);
208+ void emitExclusivityHazardDiagnostic (MarkMustCheckInst *markedValue,
209+ SILInstruction *consumingUse);
207210};
208211
209212} // namespace
210213
214+ void DiagnosticEmitter::emitExclusivityHazardDiagnostic (
215+ MarkMustCheckInst *markedValue, SILInstruction *consumingUse) {
216+ if (!useWithDiagnostic.insert (consumingUse).second )
217+ return ;
218+
219+ auto &astContext = markedValue->getFunction ()->getASTContext ();
220+ StringRef varName = getVariableNameForValue (markedValue);
221+
222+ LLVM_DEBUG (llvm::dbgs () << " Emitting error for exclusivity!\n " );
223+ LLVM_DEBUG (llvm::dbgs () << " Mark: " << *markedValue);
224+ LLVM_DEBUG (llvm::dbgs () << " Consuming use: " << *consumingUse);
225+
226+ diagnose (astContext,
227+ markedValue->getDefiningInstruction ()->getLoc ().getSourceLoc (),
228+ diag::sil_moveonlychecker_exclusivity_violation, varName);
229+ diagnose (astContext, consumingUse->getLoc ().getSourceLoc (),
230+ diag::sil_moveonlychecker_consuming_use_here);
231+ }
232+
211233void DiagnosticEmitter::emitAddressDiagnostic (
212234 MarkMustCheckInst *markedValue, SILInstruction *lastLiveUse,
213235 SILInstruction *violatingUse, bool isUseConsuming,
@@ -775,13 +797,18 @@ struct GatherUsesVisitor : public AccessUseVisitor {
775797 bool emittedEarlyDiagnostic = false ;
776798 DiagnosticEmitter &diagnosticEmitter;
777799
800+ // Pruned liveness used to validate that load [take]/load [copy] can be
801+ // converted to load_borrow without violating exclusivity.
802+ SSAPrunedLiveness &liveness;
803+
778804 GatherUsesVisitor (MoveOnlyChecker &moveChecker, UseState &useState,
779805 MarkMustCheckInst *markedValue,
780- DiagnosticEmitter &diagnosticEmitter)
806+ DiagnosticEmitter &diagnosticEmitter,
807+ SSAPrunedLiveness &gatherUsesLiveness)
781808 : AccessUseVisitor(AccessUseType::Overlapping,
782809 NestedAccessType::IgnoreAccessBegin),
783810 moveChecker (moveChecker), useState(useState), markedValue(markedValue),
784- diagnosticEmitter(diagnosticEmitter) {}
811+ diagnosticEmitter(diagnosticEmitter), liveness(gatherUsesLiveness) {}
785812
786813 bool visitUse (Operand *op, AccessUseType useTy) override ;
787814 void reset (SILValue address) { useState.address = address; }
@@ -795,6 +822,41 @@ struct GatherUsesVisitor : public AccessUseVisitor {
795822 // / base address that we are checking which should be the operand of the mark
796823 // / must check value.
797824 SILValue getRootAddress () const { return markedValue; }
825+
826+ // / Returns true if we emitted an error.
827+ bool checkForExclusivityHazards (LoadInst *li) {
828+ SWIFT_DEFER { liveness.clear (); };
829+
830+ LLVM_DEBUG (llvm::dbgs () << " Checking for exclusivity hazards for: " << *li);
831+
832+ // Grab our access path with in scope. We want to find the inner most access
833+ // scope.
834+ auto accessPathWithBase =
835+ AccessPathWithBase::computeInScope (li->getOperand ());
836+ auto accessPath = accessPathWithBase.accessPath ;
837+ // TODO: Make this a we don't understand error.
838+ assert (accessPath.isValid () && " Invalid access path?!" );
839+
840+ auto *bai = dyn_cast<BeginAccessInst>(accessPathWithBase.base );
841+
842+ if (!bai) {
843+ LLVM_DEBUG (llvm::dbgs ()
844+ << " No begin access... so no exclusivity violation!\n " );
845+ return false ;
846+ }
847+
848+ bool emittedError = false ;
849+ liveness.initializeDef (bai);
850+ liveness.computeSimple ();
851+ for (auto *consumingUse : li->getConsumingUses ()) {
852+ if (!liveness.isWithinBoundary (consumingUse->getUser ())) {
853+ diagnosticEmitter.emitExclusivityHazardDiagnostic (
854+ markedValue, consumingUse->getUser ());
855+ emittedError = true ;
856+ }
857+ }
858+ return emittedError;
859+ }
798860};
799861
800862} // end anonymous namespace
@@ -934,6 +996,14 @@ bool GatherUsesVisitor::visitUse(Operand *op, AccessUseType useTy) {
934996 return false ;
935997
936998 LLVM_DEBUG (llvm::dbgs () << " Found potential borrow: " << *user);
999+
1000+ if (checkForExclusivityHazards (li)) {
1001+ LLVM_DEBUG (llvm::dbgs () << " Found exclusivity violation?!\n " );
1002+ emittedEarlyDiagnostic = true ;
1003+ moveChecker.valuesWithDiagnostics .insert (markedValue);
1004+ return true ;
1005+ }
1006+
9371007 useState.borrows .insert ({user, *leafRange});
9381008 return true ;
9391009 }
@@ -965,7 +1035,14 @@ bool GatherUsesVisitor::visitUse(Operand *op, AccessUseType useTy) {
9651035 return false ;
9661036
9671037 if (moveChecker.finalConsumingUses .empty ()) {
968- LLVM_DEBUG (llvm::dbgs () << " Found borrow inst: " << *user);
1038+ LLVM_DEBUG (llvm::dbgs () << " Found potential borrow inst: " << *user);
1039+ if (checkForExclusivityHazards (li)) {
1040+ LLVM_DEBUG (llvm::dbgs () << " Found exclusivity violation?!\n " );
1041+ emittedEarlyDiagnostic = true ;
1042+ moveChecker.valuesWithDiagnostics .insert (markedValue);
1043+ return true ;
1044+ }
1045+
9691046 useState.borrows .insert ({user, *leafRange});
9701047 } else {
9711048 LLVM_DEBUG (llvm::dbgs () << " Found take inst: " << *user);
@@ -1155,8 +1232,10 @@ bool MoveOnlyChecker::performSingleCheck(MarkMustCheckInst *markedAddress) {
11551232 // Then gather all uses of our address by walking from def->uses. We use this
11561233 // to categorize the uses of this address into their ownership behavior (e.x.:
11571234 // init, reinit, take, destroy, etc.).
1235+ SmallVector<SILBasicBlock *, 32 > gatherUsesDiscoveredBlocks;
1236+ SSAPrunedLiveness gatherUsesLiveness (&gatherUsesDiscoveredBlocks);
11581237 GatherUsesVisitor visitor (*this , addressUseState, markedAddress,
1159- diagnosticEmitter);
1238+ diagnosticEmitter, gatherUsesLiveness );
11601239 SWIFT_DEFER { visitor.clear (); };
11611240 visitor.reset (markedAddress);
11621241 if (!visitAccessPathUses (visitor, accessPath, fn)) {
@@ -1467,13 +1546,6 @@ bool MoveOnlyChecker::performSingleCheck(MarkMustCheckInst *markedAddress) {
14671546 }
14681547 }
14691548
1470- // Now before we do anything more, just exit and say we errored. This will not
1471- // actually make us fail and will cause code later in the checker to rewrite
1472- // all non-explicit copy instructions to their explicit variant. I did this
1473- // for testing purposes only.
1474- valuesWithDiagnostics.insert (markedAddress);
1475- return true ;
1476-
14771549 // Ok, we not have emitted our main errors. Now we begin the
14781550 // transformation. We begin by processing borrows. We can also emit errors
14791551 // here if we find that we can not expand the borrow scope of the load [copy]
@@ -1487,50 +1559,16 @@ bool MoveOnlyChecker::performSingleCheck(MarkMustCheckInst *markedAddress) {
14871559 // must have been destroy_value. So we can just gather up those
14881560 // destroy_value and use then to create a new load_borrow scope.
14891561 SILBuilderWithScope builder (li);
1490- SILValue base = stripAccessMarkers (li->getOperand ());
1491- bool foundAccess = base != li->getOperand ();
1492-
1493- // Insert a new access scope.
1494- SILValue newBase = base;
1495- if (foundAccess) {
1496- newBase = builder.createBeginAccess (
1497- li->getLoc (), base, SILAccessKind::Read,
1498- SILAccessEnforcement::Static, false /* no nested conflict*/ ,
1499- false /* is from builtin*/ );
1500- }
1501- auto *lbi = builder.createLoadBorrow (li->getLoc (), newBase);
1562+ auto *lbi = builder.createLoadBorrow (li->getLoc (), li->getOperand ());
15021563
15031564 for (auto *consumeUse : li->getConsumingUses ()) {
15041565 auto *dvi = cast<DestroyValueInst>(consumeUse->getUser ());
15051566 SILBuilderWithScope destroyBuilder (dvi);
15061567 destroyBuilder.createEndBorrow (dvi->getLoc (), lbi);
1507- if (foundAccess)
1508- destroyBuilder.createEndAccess (dvi->getLoc (), newBase,
1509- false /* aborted*/ );
15101568 destroys.push_back (dvi);
15111569 changed = true ;
15121570 }
15131571
1514- // TODO: We need to check if this is the only use.
1515- if (auto *access = dyn_cast<BeginAccessInst>(li->getOperand ())) {
1516- bool foundUnknownUse = false ;
1517- for (auto *accUse : access->getUses ()) {
1518- if (accUse->getUser () == li)
1519- continue ;
1520- if (auto *ea = dyn_cast<EndAccessInst>(accUse->getUser ())) {
1521- endAccesses.push_back (ea);
1522- continue ;
1523- }
1524- foundUnknownUse = true ;
1525- }
1526- if (!foundUnknownUse) {
1527- for (auto *end : endAccesses)
1528- end->eraseFromParent ();
1529- access->replaceAllUsesWithUndef ();
1530- access->eraseFromParent ();
1531- }
1532- }
1533-
15341572 for (auto *d : destroys)
15351573 d->eraseFromParent ();
15361574 li->replaceAllUsesWith (lbi);
@@ -1539,6 +1577,7 @@ bool MoveOnlyChecker::performSingleCheck(MarkMustCheckInst *markedAddress) {
15391577 }
15401578 }
15411579
1580+ llvm::dbgs () << " Borrow: " << *pair.first ;
15421581 llvm_unreachable (" Unhandled case?!" );
15431582 }
15441583
@@ -1570,6 +1609,16 @@ bool MoveOnlyChecker::performSingleCheck(MarkMustCheckInst *markedAddress) {
15701609 }
15711610 llvm_unreachable (" Error?! This is a double destroy?!" );
15721611 }
1612+
1613+ if (auto *copyAddr = dyn_cast<CopyAddrInst>(&*ii)) {
1614+ if (!copyAddr->isTakeOfSrc ()) {
1615+ destroy->eraseFromParent ();
1616+ changed = true ;
1617+ foundSingleBlockCase = true ;
1618+ break ;
1619+ }
1620+ llvm_unreachable (" Error?! This is a double destroy?!" );
1621+ }
15731622 }
15741623
15751624 if (addressUseState.livenessUses .count (&*ii)) {
@@ -1606,6 +1655,17 @@ bool MoveOnlyChecker::performSingleCheck(MarkMustCheckInst *markedAddress) {
16061655 }
16071656 }
16081657
1658+ if (auto *copy = dyn_cast<CopyAddrInst>(take.first )) {
1659+ if (copy->isTakeOfSrc ())
1660+ continue ;
1661+ // Convert this to its take form.
1662+ if (auto *access = dyn_cast<BeginAccessInst>(copy->getSrc ()))
1663+ access->setAccessKind (SILAccessKind::Modify);
1664+ copy->setIsTakeOfSrc (IsTake);
1665+ continue ;
1666+ }
1667+
1668+ llvm::dbgs () << " Take User: " << *take.first ;
16091669 llvm_unreachable (" Unhandled case?!" );
16101670 }
16111671
0 commit comments