Skip to content

Commit e7a2a9f

Browse files
committed
[region-isolation] Ensure that actor methods without a result properly mark their operands as being actor derived.
I did this by abstracting the representative value of an equivalence class into two cases: the normal case of actually having a value and a second case which is used only to inject into a region an actor derived value. rdar://119113563
1 parent dc33b2d commit e7a2a9f

File tree

2 files changed

+228
-37
lines changed

2 files changed

+228
-37
lines changed

lib/SILOptimizer/Mandatory/TransferNonSendable.cpp

Lines changed: 170 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,87 @@ class TrackableValueState {
827827
SWIFT_DEBUG_DUMP { print(llvm::dbgs()); }
828828
};
829829

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+
830911
/// A tuple consisting of a base value and its value state.
831912
///
832913
/// DISCUSSION: We are computing regions among equivalence classes of values
@@ -843,11 +924,12 @@ class TrackableValueState {
843924
///
844925
/// In the above example, %2 will be mapped to %0 by our value mapping.
845926
class TrackableValue {
846-
SILValue representativeValue;
927+
RepresentativeValue representativeValue;
847928
TrackableValueState valueState;
848929

849930
public:
850-
TrackableValue(SILValue representativeValue, TrackableValueState valueState)
931+
TrackableValue(RepresentativeValue representativeValue,
932+
TrackableValueState valueState)
851933
: representativeValue(representativeValue), valueState(valueState) {}
852934

853935
bool isMayAlias() const { return valueState.isMayAlias(); }
@@ -865,12 +947,12 @@ class TrackableValue {
865947
}
866948

867949
/// Return the representative value of this equivalence class of values.
868-
SILValue getRepresentative() const { return representativeValue; }
950+
RepresentativeValue getRepresentative() const { return representativeValue; }
869951

870952
void print(llvm::raw_ostream &os) const {
871953
os << "TrackableValue. State: ";
872954
valueState.print(os);
873-
os << "\n Rep Value: " << *getRepresentative();
955+
os << "\n Rep Value: " << getRepresentative();
874956
}
875957

876958
SWIFT_DEBUG_DUMP { print(llvm::dbgs()); }
@@ -898,6 +980,8 @@ struct PartitionOpBuilder {
898980
TrackableValueID lookupValueID(SILValue value);
899981
bool valueHasID(SILValue value, bool dumpIfHasNoID = false);
900982

983+
TrackableValueID getActorIntroducingRepresentative();
984+
901985
void addAssignFresh(SILValue value) {
902986
currentInstPartitionOps.emplace_back(
903987
PartitionOp::AssignFresh(lookupValueID(value), currentInst));
@@ -948,6 +1032,19 @@ struct PartitionOpBuilder {
9481032
lookupValueID(fst), lookupValueID(snd), currentInst));
9491033
}
9501034

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+
9511048
void addRequire(SILValue value) {
9521049
assert(valueHasID(value, /*dumpIfHasNoID=*/true) &&
9531050
"required value should already have been encountered");
@@ -990,8 +1087,9 @@ class PartitionOpTranslator {
9901087
/// non-Sendable values. Implicit conversion from SILValue used pervasively.
9911088
/// ensure getUnderlyingTrackedValue is called on SILValues before entering
9921089
/// 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;
9951093

9961094
/// A list of values that can never be transferred.
9971095
///
@@ -1075,8 +1173,8 @@ class PartitionOpTranslator {
10751173

10761174
// Check if our base is a ref_element_addr from an actor. In such a case,
10771175
// 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());
10801178
auto storage = AccessStorageWithBase::compute(svi->getOperand(0));
10811179
if (storage.storage && isa<RefElementAddrInst>(storage.base)) {
10821180
if (storage.storage.getRoot()->getType().isActor()) {
@@ -1087,7 +1185,7 @@ class PartitionOpTranslator {
10871185

10881186
// Check if we have an unsafeMutableAddressor from a global actor, mark the
10891187
// 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())) {
10911189
if (auto *calleeFunction = applySite.getCalleeFunction()) {
10921190
if (calleeFunction->isGlobalInit() &&
10931191
isGlobalActorInit(calleeFunction)) {
@@ -1102,6 +1200,25 @@ class PartitionOpTranslator {
11021200
return {iter.first->first, iter.first->second};
11031201
}
11041202

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+
11051222
bool markValueAsActorDerived(SILValue value) {
11061223
value = getUnderlyingTrackedValue(value);
11071224
auto iter = equivalenceClassValuesToState.find(value);
@@ -1300,7 +1417,7 @@ class PartitionOpTranslator {
13001417
void dumpValues() const {
13011418
// Since this is just used for debug output, be inefficient to make nicer
13021419
// output.
1303-
std::vector<std::pair<unsigned, SILValue>> temp;
1420+
std::vector<std::pair<unsigned, RepresentativeValue>> temp;
13041421
for (auto p : stateIndexToEquivalenceClass) {
13051422
temp.emplace_back(p.first, p.second);
13061423
}
@@ -1336,13 +1453,13 @@ class PartitionOpTranslator {
13361453

13371454
for (SILValue src : sourceValues) {
13381455
if (auto value = tryToTrackValue(src)) {
1339-
assignOperands.push_back(value->getRepresentative());
1456+
assignOperands.push_back(value->getRepresentative().getValue());
13401457
}
13411458
}
13421459

13431460
for (SILValue result : resultValues) {
13441461
if (auto value = tryToTrackValue(result)) {
1345-
assignResults.push_back(value->getRepresentative());
1462+
assignResults.push_back(value->getRepresentative().getValue());
13461463
// TODO: Can we pass back a reference to value perhaps?
13471464
if (options.contains(SILMultiAssignFlags::PropagatesActorSelf)) {
13481465
markValueAsActorDerived(result);
@@ -1360,8 +1477,18 @@ class PartitionOpTranslator {
13601477
}
13611478

13621479
// 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+
13641490
return;
1491+
}
13651492

13661493
auto assignResultsRef = llvm::makeArrayRef(assignResults);
13671494
SILValue front = assignResultsRef.front();
@@ -1426,7 +1553,8 @@ class PartitionOpTranslator {
14261553
}))
14271554
continue;
14281555

1429-
builder.addUndoTransfer(trackedArgValue->getRepresentative(), ai);
1556+
builder.addUndoTransfer(trackedArgValue->getRepresentative().getValue(),
1557+
ai);
14301558
}
14311559
}
14321560
}
@@ -1444,8 +1572,9 @@ class PartitionOpTranslator {
14441572
// useValue(x2)
14451573
for (auto &op : ApplySite(pai).getArgumentOperands()) {
14461574
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);
14491578
}
14501579
}
14511580
}
@@ -1538,19 +1667,19 @@ class PartitionOpTranslator {
15381667
// require all operands
15391668
for (auto op : applySite->getOperandValues())
15401669
if (auto value = tryToTrackValue(op))
1541-
builder.addRequire(value->getRepresentative());
1670+
builder.addRequire(value->getRepresentative().getValue());
15421671

15431672
auto handleSILOperands = [&](MutableArrayRef<Operand> operands) {
15441673
for (auto &op : operands) {
15451674
if (auto value = tryToTrackValue(op.get())) {
1546-
builder.addTransfer(value->getRepresentative(), &op);
1675+
builder.addTransfer(value->getRepresentative().getValue(), &op);
15471676
}
15481677
}
15491678
};
15501679

15511680
auto handleSILSelf = [&](Operand *self) {
15521681
if (auto value = tryToTrackValue(self->get())) {
1553-
builder.addTransfer(value->getRepresentative(), self);
1682+
builder.addTransfer(value->getRepresentative().getValue(), self);
15541683
}
15551684
};
15561685

@@ -1568,7 +1697,7 @@ class PartitionOpTranslator {
15681697
getApplyResults(*applySite, applyResults);
15691698
for (auto result : applyResults)
15701699
if (auto value = tryToTrackValue(result))
1571-
builder.addAssignFresh(value->getRepresentative());
1700+
builder.addAssignFresh(value->getRepresentative().getValue());
15721701
}
15731702

15741703
template <typename DestValues>
@@ -1636,8 +1765,8 @@ class PartitionOpTranslator {
16361765
return;
16371766
for (SILValue elt : collection) {
16381767
if (auto trackableSrc = tryToTrackValue(elt)) {
1639-
builder.addMerge(trackableDest->getRepresentative(),
1640-
trackableSrc->getRepresentative());
1768+
builder.addMerge(trackableDest->getRepresentative().getValue(),
1769+
trackableSrc->getRepresentative().getValue());
16411770
}
16421771
}
16431772
}
@@ -1701,7 +1830,7 @@ class PartitionOpTranslator {
17011830

17021831
void translateSILRequire(SILValue val) {
17031832
if (auto nonSendableVal = tryToTrackValue(val))
1704-
return builder.addRequire(nonSendableVal->getRepresentative());
1833+
return builder.addRequire(nonSendableVal->getRepresentative().getValue());
17051834
}
17061835

17071836
/// An enum select is just a multi assign.
@@ -2084,6 +2213,10 @@ TrackableValueID PartitionOpBuilder::lookupValueID(SILValue value) {
20842213
return translator->lookupValueID(value);
20852214
}
20862215

2216+
TrackableValueID PartitionOpBuilder::getActorIntroducingRepresentative() {
2217+
return translator->getActorIntroducingRepresentative(currentInst).getID();
2218+
}
2219+
20872220
bool PartitionOpBuilder::valueHasID(SILValue value, bool dumpIfHasNoID) {
20882221
return translator->valueHasID(value, dumpIfHasNoID);
20892222
}
@@ -2129,7 +2262,7 @@ void PartitionOpBuilder::print(llvm::raw_ostream &os) const {
21292262
sortUnique(opsToPrint);
21302263
for (unsigned opArg : opsToPrint) {
21312264
llvm::dbgs() << " └╼ ";
2132-
SILValue value = translator->stateIndexToEquivalenceClass[opArg];
2265+
auto value = translator->stateIndexToEquivalenceClass[opArg];
21332266
auto iter = translator->equivalenceClassValuesToState.find(value);
21342267
assert(iter != translator->equivalenceClassValuesToState.end());
21352268
llvm::dbgs() << "State: %%" << opArg << ". ";
@@ -2191,8 +2324,10 @@ class BlockPartitionState {
21912324
auto iter = translator.getValueForId(element);
21922325
if (!iter)
21932326
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());
21962331
};
21972332
for (const auto &partitionOp : blockPartitionOps) {
21982333
// By calling apply without providing a `handleFailure` closure, errors
@@ -2609,8 +2744,9 @@ class PartitionAnalysis {
26092744
}
26102745
}
26112746

2612-
auto rep =
2613-
translator.getValueForId(transferredVal)->getRepresentative();
2747+
auto rep = translator.getValueForId(transferredVal)
2748+
->getRepresentative()
2749+
.getValue();
26142750
LLVM_DEBUG(
26152751
llvm::dbgs()
26162752
<< " Emitting Use After Transfer Error!\n"
@@ -2630,7 +2766,8 @@ class PartitionAnalysis {
26302766
<< " ID: %%" << transferredVal << "\n"
26312767
<< " Rep: "
26322768
<< *translator.getValueForId(transferredVal)
2633-
->getRepresentative());
2769+
->getRepresentative()
2770+
.getValue());
26342771
diagnose(partitionOp,
26352772
diag::regionbasedisolation_selforargtransferred);
26362773
};
@@ -2646,8 +2783,10 @@ class PartitionAnalysis {
26462783
auto iter = translator.getValueForId(element);
26472784
if (!iter)
26482785
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());
26512790
};
26522791

26532792
// And then evaluate all of our partition ops on the entry partition.

0 commit comments

Comments
 (0)