@@ -827,6 +827,87 @@ class TrackableValueState {
827
827
SWIFT_DEBUG_DUMP { print (llvm::dbgs ()); }
828
828
};
829
829
830
+ // / The representative value of the equivalence class that makes up a tracked
831
+ // / value.
832
+ // /
833
+ // / We use a wrapper struct here so that we can inject "fake" actor isolated
834
+ // / values into the regions of values that become merged into an actor by
835
+ // / calling a function without a non-sendable result.
836
+ class RepresentativeValue {
837
+ friend llvm::DenseMapInfo<RepresentativeValue>;
838
+
839
+ using InnerType = PointerUnion<SILValue, SILInstruction *>;
840
+
841
+ // / If this is set to a SILValue then it is the actual represented value. If
842
+ // / it is set to a SILInstruction, then this is a "fake" representative value
843
+ // / used to inject actor isolatedness. The instruction stored is the
844
+ // / instruction that introduced the actor isolated-ness.
845
+ InnerType value;
846
+
847
+ public:
848
+ RepresentativeValue () : value() {}
849
+ RepresentativeValue (SILValue value) : value(value) {}
850
+ RepresentativeValue (SILInstruction *actorRegionInst)
851
+ : value(actorRegionInst) {}
852
+
853
+ operator bool () const { return bool (value); }
854
+
855
+ void print (llvm::raw_ostream &os) const {
856
+ if (auto *inst = value.dyn_cast <SILInstruction *>()) {
857
+ os << " ActorRegionIntroducingInst: " << *inst;
858
+ return ;
859
+ }
860
+
861
+ os << *value.get <SILValue>();
862
+ }
863
+
864
+ SILValue getValue () const { return value.get <SILValue>(); }
865
+ SILValue maybeGetValue () const { return value.dyn_cast <SILValue>(); }
866
+ SILInstruction *getActorRegionIntroducingInst () const {
867
+ return value.get <SILInstruction *>();
868
+ }
869
+
870
+ SWIFT_DEBUG_DUMP { print (llvm::dbgs ()); }
871
+
872
+ private:
873
+ RepresentativeValue (InnerType value) : value(value) {}
874
+ };
875
+
876
+ } // namespace
877
+
878
+ namespace llvm {
879
+ llvm::raw_ostream &operator <<(llvm::raw_ostream &os,
880
+ const RepresentativeValue &value) {
881
+ value.print (os);
882
+ return os;
883
+ }
884
+
885
+ template <>
886
+ struct DenseMapInfo <::RepresentativeValue> {
887
+ using RepresentativeValue = ::RepresentativeValue;
888
+ using InnerType = RepresentativeValue::InnerType;
889
+ using InnerDenseMapInfo = DenseMapInfo<InnerType>;
890
+
891
+ static RepresentativeValue getEmptyKey () {
892
+ return RepresentativeValue (InnerDenseMapInfo::getEmptyKey ());
893
+ }
894
+ static RepresentativeValue getTombstoneKey () {
895
+ return RepresentativeValue (InnerDenseMapInfo::getTombstoneKey ());
896
+ }
897
+
898
+ static unsigned getHashValue (RepresentativeValue value) {
899
+ return InnerDenseMapInfo::getHashValue (value.value );
900
+ }
901
+
902
+ static bool isEqual (RepresentativeValue LHS, RepresentativeValue RHS) {
903
+ return InnerDenseMapInfo::isEqual (LHS.value , RHS.value );
904
+ }
905
+ };
906
+
907
+ } // namespace llvm
908
+
909
+ namespace {
910
+
830
911
// / A tuple consisting of a base value and its value state.
831
912
// /
832
913
// / DISCUSSION: We are computing regions among equivalence classes of values
@@ -843,11 +924,12 @@ class TrackableValueState {
843
924
// /
844
925
// / In the above example, %2 will be mapped to %0 by our value mapping.
845
926
class TrackableValue {
846
- SILValue representativeValue;
927
+ RepresentativeValue representativeValue;
847
928
TrackableValueState valueState;
848
929
849
930
public:
850
- TrackableValue (SILValue representativeValue, TrackableValueState valueState)
931
+ TrackableValue (RepresentativeValue representativeValue,
932
+ TrackableValueState valueState)
851
933
: representativeValue(representativeValue), valueState(valueState) {}
852
934
853
935
bool isMayAlias () const { return valueState.isMayAlias (); }
@@ -865,12 +947,12 @@ class TrackableValue {
865
947
}
866
948
867
949
// / Return the representative value of this equivalence class of values.
868
- SILValue getRepresentative () const { return representativeValue; }
950
+ RepresentativeValue getRepresentative () const { return representativeValue; }
869
951
870
952
void print (llvm::raw_ostream &os) const {
871
953
os << " TrackableValue. State: " ;
872
954
valueState.print (os);
873
- os << " \n Rep Value: " << * getRepresentative ();
955
+ os << " \n Rep Value: " << getRepresentative ();
874
956
}
875
957
876
958
SWIFT_DEBUG_DUMP { print (llvm::dbgs ()); }
@@ -898,6 +980,8 @@ struct PartitionOpBuilder {
898
980
TrackableValueID lookupValueID (SILValue value);
899
981
bool valueHasID (SILValue value, bool dumpIfHasNoID = false );
900
982
983
+ TrackableValueID getActorIntroducingRepresentative ();
984
+
901
985
void addAssignFresh (SILValue value) {
902
986
currentInstPartitionOps.emplace_back (
903
987
PartitionOp::AssignFresh (lookupValueID (value), currentInst));
@@ -948,6 +1032,19 @@ struct PartitionOpBuilder {
948
1032
lookupValueID (fst), lookupValueID (snd), currentInst));
949
1033
}
950
1034
1035
+ // / Mark \p value artifically as being part of an actor isolated region by
1036
+ // / introducing a new fake actor introducing representative and merging them.
1037
+ void addActorIntroducingInst (SILValue value) {
1038
+ assert (valueHasID (value, /* dumpIfHasNoID=*/ true ) &&
1039
+ " merged values should already have been encountered" );
1040
+
1041
+ auto elt = getActorIntroducingRepresentative ();
1042
+ currentInstPartitionOps.emplace_back (
1043
+ PartitionOp::AssignFresh (elt, currentInst));
1044
+ currentInstPartitionOps.emplace_back (
1045
+ PartitionOp::Merge (lookupValueID (value), elt, currentInst));
1046
+ }
1047
+
951
1048
void addRequire (SILValue value) {
952
1049
assert (valueHasID (value, /* dumpIfHasNoID=*/ true ) &&
953
1050
" required value should already have been encountered" );
@@ -990,8 +1087,9 @@ class PartitionOpTranslator {
990
1087
// / non-Sendable values. Implicit conversion from SILValue used pervasively.
991
1088
// / ensure getUnderlyingTrackedValue is called on SILValues before entering
992
1089
// / into this map
993
- llvm::DenseMap<SILValue, TrackableValueState> equivalenceClassValuesToState;
994
- llvm::DenseMap<unsigned , SILValue> stateIndexToEquivalenceClass;
1090
+ llvm::DenseMap<RepresentativeValue, TrackableValueState>
1091
+ equivalenceClassValuesToState;
1092
+ llvm::DenseMap<unsigned , RepresentativeValue> stateIndexToEquivalenceClass;
995
1093
996
1094
// / A list of values that can never be transferred.
997
1095
// /
@@ -1075,8 +1173,8 @@ class PartitionOpTranslator {
1075
1173
1076
1174
// Check if our base is a ref_element_addr from an actor. In such a case,
1077
1175
// mark this value as actor derived.
1078
- if (isa<LoadInst, LoadBorrowInst>(iter.first ->first )) {
1079
- auto *svi = cast<SingleValueInstruction>(iter.first ->first );
1176
+ if (isa<LoadInst, LoadBorrowInst>(iter.first ->first . getValue () )) {
1177
+ auto *svi = cast<SingleValueInstruction>(iter.first ->first . getValue () );
1080
1178
auto storage = AccessStorageWithBase::compute (svi->getOperand (0 ));
1081
1179
if (storage.storage && isa<RefElementAddrInst>(storage.base )) {
1082
1180
if (storage.storage .getRoot ()->getType ().isActor ()) {
@@ -1087,7 +1185,7 @@ class PartitionOpTranslator {
1087
1185
1088
1186
// Check if we have an unsafeMutableAddressor from a global actor, mark the
1089
1187
// returned value as being actor derived.
1090
- if (auto applySite = FullApplySite::isa (iter.first ->first )) {
1188
+ if (auto applySite = FullApplySite::isa (iter.first ->first . getValue () )) {
1091
1189
if (auto *calleeFunction = applySite.getCalleeFunction ()) {
1092
1190
if (calleeFunction->isGlobalInit () &&
1093
1191
isGlobalActorInit (calleeFunction)) {
@@ -1102,6 +1200,25 @@ class PartitionOpTranslator {
1102
1200
return {iter.first ->first , iter.first ->second };
1103
1201
}
1104
1202
1203
+ TrackableValue
1204
+ getActorIntroducingRepresentative (SILInstruction *introducingInst) const {
1205
+ auto *self = const_cast <PartitionOpTranslator *>(this );
1206
+ auto iter = self->equivalenceClassValuesToState .try_emplace (
1207
+ introducingInst,
1208
+ TrackableValueState (equivalenceClassValuesToState.size ()));
1209
+
1210
+ // If we did not insert, just return the already stored value.
1211
+ if (!iter.second ) {
1212
+ return {iter.first ->first , iter.first ->second };
1213
+ }
1214
+
1215
+ // Otherwise, wire up the value.
1216
+ self->stateIndexToEquivalenceClass [iter.first ->second .getID ()] =
1217
+ introducingInst;
1218
+ iter.first ->getSecond ().addFlag (TrackableValueFlag::isActorDerived);
1219
+ return {iter.first ->first , iter.first ->second };
1220
+ }
1221
+
1105
1222
bool markValueAsActorDerived (SILValue value) {
1106
1223
value = getUnderlyingTrackedValue (value);
1107
1224
auto iter = equivalenceClassValuesToState.find (value);
@@ -1300,7 +1417,7 @@ class PartitionOpTranslator {
1300
1417
void dumpValues () const {
1301
1418
// Since this is just used for debug output, be inefficient to make nicer
1302
1419
// output.
1303
- std::vector<std::pair<unsigned , SILValue >> temp;
1420
+ std::vector<std::pair<unsigned , RepresentativeValue >> temp;
1304
1421
for (auto p : stateIndexToEquivalenceClass) {
1305
1422
temp.emplace_back (p.first , p.second );
1306
1423
}
@@ -1336,13 +1453,13 @@ class PartitionOpTranslator {
1336
1453
1337
1454
for (SILValue src : sourceValues) {
1338
1455
if (auto value = tryToTrackValue (src)) {
1339
- assignOperands.push_back (value->getRepresentative ());
1456
+ assignOperands.push_back (value->getRepresentative (). getValue () );
1340
1457
}
1341
1458
}
1342
1459
1343
1460
for (SILValue result : resultValues) {
1344
1461
if (auto value = tryToTrackValue (result)) {
1345
- assignResults.push_back (value->getRepresentative ());
1462
+ assignResults.push_back (value->getRepresentative (). getValue () );
1346
1463
// TODO: Can we pass back a reference to value perhaps?
1347
1464
if (options.contains (SILMultiAssignFlags::PropagatesActorSelf)) {
1348
1465
markValueAsActorDerived (result);
@@ -1360,8 +1477,18 @@ class PartitionOpTranslator {
1360
1477
}
1361
1478
1362
1479
// If we do not have any non sendable results, return early.
1363
- if (assignResults.empty ())
1480
+ if (assignResults.empty ()) {
1481
+ // If we did not have any non-Sendable results and we did have
1482
+ // non-Sendable operands and we are supposed to mark value as actor
1483
+ // derived, introduce a fake element so we just propagate the actor
1484
+ // region.
1485
+ if (assignOperands.size () &&
1486
+ options.contains (SILMultiAssignFlags::PropagatesActorSelf)) {
1487
+ builder.addActorIntroducingInst (assignOperands.back ());
1488
+ }
1489
+
1364
1490
return ;
1491
+ }
1365
1492
1366
1493
auto assignResultsRef = llvm::makeArrayRef (assignResults);
1367
1494
SILValue front = assignResultsRef.front ();
@@ -1426,7 +1553,8 @@ class PartitionOpTranslator {
1426
1553
}))
1427
1554
continue ;
1428
1555
1429
- builder.addUndoTransfer (trackedArgValue->getRepresentative (), ai);
1556
+ builder.addUndoTransfer (trackedArgValue->getRepresentative ().getValue (),
1557
+ ai);
1430
1558
}
1431
1559
}
1432
1560
}
@@ -1444,8 +1572,9 @@ class PartitionOpTranslator {
1444
1572
// useValue(x2)
1445
1573
for (auto &op : ApplySite (pai).getArgumentOperands ()) {
1446
1574
if (auto trackedArgValue = tryToTrackValue (op.get ())) {
1447
- builder.addRequire (trackedArgValue->getRepresentative ());
1448
- builder.addTransfer (trackedArgValue->getRepresentative (), &op);
1575
+ builder.addRequire (trackedArgValue->getRepresentative ().getValue ());
1576
+ builder.addTransfer (trackedArgValue->getRepresentative ().getValue (),
1577
+ &op);
1449
1578
}
1450
1579
}
1451
1580
}
@@ -1538,19 +1667,19 @@ class PartitionOpTranslator {
1538
1667
// require all operands
1539
1668
for (auto op : applySite->getOperandValues ())
1540
1669
if (auto value = tryToTrackValue (op))
1541
- builder.addRequire (value->getRepresentative ());
1670
+ builder.addRequire (value->getRepresentative (). getValue () );
1542
1671
1543
1672
auto handleSILOperands = [&](MutableArrayRef<Operand> operands) {
1544
1673
for (auto &op : operands) {
1545
1674
if (auto value = tryToTrackValue (op.get ())) {
1546
- builder.addTransfer (value->getRepresentative (), &op);
1675
+ builder.addTransfer (value->getRepresentative (). getValue () , &op);
1547
1676
}
1548
1677
}
1549
1678
};
1550
1679
1551
1680
auto handleSILSelf = [&](Operand *self) {
1552
1681
if (auto value = tryToTrackValue (self->get ())) {
1553
- builder.addTransfer (value->getRepresentative (), self);
1682
+ builder.addTransfer (value->getRepresentative (). getValue () , self);
1554
1683
}
1555
1684
};
1556
1685
@@ -1568,7 +1697,7 @@ class PartitionOpTranslator {
1568
1697
getApplyResults (*applySite, applyResults);
1569
1698
for (auto result : applyResults)
1570
1699
if (auto value = tryToTrackValue (result))
1571
- builder.addAssignFresh (value->getRepresentative ());
1700
+ builder.addAssignFresh (value->getRepresentative (). getValue () );
1572
1701
}
1573
1702
1574
1703
template <typename DestValues>
@@ -1636,8 +1765,8 @@ class PartitionOpTranslator {
1636
1765
return ;
1637
1766
for (SILValue elt : collection) {
1638
1767
if (auto trackableSrc = tryToTrackValue (elt)) {
1639
- builder.addMerge (trackableDest->getRepresentative (),
1640
- trackableSrc->getRepresentative ());
1768
+ builder.addMerge (trackableDest->getRepresentative (). getValue () ,
1769
+ trackableSrc->getRepresentative (). getValue () );
1641
1770
}
1642
1771
}
1643
1772
}
@@ -1701,7 +1830,7 @@ class PartitionOpTranslator {
1701
1830
1702
1831
void translateSILRequire (SILValue val) {
1703
1832
if (auto nonSendableVal = tryToTrackValue (val))
1704
- return builder.addRequire (nonSendableVal->getRepresentative ());
1833
+ return builder.addRequire (nonSendableVal->getRepresentative (). getValue () );
1705
1834
}
1706
1835
1707
1836
// / An enum select is just a multi assign.
@@ -2084,6 +2213,10 @@ TrackableValueID PartitionOpBuilder::lookupValueID(SILValue value) {
2084
2213
return translator->lookupValueID (value);
2085
2214
}
2086
2215
2216
+ TrackableValueID PartitionOpBuilder::getActorIntroducingRepresentative () {
2217
+ return translator->getActorIntroducingRepresentative (currentInst).getID ();
2218
+ }
2219
+
2087
2220
bool PartitionOpBuilder::valueHasID (SILValue value, bool dumpIfHasNoID) {
2088
2221
return translator->valueHasID (value, dumpIfHasNoID);
2089
2222
}
@@ -2129,7 +2262,7 @@ void PartitionOpBuilder::print(llvm::raw_ostream &os) const {
2129
2262
sortUnique (opsToPrint);
2130
2263
for (unsigned opArg : opsToPrint) {
2131
2264
llvm::dbgs () << " └╼ " ;
2132
- SILValue value = translator->stateIndexToEquivalenceClass [opArg];
2265
+ auto value = translator->stateIndexToEquivalenceClass [opArg];
2133
2266
auto iter = translator->equivalenceClassValuesToState .find (value);
2134
2267
assert (iter != translator->equivalenceClassValuesToState .end ());
2135
2268
llvm::dbgs () << " State: %%" << opArg << " . " ;
@@ -2191,8 +2324,10 @@ class BlockPartitionState {
2191
2324
auto iter = translator.getValueForId (element);
2192
2325
if (!iter)
2193
2326
return false ;
2194
- return translator.isClosureCaptured (iter->getRepresentative (),
2195
- op->getUser ());
2327
+ auto value = iter->getRepresentative ().maybeGetValue ();
2328
+ if (!value)
2329
+ return false ;
2330
+ return translator.isClosureCaptured (value, op->getUser ());
2196
2331
};
2197
2332
for (const auto &partitionOp : blockPartitionOps) {
2198
2333
// By calling apply without providing a `handleFailure` closure, errors
@@ -2609,8 +2744,9 @@ class PartitionAnalysis {
2609
2744
}
2610
2745
}
2611
2746
2612
- auto rep =
2613
- translator.getValueForId (transferredVal)->getRepresentative ();
2747
+ auto rep = translator.getValueForId (transferredVal)
2748
+ ->getRepresentative ()
2749
+ .getValue ();
2614
2750
LLVM_DEBUG (
2615
2751
llvm::dbgs ()
2616
2752
<< " Emitting Use After Transfer Error!\n "
@@ -2630,7 +2766,8 @@ class PartitionAnalysis {
2630
2766
<< " ID: %%" << transferredVal << " \n "
2631
2767
<< " Rep: "
2632
2768
<< *translator.getValueForId (transferredVal)
2633
- ->getRepresentative ());
2769
+ ->getRepresentative ()
2770
+ .getValue ());
2634
2771
diagnose (partitionOp,
2635
2772
diag::regionbasedisolation_selforargtransferred);
2636
2773
};
@@ -2646,8 +2783,10 @@ class PartitionAnalysis {
2646
2783
auto iter = translator.getValueForId (element);
2647
2784
if (!iter)
2648
2785
return false ;
2649
- return translator.isClosureCaptured (iter->getRepresentative (),
2650
- op->getUser ());
2786
+ auto value = iter->getRepresentative ().maybeGetValue ();
2787
+ if (!value)
2788
+ return false ;
2789
+ return translator.isClosureCaptured (value, op->getUser ());
2651
2790
};
2652
2791
2653
2792
// And then evaluate all of our partition ops on the entry partition.
0 commit comments