Skip to content

Commit 60a4b8b

Browse files
authored
Merge pull request #19857 from eeckstein/early-rle
SILOptimizer: fix a phase ordering problem, which prevented array optimizations to work in some cases
2 parents 5cebbb2 + 7b16f7f commit 60a4b8b

File tree

4 files changed

+80
-7
lines changed

4 files changed

+80
-7
lines changed

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ PASS(ARCSequenceOpts, "arc-sequence-opts",
154154
"ARC Sequence Optimization")
155155
PASS(ARCLoopOpts, "arc-loop-opts",
156156
"ARC Loop Optimization")
157+
PASS(EarlyRedundantLoadElimination, "early-redundant-load-elim",
158+
"Early Redundant Load Elimination")
157159
PASS(RedundantLoadElimination, "redundant-load-elim",
158160
"Redundant Load Elimination")
159161
PASS(DeadStoreElimination, "dead-store-elim",

lib/SILOptimizer/PassManager/PassPipeline.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,14 @@ void addSSAPasses(SILPassPipelinePlan &P, OptimizationLevelKind OpLevel) {
305305
P.addSimplifyCFG();
306306

307307
P.addCSE();
308-
P.addRedundantLoadElimination();
308+
if (OpLevel == OptimizationLevelKind::HighLevel) {
309+
// Early RLE does not touch loads from Arrays. This is important because
310+
// later array optimizations, like ABCOpt, get confused if an array load in
311+
// a loop is converted to a pattern with a phi argument.
312+
P.addEarlyRedundantLoadElimination();
313+
} else {
314+
P.addRedundantLoadElimination();
315+
}
309316

310317
P.addPerformanceConstantPropagation();
311318
P.addCSE();

lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -481,14 +481,17 @@ class RLEContext {
481481
/// walked, i.e. when the we generate the genset and killset.
482482
llvm::DenseSet<SILBasicBlock *> BBWithLoads;
483483

484+
/// If set, RLE ignores loads from that array type.
485+
NominalTypeDecl *ArrayType;
486+
484487
#ifndef NDEBUG
485488
SILPrintContext printCtx;
486489
#endif
487490

488491
public:
489492
RLEContext(SILFunction *F, SILPassManager *PM, AliasAnalysis *AA,
490493
TypeExpansionAnalysis *TE, PostOrderFunctionInfo *PO,
491-
EpilogueARCFunctionInfo *EAFI);
494+
EpilogueARCFunctionInfo *EAFI, bool disableArrayLoads);
492495

493496
RLEContext(const RLEContext &) = delete;
494497
RLEContext(RLEContext &&) = default;
@@ -555,6 +558,17 @@ class RLEContext {
555558
/// Transitively collect all the values that make up this location and
556559
/// create a SILArgument out of them.
557560
SILValue computePredecessorLocationValue(SILBasicBlock *BB, LSLocation &L);
561+
562+
/// Returns the LoadInst if \p Inst is a load inst we want to handle.
563+
LoadInst *isLoadInstToHandle(SILInstruction *Inst) {
564+
if (auto *LI = dyn_cast<LoadInst>(Inst)) {
565+
if (!ArrayType ||
566+
LI->getType().getNominalOrBoundGenericNominal() != ArrayType) {
567+
return LI;
568+
}
569+
}
570+
return nullptr;
571+
}
558572
};
559573

560574
} // end anonymous namespace
@@ -1054,7 +1068,7 @@ void BlockState::processInstructionWithKind(RLEContext &Ctx,
10541068

10551069
// This is a LoadInst. Let's see if we can find a previous loaded, stored
10561070
// value to use instead of this load.
1057-
if (auto *LI = dyn_cast<LoadInst>(Inst)) {
1071+
if (auto *LI = Ctx.isLoadInstToHandle(Inst)) {
10581072
processLoadInst(Ctx, LI, Kind);
10591073
return;
10601074
}
@@ -1174,8 +1188,10 @@ void BlockState::dump(RLEContext &Ctx) {
11741188

11751189
RLEContext::RLEContext(SILFunction *F, SILPassManager *PM, AliasAnalysis *AA,
11761190
TypeExpansionAnalysis *TE, PostOrderFunctionInfo *PO,
1177-
EpilogueARCFunctionInfo *EAFI)
1178-
: Fn(F), PM(PM), AA(AA), TE(TE), PO(PO), EAFI(EAFI)
1191+
EpilogueARCFunctionInfo *EAFI, bool disableArrayLoads)
1192+
: Fn(F), PM(PM), AA(AA), TE(TE), PO(PO), EAFI(EAFI),
1193+
ArrayType(disableArrayLoads ?
1194+
F->getModule().getASTContext().getArrayDecl() : nullptr)
11791195
#ifndef NDEBUG
11801196
,
11811197
printCtx(llvm::dbgs(), /*Verbose=*/false, /*Sorted=*/true)
@@ -1612,6 +1628,14 @@ namespace {
16121628

16131629
class RedundantLoadElimination : public SILFunctionTransform {
16141630

1631+
private:
1632+
bool disableArrayLoads;
1633+
1634+
public:
1635+
1636+
RedundantLoadElimination(bool disableArrayLoads)
1637+
: disableArrayLoads(disableArrayLoads) { }
1638+
16151639
/// The entry point to the transformation.
16161640
void run() override {
16171641
SILFunction *F = getFunction();
@@ -1623,7 +1647,7 @@ class RedundantLoadElimination : public SILFunctionTransform {
16231647
auto *PO = PM->getAnalysis<PostOrderAnalysis>()->get(F);
16241648
auto *EAFI = PM->getAnalysis<EpilogueARCAnalysis>()->get(F);
16251649

1626-
RLEContext RLE(F, PM, AA, TE, PO, EAFI);
1650+
RLEContext RLE(F, PM, AA, TE, PO, EAFI, disableArrayLoads);
16271651
if (RLE.run()) {
16281652
invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
16291653
}
@@ -1632,6 +1656,10 @@ class RedundantLoadElimination : public SILFunctionTransform {
16321656

16331657
} // end anonymous namespace
16341658

1659+
SILTransform *swift::createEarlyRedundantLoadElimination() {
1660+
return new RedundantLoadElimination(/*disableArrayLoads=*/true);
1661+
}
1662+
16351663
SILTransform *swift::createRedundantLoadElimination() {
1636-
return new RedundantLoadElimination();
1664+
return new RedundantLoadElimination(/*disableArrayLoads=*/false);
16371665
}

test/SILOptimizer/early-rle.sil

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -early-redundant-load-elim | %FileCheck %s
2+
3+
sil_stage canonical
4+
5+
import Builtin
6+
import Swift
7+
import SwiftShims
8+
9+
10+
// Check that earlyl redundant load elimination ignores arrays.
11+
12+
13+
// CHECK-LABEL: test_array
14+
// CHECK: %1 = load
15+
// CHECK: %2 = load
16+
// CHECK: %3 = tuple (%1 {{.*}}, %2 {{.*}})
17+
sil @test_array : $@convention(thin) (@inout Array<Int>) -> (Array<Int>, Array<Int>) {
18+
bb0(%0 : $*Array<Int>):
19+
%1 = load %0 : $*Array<Int>
20+
%2 = load %0 : $*Array<Int>
21+
%3 = tuple (%1: $Array<Int>, %2: $Array<Int>)
22+
return %3 : $(Array<Int>, Array<Int>)
23+
}
24+
25+
// CHECK-LABEL: test_non_array
26+
// CHECK: %1 = load
27+
// CHECK: %2 = tuple (%1 {{.*}}, %1 {{.*}})
28+
sil @test_non_array : $@convention(thin) (@inout Int) -> (Int, Int) {
29+
bb0(%0 : $*Int):
30+
%1 = load %0 : $*Int
31+
%2 = load %0 : $*Int
32+
%3 = tuple (%1: $Int, %2: $Int)
33+
return %3 : $(Int, Int)
34+
}
35+
36+

0 commit comments

Comments
 (0)