@@ -594,6 +594,62 @@ SILInstruction *SILCombiner::optimizeLoadFromStringLiteral(LoadInst *LI) {
594594 return Builder.createIntegerLiteral (LI->getLoc (), LI->getType (), str[index]);
595595}
596596
597+ // / Returns true if \p LI loads a zero integer from the empty Array, Dictionary
598+ // / or Set singleton.
599+ static bool isZeroLoadFromEmptyCollection (LoadInst *LI) {
600+ auto intTy = LI->getType ().getAs <BuiltinIntegerType>();
601+ if (!intTy)
602+ return false ;
603+
604+ SILValue addr = LI->getOperand ();
605+
606+ // Find the root object of the load-address.
607+ for (;;) {
608+ switch (addr->getKind ()) {
609+ case ValueKind::GlobalAddrInst: {
610+ StringRef gName =
611+ cast<GlobalAddrInst>(addr)->getReferencedGlobal ()->getName ();
612+ return gName == " _swiftEmptyArrayStorage" ||
613+ gName == " _swiftEmptyDictionarySingleton" ||
614+ gName == " _swiftEmptySetSingleton" ;
615+ }
616+ case ValueKind::StructElementAddrInst: {
617+ auto *SEA = cast<StructElementAddrInst>(addr);
618+ // For Array, we only support "count". The value of "capacityAndFlags"
619+ // is not defined in the ABI and could change in another version of the
620+ // runtime (the capacity must be 0, but the flags may be not 0).
621+ if (SEA->getStructDecl ()->getName ().is (" _SwiftArrayBodyStorage" ) &&
622+ !SEA->getField ()->getName ().is (" count" )) {
623+ return false ;
624+ }
625+ addr = SEA->getOperand ();
626+ break ;
627+ }
628+ case ValueKind::RefElementAddrInst: {
629+ auto *REA = cast<RefElementAddrInst>(addr);
630+ Identifier className = REA->getClassDecl ()->getName ();
631+ // For Dictionary and Set we support "count" and "capacity".
632+ if (className.is (" __RawDictionaryStorage" ) ||
633+ className.is (" __RawSetStorage" )) {
634+ Identifier fieldName = REA->getField ()->getName ();
635+ if (!fieldName.is (" _count" ) && !fieldName.is (" _capacity" ))
636+ return false ;
637+ }
638+ addr = REA->getOperand ();
639+ break ;
640+ }
641+ case ValueKind::UncheckedRefCastInst:
642+ case ValueKind::UpcastInst:
643+ case ValueKind::RawPointerToRefInst:
644+ case ValueKind::AddressToPointerInst:
645+ addr = cast<SingleValueInstruction>(addr)->getOperand (0 );
646+ break ;
647+ default :
648+ return false ;
649+ }
650+ }
651+ }
652+
597653SILInstruction *SILCombiner::visitLoadInst (LoadInst *LI) {
598654 // (load (upcast-ptr %x)) -> (upcast-ref (load %x))
599655 Builder.setCurrentDebugScope (LI->getDebugScope ());
@@ -606,6 +662,17 @@ SILInstruction *SILCombiner::visitLoadInst(LoadInst *LI) {
606662 if (SILInstruction *I = optimizeLoadFromStringLiteral (LI))
607663 return I;
608664
665+ // Constant-propagate the 0 value when loading "count" or "capacity" from the
666+ // empty Array, Set or Dictionary storage.
667+ // On high-level SIL this optimization is also done by the
668+ // ArrayCountPropagation pass, but only for Array. And even for Array it's
669+ // sometimes needed to propagate the empty-array count when high-level
670+ // semantics function are already inlined.
671+ // Note that for non-empty arrays/sets/dictionaries, the count can be
672+ // propagated by redundant load elimination.
673+ if (isZeroLoadFromEmptyCollection (LI))
674+ return Builder.createIntegerLiteral (LI->getLoc (), LI->getType (), 0 );
675+
609676 return nullptr ;
610677}
611678
0 commit comments