1919#include " swift/SILOptimizer/Utils/PartitionUtils.h"
2020
2121#include < optional>
22+ #include < variant>
2223
2324namespace 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
139131using 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
143284class regionanalysisimpl ::TrackableValueState {
144285 unsigned id;
145286 TrackedValueFlagSet flagSet = {TrackableValueFlag::isMayAlias};
287+ ValueIsolationRegionInfo regionInfo =
288+ ValueIsolationRegionInfo::getDisconnected ();
146289
147290public:
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
297456private:
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
318472public:
@@ -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+
344506private:
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