28
28
#include " swift/AST/IRGenOptions.h"
29
29
#include " swift/AST/PackConformance.h"
30
30
#include " swift/AST/ProtocolConformance.h"
31
+ #include " swift/Basic/GraphNodeWorklist.h"
31
32
#include " swift/SIL/SILModule.h"
32
33
33
34
using namespace swift ;
@@ -304,6 +305,84 @@ LocalTypeDataCache::tryGet(IRGenFunction &IGF, LocalTypeDataKey key,
304
305
llvm_unreachable (" bad cache entry kind" );
305
306
}
306
307
308
+ LocalTypeDataCache::StateAdvancement LocalTypeDataCache::advanceStateInScope (
309
+ IRGenFunction &IGF, LocalTypeDataKey key, MetadataState state) {
310
+ // Use the caching key.
311
+ key = key.getCachingKey ();
312
+
313
+ auto iterator = Map.find (key);
314
+ // There's no chain of entries, no no entry which could possibly be used.
315
+ if (iterator == Map.end ())
316
+ return StateAdvancement::NoEntry;
317
+ auto &chain = iterator->second ;
318
+
319
+ // Scan the chain for entries with the appropriate relationship to the active
320
+ // dominance scope, and "promote their state". Any entry whose state is
321
+ // already at least as complete than `state` is unaffected, and results in
322
+ // exiting early.
323
+ //
324
+ // There are two cases of interest:
325
+ //
326
+ // (1) DominancePoint(entry) dominates ActiveDominancePoint .
327
+ // (2) DominancePoint(entry) is dominated by ActiveDominancePoint .
328
+ //
329
+ // For (1), a new cache entry is created at ActiveDominancePoint.
330
+ // For (2), the state of the existing entry would be updated.
331
+ //
332
+ // Because of the order in which IRGen lowers, however, (2) can't actually
333
+ // happen: metadata whose dominance point is dominated by
334
+ // ActiveDominancePoint would not have been emitted yet.
335
+
336
+ // Find the best entry in the chain from which to produce a new entry.
337
+ CacheEntry *best = nullptr ;
338
+ for (auto *link = chain.Root ; link; link = link->getNext ()) {
339
+ // In case (1)?
340
+ if (!IGF.isActiveDominancePointDominatedBy (link->DefinitionPoint ))
341
+ continue ;
342
+
343
+ switch (link->getKind ()) {
344
+ case CacheEntry::Kind::Concrete: {
345
+ auto entry = cast<ConcreteCacheEntry>(link);
346
+ // If the entry is already as complete as `state`, it doesn't need to be
347
+ // used to create a new entry. In fact, no new entry needs to be created
348
+ // at all: this entry will be seen to be best if locally cached metadata
349
+ // is requested later. Stop traversal and return.
350
+ if (isAtLeast (entry->Value .getStaticLowerBoundOnState (), state))
351
+ return StateAdvancement::AlreadyAtLeast;
352
+
353
+ // Any suitable concrete entry is equally ideal.
354
+ best = entry;
355
+ break ;
356
+ }
357
+ case CacheEntry::Kind::Abstract: {
358
+ // TODO: Consider the cost to materialize the abstract entry in order to
359
+ // determine which is best.
360
+ break ;
361
+ }
362
+ }
363
+ }
364
+
365
+ if (!best)
366
+ return StateAdvancement::NoEntry;
367
+
368
+ switch (best->getKind ()) {
369
+ case CacheEntry::Kind::Concrete: {
370
+ auto *entry = cast<ConcreteCacheEntry>(best);
371
+ // Create a new entry at the ActiveDominancePoint.
372
+ auto response =
373
+ MetadataResponse::forBounded (entry->Value .getMetadata (), state);
374
+ IGF.setScopedLocalTypeData (key, response,
375
+ /* mayEmitDebugInfo=*/ false );
376
+
377
+ return StateAdvancement::Advanced;
378
+ }
379
+ case CacheEntry::Kind::Abstract:
380
+ // TODO: Advance abstract entries.
381
+ return StateAdvancement::NoEntry;
382
+ }
383
+ llvm_unreachable (" covered switch!?" );
384
+ }
385
+
307
386
MetadataResponse
308
387
LocalTypeDataCache::AbstractCacheEntry::follow (IRGenFunction &IGF,
309
388
AbstractSource &source,
@@ -381,10 +460,112 @@ IRGenFunction::setScopedLocalTypeMetadataForLayout(SILType type,
381
460
setScopedLocalTypeData (key, response);
382
461
}
383
462
384
- void IRGenFunction::setScopedLocalTypeMetadata (CanType type,
385
- MetadataResponse response) {
463
+ namespace {
464
+
465
+ void setScopedLocalTypeMetadataImpl (IRGenFunction &IGF, CanType type,
466
+ MetadataResponse response) {
386
467
auto key = LocalTypeDataKey (type, LocalTypeDataKind::forFormalTypeMetadata ());
387
- setScopedLocalTypeData (key, response);
468
+ IGF.setScopedLocalTypeData (key, response);
469
+ }
470
+
471
+ // / Walks the types upon whose corresponding metadata records' completeness the
472
+ // / completeness of \p rootTy's metadata record depends. For each such type,
473
+ // / marks the corresponding locally cached metadata record, if any, complete.
474
+ class TransitiveMetadataCompletion {
475
+ IRGenFunction &IGF;
476
+ LocalTypeDataCache &cache;
477
+ CanType rootTy;
478
+ GraphNodeWorklist<CanType, 4 > worklist;
479
+
480
+ public:
481
+ TransitiveMetadataCompletion (IRGenFunction &IGF, LocalTypeDataCache &cache,
482
+ CanType rootTy)
483
+ : IGF(IGF), cache(cache), rootTy(rootTy) {}
484
+
485
+ void complete ();
486
+
487
+ private:
488
+ // / Marks the metadata record currently locally cached corresponding to \p ty
489
+ // / complete.
490
+ // /
491
+ // / Returns whether \p ty's transitive metadata should be marked complete.
492
+ bool visit (CanType ty) {
493
+ // If it's the root type, it's already been marked complete, but we want to
494
+ // mark its transitively dependent metadata as complete.
495
+ if (ty == rootTy)
496
+ return true ;
497
+ auto key = LocalTypeDataKey (ty, LocalTypeDataKind::forFormalTypeMetadata ());
498
+ // The metadata record was already marked complete. When that was done, the
499
+ // records for types it has transitive completeness requirements on would
500
+ // have been marked complete, if they had already been materialized.
501
+ //
502
+ // Such records may have been materialized since then in an abstract state,
503
+ // but that is an unlikely case and scanning again would incur compile-time
504
+ // overhead.
505
+ if (cache.advanceStateInScope (IGF, key, MetadataState::Complete) ==
506
+ LocalTypeDataCache::StateAdvancement::AlreadyAtLeast)
507
+ return false ;
508
+ return true ;
509
+ }
510
+ };
511
+
512
+ void TransitiveMetadataCompletion::complete () {
513
+ worklist.initialize (rootTy);
514
+
515
+ while (auto ty = worklist.pop ()) {
516
+ if (!visit (ty)) {
517
+ // The transitively dependent metadata of `ty` doesn't need to be marked
518
+ // complete.
519
+ continue ;
520
+ }
521
+
522
+ // Walk into every type that `ty` has transitive completeness requirements
523
+ // on and mark each one transitively complete.
524
+ //
525
+ // This should mirror findAnyTransitiveMetadata: every type whose metadata
526
+ // is visited (i.e. has predicate called on it) by that function should be
527
+ // pushed onto the worklist.
528
+ if (auto ct = dyn_cast<ClassType>(ty)) {
529
+ if (auto rawSuperTy = ct->getSuperclass ()) {
530
+ auto superTy = rawSuperTy->getCanonicalType ();
531
+ worklist.insert (superTy);
532
+ }
533
+ } else if (auto bgt = dyn_cast<BoundGenericType>(ty)) {
534
+ if (auto ct = dyn_cast<BoundGenericClassType>(bgt)) {
535
+ if (auto rawSuperTy = ct->getSuperclass ()) {
536
+ auto superTy = rawSuperTy->getCanonicalType ();
537
+ worklist.insert (superTy);
538
+ }
539
+ }
540
+ for (auto arg : bgt->getExpandedGenericArgs ()) {
541
+ auto childTy = arg->getCanonicalType ();
542
+ worklist.insert (childTy);
543
+ }
544
+ } else if (auto tt = dyn_cast<TupleType>(ty)) {
545
+ for (auto elt : tt.getElementTypes ()) {
546
+ worklist.insert (elt);
547
+ }
548
+ }
549
+ }
550
+ }
551
+
552
+ } // end anonymous namespace
553
+
554
+ void IRGenFunction::setScopedLocalTypeMetadata (CanType rootTy,
555
+ MetadataResponse response) {
556
+ setScopedLocalTypeMetadataImpl (*this , rootTy, response);
557
+
558
+ if (response.getStaticLowerBoundOnState () != MetadataState::Complete)
559
+ return ;
560
+
561
+ // If the metadata record is complete, then it is _transitively_ complete.
562
+ // So every metadata record that it has transitive completeness requirements
563
+ // on must also be complete.
564
+ //
565
+ // Mark all such already materialized metadata that the given type has
566
+ // transitive completeness requirements on as complete.
567
+ TransitiveMetadataCompletion (*this , getOrCreateLocalTypeData (), rootTy)
568
+ .complete ();
388
569
}
389
570
390
571
void IRGenFunction::setScopedLocalTypeData (CanType type,
@@ -404,8 +585,10 @@ void IRGenFunction::setScopedLocalTypeDataForLayout(SILType type,
404
585
}
405
586
406
587
void IRGenFunction::setScopedLocalTypeData (LocalTypeDataKey key,
407
- MetadataResponse value) {
408
- maybeEmitDebugInfoForLocalTypeData (*this , key, value);
588
+ MetadataResponse value,
589
+ bool mayEmitDebugInfo) {
590
+ if (mayEmitDebugInfo)
591
+ maybeEmitDebugInfoForLocalTypeData (*this , key, value);
409
592
410
593
// Register with the active ConditionalDominanceScope if necessary.
411
594
bool isConditional = isConditionalDominancePoint ();
0 commit comments