44
44
// / 3. getAccessBase(): Find the ultimate base of any address corresponding to
45
45
// / the accessed object, regardless of whether the address is nested within
46
46
// / access scopes, and regardless of any storage casts. This returns either an
47
- // / address type, pointer type, or box type, but never a reference type.
47
+ // / address or pointer type, but never a reference or box type.
48
48
// / Each object's property or its tail storage is separately accessed.
49
49
// /
50
50
// / For better identification an access base, use
@@ -166,6 +166,11 @@ SILValue getAccessScope(SILValue address);
166
166
// / return the same base address, then they must also have the same storage.
167
167
SILValue getAccessBase (SILValue address);
168
168
169
+ // / Find the root of a reference, which may be a non-trivial type, box type, or
170
+ // / BridgeObject. This is guaranteed to be consistent with
171
+ // / AccessedStorage::getRoot() and AccessPath::getRoot().
172
+ SILValue findReferenceRoot (SILValue ref);
173
+
169
174
// / Return true if \p address points to a let-variable.
170
175
// /
171
176
// / let-variables are only written during let-variable initialization, which is
@@ -237,7 +242,8 @@ enum class AccessUseType { Exact, Inner, Overlapping };
237
242
// / represent any arbitrary base address--it must at least been proven not to
238
243
// / correspond to any class or global variable access, unless it's nested within
239
244
// / another access to the same object. So, Unidentified can overlap with
240
- // / Class/Global access, but it cannot be the only formal access to that memory.
245
+ // / Class/Global access because it was derived from another Class/Global access,
246
+ // / but Unidentified can never be the only formal access to that memory.
241
247
// /
242
248
// / An *invalid* AccessedStorage object is Unidentified and associated with an
243
249
// / invalid SILValue. This signals that analysis has failed to recognize an
@@ -268,7 +274,7 @@ class AccessedStorage {
268
274
Global,
269
275
Class,
270
276
Tail,
271
- Argument,
277
+ Argument, // Address or RawPointer argument
272
278
Yield,
273
279
Nested,
274
280
Unidentified,
@@ -280,22 +286,11 @@ class AccessedStorage {
280
286
// Give object tail storage a fake large property index for convenience.
281
287
static constexpr unsigned TailIndex = std::numeric_limits<int >::max();
282
288
283
- // / Directly create an AccessedStorage for class or tail property access.
284
- static AccessedStorage forClass (SILValue object, unsigned propertyIndex) {
285
- AccessedStorage storage;
286
- if (propertyIndex == TailIndex)
287
- storage.initKind (Tail);
288
- else
289
- storage.initKind (Class, propertyIndex);
290
- storage.value = object;
291
- return storage;
292
- }
293
-
294
289
// / Return an AccessedStorage value that best identifies a formally accessed
295
290
// / variable pointed to by \p sourceAddress, looking through any nested
296
291
// / formal accesses to find the underlying storage.
297
292
// /
298
- // / \p sourceAddress may be an address, pointer, or box type .
293
+ // / \p sourceAddress may be an address type or Builtin.RawPointer .
299
294
// /
300
295
// / If \p sourceAddress is within a formal access scope, which does not have
301
296
// / "Unsafe" enforcement, then this always returns valid storage.
@@ -308,7 +303,7 @@ class AccessedStorage {
308
303
// / Return an AccessedStorage object that identifies formal access scope that
309
304
// / immediately encloses \p sourceAddress.
310
305
// /
311
- // / \p sourceAddress may be an address, pointer, or box type .
306
+ // / \p sourceAddress may be an address type or Builtin.RawPointer .
312
307
// /
313
308
// / If \p sourceAddress is within a formal access scope, this always returns a
314
309
// / valid "Nested" storage value.
@@ -317,6 +312,14 @@ class AccessedStorage {
317
312
// / the formal storage if possible, otherwise returning invalid storage.
318
313
static AccessedStorage computeInScope (SILValue sourceAddress);
319
314
315
+ // / Create storage for the tail elements of \p object.
316
+ static AccessedStorage forObjectTail (SILValue object) {
317
+ AccessedStorage storage;
318
+ storage.initKind (Tail, TailIndex);
319
+ storage.value = findReferenceRoot (object);
320
+ return storage;
321
+ }
322
+
320
323
protected:
321
324
// Checking the storage kind is far more common than other fields. Make sure
322
325
// it can be byte load with no shift.
@@ -389,7 +392,7 @@ class AccessedStorage {
389
392
SILGlobalVariable *global;
390
393
};
391
394
392
- void initKind (Kind k, unsigned elementIndex = InvalidElementIndex ) {
395
+ void initKind (Kind k, unsigned elementIndex) {
393
396
Bits.opaqueBits = 0 ;
394
397
Bits.AccessedStorage .kind = k;
395
398
Bits.AccessedStorage .elementIndex = elementIndex;
@@ -401,7 +404,7 @@ class AccessedStorage {
401
404
}
402
405
403
406
public:
404
- AccessedStorage () : value() { initKind (Unidentified); }
407
+ AccessedStorage () : value() { initKind (Unidentified, InvalidElementIndex ); }
405
408
406
409
AccessedStorage (SILValue base, Kind kind);
407
410
@@ -418,6 +421,7 @@ class AccessedStorage {
418
421
419
422
SILValue getValue () const {
420
423
assert (getKind () != Global && getKind () != Class && getKind () != Tail);
424
+ assert (value && " Invalid storage has an invalid value" );
421
425
return value;
422
426
}
423
427
@@ -436,7 +440,9 @@ class AccessedStorage {
436
440
return global;
437
441
}
438
442
439
- bool isReference () const { return getKind () == Class || getKind () == Tail; }
443
+ bool isReference () const {
444
+ return getKind () == Box || getKind () == Class || getKind () == Tail;
445
+ }
440
446
441
447
SILValue getObject () const {
442
448
assert (isReference ());
@@ -447,6 +453,15 @@ class AccessedStorage {
447
453
return getElementIndex ();
448
454
}
449
455
456
+ // / Return a new AccessedStorage for Class/Tail/Box access based on
457
+ // / existing storage and a new object.
458
+ AccessedStorage transformReference (SILValue object) const {
459
+ AccessedStorage storage;
460
+ storage.initKind (getKind (), getElementIndex ());
461
+ storage.value = findReferenceRoot (object);
462
+ return storage;
463
+ }
464
+
450
465
// / Return the address or reference root that the storage was based
451
466
// / on. Returns an invalid SILValue for globals or invalid storage.
452
467
SILValue getRoot () const {
@@ -457,7 +472,7 @@ class AccessedStorage {
457
472
case AccessedStorage::Argument:
458
473
case AccessedStorage::Yield:
459
474
case AccessedStorage::Unidentified:
460
- return getValue (); // Can be invalid for Unidentified storage.
475
+ return getValue ();
461
476
case AccessedStorage::Global:
462
477
return SILValue ();
463
478
case AccessedStorage::Class:
@@ -511,6 +526,7 @@ class AccessedStorage {
511
526
bool isLocal () const {
512
527
switch (getKind ()) {
513
528
case Box:
529
+ return isa<AllocBoxInst>(value);
514
530
case Stack:
515
531
return true ;
516
532
case Global:
@@ -538,6 +554,7 @@ class AccessedStorage {
538
554
bool isUniquelyIdentified () const {
539
555
switch (getKind ()) {
540
556
case Box:
557
+ return isa<AllocBoxInst>(value);
541
558
case Stack:
542
559
case Global:
543
560
return true ;
@@ -686,11 +703,14 @@ template <> struct DenseMapInfo<swift::AccessedStorage> {
686
703
687
704
static unsigned getHashValue (swift::AccessedStorage storage) {
688
705
switch (storage.getKind ()) {
706
+ case swift::AccessedStorage::Unidentified:
707
+ if (!storage)
708
+ return DenseMapInfo<swift::SILValue>::getHashValue (swift::SILValue ());
709
+ LLVM_FALLTHROUGH;
689
710
case swift::AccessedStorage::Box:
690
711
case swift::AccessedStorage::Stack:
691
712
case swift::AccessedStorage::Nested:
692
713
case swift::AccessedStorage::Yield:
693
- case swift::AccessedStorage::Unidentified:
694
714
return DenseMapInfo<swift::SILValue>::getHashValue (storage.getValue ());
695
715
case swift::AccessedStorage::Argument:
696
716
return storage.getParamIndex ();
@@ -1008,15 +1028,19 @@ class AccessPath {
1008
1028
// recover the def-use chain for a specific global_addr or ref_element_addr.
1009
1029
struct AccessPathWithBase {
1010
1030
AccessPath accessPath;
1011
- // The address-type value that is the base of the formal access. For
1012
- // class storage, it is the ref_element_addr. For global storage it is the
1013
- // global_addr or initializer apply. For other storage, it is the same as
1014
- // accessPath.getRoot().
1031
+ // The address-type value that is the base of the formal access. For class
1032
+ // storage, it is the ref_element_addr; for box storage, the project_box; for
1033
+ // global storage the global_addr or initializer apply. For other
1034
+ // storage, it is the same as accessPath.getRoot().
1015
1035
//
1016
- // Note: base may be invalid for global_addr -> address_to_pointer -> phi
1017
- // patterns, while the accessPath is still valid.
1036
+ // Note: base may be invalid for phi patterns, even though the accessPath is
1037
+ // valid because we don't currently keep track of multiple bases. Multiple
1038
+ // bases for the same storage can happen with global_addr, ref_element_addr,
1039
+ // ref_tail_addr, and project_box.
1018
1040
//
1019
- // FIXME: add a structural requirement to SIL so base is always valid in OSSA.
1041
+ // FIXME: add a structural requirement to SIL/OSSA so valid storage has
1042
+ // a single base. For most cases, it is as simple by sinking the
1043
+ // projection. For index_addr, it may require hoisting ref_tail_addr.
1020
1044
SILValue base;
1021
1045
1022
1046
// / Compute the access path at \p address, and record the access base. This
@@ -1309,14 +1333,7 @@ inline bool isAccessedStorageCast(SingleValueInstruction *svi) {
1309
1333
case SILInstructionKind::MarkUninitializedInst:
1310
1334
case SILInstructionKind::UncheckedAddrCastInst:
1311
1335
case SILInstructionKind::MarkDependenceInst:
1312
- // Look through a project_box to identify the underlying alloc_box as the
1313
- // accesed object. It must be possible to reach either the alloc_box or the
1314
- // containing enum in this loop, only looking through simple value
1315
- // propagation such as copy_value and begin_borrow.
1316
- case SILInstructionKind::ProjectBoxInst:
1317
- case SILInstructionKind::ProjectBlockStorageInst:
1318
1336
case SILInstructionKind::CopyValueInst:
1319
- case SILInstructionKind::BeginBorrowInst:
1320
1337
// Casting to RawPointer does not affect the AccessPath. When converting
1321
1338
// between address types, they must be layout compatible (with truncation).
1322
1339
case SILInstructionKind::AddressToPointerInst:
@@ -1366,7 +1383,7 @@ class AccessUseDefChainVisitor {
1366
1383
Result visitArgumentAccess (SILFunctionArgument *arg) {
1367
1384
return asImpl ().visitBase (arg, AccessedStorage::Argument);
1368
1385
}
1369
- Result visitBoxAccess (AllocBoxInst *box) {
1386
+ Result visitBoxAccess (ProjectBoxInst *box) {
1370
1387
return asImpl ().visitBase (box, AccessedStorage::Box);
1371
1388
}
1372
1389
// / \p global may be either a GlobalAddrInst or the ApplyInst for a global
@@ -1414,9 +1431,8 @@ Result AccessUseDefChainVisitor<Impl, Result>::visit(SILValue sourceAddr) {
1414
1431
1415
1432
// MARK: Handle immediately-identifiable instructions.
1416
1433
1417
- // An AllocBox is a fully identified memory location.
1418
- case ValueKind::AllocBoxInst:
1419
- return asImpl ().visitBoxAccess (cast<AllocBoxInst>(sourceAddr));
1434
+ case ValueKind::ProjectBoxInst:
1435
+ return asImpl ().visitBoxAccess (cast<ProjectBoxInst>(sourceAddr));
1420
1436
1421
1437
// An AllocStack is a fully identified memory location, which may occur
1422
1438
// after inlining code already subjected to stack promotion.
0 commit comments