@@ -243,153 +243,199 @@ static bool isAddressForLocalInitOnly(SILValue sourceAddr) {
243
243
}
244
244
}
245
245
246
+ namespace {
247
+ // The result of an accessed storage query. A complete result produces an
248
+ // AccessedStorage object, which may or may not be valid. An incomplete result
249
+ // produces a SILValue representing the source address for use with deeper
250
+ // queries. The source address is not necessarily a SIL address type because
251
+ // the query can extend past pointer-to-address casts.
252
+ class AccessedStorageResult {
253
+ AccessedStorage storage;
254
+ SILValue address;
255
+ bool complete;
256
+
257
+ explicit AccessedStorageResult (SILValue address)
258
+ : address(address), complete(false ) {}
259
+
260
+ public:
261
+ AccessedStorageResult (const AccessedStorage &storage)
262
+ : storage(storage), complete(true ) {}
263
+
264
+ static AccessedStorageResult incomplete (SILValue address) {
265
+ return AccessedStorageResult (address);
266
+ }
267
+
268
+ bool isComplete () const { return complete; }
269
+
270
+ AccessedStorage getStorage () const { assert (complete); return storage; }
271
+
272
+ SILValue getAddress () const { assert (!complete); return address; }
273
+ };
274
+ } // namespace
275
+
246
276
// AccessEnforcementWMO makes a strong assumption that all accesses are either
247
277
// identified or are *not* accessing a global variable or class property defined
248
278
// in this module. Consequently, we cannot simply bail out on
249
279
// PointerToAddressInst as an Unidentified access.
250
- AccessedStorage swift::findAccessedStorage (SILValue sourceAddr) {
251
- SILValue address = sourceAddr;
252
- while (true ) {
253
- AccessedStorage::Kind kind = AccessedStorage::classify (address);
254
- // First handle identified cases: these are always valid as the base of
255
- // a formal access.
256
- if (kind != AccessedStorage::Unidentified)
257
- return AccessedStorage (address, kind);
258
-
259
- // If the address producer cannot immediately be classified, follow the
260
- // use-def chain of address, box, or RawPointer producers.
261
- assert (address->getType ().isAddress ()
262
- || isa<SILBoxType>(address->getType ().getASTType ())
263
- || isa<BuiltinRawPointerType>(address->getType ().getASTType ()));
264
-
265
- // Handle other unidentified address sources.
266
- switch (address->getKind ()) {
267
- default :
268
- if (isAddressForLocalInitOnly (address))
269
- return AccessedStorage (address, AccessedStorage::Unidentified);
270
- return AccessedStorage ();
271
-
272
- case ValueKind::SILUndef:
273
- return AccessedStorage (address, AccessedStorage::Unidentified);
274
-
275
- case ValueKind::ApplyInst:
276
- if (isExternalGlobalAddressor (cast<ApplyInst>(address)))
277
- return AccessedStorage (address, AccessedStorage::Unidentified);
278
-
279
- // Don't currently allow any other calls to return an accessed address.
280
+ static AccessedStorageResult getAccessedStorageFromAddress (SILValue sourceAddr) {
281
+ AccessedStorage::Kind kind = AccessedStorage::classify (sourceAddr);
282
+ // First handle identified cases: these are always valid as the base of
283
+ // a formal access.
284
+ if (kind != AccessedStorage::Unidentified)
285
+ return AccessedStorage (sourceAddr, kind);
286
+
287
+ // If the sourceAddr producer cannot immediately be classified, follow the
288
+ // use-def chain of sourceAddr, box, or RawPointer producers.
289
+ assert (sourceAddr->getType ().isAddress ()
290
+ || isa<SILBoxType>(sourceAddr->getType ().getASTType ())
291
+ || isa<BuiltinRawPointerType>(sourceAddr->getType ().getASTType ()));
292
+
293
+ // Handle other unidentified address sources.
294
+ switch (sourceAddr->getKind ()) {
295
+ default :
296
+ if (isAddressForLocalInitOnly (sourceAddr))
297
+ return AccessedStorage (sourceAddr, AccessedStorage::Unidentified);
298
+ return AccessedStorage ();
299
+
300
+ case ValueKind::SILUndef:
301
+ return AccessedStorage (sourceAddr, AccessedStorage::Unidentified);
302
+
303
+ case ValueKind::ApplyInst:
304
+ if (isExternalGlobalAddressor (cast<ApplyInst>(sourceAddr)))
305
+ return AccessedStorage (sourceAddr, AccessedStorage::Unidentified);
306
+
307
+ // Don't currently allow any other calls to return an accessed address.
308
+ return AccessedStorage ();
309
+
310
+ case ValueKind::StructExtractInst:
311
+ // Handle nested access to a KeyPath projection. The projection itself
312
+ // uses a Builtin. However, the returned UnsafeMutablePointer may be
313
+ // converted to an address and accessed via an inout argument.
314
+ if (isUnsafePointerExtraction (cast<StructExtractInst>(sourceAddr)))
315
+ return AccessedStorage (sourceAddr, AccessedStorage::Unidentified);
316
+ return AccessedStorage ();
317
+
318
+ case ValueKind::SILPhiArgument: {
319
+ auto *phiArg = cast<SILPhiArgument>(sourceAddr);
320
+ if (phiArg->isPhiArgument ())
321
+ return AccessedStorageResult::incomplete (phiArg);
322
+
323
+ // A non-phi block argument may be a box value projected out of
324
+ // switch_enum. Address-type block arguments are not allowed.
325
+ if (sourceAddr->getType ().isAddress ())
280
326
return AccessedStorage ();
281
327
282
- case ValueKind::StructExtractInst:
283
- // Handle nested access to a KeyPath projection. The projection itself
284
- // uses a Builtin. However, the returned UnsafeMutablePointer may be
285
- // converted to an address and accessed via an inout argument.
286
- if (isUnsafePointerExtraction (cast<StructExtractInst>(address)))
287
- return AccessedStorage (address, AccessedStorage::Unidentified);
288
- return AccessedStorage ();
328
+ checkSwitchEnumBlockArg (cast<SILPhiArgument>(sourceAddr));
329
+ return AccessedStorage (sourceAddr, AccessedStorage::Unidentified);
330
+ }
331
+ // Load a box from an indirect payload of an opaque enum.
332
+ // We must have peeked past the project_box earlier in this loop.
333
+ // (the indirectness makes it a box, the load is for address-only).
334
+ //
335
+ // %payload_adr = unchecked_take_enum_data_addr %enum : $*Enum, #Enum.case
336
+ // %box = load [take] %payload_adr : $*{ var Enum }
337
+ //
338
+ // FIXME: this case should go away with opaque values.
339
+ //
340
+ // Otherwise return invalid AccessedStorage.
341
+ case ValueKind::LoadInst:
342
+ if (sourceAddr->getType ().is <SILBoxType>()) {
343
+ SILValue operAddr = cast<LoadInst>(sourceAddr)->getOperand ();
344
+ assert (isa<UncheckedTakeEnumDataAddrInst>(operAddr));
345
+ return AccessedStorageResult::incomplete (operAddr);
346
+ }
347
+ return AccessedStorage ();
348
+
349
+ // ref_tail_addr project an address from a reference.
350
+ // This is a valid address producer for nested @inout argument
351
+ // access, but it is never used for formal access of identified objects.
352
+ case ValueKind::RefTailAddrInst:
353
+ return AccessedStorage (sourceAddr, AccessedStorage::Unidentified);
354
+
355
+ // Inductive single-operand cases:
356
+ // Look through address casts to find the source address.
357
+ case ValueKind::MarkUninitializedInst:
358
+ case ValueKind::OpenExistentialAddrInst:
359
+ case ValueKind::UncheckedAddrCastInst:
360
+ // Inductive cases that apply to any type.
361
+ case ValueKind::CopyValueInst:
362
+ case ValueKind::MarkDependenceInst:
363
+ // Look through a project_box to identify the underlying alloc_box as the
364
+ // accesed object. It must be possible to reach either the alloc_box or the
365
+ // containing enum in this loop, only looking through simple value
366
+ // propagation such as copy_value.
367
+ case ValueKind::ProjectBoxInst:
368
+ // Handle project_block_storage just like project_box.
369
+ case ValueKind::ProjectBlockStorageInst:
370
+ // Look through begin_borrow in case a local box is borrowed.
371
+ case ValueKind::BeginBorrowInst:
372
+ return AccessedStorageResult::incomplete (
373
+ cast<SingleValueInstruction>(sourceAddr)->getOperand (0 ));
374
+
375
+ // Access to a Builtin.RawPointer. Treat this like the inductive cases
376
+ // above because some RawPointers originate from identified locations. See
377
+ // the special case for global addressors, which return RawPointer, above.
378
+ //
379
+ // If the inductive search does not find a valid addressor, it will
380
+ // eventually reach the default case that returns in invalid location. This
381
+ // is correct for RawPointer because, although accessing a RawPointer is
382
+ // legal SIL, there is no way to guarantee that it doesn't access class or
383
+ // global storage, so returning a valid unidentified storage object would be
384
+ // incorrect. It is the caller's responsibility to know that formal access
385
+ // to such a location can be safely ignored.
386
+ //
387
+ // For example:
388
+ //
389
+ // - KeyPath Builtins access RawPointer. However, the caller can check
390
+ // that the access `isFromBuilin` and ignore the storage.
391
+ //
392
+ // - lldb generates RawPointer access for debugger variables, but SILGen
393
+ // marks debug VarDecl access as 'Unsafe' and SIL passes don't need the
394
+ // AccessedStorage for 'Unsafe' access.
395
+ case ValueKind::PointerToAddressInst:
396
+ return AccessedStorageResult::incomplete (
397
+ cast<SingleValueInstruction>(sourceAddr)->getOperand (0 ));
398
+
399
+ // Address-to-address subobject projections.
400
+ case ValueKind::StructElementAddrInst:
401
+ case ValueKind::TupleElementAddrInst:
402
+ case ValueKind::UncheckedTakeEnumDataAddrInst:
403
+ case ValueKind::TailAddrInst:
404
+ case ValueKind::IndexAddrInst:
405
+ return AccessedStorageResult::incomplete (
406
+ cast<SingleValueInstruction>(sourceAddr)->getOperand (0 ));
407
+ }
408
+ }
289
409
290
- case ValueKind::SILPhiArgument: {
291
- auto *phiArg = cast<SILPhiArgument>(address);
292
- if (phiArg->isPhiArgument ()) {
293
- SmallVector<SILValue, 8 > incomingValues;
294
- phiArg->getIncomingPhiValues (incomingValues);
295
- if (incomingValues.empty ())
296
- return AccessedStorage ();
297
-
298
- auto storage = findAccessedStorage (incomingValues.pop_back_val ());
299
- for (auto val : incomingValues) {
300
- auto otherStorage = findAccessedStorage (val);
301
- if (!accessingIdenticalLocations (storage, otherStorage))
302
- return AccessedStorage ();
410
+ AccessedStorage swift::findAccessedStorage (SILValue sourceAddr) {
411
+ SmallVector<SILValue, 8 > addressWorklist ({sourceAddr});
412
+ SmallPtrSet<SILPhiArgument *, 4 > visitedPhis;
413
+ Optional<AccessedStorage> storage;
414
+
415
+ while (!addressWorklist.empty ()) {
416
+ AccessedStorageResult result =
417
+ getAccessedStorageFromAddress (addressWorklist.pop_back_val ());
418
+
419
+ if (!result.isComplete ()) {
420
+ SILValue operAddr = result.getAddress ();
421
+ if (auto *phiArg = dyn_cast<SILPhiArgument>(operAddr)) {
422
+ if (phiArg->isPhiArgument ()) {
423
+ if (visitedPhis.insert (phiArg).second )
424
+ phiArg->getIncomingPhiValues (addressWorklist);
425
+ continue ;
303
426
}
304
- return storage;
305
427
}
306
- // A non-phi block argument may be a box value projected out of
307
- // switch_enum. Address-type block arguments are not allowed.
308
- if (address->getType ().isAddress ())
309
- return AccessedStorage ();
310
-
311
- checkSwitchEnumBlockArg (cast<SILPhiArgument>(address));
312
- return AccessedStorage (address, AccessedStorage::Unidentified);
313
- }
314
- // Load a box from an indirect payload of an opaque enum.
315
- // We must have peeked past the project_box earlier in this loop.
316
- // (the indirectness makes it a box, the load is for address-only).
317
- //
318
- // %payload_adr = unchecked_take_enum_data_addr %enum : $*Enum, #Enum.case
319
- // %box = load [take] %payload_adr : $*{ var Enum }
320
- //
321
- // FIXME: this case should go away with opaque values.
322
- //
323
- // Otherwise return invalid AccessedStorage.
324
- case ValueKind::LoadInst: {
325
- if (address->getType ().is <SILBoxType>()) {
326
- address = cast<LoadInst>(address)->getOperand ();
327
- assert (isa<UncheckedTakeEnumDataAddrInst>(address));
328
- continue ;
329
- }
330
- return AccessedStorage ();
331
- }
332
-
333
- // ref_tail_addr project an address from a reference.
334
- // This is a valid address producer for nested @inout argument
335
- // access, but it is never used for formal access of identified objects.
336
- case ValueKind::RefTailAddrInst:
337
- return AccessedStorage (address, AccessedStorage::Unidentified);
338
-
339
- // Inductive cases:
340
- // Look through address casts to find the source address.
341
- case ValueKind::MarkUninitializedInst:
342
- case ValueKind::OpenExistentialAddrInst:
343
- case ValueKind::UncheckedAddrCastInst:
344
- // Inductive cases that apply to any type.
345
- case ValueKind::CopyValueInst:
346
- case ValueKind::MarkDependenceInst:
347
- // Look through a project_box to identify the underlying alloc_box as the
348
- // accesed object. It must be possible to reach either the alloc_box or the
349
- // containing enum in this loop, only looking through simple value
350
- // propagation such as copy_value.
351
- case ValueKind::ProjectBoxInst:
352
- // Handle project_block_storage just like project_box.
353
- case ValueKind::ProjectBlockStorageInst:
354
- // Look through begin_borrow in case a local box is borrowed.
355
- case ValueKind::BeginBorrowInst:
356
- address = cast<SingleValueInstruction>(address)->getOperand (0 );
357
- continue ;
358
-
359
- // Access to a Builtin.RawPointer. Treat this like the inductive cases
360
- // above because some RawPointers originate from identified locations. See
361
- // the special case for global addressors, which return RawPointer, above.
362
- //
363
- // If the inductive search does not find a valid addressor, it will
364
- // eventually reach the default case that returns in invalid location. This
365
- // is correct for RawPointer because, although accessing a RawPointer is
366
- // legal SIL, there is no way to guarantee that it doesn't access class or
367
- // global storage, so returning a valid unidentified storage object would be
368
- // incorrect. It is the caller's responsibility to know that formal access
369
- // to such a location can be safely ignored.
370
- //
371
- // For example:
372
- //
373
- // - KeyPath Builtins access RawPointer. However, the caller can check
374
- // that the access `isFromBuilin` and ignore the storage.
375
- //
376
- // - lldb generates RawPointer access for debugger variables, but SILGen
377
- // marks debug VarDecl access as 'Unsafe' and SIL passes don't need the
378
- // AccessedStorage for 'Unsafe' access.
379
- case ValueKind::PointerToAddressInst:
380
- address = cast<SingleValueInstruction>(address)->getOperand (0 );
428
+ addressWorklist.push_back (operAddr);
381
429
continue ;
382
-
383
- // Address-to-address subobject projections.
384
- case ValueKind::StructElementAddrInst:
385
- case ValueKind::TupleElementAddrInst:
386
- case ValueKind::UncheckedTakeEnumDataAddrInst:
387
- case ValueKind::TailAddrInst:
388
- case ValueKind::IndexAddrInst:
389
- address = cast<SingleValueInstruction>(address)->getOperand (0 );
430
+ }
431
+ if (!storage.hasValue ()) {
432
+ storage = result.getStorage ();
390
433
continue ;
391
434
}
435
+ if (!accessingIdenticalLocations (storage.getValue (), result.getStorage ()))
436
+ return AccessedStorage ();
392
437
}
438
+ return storage.getValueOr (AccessedStorage ());
393
439
}
394
440
395
441
AccessedStorage swift::findAccessedStorageNonNested (SILValue sourceAddr) {
0 commit comments