Skip to content

Commit a5e4fd5

Browse files
authored
Merge pull request swiftlang#22801 from slavapestov/let-optimization-sillyness
Fix problems with resilient global optimization
2 parents 29dd7f8 + 23f7c4f commit a5e4fd5

File tree

5 files changed

+93
-39
lines changed

5 files changed

+93
-39
lines changed

include/swift/SILOptimizer/Utils/Local.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -535,13 +535,15 @@ bool isSimpleType(SILType SILTy, SILModule& Module);
535535
bool analyzeStaticInitializer(SILValue V,
536536
SmallVectorImpl<SILInstruction *> &Insns);
537537

538+
/// Returns true if the below operation will succeed.
539+
bool canReplaceLoadSequence(SILInstruction *I);
540+
538541
/// Replace load sequence which may contain
539542
/// a chain of struct_element_addr followed by a load.
540543
/// The sequence is traversed inside out, i.e.
541544
/// starting with the innermost struct_element_addr
542545
void replaceLoadSequence(SILInstruction *I,
543-
SILValue Value,
544-
SILBuilder &B);
546+
SILValue Value);
545547

546548

547549
/// Do we have enough information to determine all callees that could

lib/SILOptimizer/IPO/GlobalOpt.cpp

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -648,29 +648,26 @@ replaceLoadsByKnownValue(BuiltinInst *CallToOnce, SILFunction *AddrF,
648648
// Make this addressor transparent.
649649
AddrF->setTransparent(IsTransparent_t::IsTransparent);
650650

651-
for (int i = 0, e = Calls.size(); i < e; ++i) {
652-
auto *Call = Calls[i];
653-
SILBuilderWithScope B(Call);
654-
SmallVector<SILValue, 1> Args;
655-
auto *NewAI = B.createApply(Call->getLoc(), Call->getCallee(), Args, false);
656-
Call->replaceAllUsesWith(NewAI);
657-
eraseUsesOfInstruction(Call);
658-
recursivelyDeleteTriviallyDeadInstructions(Call, true);
659-
Calls[i] = NewAI;
660-
}
661-
662651
// Generate a getter from InitF which returns the value of the global.
663652
auto *GetterF = genGetterFromInit(FunctionBuilder, InitF, SILG->getDecl());
664653

665-
// Replace all calls of an addressor by calls of a getter .
654+
// Replace all calls of an addressor by calls of a getter.
666655
for (int i = 0, e = Calls.size(); i < e; ++i) {
667656
auto *Call = Calls[i];
668657

669-
// Now find all uses of Call. They all should be loads, so that
670-
// we can replace it.
658+
// Make sure that we can go ahead and replace all uses of the
659+
// address with the value.
671660
bool isValid = true;
672661
for (auto Use : Call->getUses()) {
673-
if (!isa<PointerToAddressInst>(Use->getUser())) {
662+
if (auto *PTAI = dyn_cast<PointerToAddressInst>(Use->getUser())) {
663+
for (auto PTAIUse : PTAI->getUses()) {
664+
SILInstruction *Use = PTAIUse->getUser();
665+
if (!canReplaceLoadSequence(Use)) {
666+
isValid = false;
667+
break;
668+
}
669+
}
670+
} else {
674671
isValid = false;
675672
break;
676673
}
@@ -679,6 +676,8 @@ replaceLoadsByKnownValue(BuiltinInst *CallToOnce, SILFunction *AddrF,
679676
if (!isValid)
680677
continue;
681678

679+
// Now find all uses of Call. They all should be loads, so that
680+
// we can replace it.
682681
SILBuilderWithScope B(Call);
683682
SmallVector<SILValue, 1> Args;
684683
auto *GetterRef = B.createFunctionRef(Call->getLoc(), GetterF);
@@ -692,16 +691,10 @@ replaceLoadsByKnownValue(BuiltinInst *CallToOnce, SILFunction *AddrF,
692691
auto *PTAI = dyn_cast<PointerToAddressInst>(Use->getUser());
693692
assert(PTAI && "All uses should be pointer_to_address");
694693
for (auto PTAIUse : PTAI->getUses()) {
695-
SILInstruction *Load = PTAIUse->getUser();
696-
if (auto *CA = dyn_cast<CopyAddrInst>(Load)) {
697-
// The result of the initializer is stored to another location.
698-
SILBuilder B(CA);
699-
B.createStore(CA->getLoc(), NewAI, CA->getDest(),
700-
StoreOwnershipQualifier::Unqualified);
701-
} else {
702-
// The result of the initializer is used as a value.
703-
replaceLoadSequence(Load, NewAI, B);
704-
}
694+
SILInstruction *Use = PTAIUse->getUser();
695+
696+
// The result of the getter is used as a value.
697+
replaceLoadSequence(Use, NewAI);
705698
}
706699
}
707700

lib/SILOptimizer/IPO/LetPropertiesOpts.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -210,22 +210,18 @@ void LetPropertiesOpt::optimizeLetPropertyAccess(VarDecl *Property,
210210
// Replace the access to a let property by the value
211211
// computed by this initializer.
212212
SILValue clonedInit = cloneInitAt(proj);
213-
SILBuilderWithScope B(proj);
214213
for (auto UI = proj->use_begin(), E = proj->use_end(); UI != E;) {
215214
auto *User = UI->getUser();
216215
++UI;
217216

218-
if (isIncidentalUse(User))
219-
continue;
220-
221217
// A nested begin_access will be mapped as a separate "Load".
222218
if (isa<BeginAccessInst>(User))
223219
continue;
224220

225-
if (isa<StoreInst>(User))
221+
if (!canReplaceLoadSequence(User))
226222
continue;
227223

228-
replaceLoadSequence(User, clonedInit, B);
224+
replaceLoadSequence(User, clonedInit);
229225
eraseUsesOfInstruction(User);
230226
User->eraseFromParent();
231227
++NumReplaced;

lib/SILOptimizer/Utils/Local.cpp

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1624,6 +1624,47 @@ bool swift::analyzeStaticInitializer(
16241624
return StaticInitializerAnalysis(forwardInstructions).analyze(V);
16251625
}
16261626

1627+
/// FIXME: This must be kept in sync with replaceLoadSequence()
1628+
/// below. What a horrible design.
1629+
bool swift::canReplaceLoadSequence(SILInstruction *I) {
1630+
if (auto *CAI = dyn_cast<CopyAddrInst>(I))
1631+
return true;
1632+
1633+
if (auto *LI = dyn_cast<LoadInst>(I))
1634+
return true;
1635+
1636+
if (auto *SEAI = dyn_cast<StructElementAddrInst>(I)) {
1637+
for (auto SEAIUse : SEAI->getUses()) {
1638+
if (!canReplaceLoadSequence(SEAIUse->getUser()))
1639+
return false;
1640+
}
1641+
return true;
1642+
}
1643+
1644+
if (auto *TEAI = dyn_cast<TupleElementAddrInst>(I)) {
1645+
for (auto TEAIUse : TEAI->getUses()) {
1646+
if (!canReplaceLoadSequence(TEAIUse->getUser()))
1647+
return false;
1648+
}
1649+
return true;
1650+
}
1651+
1652+
if (auto *BA = dyn_cast<BeginAccessInst>(I)) {
1653+
for (auto Use : BA->getUses()) {
1654+
if (!canReplaceLoadSequence(Use->getUser()))
1655+
return false;
1656+
}
1657+
return true;
1658+
}
1659+
1660+
// Incidental uses of an address are meaningless with regard to the loaded
1661+
// value.
1662+
if (isIncidentalUse(I) || isa<BeginUnpairedAccessInst>(I))
1663+
return true;
1664+
1665+
return false;
1666+
}
1667+
16271668
/// Replace load sequence which may contain
16281669
/// a chain of struct_element_addr followed by a load.
16291670
/// The sequence is traversed inside out, i.e.
@@ -1634,33 +1675,40 @@ bool swift::analyzeStaticInitializer(
16341675
/// guarantee that the only uses of `I` are struct_element_addr and
16351676
/// tuple_element_addr?
16361677
void swift::replaceLoadSequence(SILInstruction *I,
1637-
SILValue Value,
1638-
SILBuilder &B) {
1678+
SILValue Value) {
1679+
if (auto *CAI = dyn_cast<CopyAddrInst>(I)) {
1680+
SILBuilder B(CAI);
1681+
B.createStore(CAI->getLoc(), Value, CAI->getDest(),
1682+
StoreOwnershipQualifier::Unqualified);
1683+
return;
1684+
}
1685+
16391686
if (auto *LI = dyn_cast<LoadInst>(I)) {
16401687
LI->replaceAllUsesWith(Value);
16411688
return;
16421689
}
16431690

1644-
// It is a series of struct_element_addr followed by load.
16451691
if (auto *SEAI = dyn_cast<StructElementAddrInst>(I)) {
1692+
SILBuilder B(SEAI);
16461693
auto *SEI = B.createStructExtract(SEAI->getLoc(), Value, SEAI->getField());
16471694
for (auto SEAIUse : SEAI->getUses()) {
1648-
replaceLoadSequence(SEAIUse->getUser(), SEI, B);
1695+
replaceLoadSequence(SEAIUse->getUser(), SEI);
16491696
}
16501697
return;
16511698
}
16521699

16531700
if (auto *TEAI = dyn_cast<TupleElementAddrInst>(I)) {
1701+
SILBuilder B(TEAI);
16541702
auto *TEI = B.createTupleExtract(TEAI->getLoc(), Value, TEAI->getFieldNo());
16551703
for (auto TEAIUse : TEAI->getUses()) {
1656-
replaceLoadSequence(TEAIUse->getUser(), TEI, B);
1704+
replaceLoadSequence(TEAIUse->getUser(), TEI);
16571705
}
16581706
return;
16591707
}
16601708

16611709
if (auto *BA = dyn_cast<BeginAccessInst>(I)) {
16621710
for (auto Use : BA->getUses()) {
1663-
replaceLoadSequence(Use->getUser(), Value, B);
1711+
replaceLoadSequence(Use->getUser(), Value);
16641712
}
16651713
return;
16661714
}

test/SILOptimizer/globalopt_resilience.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,20 @@ public struct ResilientStruct {
1515
var rawValue: Int
1616

1717
public static let staticVal = ResilientStruct(rawValue: 27)
18+
19+
@_optimize(none)
20+
public func method() {}
21+
}
22+
23+
public func cannotConvertToValueUse() {
24+
// We can't optimize this because the method takes the resilient value as
25+
// @in_guaranteed
26+
ResilientStruct.staticVal.method()
1827
}
1928

29+
// CHECK-LABEL: sil @$s4test23cannotConvertToValueUseyyF : $@convention(thin) () -> ()
30+
// CHECK: [[ADDR:%.*]] = global_addr @$s4test15ResilientStructV9staticValACvpZ : $*ResilientStruct
31+
// CHECK: [[METHOD:%.*]] = function_ref @$s4test15ResilientStructV6methodyyF : $@convention(method) (@in_guaranteed ResilientStruct) -> ()
32+
// CHECK: apply [[METHOD]]([[ADDR]]) : $@convention(method) (@in_guaranteed ResilientStruct) -> ()
33+
// CHECK: [[RESULT:%.*]] = tuple ()
34+
// CHECK: return [[RESULT]] : $()

0 commit comments

Comments
 (0)