146
146
#include " llvm/ADT/PointerUnion.h"
147
147
#include " llvm/ADT/SmallBitVector.h"
148
148
#include " llvm/ADT/SmallPtrSet.h"
149
+ #include " llvm/ADT/SmallVector.h"
149
150
#include " llvm/Support/Debug.h"
150
151
#include " llvm/Support/ErrorHandling.h"
151
152
@@ -204,10 +205,31 @@ struct DiagnosticEmitter {
204
205
SILInstruction *violatingUse);
205
206
void emitAddressDiagnosticNoCopy (MarkMustCheckInst *markedValue,
206
207
SILInstruction *consumingUse);
208
+ void emitExclusivityHazardDiagnostic (MarkMustCheckInst *markedValue,
209
+ SILInstruction *consumingUse);
207
210
};
208
211
209
212
} // namespace
210
213
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
+
211
233
void DiagnosticEmitter::emitAddressDiagnostic (
212
234
MarkMustCheckInst *markedValue, SILInstruction *lastLiveUse,
213
235
SILInstruction *violatingUse, bool isUseConsuming,
@@ -775,13 +797,18 @@ struct GatherUsesVisitor : public AccessUseVisitor {
775
797
bool emittedEarlyDiagnostic = false ;
776
798
DiagnosticEmitter &diagnosticEmitter;
777
799
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
+
778
804
GatherUsesVisitor (MoveOnlyChecker &moveChecker, UseState &useState,
779
805
MarkMustCheckInst *markedValue,
780
- DiagnosticEmitter &diagnosticEmitter)
806
+ DiagnosticEmitter &diagnosticEmitter,
807
+ SSAPrunedLiveness &gatherUsesLiveness)
781
808
: AccessUseVisitor(AccessUseType::Overlapping,
782
809
NestedAccessType::IgnoreAccessBegin),
783
810
moveChecker (moveChecker), useState(useState), markedValue(markedValue),
784
- diagnosticEmitter(diagnosticEmitter) {}
811
+ diagnosticEmitter(diagnosticEmitter), liveness(gatherUsesLiveness) {}
785
812
786
813
bool visitUse (Operand *op, AccessUseType useTy) override ;
787
814
void reset (SILValue address) { useState.address = address; }
@@ -795,6 +822,41 @@ struct GatherUsesVisitor : public AccessUseVisitor {
795
822
// / base address that we are checking which should be the operand of the mark
796
823
// / must check value.
797
824
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
+ }
798
860
};
799
861
800
862
} // end anonymous namespace
@@ -934,6 +996,14 @@ bool GatherUsesVisitor::visitUse(Operand *op, AccessUseType useTy) {
934
996
return false ;
935
997
936
998
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
+
937
1007
useState.borrows .insert ({user, *leafRange});
938
1008
return true ;
939
1009
}
@@ -965,7 +1035,14 @@ bool GatherUsesVisitor::visitUse(Operand *op, AccessUseType useTy) {
965
1035
return false ;
966
1036
967
1037
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
+
969
1046
useState.borrows .insert ({user, *leafRange});
970
1047
} else {
971
1048
LLVM_DEBUG (llvm::dbgs () << " Found take inst: " << *user);
@@ -1155,8 +1232,10 @@ bool MoveOnlyChecker::performSingleCheck(MarkMustCheckInst *markedAddress) {
1155
1232
// Then gather all uses of our address by walking from def->uses. We use this
1156
1233
// to categorize the uses of this address into their ownership behavior (e.x.:
1157
1234
// init, reinit, take, destroy, etc.).
1235
+ SmallVector<SILBasicBlock *, 32 > gatherUsesDiscoveredBlocks;
1236
+ SSAPrunedLiveness gatherUsesLiveness (&gatherUsesDiscoveredBlocks);
1158
1237
GatherUsesVisitor visitor (*this , addressUseState, markedAddress,
1159
- diagnosticEmitter);
1238
+ diagnosticEmitter, gatherUsesLiveness );
1160
1239
SWIFT_DEFER { visitor.clear (); };
1161
1240
visitor.reset (markedAddress);
1162
1241
if (!visitAccessPathUses (visitor, accessPath, fn)) {
@@ -1467,13 +1546,6 @@ bool MoveOnlyChecker::performSingleCheck(MarkMustCheckInst *markedAddress) {
1467
1546
}
1468
1547
}
1469
1548
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
-
1477
1549
// Ok, we not have emitted our main errors. Now we begin the
1478
1550
// transformation. We begin by processing borrows. We can also emit errors
1479
1551
// 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) {
1487
1559
// must have been destroy_value. So we can just gather up those
1488
1560
// destroy_value and use then to create a new load_borrow scope.
1489
1561
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 ());
1502
1563
1503
1564
for (auto *consumeUse : li->getConsumingUses ()) {
1504
1565
auto *dvi = cast<DestroyValueInst>(consumeUse->getUser ());
1505
1566
SILBuilderWithScope destroyBuilder (dvi);
1506
1567
destroyBuilder.createEndBorrow (dvi->getLoc (), lbi);
1507
- if (foundAccess)
1508
- destroyBuilder.createEndAccess (dvi->getLoc (), newBase,
1509
- false /* aborted*/ );
1510
1568
destroys.push_back (dvi);
1511
1569
changed = true ;
1512
1570
}
1513
1571
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
-
1534
1572
for (auto *d : destroys)
1535
1573
d->eraseFromParent ();
1536
1574
li->replaceAllUsesWith (lbi);
@@ -1539,6 +1577,7 @@ bool MoveOnlyChecker::performSingleCheck(MarkMustCheckInst *markedAddress) {
1539
1577
}
1540
1578
}
1541
1579
1580
+ llvm::dbgs () << " Borrow: " << *pair.first ;
1542
1581
llvm_unreachable (" Unhandled case?!" );
1543
1582
}
1544
1583
@@ -1570,6 +1609,16 @@ bool MoveOnlyChecker::performSingleCheck(MarkMustCheckInst *markedAddress) {
1570
1609
}
1571
1610
llvm_unreachable (" Error?! This is a double destroy?!" );
1572
1611
}
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
+ }
1573
1622
}
1574
1623
1575
1624
if (addressUseState.livenessUses .count (&*ii)) {
@@ -1606,6 +1655,17 @@ bool MoveOnlyChecker::performSingleCheck(MarkMustCheckInst *markedAddress) {
1606
1655
}
1607
1656
}
1608
1657
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 ;
1609
1669
llvm_unreachable (" Unhandled case?!" );
1610
1670
}
1611
1671
0 commit comments