@@ -189,7 +189,9 @@ namespace swift {
189
189
// / the base of a formal access. It may be from a ref_tail_addr, undef, or some
190
190
// / recognized memory initialization pattern. Unidentified valid storage cannot
191
191
// / represent any arbitrary base address--it must at least been proven not to
192
- // / correspond to any class or global variable access.
192
+ // / correspond to any class or global variable access, unless it's nested within
193
+ // / another access to the same object. So, Unidentified can overlap with
194
+ // / Class/Global access, but it cannot be the only formal access to that memory.
193
195
// /
194
196
// / An *invalid* AccessedStorage object is Unidentified and associated with an
195
197
// / invalid SILValue. This signals that analysis has failed to recognize an
@@ -219,6 +221,7 @@ class AccessedStorage {
219
221
Stack,
220
222
Global,
221
223
Class,
224
+ Tail,
222
225
Argument,
223
226
Yield,
224
227
Nested,
@@ -228,10 +231,16 @@ class AccessedStorage {
228
231
229
232
static const char *getKindName (Kind k);
230
233
231
- // / Directly create an AccessedStorage for class property access.
234
+ // Give object tail storage a fake property index for convenience.
235
+ static constexpr unsigned TailIndex = ~0U ;
236
+
237
+ // / Directly create an AccessedStorage for class or tail property access.
232
238
static AccessedStorage forClass (SILValue object, unsigned propertyIndex) {
233
239
AccessedStorage storage;
234
- storage.initKind (Class, propertyIndex);
240
+ if (propertyIndex == TailIndex)
241
+ storage.initKind (Tail);
242
+ else
243
+ storage.initKind (Class, propertyIndex);
235
244
storage.value = object;
236
245
return storage;
237
246
}
@@ -301,7 +310,8 @@ class AccessedStorage {
301
310
union {
302
311
// For non-class storage, 'value' is the access base. For class storage
303
312
// 'value' is the object base, where the access base is the class' stored
304
- // property.
313
+ // property. For tail storage 'value' is the object base and there is no
314
+ // value for the access base.
305
315
SILValue value;
306
316
SILGlobalVariable *global;
307
317
};
@@ -334,7 +344,7 @@ class AccessedStorage {
334
344
}
335
345
336
346
SILValue getValue () const {
337
- assert (getKind () != Global && getKind () != Class);
347
+ assert (getKind () != Global && getKind () != Class && getKind () != Tail );
338
348
return value;
339
349
}
340
350
@@ -354,7 +364,7 @@ class AccessedStorage {
354
364
}
355
365
356
366
SILValue getObject () const {
357
- assert (getKind () == Class);
367
+ assert (getKind () == Class || getKind () == Tail );
358
368
return value;
359
369
}
360
370
unsigned getPropertyIndex () const {
@@ -374,6 +384,7 @@ class AccessedStorage {
374
384
switch (getKind ()) {
375
385
case Box:
376
386
case Stack:
387
+ case Tail:
377
388
case Argument:
378
389
case Yield:
379
390
case Nested:
@@ -396,6 +407,7 @@ class AccessedStorage {
396
407
return true ;
397
408
case Global:
398
409
case Class:
410
+ case Tail:
399
411
case Argument:
400
412
case Yield:
401
413
case Nested:
@@ -405,6 +417,11 @@ class AccessedStorage {
405
417
llvm_unreachable (" unhandled kind" );
406
418
}
407
419
420
+ // / Return trye if the given access is guaranteed to be within a heap object.
421
+ bool isObjectAccess () const {
422
+ return getKind () == Class || getKind () == Tail;
423
+ }
424
+
408
425
// / Return true if the given access is on a 'let' lvalue.
409
426
bool isLetAccess (SILFunction *F) const ;
410
427
@@ -420,6 +437,7 @@ class AccessedStorage {
420
437
case Global:
421
438
return true ;
422
439
case Class:
440
+ case Tail:
423
441
case Argument:
424
442
case Yield:
425
443
case Nested:
@@ -455,20 +473,47 @@ class AccessedStorage {
455
473
// Return true if this storage is guaranteed not to overlap with \p other's
456
474
// storage.
457
475
bool isDistinctFrom (const AccessedStorage &other) const {
458
- if (isUniquelyIdentified () && other.isUniquelyIdentified ()) {
459
- return !hasIdenticalBase (other);
476
+ if (isUniquelyIdentified ()) {
477
+ if (other.isUniquelyIdentified () && !hasIdenticalBase (other))
478
+ return true ;
479
+
480
+ if (other.isObjectAccess ())
481
+ return true ;
482
+
483
+ // We currently assume that Unidentified storage may overlap with
484
+ // Box/Stack storage.
485
+ return false ;
460
486
}
461
- if (getKind () != Class || other.getKind () != Class)
462
- // At least one side is an Argument or Yield, or is unidentified.
487
+ if (other.isUniquelyIdentified ())
488
+ return other.isDistinctFrom (*this );
489
+
490
+ // Neither storage is uniquely identified.
491
+ if (isObjectAccess ()) {
492
+ if (other.isObjectAccess ()) {
493
+ // Property access cannot overlap with Tail access.
494
+ if (getKind () != other.getKind ())
495
+ return true ;
496
+
497
+ // We could also check if the object types are distinct, but that only
498
+ // helps if we know the relationships between class types.
499
+ return getKind () == Class
500
+ && getPropertyIndex () != other.getPropertyIndex ();
501
+ }
502
+ // Any type of nested/argument address may be within the same object.
503
+ //
504
+ // We also currently assume Unidentified access may be within an object
505
+ // purely to handle KeyPath accesses. The deriviation of the KeyPath
506
+ // address must separately appear to be a Class access so that all Class
507
+ // accesses are accounted for.
463
508
return false ;
464
-
465
- // Classes are not uniquely identified by their base. However, if the
466
- // underling objects have identical types and distinct property indices then
467
- // they are distinct storage locations.
468
- if (getObject ()->getType () == other.getObject ()->getType ()
469
- && getPropertyIndex () != other.getPropertyIndex ()) {
470
- return true ;
471
509
}
510
+ if (other.isObjectAccess ())
511
+ return other.isDistinctFrom (*this );
512
+
513
+ // Neither storage is from a class or tail.
514
+ //
515
+ // Unidentified values may alias with each other or with any kind of
516
+ // nested/argument access.
472
517
return false ;
473
518
}
474
519
@@ -530,10 +575,11 @@ template <> struct DenseMapInfo<swift::AccessedStorage> {
530
575
return storage.getParamIndex ();
531
576
case swift::AccessedStorage::Global:
532
577
return DenseMapInfo<void *>::getHashValue (storage.getGlobal ());
533
- case swift::AccessedStorage::Class: {
578
+ case swift::AccessedStorage::Class:
534
579
return llvm::hash_combine (storage.getObject (),
535
580
storage.getPropertyIndex ());
536
- }
581
+ case swift::AccessedStorage::Tail:
582
+ return DenseMapInfo<swift::SILValue>::getHashValue (storage.getObject ());
537
583
}
538
584
llvm_unreachable (" Unhandled AccessedStorageKind" );
539
585
}
@@ -673,6 +719,9 @@ class AccessUseDefChainVisitor {
673
719
Result visitClassAccess (RefElementAddrInst *field) {
674
720
return asImpl ().visitBase (field, AccessedStorage::Class);
675
721
}
722
+ Result visitTailAccess (RefTailAddrInst *tail) {
723
+ return asImpl ().visitBase (tail, AccessedStorage::Tail);
724
+ }
676
725
Result visitArgumentAccess (SILFunctionArgument *arg) {
677
726
return asImpl ().visitBase (arg, AccessedStorage::Argument);
678
727
}
@@ -808,7 +857,7 @@ Result AccessUseDefChainVisitor<Impl, Result>::visit(SILValue sourceAddr) {
808
857
// This is a valid address producer for nested @inout argument
809
858
// access, but it is never used for formal access of identified objects.
810
859
case ValueKind::RefTailAddrInst:
811
- return asImpl ().visitUnidentified ( sourceAddr);
860
+ return asImpl ().visitTailAccess (cast<RefTailAddrInst>( sourceAddr) );
812
861
813
862
// Inductive single-operand cases:
814
863
// Look through address casts to find the source address.
0 commit comments