24
24
#include " swift/SILOptimizer/Analysis/AliasAnalysis.h"
25
25
#include " swift/SILOptimizer/Analysis/Analysis.h"
26
26
#include " swift/SILOptimizer/Analysis/ArraySemantic.h"
27
+ #include " swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h"
27
28
#include " swift/SILOptimizer/Analysis/DominanceAnalysis.h"
28
29
#include " swift/SILOptimizer/Analysis/LoopAnalysis.h"
29
- #include " swift/SILOptimizer/Analysis/SideEffectAnalysis.h"
30
30
#include " swift/SILOptimizer/PassManager/Passes.h"
31
31
#include " swift/SILOptimizer/PassManager/Transforms.h"
32
32
#include " swift/SILOptimizer/Utils/CFGOptUtils.h"
@@ -166,31 +166,56 @@ static bool isOnlyLoadedAndStored(AliasAnalysis *AA, InstSet &SideEffectInsts,
166
166
// / Returns true if the \p SideEffectInsts set contains any memory writes which
167
167
// / may alias with any memory which is read by \p AI.
168
168
// / Note: This function should only be called on a read-only apply!
169
- static bool mayWriteTo (AliasAnalysis *AA, SideEffectAnalysis *SEA ,
169
+ static bool mayWriteTo (AliasAnalysis *AA, BasicCalleeAnalysis *BCA ,
170
170
InstSet &SideEffectInsts, ApplyInst *AI) {
171
- FunctionSideEffects E;
172
- SEA->getCalleeEffects (E, AI);
173
- assert (E.getMemBehavior (RetainObserveKind::IgnoreRetains) <=
174
- SILInstruction::MemoryBehavior::MayRead &&
175
- " apply should only read from memory" );
176
- assert (!E.getGlobalEffects ().mayRead () &&
177
- " apply should not have global effects" );
178
-
179
- for (unsigned Idx = 0 , End = AI->getNumArguments (); Idx < End; ++Idx) {
180
- auto &ArgEffect = E.getParameterEffects ()[Idx];
181
- assert (!ArgEffect.mayRelease () && " apply should only read from memory" );
182
- if (!ArgEffect.mayRead ())
183
- continue ;
184
171
185
- SILValue Arg = AI->getArgument (Idx);
172
+ if (BCA->getMemoryBehavior (FullApplySite::isa (AI), /* observeRetains*/ true ) ==
173
+ SILInstruction::MemoryBehavior::None) {
174
+ return false ;
175
+ }
186
176
187
- // Check if the memory addressed by the argument may alias any writes.
188
- for (auto *I : SideEffectInsts) {
189
- if (AA->mayWriteToMemory (I, Arg)) {
190
- LLVM_DEBUG (llvm::dbgs () << " mayWriteTo\n " << *I << " to "
191
- << *AI << " \n " );
192
- return true ;
177
+ // Check if the memory addressed by the argument may alias any writes.
178
+ for (auto *inst : SideEffectInsts) {
179
+ switch (inst->getKind ()) {
180
+ case SILInstructionKind::StoreInst: {
181
+ auto *si = cast<StoreInst>(inst);
182
+ if (si->getOwnershipQualifier () == StoreOwnershipQualifier::Assign)
183
+ return true ;
184
+ if (AA->mayReadFromMemory (AI, si->getDest ()))
185
+ return true ;
186
+ break ;
187
+ }
188
+ case SILInstructionKind::CopyAddrInst: {
189
+ auto *ca = cast<CopyAddrInst>(inst);
190
+ if (!ca->isInitializationOfDest ())
191
+ return true ;
192
+ if (AA->mayReadFromMemory (AI, ca->getDest ()))
193
+ return true ;
194
+ break ;
193
195
}
196
+ case SILInstructionKind::ApplyInst:
197
+ case SILInstructionKind::BeginApplyInst:
198
+ case SILInstructionKind::TryApplyInst: {
199
+ if (BCA->getMemoryBehavior (FullApplySite::isa (inst), /* observeRetains*/ false ) >
200
+ SILInstruction::MemoryBehavior::MayRead)
201
+ return true ;
202
+ break ;
203
+ }
204
+ case SILInstructionKind::CondFailInst:
205
+ case SILInstructionKind::StrongRetainInst:
206
+ case SILInstructionKind::UnmanagedRetainValueInst:
207
+ case SILInstructionKind::RetainValueInst:
208
+ case SILInstructionKind::StrongRetainUnownedInst:
209
+ case SILInstructionKind::FixLifetimeInst:
210
+ case SILInstructionKind::KeyPathInst:
211
+ case SILInstructionKind::DeallocStackInst:
212
+ case SILInstructionKind::DeallocStackRefInst:
213
+ case SILInstructionKind::DeallocRefInst:
214
+ break ;
215
+ default :
216
+ if (inst->mayWriteToMemory ())
217
+ return true ;
218
+ break ;
194
219
}
195
220
}
196
221
return false ;
@@ -509,7 +534,7 @@ class LoopTreeOptimization {
509
534
InstSet toDelete;
510
535
SILLoopInfo *LoopInfo;
511
536
AliasAnalysis *AA;
512
- SideEffectAnalysis *SEA ;
537
+ BasicCalleeAnalysis *BCA ;
513
538
DominanceInfo *DomTree;
514
539
PostDominanceAnalysis *PDA;
515
540
PostDominanceInfo *postDomTree = nullptr ;
@@ -540,11 +565,11 @@ class LoopTreeOptimization {
540
565
541
566
public:
542
567
LoopTreeOptimization (SILLoop *TopLevelLoop, SILLoopInfo *LI,
543
- AliasAnalysis *AA, SideEffectAnalysis *SEA ,
568
+ AliasAnalysis *AA, BasicCalleeAnalysis *BCA ,
544
569
DominanceInfo *DT, PostDominanceAnalysis *PDA,
545
570
AccessStorageAnalysis *ASA,
546
571
bool RunsOnHighLevelSil)
547
- : LoopInfo(LI), AA(AA), SEA(SEA ), DomTree(DT), PDA(PDA), ASA(ASA),
572
+ : LoopInfo(LI), AA(AA), BCA(BCA ), DomTree(DT), PDA(PDA), ASA(ASA),
548
573
Changed (false ), RunsOnHighLevelSIL(RunsOnHighLevelSil) {
549
574
// Collect loops for a recursive bottom-up traversal in the loop tree.
550
575
BotUpWorkList.push_back (TopLevelLoop);
@@ -562,6 +587,8 @@ class LoopTreeOptimization {
562
587
// / Propagate the sub-loops' summaries up to the current loop.
563
588
void propagateSummaries (std::unique_ptr<LoopNestSummary> &CurrSummary);
564
589
590
+ bool isSafeReadOnlyApply (BasicCalleeAnalysis *BCA, ApplyInst *AI);
591
+
565
592
// / Collect a set of instructions that can be hoisted
566
593
void analyzeCurrentLoop (std::unique_ptr<LoopNestSummary> &CurrSummary);
567
594
@@ -658,19 +685,22 @@ void LoopTreeOptimization::propagateSummaries(
658
685
}
659
686
}
660
687
661
- static bool isSafeReadOnlyApply (SideEffectAnalysis *SEA, ApplyInst *AI) {
662
- FunctionSideEffects E;
663
- SEA->getCalleeEffects (E, AI);
688
+ bool LoopTreeOptimization::isSafeReadOnlyApply (BasicCalleeAnalysis *BCA, ApplyInst *AI) {
689
+ if (auto ri = AI->getSingleResult ()) {
690
+ // We don't balance CSE'd apply results which return an owned value.
691
+ if (ri.getValue ().getConvention () != ResultConvention::Unowned)
692
+ return false ;
693
+ }
664
694
665
- if (E. getGlobalEffects (). mayRead () ) {
666
- // If we have Global effects,
667
- // we don't know which memory is read in the callee .
668
- // Therefore we bail for safety
669
- return false ;
695
+ if (RunsOnHighLevelSIL ) {
696
+ // The array-property-opt needs this semantic call inside the loop.
697
+ // After high-level SIL we can hoist it (if it's not inlined already) .
698
+ if ( ArraySemanticsCall (AI, " array.props.isNativeTypeChecked " ))
699
+ return false ;
670
700
}
671
701
672
- auto MB = E. getMemBehavior (RetainObserveKind::ObserveRetains);
673
- return (MB <= SILInstruction::MemoryBehavior::MayRead) ;
702
+ return BCA-> getMemoryBehavior (AI, /* observeRetains */ false ) <=
703
+ SILInstruction::MemoryBehavior::MayRead;
674
704
}
675
705
676
706
static void checkSideEffects (swift::SILInstruction &Inst,
@@ -695,26 +725,31 @@ static bool canHoistUpDefault(SILInstruction *inst, SILLoop *Loop,
695
725
return false ;
696
726
}
697
727
698
- if (inst->getMemoryBehavior () == SILInstruction::MemoryBehavior::None) {
699
- return true ;
700
- }
701
-
702
- if (!RunsOnHighLevelSil) {
703
- return false ;
704
- }
705
-
706
728
// We can’t hoist everything that is hoist-able
707
729
// The canHoist method does not do all the required analysis
708
730
// Some of the work is done at COW Array Opt
709
731
// TODO: Refactor COW Array Opt + canHoist - radar 41601468
710
732
ArraySemanticsCall semCall (inst);
711
733
switch (semCall.getKind ()) {
712
- case ArrayCallKind::kGetCount :
713
- case ArrayCallKind::kGetCapacity :
714
- return semCall.canHoist (Preheader->getTerminator (), DT);
715
- default :
716
- return false ;
734
+ case ArrayCallKind::kGetCount :
735
+ case ArrayCallKind::kGetCapacity :
736
+ if (RunsOnHighLevelSil && semCall.canHoist (Preheader->getTerminator (), DT))
737
+ return true ;
738
+ break ;
739
+ case ArrayCallKind::kArrayPropsIsNativeTypeChecked :
740
+ // The array-property-opt needs this semantic call inside the loop.
741
+ // After high-level SIL we can hoist it (if it's not inlined already).
742
+ if (RunsOnHighLevelSil)
743
+ return false ;
744
+ break ;
745
+ default :
746
+ break ;
747
+ }
748
+
749
+ if (inst->getMemoryBehavior () == SILInstruction::MemoryBehavior::None) {
750
+ return true ;
717
751
}
752
+ return false ;
718
753
}
719
754
720
755
// Check If all the end accesses of the given begin do not prevent hoisting
@@ -874,7 +909,7 @@ void LoopTreeOptimization::analyzeCurrentLoop(
874
909
break ;
875
910
case SILInstructionKind::ApplyInst: {
876
911
auto *AI = cast<ApplyInst>(&Inst);
877
- if (isSafeReadOnlyApply (SEA , AI)) {
912
+ if (isSafeReadOnlyApply (BCA , AI)) {
878
913
ReadOnlyApplies.push_back (AI);
879
914
} else if (SILFunction *callee = AI->getReferencedFunctionOrNull ()) {
880
915
// Calls to global inits are different because we don't care about
@@ -903,7 +938,7 @@ void LoopTreeOptimization::analyzeCurrentLoop(
903
938
}
904
939
905
940
for (auto *AI : ReadOnlyApplies) {
906
- if (!mayWriteTo (AA, SEA , sideEffects, AI)) {
941
+ if (!mayWriteTo (AA, BCA , sideEffects, AI)) {
907
942
HoistUp.insert (AI);
908
943
}
909
944
}
@@ -1471,7 +1506,7 @@ class LICM : public SILFunctionTransform {
1471
1506
DominanceAnalysis *DA = PM->getAnalysis <DominanceAnalysis>();
1472
1507
PostDominanceAnalysis *PDA = PM->getAnalysis <PostDominanceAnalysis>();
1473
1508
AliasAnalysis *AA = PM->getAnalysis <AliasAnalysis>(F);
1474
- SideEffectAnalysis *SEA = PM->getAnalysis <SideEffectAnalysis >();
1509
+ BasicCalleeAnalysis *BCA = PM->getAnalysis <BasicCalleeAnalysis >();
1475
1510
AccessStorageAnalysis *ASA = getAnalysis<AccessStorageAnalysis>();
1476
1511
DominanceInfo *DomTree = nullptr ;
1477
1512
@@ -1480,7 +1515,7 @@ class LICM : public SILFunctionTransform {
1480
1515
1481
1516
for (auto *TopLevelLoop : *LoopInfo) {
1482
1517
if (!DomTree) DomTree = DA->get (F);
1483
- LoopTreeOptimization Opt (TopLevelLoop, LoopInfo, AA, SEA , DomTree, PDA,
1518
+ LoopTreeOptimization Opt (TopLevelLoop, LoopInfo, AA, BCA , DomTree, PDA,
1484
1519
ASA, RunsOnHighLevelSil);
1485
1520
Changed |= Opt.optimize ();
1486
1521
}
0 commit comments