Skip to content

Commit 75826c0

Browse files
authored
Merge pull request #72222 from gottesmm/propagate-actor-information
[region-isolation] Propagate region information from the analysis into the diagnostic emitter and fix a bunch of issues on the way
2 parents 143d8f9 + 258992c commit 75826c0

18 files changed

+668
-315
lines changed

include/swift/AST/ActorIsolation.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,9 @@ class ActorIsolation {
274274
llvm_unreachable("Covered switch isn't covered?!");
275275
}
276276

277+
void printForDiagnostics(llvm::raw_ostream &os,
278+
StringRef openingQuotationMark = "'") const;
279+
277280
SWIFT_DEBUG_DUMP { print(llvm::dbgs()); }
278281
};
279282

include/swift/AST/DiagnosticsSIL.def

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -954,10 +954,10 @@ ERROR(regionbasedisolation_transfer_yields_race_stronglytransferred_binding, non
954954
"binding of non-Sendable type %0 accessed after being transferred; later accesses could race",
955955
(Type))
956956
ERROR(regionbasedisolation_arg_transferred, none,
957-
"task isolated value of type %0 transferred to %1 context; later accesses to value could race",
958-
(Type, ActorIsolation))
957+
"%0 value of type %1 transferred to %2 context; later accesses to value could race",
958+
(StringRef, Type, ActorIsolation))
959959
ERROR(regionbasedisolation_arg_passed_to_strongly_transferred_param, none,
960-
"task isolated value of type %0 passed as a strongly transferred parameter; later accesses could race",
960+
"task-isolated value of type %0 passed as a strongly transferred parameter; later accesses could race",
961961
(Type))
962962
NOTE(regionbasedisolation_isolated_since_in_same_region_basename, none,
963963
"value is %0 since it is in the same region as %1",
@@ -974,7 +974,7 @@ ERROR(regionbasedisolation_stronglytransfer_assignment_yields_race_name, none,
974974
"assigning %0 to transferring parameter %1 may cause a race",
975975
(Identifier, Identifier))
976976
NOTE(regionbasedisolation_stronglytransfer_taskisolated_assign_note, none,
977-
"%0 is a task isolated value that is assigned into transferring parameter %1. Transferred uses of %1 may race with caller uses of %0",
977+
"%0 is a task-isolated value that is assigned into transferring parameter %1. Transferred uses of %1 may race with caller uses of %0",
978978
(Identifier, Identifier))
979979

980980
NOTE(regionbasedisolation_named_info_transfer_yields_race, none,
@@ -987,7 +987,7 @@ NOTE(regionbasedisolation_named_info_isolated_capture, none,
987987
"%1 value %0 is captured by %2 closure. Later local uses could race",
988988
(Identifier, ActorIsolation, ActorIsolation))
989989
NOTE(regionbasedisolation_named_arg_info, none,
990-
"Transferring task isolated function argument %0 could yield races with caller uses",
990+
"Transferring task-isolated function argument %0 could yield races with caller uses",
991991
(Identifier))
992992
NOTE(regionbasedisolation_named_stronglytransferred_binding, none,
993993
"Cannot access a transferring parameter after the parameter has been transferred", ())

include/swift/SILOptimizer/Analysis/RegionAnalysis.h

Lines changed: 190 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "swift/SILOptimizer/Utils/PartitionUtils.h"
2020

2121
#include <optional>
22+
#include <variant>
2223

2324
namespace swift {
2425

@@ -125,24 +126,166 @@ enum class TrackableValueFlag {
125126

126127
/// Set to true if this TrackableValue's representative is Sendable.
127128
isSendable = 0x2,
128-
129-
/// Set to true if this TrackableValue is a non-sendable object derived from
130-
/// an actor. Example: a value loaded from a ref_element_addr from an actor.
131-
///
132-
/// NOTE: We track values with an actor representative even though actors are
133-
/// sendable to be able to properly identify values that escape an actor since
134-
/// if we escape an actor into a closure, we want to mark the closure as actor
135-
/// derived.
136-
isActorDerived = 0x4,
137129
};
138130

139131
using TrackedValueFlagSet = OptionSet<TrackableValueFlag>;
140132

133+
class ValueIsolationRegionInfo {
134+
public:
135+
/// The lattice is:
136+
///
137+
/// Unknown -> Disconnected -> TransferringParameter -> Task -> Actor.
138+
///
139+
/// Unknown means no information. We error when merging on it.
140+
enum Kind {
141+
Unknown,
142+
Disconnected,
143+
Task,
144+
Actor,
145+
};
146+
147+
private:
148+
Kind kind;
149+
// clang-format off
150+
std::variant<
151+
// Used for actor isolated when we have ActorIsolation info from the AST.
152+
std::optional<ActorIsolation>,
153+
// Used for actor isolation when we infer the actor at the SIL level.
154+
NominalTypeDecl *,
155+
// The task isolated parameter when we find a task isolated value.
156+
SILValue
157+
> data;
158+
// clang-format on
159+
160+
ValueIsolationRegionInfo(Kind kind,
161+
std::optional<ActorIsolation> actorIsolation)
162+
: kind(kind), data(actorIsolation) {}
163+
ValueIsolationRegionInfo(Kind kind, NominalTypeDecl *decl)
164+
: kind(kind), data(decl) {}
165+
166+
ValueIsolationRegionInfo(Kind kind, SILValue value)
167+
: kind(kind), data(value) {}
168+
169+
public:
170+
ValueIsolationRegionInfo() : kind(Kind::Unknown), data() {}
171+
172+
operator bool() const { return kind != Kind::Unknown; }
173+
174+
operator Kind() const { return kind; }
175+
176+
Kind getKind() const { return kind; }
177+
178+
bool isDisconnected() const { return kind == Kind::Disconnected; }
179+
bool isActorIsolated() const { return kind == Kind::Actor; }
180+
bool isTaskIsolated() const { return kind == Kind::Task; }
181+
182+
void print(llvm::raw_ostream &os) const {
183+
switch (Kind(*this)) {
184+
case Unknown:
185+
os << "unknown";
186+
return;
187+
case Disconnected:
188+
os << "disconnected";
189+
return;
190+
case Actor:
191+
os << "actor";
192+
return;
193+
case Task:
194+
os << "task";
195+
return;
196+
}
197+
}
198+
199+
void printForDiagnostics(llvm::raw_ostream &os) const;
200+
201+
SWIFT_DEBUG_DUMP {
202+
print(llvm::dbgs());
203+
llvm::dbgs() << '\n';
204+
}
205+
206+
std::optional<ActorIsolation> getActorIsolation() const {
207+
assert(kind == Actor);
208+
assert(std::holds_alternative<std::optional<ActorIsolation>>(data) &&
209+
"Doesn't have an actor isolation?!");
210+
return std::get<std::optional<ActorIsolation>>(data);
211+
}
212+
213+
NominalTypeDecl *getActorInstance() const {
214+
assert(kind == Actor);
215+
assert(std::holds_alternative<NominalTypeDecl *>(data) &&
216+
"Doesn't have an actor instance?!");
217+
return std::get<NominalTypeDecl *>(data);
218+
}
219+
220+
SILValue getTaskIsolatedValue() const {
221+
assert(kind == Task);
222+
assert(std::holds_alternative<SILValue>(data) &&
223+
"Doesn't have a task isolated value");
224+
return std::get<SILValue>(data);
225+
}
226+
227+
bool hasActorIsolation() const {
228+
return std::holds_alternative<std::optional<ActorIsolation>>(data);
229+
}
230+
231+
bool hasActorInstance() const {
232+
return std::holds_alternative<NominalTypeDecl *>(data);
233+
}
234+
235+
bool hasTaskIsolatedValue() const {
236+
return std::holds_alternative<SILValue>(data);
237+
}
238+
239+
[[nodiscard]] ValueIsolationRegionInfo
240+
merge(ValueIsolationRegionInfo other) const {
241+
// If we are greater than the other kind, then we are further along the
242+
// lattice. We ignore the change.
243+
if (unsigned(other.kind) < unsigned(kind))
244+
return *this;
245+
246+
assert(kind != ValueIsolationRegionInfo::Actor &&
247+
"Actor should never be merged with another actor?!");
248+
249+
// Otherwise, take the other value.
250+
return other;
251+
}
252+
253+
ValueIsolationRegionInfo withActorIsolated(ActorIsolation isolation) {
254+
return ValueIsolationRegionInfo::getActorIsolated(isolation);
255+
}
256+
257+
static ValueIsolationRegionInfo getDisconnected() {
258+
return {Kind::Disconnected, {}};
259+
}
260+
261+
static ValueIsolationRegionInfo
262+
getActorIsolated(ActorIsolation actorIsolation) {
263+
return {Kind::Actor, actorIsolation};
264+
}
265+
266+
/// Sometimes we may have something that is actor isolated or that comes from
267+
/// a type. First try getActorIsolation and otherwise, just use the type.
268+
static ValueIsolationRegionInfo getActorIsolated(NominalTypeDecl *nomDecl) {
269+
auto actorIsolation = swift::getActorIsolation(nomDecl);
270+
if (actorIsolation.isActorIsolated())
271+
return getActorIsolated(actorIsolation);
272+
if (nomDecl->isActor())
273+
return {Kind::Actor, nomDecl};
274+
return {};
275+
}
276+
277+
static ValueIsolationRegionInfo getTaskIsolated(SILValue value) {
278+
return {Kind::Task, value};
279+
}
280+
};
281+
141282
} // namespace regionanalysisimpl
142283

143284
class regionanalysisimpl::TrackableValueState {
144285
unsigned id;
145286
TrackedValueFlagSet flagSet = {TrackableValueFlag::isMayAlias};
287+
ValueIsolationRegionInfo regionInfo =
288+
ValueIsolationRegionInfo::getDisconnected();
146289

147290
public:
148291
TrackableValueState(unsigned newID) : id(newID) {}
@@ -159,10 +302,20 @@ class regionanalysisimpl::TrackableValueState {
159302

160303
bool isNonSendable() const { return !isSendable(); }
161304

162-
bool isActorDerived() const {
163-
return flagSet.contains(TrackableValueFlag::isActorDerived);
305+
ValueIsolationRegionInfo::Kind getRegionInfoKind() {
306+
return regionInfo.getKind();
307+
}
308+
309+
ActorIsolation getActorIsolation() const {
310+
return regionInfo.getActorIsolation().value();
311+
}
312+
313+
void mergeIsolationRegionInfo(ValueIsolationRegionInfo newRegionInfo) {
314+
regionInfo = regionInfo.merge(newRegionInfo);
164315
}
165316

317+
ValueIsolationRegionInfo getIsolationRegionInfo() const { return regionInfo; }
318+
166319
TrackableValueID getID() const { return TrackableValueID(id); }
167320

168321
void addFlag(TrackableValueFlag flag) { flagSet |= flag; }
@@ -173,7 +326,9 @@ class regionanalysisimpl::TrackableValueState {
173326
os << "TrackableValueState[id: " << id
174327
<< "][is_no_alias: " << (isNoAlias() ? "yes" : "no")
175328
<< "][is_sendable: " << (isSendable() ? "yes" : "no")
176-
<< "][is_actor_derived: " << (isActorDerived() ? "yes" : "no") << "].";
329+
<< "][region_value_kind: ";
330+
getIsolationRegionInfo().print(os);
331+
os << "].";
177332
}
178333

179334
SWIFT_DEBUG_DUMP { print(llvm::dbgs()); }
@@ -215,6 +370,7 @@ class regionanalysisimpl::RepresentativeValue {
215370

216371
SILValue getValue() const { return value.get<SILValue>(); }
217372
SILValue maybeGetValue() const { return value.dyn_cast<SILValue>(); }
373+
bool hasRegionIntroducingInst() const { return value.is<SILInstruction *>(); }
218374
SILInstruction *getActorRegionIntroducingInst() const {
219375
return value.get<SILInstruction *>();
220376
}
@@ -257,7 +413,9 @@ class regionanalysisimpl::TrackableValue {
257413

258414
bool isNonSendable() const { return !isSendable(); }
259415

260-
bool isActorDerived() const { return valueState.isActorDerived(); }
416+
ValueIsolationRegionInfo getIsolationRegionInfo() const {
417+
return valueState.getIsolationRegionInfo();
418+
}
261419

262420
TrackableValueID getID() const {
263421
return TrackableValueID(valueState.getID());
@@ -293,6 +451,7 @@ class RegionAnalysisValueMap {
293451
using TrackableValueState = regionanalysisimpl::TrackableValueState;
294452
using TrackableValueID = Element;
295453
using RepresentativeValue = regionanalysisimpl::RepresentativeValue;
454+
using ValueIsolationRegionInfo = regionanalysisimpl::ValueIsolationRegionInfo;
296455

297456
private:
298457
/// A map from the representative of an equivalence class of values to their
@@ -308,11 +467,6 @@ class RegionAnalysisValueMap {
308467
equivalenceClassValuesToState;
309468
llvm::DenseMap<unsigned, RepresentativeValue> stateIndexToEquivalenceClass;
310469

311-
/// A list of values that can never be transferred.
312-
///
313-
/// This only includes function arguments.
314-
std::vector<TrackableValueID> neverTransferredValueIDs;
315-
316470
SILFunction *fn;
317471

318472
public:
@@ -326,13 +480,12 @@ class RegionAnalysisValueMap {
326480
/// value" returns an empty SILValue.
327481
SILValue maybeGetRepresentative(Element trackableValueID) const;
328482

329-
bool isActorDerived(Element trackableValueID) const;
330-
331-
ArrayRef<Element> getNonTransferrableElements() const {
332-
return neverTransferredValueIDs;
333-
}
483+
/// Returns the fake "representative value" for this element if it
484+
/// exists. Returns nullptr otherwise.
485+
SILInstruction *maybeGetActorIntroducingInst(Element trackableValueID) const;
334486

335-
void sortUniqueNeverTransferredValues();
487+
ValueIsolationRegionInfo getIsolationRegion(Element trackableValueID) const;
488+
ValueIsolationRegionInfo getIsolationRegion(SILValue trackableValueID) const;
336489

337490
void print(llvm::raw_ostream &os) const;
338491
SWIFT_DEBUG_DUMP { print(llvm::dbgs()); }
@@ -341,15 +494,23 @@ class RegionAnalysisValueMap {
341494
getTrackableValue(SILValue value,
342495
bool isAddressCapturedByPartialApply = false) const;
343496

497+
/// An actor introducing inst is an instruction that doesn't have any
498+
/// non-Sendable parameters and produces a new value that has to be actor
499+
/// isolated.
500+
///
501+
/// This is just for looking up the ValueIsolationRegionInfo for a
502+
/// instructionInst if we have one. So it is a find like function.
503+
std::optional<TrackableValue> getTrackableValueForActorIntroducingInst(
504+
SILInstruction *introducingInst) const;
505+
344506
private:
345507
std::optional<TrackableValue> getValueForId(TrackableValueID id) const;
346508
std::optional<TrackableValue> tryToTrackValue(SILValue value) const;
347509
TrackableValue
348-
getActorIntroducingRepresentative(SILInstruction *introducingInst) const;
349-
bool markValueAsActorDerived(SILValue value);
350-
void addNeverTransferredValueID(TrackableValueID valueID) {
351-
neverTransferredValueIDs.push_back(valueID);
352-
}
510+
getActorIntroducingRepresentative(SILInstruction *introducingInst,
511+
ValueIsolationRegionInfo isolation) const;
512+
bool mergeIsolationRegionInfo(SILValue value,
513+
ValueIsolationRegionInfo isolation);
353514
bool valueHasID(SILValue value, bool dumpIfHasNoID = false);
354515
TrackableValueID lookupValueID(SILValue value);
355516
};

0 commit comments

Comments
 (0)