2828#include " swift/AST/IRGenOptions.h"
2929#include " swift/AST/PackConformance.h"
3030#include " swift/AST/ProtocolConformance.h"
31+ #include " swift/Basic/GraphNodeWorklist.h"
3132#include " swift/SIL/SILModule.h"
3233
3334using namespace swift ;
@@ -304,6 +305,84 @@ LocalTypeDataCache::tryGet(IRGenFunction &IGF, LocalTypeDataKey key,
304305 llvm_unreachable (" bad cache entry kind" );
305306}
306307
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+
307386MetadataResponse
308387LocalTypeDataCache::AbstractCacheEntry::follow (IRGenFunction &IGF,
309388 AbstractSource &source,
@@ -381,10 +460,112 @@ IRGenFunction::setScopedLocalTypeMetadataForLayout(SILType type,
381460 setScopedLocalTypeData (key, response);
382461}
383462
384- void IRGenFunction::setScopedLocalTypeMetadata (CanType type,
385- MetadataResponse response) {
463+ namespace {
464+
465+ void setScopedLocalTypeMetadataImpl (IRGenFunction &IGF, CanType type,
466+ MetadataResponse response) {
386467 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 ();
388569}
389570
390571void IRGenFunction::setScopedLocalTypeData (CanType type,
@@ -404,8 +585,10 @@ void IRGenFunction::setScopedLocalTypeDataForLayout(SILType type,
404585}
405586
406587void 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);
409592
410593 // Register with the active ConditionalDominanceScope if necessary.
411594 bool isConditional = isConditionalDominancePoint ();
0 commit comments