19
19
#include " swift/SILOptimizer/Utils/PartitionUtils.h"
20
20
21
21
#include < optional>
22
+ #include < variant>
22
23
23
24
namespace swift {
24
25
@@ -125,24 +126,166 @@ enum class TrackableValueFlag {
125
126
126
127
// / Set to true if this TrackableValue's representative is Sendable.
127
128
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 ,
137
129
};
138
130
139
131
using TrackedValueFlagSet = OptionSet<TrackableValueFlag>;
140
132
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
+
141
282
} // namespace regionanalysisimpl
142
283
143
284
class regionanalysisimpl ::TrackableValueState {
144
285
unsigned id;
145
286
TrackedValueFlagSet flagSet = {TrackableValueFlag::isMayAlias};
287
+ ValueIsolationRegionInfo regionInfo =
288
+ ValueIsolationRegionInfo::getDisconnected ();
146
289
147
290
public:
148
291
TrackableValueState (unsigned newID) : id(newID) {}
@@ -159,10 +302,20 @@ class regionanalysisimpl::TrackableValueState {
159
302
160
303
bool isNonSendable () const { return !isSendable (); }
161
304
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);
164
315
}
165
316
317
+ ValueIsolationRegionInfo getIsolationRegionInfo () const { return regionInfo; }
318
+
166
319
TrackableValueID getID () const { return TrackableValueID (id); }
167
320
168
321
void addFlag (TrackableValueFlag flag) { flagSet |= flag; }
@@ -173,7 +326,9 @@ class regionanalysisimpl::TrackableValueState {
173
326
os << " TrackableValueState[id: " << id
174
327
<< " ][is_no_alias: " << (isNoAlias () ? " yes" : " no" )
175
328
<< " ][is_sendable: " << (isSendable () ? " yes" : " no" )
176
- << " ][is_actor_derived: " << (isActorDerived () ? " yes" : " no" ) << " ]." ;
329
+ << " ][region_value_kind: " ;
330
+ getIsolationRegionInfo ().print (os);
331
+ os << " ]." ;
177
332
}
178
333
179
334
SWIFT_DEBUG_DUMP { print (llvm::dbgs ()); }
@@ -215,6 +370,7 @@ class regionanalysisimpl::RepresentativeValue {
215
370
216
371
SILValue getValue () const { return value.get <SILValue>(); }
217
372
SILValue maybeGetValue () const { return value.dyn_cast <SILValue>(); }
373
+ bool hasRegionIntroducingInst () const { return value.is <SILInstruction *>(); }
218
374
SILInstruction *getActorRegionIntroducingInst () const {
219
375
return value.get <SILInstruction *>();
220
376
}
@@ -257,7 +413,9 @@ class regionanalysisimpl::TrackableValue {
257
413
258
414
bool isNonSendable () const { return !isSendable (); }
259
415
260
- bool isActorDerived () const { return valueState.isActorDerived (); }
416
+ ValueIsolationRegionInfo getIsolationRegionInfo () const {
417
+ return valueState.getIsolationRegionInfo ();
418
+ }
261
419
262
420
TrackableValueID getID () const {
263
421
return TrackableValueID (valueState.getID ());
@@ -293,6 +451,7 @@ class RegionAnalysisValueMap {
293
451
using TrackableValueState = regionanalysisimpl::TrackableValueState;
294
452
using TrackableValueID = Element;
295
453
using RepresentativeValue = regionanalysisimpl::RepresentativeValue;
454
+ using ValueIsolationRegionInfo = regionanalysisimpl::ValueIsolationRegionInfo;
296
455
297
456
private:
298
457
// / A map from the representative of an equivalence class of values to their
@@ -308,11 +467,6 @@ class RegionAnalysisValueMap {
308
467
equivalenceClassValuesToState;
309
468
llvm::DenseMap<unsigned , RepresentativeValue> stateIndexToEquivalenceClass;
310
469
311
- // / A list of values that can never be transferred.
312
- // /
313
- // / This only includes function arguments.
314
- std::vector<TrackableValueID> neverTransferredValueIDs;
315
-
316
470
SILFunction *fn;
317
471
318
472
public:
@@ -326,13 +480,12 @@ class RegionAnalysisValueMap {
326
480
// / value" returns an empty SILValue.
327
481
SILValue maybeGetRepresentative (Element trackableValueID) const ;
328
482
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 ;
334
486
335
- void sortUniqueNeverTransferredValues ();
487
+ ValueIsolationRegionInfo getIsolationRegion (Element trackableValueID) const ;
488
+ ValueIsolationRegionInfo getIsolationRegion (SILValue trackableValueID) const ;
336
489
337
490
void print (llvm::raw_ostream &os) const ;
338
491
SWIFT_DEBUG_DUMP { print (llvm::dbgs ()); }
@@ -341,15 +494,23 @@ class RegionAnalysisValueMap {
341
494
getTrackableValue (SILValue value,
342
495
bool isAddressCapturedByPartialApply = false ) const ;
343
496
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
+
344
506
private:
345
507
std::optional<TrackableValue> getValueForId (TrackableValueID id) const ;
346
508
std::optional<TrackableValue> tryToTrackValue (SILValue value) const ;
347
509
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);
353
514
bool valueHasID (SILValue value, bool dumpIfHasNoID = false );
354
515
TrackableValueID lookupValueID (SILValue value);
355
516
};
0 commit comments