|
19 | 19 | #include "swift/Basic/LLVM.h" |
20 | 20 | #include "swift/SIL/SILFunction.h" |
21 | 21 | #include "swift/SIL/SILInstruction.h" |
| 22 | +#include "swift/SILOptimizer/Utils/SILIsolationInfo.h" |
22 | 23 |
|
23 | 24 | #include "llvm/ADT/MapVector.h" |
24 | 25 | #include "llvm/ADT/STLExtras.h" |
@@ -95,311 +96,6 @@ struct DenseMapInfo<swift::PartitionPrimitives::Region> { |
95 | 96 |
|
96 | 97 | namespace swift { |
97 | 98 |
|
98 | | -class ActorInstance { |
99 | | -public: |
100 | | - enum class Kind : uint8_t { |
101 | | - Value, |
102 | | - ActorAccessorInit = 0x1, |
103 | | - }; |
104 | | - |
105 | | - llvm::PointerIntPair<SILValue, 1> value; |
106 | | - |
107 | | - ActorInstance(SILValue value, Kind kind) |
108 | | - : value(value, std::underlying_type<Kind>::type(kind)) {} |
109 | | - |
110 | | -public: |
111 | | - ActorInstance() : ActorInstance(SILValue(), Kind::Value) {} |
112 | | - |
113 | | - static ActorInstance getForValue(SILValue value) { |
114 | | - return ActorInstance(value, Kind::Value); |
115 | | - } |
116 | | - |
117 | | - static ActorInstance getForActorAccessorInit() { |
118 | | - return ActorInstance(SILValue(), Kind::ActorAccessorInit); |
119 | | - } |
120 | | - |
121 | | - explicit operator bool() const { return bool(value.getOpaqueValue()); } |
122 | | - |
123 | | - Kind getKind() const { return Kind(value.getInt()); } |
124 | | - |
125 | | - SILValue getValue() const { |
126 | | - assert(getKind() == Kind::Value); |
127 | | - return value.getPointer(); |
128 | | - } |
129 | | - |
130 | | - bool isValue() const { return getKind() == Kind::Value; } |
131 | | - |
132 | | - bool isAccessorInit() const { return getKind() == Kind::ActorAccessorInit; } |
133 | | - |
134 | | - bool operator==(const ActorInstance &other) const { |
135 | | - // If both are null, return true. |
136 | | - if (!bool(*this) && !bool(other)) |
137 | | - return true; |
138 | | - |
139 | | - // Otherwise, check if the kinds match. |
140 | | - if (getKind() != other.getKind()) |
141 | | - return false; |
142 | | - |
143 | | - // Now that we know that the kinds match, perform the kind specific check. |
144 | | - switch (getKind()) { |
145 | | - case Kind::Value: |
146 | | - return getValue() == other.getValue(); |
147 | | - case Kind::ActorAccessorInit: |
148 | | - return true; |
149 | | - } |
150 | | - } |
151 | | - |
152 | | - bool operator!=(const ActorInstance &other) const { |
153 | | - return !(*this == other); |
154 | | - } |
155 | | -}; |
156 | | - |
157 | | -class SILIsolationInfo { |
158 | | -public: |
159 | | - /// The lattice is: |
160 | | - /// |
161 | | - /// Unknown -> Disconnected -> TransferringParameter -> Task -> Actor. |
162 | | - /// |
163 | | - /// Unknown means no information. We error when merging on it. |
164 | | - enum Kind { |
165 | | - Unknown, |
166 | | - Disconnected, |
167 | | - Task, |
168 | | - Actor, |
169 | | - }; |
170 | | - |
171 | | -private: |
172 | | - Kind kind; |
173 | | - |
174 | | - /// The actor isolation if this value has one. The default unspecified case |
175 | | - /// otherwise. |
176 | | - ActorIsolation actorIsolation; |
177 | | - |
178 | | - /// This is the value that we got isolation from if we were able to find |
179 | | - /// one. Used for isolation history. |
180 | | - SILValue isolatedValue; |
181 | | - |
182 | | - /// If set this is the SILValue that represents the actor instance that we |
183 | | - /// derived isolatedValue from. |
184 | | - /// |
185 | | - /// If set to (SILValue(), 1), then we are in an |
186 | | - ActorInstance actorInstance; |
187 | | - |
188 | | - SILIsolationInfo(SILValue isolatedValue, SILValue actorInstance, |
189 | | - ActorIsolation actorIsolation) |
190 | | - : kind(Actor), actorIsolation(actorIsolation), |
191 | | - isolatedValue(isolatedValue), |
192 | | - actorInstance(ActorInstance::getForValue(actorInstance)) { |
193 | | - assert((!actorInstance || |
194 | | - (actorIsolation.getKind() == ActorIsolation::ActorInstance && |
195 | | - actorInstance->getType() |
196 | | - .getASTType() |
197 | | - ->lookThroughAllOptionalTypes() |
198 | | - ->getAnyActor())) && |
199 | | - "actorInstance must be an actor if it is non-empty"); |
200 | | - } |
201 | | - |
202 | | - SILIsolationInfo(SILValue isolatedValue, ActorInstance actorInstance, |
203 | | - ActorIsolation actorIsolation) |
204 | | - : kind(Actor), actorIsolation(actorIsolation), |
205 | | - isolatedValue(isolatedValue), actorInstance(actorInstance) { |
206 | | - assert(actorInstance); |
207 | | - assert(actorIsolation.getKind() == ActorIsolation::ActorInstance); |
208 | | - } |
209 | | - |
210 | | - SILIsolationInfo(Kind kind, SILValue isolatedValue) |
211 | | - : kind(kind), actorIsolation(), isolatedValue(isolatedValue) {} |
212 | | - |
213 | | - SILIsolationInfo(Kind kind) : kind(kind), actorIsolation() {} |
214 | | - |
215 | | -public: |
216 | | - SILIsolationInfo() : kind(Kind::Unknown), actorIsolation() {} |
217 | | - |
218 | | - operator bool() const { return kind != Kind::Unknown; } |
219 | | - |
220 | | - operator Kind() const { return kind; } |
221 | | - |
222 | | - Kind getKind() const { return kind; } |
223 | | - |
224 | | - bool isDisconnected() const { return kind == Kind::Disconnected; } |
225 | | - bool isActorIsolated() const { return kind == Kind::Actor; } |
226 | | - bool isTaskIsolated() const { return kind == Kind::Task; } |
227 | | - |
228 | | - void print(llvm::raw_ostream &os) const; |
229 | | - |
230 | | - SWIFT_DEBUG_DUMP { |
231 | | - print(llvm::dbgs()); |
232 | | - llvm::dbgs() << '\n'; |
233 | | - } |
234 | | - |
235 | | - void printForDiagnostics(llvm::raw_ostream &os) const; |
236 | | - |
237 | | - SWIFT_DEBUG_DUMPER(dumpForDiagnostics()) { |
238 | | - printForDiagnostics(llvm::dbgs()); |
239 | | - llvm::dbgs() << '\n'; |
240 | | - } |
241 | | - |
242 | | - ActorIsolation getActorIsolation() const { |
243 | | - assert(kind == Actor); |
244 | | - return actorIsolation; |
245 | | - } |
246 | | - |
247 | | - /// If we are actor or task isolated and could find a specific value that |
248 | | - /// caused the isolation, put it here. Used for isolation history. |
249 | | - SILValue getIsolatedValue() const { |
250 | | - assert(kind == Task || kind == Actor); |
251 | | - return isolatedValue; |
252 | | - } |
253 | | - |
254 | | - /// Return the specific SILValue for the actor that our isolated value is |
255 | | - /// isolated to if one exists. |
256 | | - ActorInstance getActorInstance() const { |
257 | | - assert(kind == Actor); |
258 | | - return actorInstance; |
259 | | - } |
260 | | - |
261 | | - bool hasActorIsolation() const { return kind == Actor; } |
262 | | - |
263 | | - bool hasIsolatedValue() const { |
264 | | - return (kind == Task || kind == Actor) && bool(isolatedValue); |
265 | | - } |
266 | | - |
267 | | - [[nodiscard]] SILIsolationInfo merge(SILIsolationInfo other) const; |
268 | | - |
269 | | - static SILIsolationInfo getDisconnected() { return {Kind::Disconnected}; } |
270 | | - |
271 | | - /// Create an actor isolation for a value that we know is actor isolated to a |
272 | | - /// specific actor, but we do not know the specific instance yet. |
273 | | - /// |
274 | | - /// This can occur when closing over a closure with an isolated parameter or |
275 | | - /// if we are determining isolation of a function_ref that takes an isolated |
276 | | - /// parameter. In both cases, we cannot know what the actual isolation is |
277 | | - /// until we invoke the closure or function. |
278 | | - /// |
279 | | - /// TODO: This is just a stub currently until I implement the flow sensitive |
280 | | - /// part. We just treat all instances the same. There are tests that validate |
281 | | - /// this behavior. |
282 | | - static SILIsolationInfo |
283 | | - getFlowSensitiveActorIsolated(SILValue isolatedValue, |
284 | | - ActorIsolation actorIsolation) { |
285 | | - return {isolatedValue, SILValue(), actorIsolation}; |
286 | | - } |
287 | | - |
288 | | - /// Only use this as a fallback if we cannot find better information. |
289 | | - static SILIsolationInfo |
290 | | - getWithIsolationCrossing(ApplyIsolationCrossing crossing) { |
291 | | - if (crossing.getCalleeIsolation().isActorIsolated()) { |
292 | | - // SIL level, just let it through |
293 | | - return SILIsolationInfo(SILValue(), SILValue(), |
294 | | - crossing.getCalleeIsolation()); |
295 | | - } |
296 | | - |
297 | | - return {}; |
298 | | - } |
299 | | - |
300 | | - static SILIsolationInfo getActorInstanceIsolated(SILValue isolatedValue, |
301 | | - SILValue actorInstance, |
302 | | - NominalTypeDecl *typeDecl) { |
303 | | - assert(actorInstance); |
304 | | - if (!typeDecl->isAnyActor()) { |
305 | | - assert(!swift::getActorIsolation(typeDecl).isGlobalActor() && |
306 | | - "Should have called getGlobalActorIsolated"); |
307 | | - return {}; |
308 | | - } |
309 | | - return {isolatedValue, actorInstance, |
310 | | - ActorIsolation::forActorInstanceSelf(typeDecl)}; |
311 | | - } |
312 | | - |
313 | | - static SILIsolationInfo getActorInstanceIsolated(SILValue isolatedValue, |
314 | | - ActorInstance actorInstance, |
315 | | - NominalTypeDecl *typeDecl) { |
316 | | - assert(actorInstance); |
317 | | - if (!typeDecl->isAnyActor()) { |
318 | | - assert(!swift::getActorIsolation(typeDecl).isGlobalActor() && |
319 | | - "Should have called getGlobalActorIsolated"); |
320 | | - return {}; |
321 | | - } |
322 | | - return {isolatedValue, actorInstance, |
323 | | - ActorIsolation::forActorInstanceSelf(typeDecl)}; |
324 | | - } |
325 | | - |
326 | | - /// A special actor instance isolated for partial apply cases where we do not |
327 | | - /// close over the isolated parameter and thus do not know the actual actor |
328 | | - /// instance that we are going to use. |
329 | | - static SILIsolationInfo |
330 | | - getPartialApplyActorInstanceIsolated(SILValue isolatedValue, |
331 | | - NominalTypeDecl *typeDecl) { |
332 | | - if (!typeDecl->isAnyActor()) { |
333 | | - assert(!swift::getActorIsolation(typeDecl).isGlobalActor() && |
334 | | - "Should have called getGlobalActorIsolated"); |
335 | | - return {}; |
336 | | - } |
337 | | - return {isolatedValue, SILValue(), |
338 | | - ActorIsolation::forActorInstanceSelf(typeDecl)}; |
339 | | - } |
340 | | - |
341 | | - static SILIsolationInfo getGlobalActorIsolated(SILValue value, |
342 | | - Type globalActorType) { |
343 | | - return {value, SILValue() /*no actor instance*/, |
344 | | - ActorIsolation::forGlobalActor(globalActorType)}; |
345 | | - } |
346 | | - |
347 | | - static SILIsolationInfo getGlobalActorIsolated(SILValue value, |
348 | | - ValueDecl *decl) { |
349 | | - auto isolation = swift::getActorIsolation(decl); |
350 | | - if (!isolation.isGlobalActor()) |
351 | | - return {}; |
352 | | - return SILIsolationInfo::getGlobalActorIsolated(value, |
353 | | - isolation.getGlobalActor()); |
354 | | - } |
355 | | - |
356 | | - static SILIsolationInfo getTaskIsolated(SILValue value) { |
357 | | - return {Kind::Task, value}; |
358 | | - } |
359 | | - |
360 | | - /// Attempt to infer the isolation region info for \p inst. |
361 | | - static SILIsolationInfo get(SILInstruction *inst); |
362 | | - |
363 | | - /// Attempt to infer the isolation region info for \p arg. |
364 | | - static SILIsolationInfo get(SILArgument *arg); |
365 | | - |
366 | | - static SILIsolationInfo get(SILValue value) { |
367 | | - if (auto *arg = dyn_cast<SILArgument>(value)) |
368 | | - return get(arg); |
369 | | - if (auto *inst = dyn_cast<SingleValueInstruction>(value)) |
370 | | - return get(inst); |
371 | | - return {}; |
372 | | - } |
373 | | - |
374 | | - /// A helper that is used to ensure that we treat certain builtin values as |
375 | | - /// non-Sendable that the AST level otherwise thinks are non-Sendable. |
376 | | - /// |
377 | | - /// E.x.: Builtin.RawPointer and Builtin.NativeObject |
378 | | - /// |
379 | | - /// TODO: Fix the type checker. |
380 | | - static bool isNonSendableType(SILType type, SILFunction *fn); |
381 | | - |
382 | | - static bool isNonSendableType(SILValue value) { |
383 | | - return isNonSendableType(value->getType(), value->getFunction()); |
384 | | - } |
385 | | - |
386 | | - bool hasSameIsolation(ActorIsolation actorIsolation) const; |
387 | | - |
388 | | - /// Returns true if \p this and \p other have the same isolation. It allows |
389 | | - /// for the isolated values if any to not match. |
390 | | - /// |
391 | | - /// This is useful if one has two non-Sendable values projected from the same |
392 | | - /// actor or global actor isolated value. E.x.: two different ref_element_addr |
393 | | - /// from the same actor. |
394 | | - bool hasSameIsolation(const SILIsolationInfo &other) const; |
395 | | - |
396 | | - /// Returns true if this SILIsolationInfo is deeply equal to other. This means |
397 | | - /// that the isolation and the isolated value match. |
398 | | - bool isEqual(const SILIsolationInfo &other) const; |
399 | | - |
400 | | - void Profile(llvm::FoldingSetNodeID &id) const; |
401 | | -}; |
402 | | - |
403 | 99 | class Partition; |
404 | 100 | class TransferringOperandToStateMap; |
405 | 101 |
|
|
0 commit comments