@@ -137,6 +137,9 @@ class SILGlobalOpt {
137
137
// / can be statically initialized.
138
138
void optimizeInitializer (SILFunction *AddrF, GlobalInitCalls &Calls);
139
139
140
+ // / Perform peephole optimizations on the initializer list.
141
+ void peepholeInitializer (SILFunction *InitFunc);
142
+
140
143
// / Optimize access to the global variable, which is known to have a constant
141
144
// / value. Replace all loads from the global address by invocations of a
142
145
// / getter that returns the value of this variable.
@@ -253,12 +256,14 @@ static SILFunction *getGlobalGetterFunction(SILOptFunctionBuilder &FunctionBuild
253
256
if (auto *F = M.lookUpFunction (getterNameTmp))
254
257
return F;
255
258
256
- auto Linkage = (varDecl->getEffectiveAccess () >= AccessLevel::Public
257
- ? SILLinkage::PublicNonABI
258
- : SILLinkage::Private);
259
- auto Serialized = (varDecl->getEffectiveAccess () >= AccessLevel::Public
260
- ? IsSerialized
261
- : IsNotSerialized);
259
+ auto Linkage = SILLinkage::Private;
260
+ auto Serialized = IsNotSerialized;
261
+
262
+ if (varDecl->getEffectiveAccess () >= AccessLevel::Public &&
263
+ !varDecl->isResilient ()) {
264
+ Linkage = SILLinkage::PublicNonABI;
265
+ Serialized = IsSerialized;
266
+ }
262
267
263
268
auto refType = M.Types .getLoweredType (varDecl->getInterfaceType ());
264
269
@@ -690,7 +695,17 @@ replaceLoadsByKnownValue(BuiltinInst *CallToOnce, SILFunction *AddrF,
690
695
auto *PTAI = dyn_cast<PointerToAddressInst>(Use->getUser ());
691
696
assert (PTAI && " All uses should be pointer_to_address" );
692
697
for (auto PTAIUse : PTAI->getUses ()) {
693
- replaceLoadSequence (PTAIUse->getUser (), NewAI, B);
698
+ SILInstruction *Load = PTAIUse->getUser ();
699
+ if (auto *CA = dyn_cast<CopyAddrInst>(Load)) {
700
+ // The result of the initializer is stored to another location.
701
+ SILBuilder B (CA);
702
+ B.createStore (CA->getLoc (), NewAI, CA->getDest (),
703
+ StoreOwnershipQualifier::Unqualified);
704
+ CA->eraseFromParent ();
705
+ } else {
706
+ // The result of the initializer is used as a value.
707
+ replaceLoadSequence (Load, NewAI, B);
708
+ }
694
709
}
695
710
}
696
711
@@ -721,6 +736,8 @@ void SILGlobalOpt::optimizeInitializer(SILFunction *AddrF,
721
736
InitializerCount[InitF] > 1 )
722
737
return ;
723
738
739
+ peepholeInitializer (InitF);
740
+
724
741
// If the globalinit_func is trivial, continue; otherwise bail.
725
742
SingleValueInstruction *InitVal;
726
743
SILGlobalVariable *SILG = getVariableOfStaticInitializer (InitF, InitVal);
@@ -743,6 +760,58 @@ void SILGlobalOpt::optimizeInitializer(SILFunction *AddrF,
743
760
HasChanged = true ;
744
761
}
745
762
763
+ void SILGlobalOpt::peepholeInitializer (SILFunction *InitFunc) {
764
+ if (InitFunc->size () != 1 )
765
+ return ;
766
+ SILBasicBlock *BB = &InitFunc->front ();
767
+
768
+ for (auto &I : *BB) {
769
+ if (auto *SI = dyn_cast<StoreInst>(&I)) {
770
+
771
+ // If struct S has a single field, replace
772
+ // %a = struct_element_addr %s : $*S
773
+ // store %x to %a
774
+ // with
775
+ // %y = struct $S (%x)
776
+ // store %y to %s
777
+ //
778
+ // This pattern occurs with resilient static properties, like
779
+ // struct ResilientStruct {
780
+ // var singleField: Int
781
+ // public static let x = ResilientStruct(singleField: 27)
782
+ // }
783
+ //
784
+ // TODO: handle structs with multiple fields.
785
+ SILValue Addr = SI->getDest ();
786
+ auto *SEA = dyn_cast<StructElementAddrInst>(Addr);
787
+ if (!SEA)
788
+ continue ;
789
+
790
+ if (SEA->getOperand ()->getType ().isAddressOnly (InitFunc))
791
+ continue ;
792
+
793
+ StructDecl *Decl = SEA->getStructDecl ();
794
+ auto beginProp = Decl->getStoredProperties ().begin ();
795
+ if (std::next (beginProp) != Decl->getStoredProperties ().end ())
796
+ continue ;
797
+
798
+ assert (*beginProp == SEA->getField ());
799
+
800
+ SILBuilder B (SI);
801
+ SILValue StructAddr = SEA->getOperand ();
802
+ StructInst *Struct = B.createStruct (SEA->getLoc (),
803
+ StructAddr->getType ().getObjectType (),
804
+ { SI->getSrc () });
805
+ SI->setOperand (StoreInst::Src, Struct);
806
+ SI->setOperand (StoreInst::Dest, StructAddr);
807
+ if (SEA->use_empty ()) {
808
+ SEA->eraseFromParent ();
809
+ }
810
+ HasChanged = true ;
811
+ }
812
+ }
813
+ }
814
+
746
815
static bool canBeChangedExternally (SILGlobalVariable *SILG) {
747
816
// Don't assume anything about globals which are imported from other modules.
748
817
if (isAvailableExternally (SILG->getLinkage ()))
0 commit comments