Skip to content

Commit e140015

Browse files
authored
Merge pull request #21961 from gottesmm/pr-3f0087ca02c8ed653f9fd81e659e0d0a94a7abe8
Split predictable mem opts into two different passes, one that runs b…
2 parents 3dda7ee + ac1f956 commit e140015

File tree

4 files changed

+126
-50
lines changed

4 files changed

+126
-50
lines changed

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,8 +232,10 @@ PASS(PerfInliner, "inline",
232232
"Performance Function Inlining")
233233
PASS(PerformanceConstantPropagation, "performance-constant-propagation",
234234
"Constant Propagation for Performance without Diagnostics")
235-
PASS(PredictableMemoryOptimizations, "predictable-memopt",
236-
"Predictable Memory Optimization for Diagnostics")
235+
PASS(PredictableMemoryAccessOptimizations, "predictable-memaccess-opts",
236+
"Predictable Memory Access Optimizations for Diagnostics")
237+
PASS(PredictableDeadAllocationElimination, "predictable-deadalloc-elim",
238+
"Eliminate dead temporary allocations after diagnostics")
237239
PASS(ReleaseDevirtualizer, "release-devirtualizer",
238240
"SIL release Devirtualization")
239241
PASS(RetainSinking, "retain-sinking",

lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp

Lines changed: 112 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,16 +1011,15 @@ class AllocOptimize {
10111011
AllocOptimize(AllocationInst *TheMemory, SmallVectorImpl<PMOMemoryUse> &Uses,
10121012
SmallVectorImpl<SILInstruction *> &Releases);
10131013

1014-
bool doIt();
1014+
bool optimizeMemoryAccesses();
1015+
bool tryToRemoveDeadAllocation();
10151016

10161017
private:
10171018
bool promoteLoad(SILInstruction *Inst);
10181019
void promoteDestroyAddr(DestroyAddrInst *DAI,
10191020
MutableArrayRef<AvailableValue> Values);
10201021
bool canPromoteDestroyAddr(DestroyAddrInst *DAI,
10211022
SmallVectorImpl<AvailableValue> &AvailableValues);
1022-
1023-
bool tryToRemoveDeadAllocation();
10241023
};
10251024

10261025
} // end anonymous namespace
@@ -1376,79 +1375,135 @@ bool AllocOptimize::tryToRemoveDeadAllocation() {
13761375
return true;
13771376
}
13781377

1379-
/// doIt - returns true on error.
1380-
bool AllocOptimize::doIt() {
1381-
bool Changed = false;
1382-
1383-
// Don't try to optimize incomplete aggregates.
1384-
if (MemoryType.aggregateHasUnreferenceableStorage())
1385-
return false;
1378+
bool AllocOptimize::optimizeMemoryAccesses() {
1379+
bool changed = false;
13861380

13871381
// If we've successfully checked all of the definitive initialization
13881382
// requirements, try to promote loads. This can explode copy_addrs, so the
13891383
// use list may change size.
13901384
for (unsigned i = 0; i != Uses.size(); ++i) {
1391-
auto &Use = Uses[i];
1385+
auto &use = Uses[i];
13921386
// Ignore entries for instructions that got expanded along the way.
1393-
if (Use.Inst && Use.Kind == PMOUseKind::Load) {
1394-
if (promoteLoad(Use.Inst)) {
1387+
if (use.Inst && use.Kind == PMOUseKind::Load) {
1388+
if (promoteLoad(use.Inst)) {
13951389
Uses[i].Inst = nullptr; // remove entry if load got deleted.
1396-
Changed = true;
1390+
changed = true;
13971391
}
13981392
}
13991393
}
1400-
1401-
// If this is an allocation, try to remove it completely.
1402-
Changed |= tryToRemoveDeadAllocation();
14031394

1404-
return Changed;
1395+
return changed;
1396+
}
1397+
1398+
//===----------------------------------------------------------------------===//
1399+
// Top Level Entrypoints
1400+
//===----------------------------------------------------------------------===//
1401+
1402+
static AllocationInst *getOptimizableAllocation(SILInstruction *i) {
1403+
if (!isa<AllocBoxInst>(i) && !isa<AllocStackInst>(i)) {
1404+
return nullptr;
1405+
}
1406+
1407+
auto *alloc = cast<AllocationInst>(i);
1408+
1409+
// If our aggregate has unreferencable storage, we can't optimize. Return
1410+
// nullptr.
1411+
if (getMemoryType(alloc).aggregateHasUnreferenceableStorage())
1412+
return nullptr;
1413+
1414+
// Otherwise we are good to go. Lets try to optimize this memory!
1415+
return alloc;
14051416
}
14061417

1407-
static bool optimizeMemoryAllocations(SILFunction &Fn) {
1408-
bool Changed = false;
1409-
for (auto &BB : Fn) {
1410-
auto I = BB.begin(), E = BB.end();
1411-
while (I != E) {
1412-
SILInstruction *Inst = &*I;
1413-
if (!isa<AllocBoxInst>(Inst) && !isa<AllocStackInst>(Inst)) {
1414-
++I;
1418+
static bool optimizeMemoryAccesses(SILFunction &fn) {
1419+
bool changed = false;
1420+
for (auto &bb : fn) {
1421+
auto i = bb.begin(), e = bb.end();
1422+
while (i != e) {
1423+
// First see if i is an allocation that we can optimize. If not, skip it.
1424+
AllocationInst *alloc = getOptimizableAllocation(&*i);
1425+
if (!alloc) {
1426+
++i;
14151427
continue;
14161428
}
1417-
auto Alloc = cast<AllocationInst>(Inst);
14181429

1419-
LLVM_DEBUG(llvm::dbgs() << "*** PMO Optimize looking at: " << *Alloc
1420-
<< "\n");
1421-
PMOMemoryObjectInfo MemInfo(Alloc);
1430+
LLVM_DEBUG(llvm::dbgs() << "*** PMO Optimize Memory Accesses looking at: "
1431+
<< *alloc << "\n");
1432+
PMOMemoryObjectInfo memInfo(alloc);
14221433

14231434
// Set up the datastructure used to collect the uses of the allocation.
1424-
SmallVector<PMOMemoryUse, 16> Uses;
1425-
SmallVector<SILInstruction*, 4> Releases;
1435+
SmallVector<PMOMemoryUse, 16> uses;
1436+
SmallVector<SILInstruction *, 4> destroys;
14261437

14271438
// Walk the use list of the pointer, collecting them. If we are not able
14281439
// to optimize, skip this value. *NOTE* We may still scalarize values
14291440
// inside the value.
1430-
if (!collectPMOElementUsesFrom(MemInfo, Uses, Releases)) {
1431-
++I;
1441+
if (!collectPMOElementUsesFrom(memInfo, uses, destroys)) {
1442+
++i;
14321443
continue;
14331444
}
14341445

1435-
Changed |= AllocOptimize(Alloc, Uses, Releases).doIt();
1436-
1437-
// Carefully move iterator to avoid invalidation problems.
1438-
++I;
1439-
if (Alloc->use_empty()) {
1440-
Alloc->eraseFromParent();
1446+
AllocOptimize allocOptimize(alloc, uses, destroys);
1447+
changed |= allocOptimize.optimizeMemoryAccesses();
1448+
1449+
// Move onto the next instruction. We know this is safe since we do not
1450+
// eliminate allocations here.
1451+
++i;
1452+
}
1453+
}
1454+
1455+
return changed;
1456+
}
1457+
1458+
static bool eliminateDeadAllocations(SILFunction &fn) {
1459+
bool changed = false;
1460+
for (auto &bb : fn) {
1461+
auto i = bb.begin(), e = bb.end();
1462+
while (i != e) {
1463+
// First see if i is an allocation that we can optimize. If not, skip it.
1464+
AllocationInst *alloc = getOptimizableAllocation(&*i);
1465+
if (!alloc) {
1466+
++i;
1467+
continue;
1468+
}
1469+
1470+
LLVM_DEBUG(llvm::dbgs()
1471+
<< "*** PMO Dead Allocation Elimination looking at: " << *alloc
1472+
<< "\n");
1473+
PMOMemoryObjectInfo memInfo(alloc);
1474+
1475+
// Set up the datastructure used to collect the uses of the allocation.
1476+
SmallVector<PMOMemoryUse, 16> uses;
1477+
SmallVector<SILInstruction *, 4> destroys;
1478+
1479+
// Walk the use list of the pointer, collecting them. If we are not able
1480+
// to optimize, skip this value. *NOTE* We may still scalarize values
1481+
// inside the value.
1482+
if (!collectPMOElementUsesFrom(memInfo, uses, destroys)) {
1483+
++i;
1484+
continue;
1485+
}
1486+
1487+
AllocOptimize allocOptimize(alloc, uses, destroys);
1488+
changed |= allocOptimize.tryToRemoveDeadAllocation();
1489+
1490+
// Move onto the next instruction. We know this is safe since we do not
1491+
// eliminate allocations here.
1492+
++i;
1493+
if (alloc->use_empty()) {
1494+
alloc->eraseFromParent();
14411495
++NumAllocRemoved;
1442-
Changed = true;
1496+
changed = true;
14431497
}
14441498
}
14451499
}
1446-
return Changed;
1500+
1501+
return changed;
14471502
}
14481503

14491504
namespace {
14501505

1451-
class PredictableMemoryOptimizations : public SILFunctionTransform {
1506+
class PredictableMemoryAccessOptimizations : public SILFunctionTransform {
14521507
/// The entry point to the transformation.
14531508
///
14541509
/// FIXME: This pass should not need to rerun on deserialized
@@ -1457,14 +1512,25 @@ class PredictableMemoryOptimizations : public SILFunctionTransform {
14571512
/// either indicates that this pass missing some opportunities the first time,
14581513
/// or has a pass order dependency on other early passes.
14591514
void run() override {
1460-
if (optimizeMemoryAllocations(*getFunction()))
1515+
// TODO: Can we invalidate here just instructions?
1516+
if (optimizeMemoryAccesses(*getFunction()))
1517+
invalidateAnalysis(SILAnalysis::InvalidationKind::FunctionBody);
1518+
}
1519+
};
1520+
1521+
class PredictableDeadAllocationElimination : public SILFunctionTransform {
1522+
void run() override {
1523+
if (eliminateDeadAllocations(*getFunction()))
14611524
invalidateAnalysis(SILAnalysis::InvalidationKind::FunctionBody);
14621525
}
14631526
};
14641527

14651528
} // end anonymous namespace
14661529

1530+
SILTransform *swift::createPredictableMemoryAccessOptimizations() {
1531+
return new PredictableMemoryAccessOptimizations();
1532+
}
14671533

1468-
SILTransform *swift::createPredictableMemoryOptimizations() {
1469-
return new PredictableMemoryOptimizations();
1534+
SILTransform *swift::createPredictableDeadAllocationElimination() {
1535+
return new PredictableDeadAllocationElimination();
14701536
}

lib/SILOptimizer/PassManager/PassPipeline.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,20 @@ static void addMandatoryOptPipeline(SILPassPipelinePlan &P,
106106
P.addOwnershipModelEliminator();
107107
P.addMandatoryInlining();
108108
P.addMandatorySILLinker();
109-
P.addPredictableMemoryOptimizations();
109+
110+
// Promote loads as necessary to ensure we have enough SSA formation to emit
111+
// SSA based diagnostics.
112+
P.addPredictableMemoryAccessOptimizations();
110113

111114
// Diagnostic ConstantPropagation must be rerun on deserialized functions
112115
// because it is sensitive to the assert configuration.
113116
// Consequently, certain optimization passes beyond this point will also rerun.
114117
P.addDiagnosticConstantPropagation();
118+
119+
// Now that we have emitted constant propagation diagnostics, try to eliminate
120+
// dead allocations.
121+
P.addPredictableDeadAllocationElimination();
122+
115123
P.addGuaranteedARCOpts();
116124
P.addDiagnoseUnreachable();
117125
P.addDiagnoseInfiniteRecursion();

test/SILOptimizer/predictable_memopt.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-sil-opt -enable-sil-verify-all %s -predictable-memopt | %FileCheck %s
1+
// RUN: %target-sil-opt -enable-sil-verify-all %s -predictable-memaccess-opts -predictable-deadalloc-elim | %FileCheck %s
22

33
import Builtin
44
import Swift

0 commit comments

Comments
 (0)