Skip to content

Commit 2e9daa4

Browse files
committed
PredictableMemOpts: handle MarkDependence base uses.
1 parent 830a366 commit 2e9daa4

File tree

3 files changed

+84
-3
lines changed

3 files changed

+84
-3
lines changed

lib/SILOptimizer/Mandatory/PMOMemoryUseCollector.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,14 @@ bool ElementUseCollector::collectContainerUses(SILValue boxValue) {
223223
return false;
224224
continue;
225225
}
226-
226+
if (auto *md = dyn_cast<MarkDependenceInst>(user)) {
227+
// Another value depends on the current in-memory value. Consider that a
228+
// load.
229+
if (md->getBase() == ui->get()) {
230+
Uses.emplace_back(user, PMOUseKind::DependenceBase);
231+
continue;
232+
}
233+
}
227234
// Other uses of the container are considered escapes of the underlying
228235
// value.
229236
//
@@ -457,6 +464,12 @@ bool ElementUseCollector::collectUses(SILValue Pointer) {
457464
if (User->isDebugInstruction())
458465
continue;
459466

467+
if (auto *md = dyn_cast<MarkDependenceInst>(User)) {
468+
if (md->getBase() == UI->get()) {
469+
Uses.emplace_back(User, PMOUseKind::DependenceBase);
470+
continue;
471+
}
472+
}
460473
// Otherwise, the use is something complicated, it escapes.
461474
Uses.emplace_back(User, PMOUseKind::Escape);
462475
}

lib/SILOptimizer/Mandatory/PMOMemoryUseCollector.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ enum PMOUseKind {
122122
/// An indirect 'in' parameter of an Apply instruction.
123123
IndirectIn,
124124

125+
/// The base of a dependence.
126+
DependenceBase,
127+
125128
/// This instruction is a general escape of the value, e.g. a call to a
126129
/// closure that captures it.
127130
Escape,

lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1553,7 +1553,10 @@ AvailableValueDataflowContext::AvailableValueDataflowContext(
15531553

15541554
llvm_unreachable("Unhandled SILInstructionKind for PMOUseKind::Load?!");
15551555
}
1556-
1556+
if (Use.Kind == PMOUseKind::DependenceBase) {
1557+
// An address used as a dependence base does not affect load promotion.
1558+
continue;
1559+
}
15571560
// Keep track of all the uses that aren't loads.
15581561
NonLoadUses[Use.Inst] = ui;
15591562
HasLocalDefinition.set(Use.Inst->getParent());
@@ -2421,14 +2424,17 @@ struct Promotions {
24212424
SmallVector<AvailableValue, 32> allAvailableValues;
24222425
PromotableInstructions loadTakes;
24232426
PromotableInstructions destroys;
2427+
PromotableInstructions markDepBases;
24242428

24252429
Promotions()
2426-
: loadTakes(allAvailableValues), destroys(allAvailableValues) {}
2430+
: loadTakes(allAvailableValues), destroys(allAvailableValues),
2431+
markDepBases(allAvailableValues) {}
24272432

24282433
#ifndef NDEBUG
24292434
void verify() {
24302435
loadTakes.verify();
24312436
destroys.verify();
2437+
markDepBases.verify();
24322438
}
24332439
#endif
24342440
};
@@ -2496,11 +2502,18 @@ class OptimizeDeadAlloc {
24962502
private:
24972503
SILInstruction *collectUsesForPromotion();
24982504

2505+
/// Return true if a mark_dependence can be promoted. If so, this initializes
2506+
/// the available values in promotions.
2507+
bool canPromoteMarkDepBase(MarkDependenceInst *md);
2508+
24992509
/// Return true if a load [take] or destroy_addr can be promoted. If so, this
25002510
/// initializes the available values in promotions.
25012511
bool canPromoteTake(SILInstruction *i,
25022512
PromotableInstructions &promotableInsts);
25032513

2514+
SILValue promoteMarkDepBase(MarkDependenceInst *md,
2515+
ArrayRef<AvailableValue> availableValues);
2516+
25042517
/// Promote a load take cleaning up everything except for RAUWing the
25052518
/// instruction with the aggregated result. The routine returns the new
25062519
/// aggregated result to the caller and expects the caller to eventually RAUW
@@ -2552,6 +2565,10 @@ bool OptimizeDeadAlloc::tryToRemoveDeadAllocation() {
25522565

25532566
SWIFT_DEFER { DataflowContext.fixupOwnership(deleter, deadEndBlocks); };
25542567

2568+
for (auto *md : promotions.markDepBases.instructions()) {
2569+
if (!canPromoteMarkDepBase(cast<MarkDependenceInst>(md)))
2570+
return false;
2571+
}
25552572
if (isTrivial()) {
25562573
removeDeadAllocation();
25572574
return true;
@@ -2620,6 +2637,9 @@ SILInstruction *OptimizeDeadAlloc::collectUsesForPromotion() {
26202637
}
26212638
}
26222639
return u.Inst;
2640+
case PMOUseKind::DependenceBase:
2641+
promotions.markDepBases.push(u.Inst);
2642+
continue;
26232643
case PMOUseKind::Initialization:
26242644
if (!isa<ApplyInst>(u.Inst) &&
26252645
// A copy_addr that is not a take affects the retain count
@@ -2652,6 +2672,28 @@ SILInstruction *OptimizeDeadAlloc::collectUsesForPromotion() {
26522672
return nullptr;
26532673
}
26542674

2675+
bool OptimizeDeadAlloc::canPromoteMarkDepBase(MarkDependenceInst *md) {
2676+
SILValue srcAddr = md->getBase();
2677+
SmallVector<AvailableValue, 8> availableValues;
2678+
auto result =
2679+
DataflowContext.computeAvailableValues(srcAddr, md, availableValues);
2680+
if (!result.has_value())
2681+
return false;
2682+
2683+
unsigned index = promotions.markDepBases.initializeAvailableValues(
2684+
md, std::move(availableValues));
2685+
2686+
SILType baseTy = result->first;
2687+
if (auto *abi = dyn_cast<AllocBoxInst>(TheMemory)) {
2688+
if (baseTy == abi->getType()) {
2689+
baseTy = MemoryType.getObjectType();
2690+
}
2691+
}
2692+
unsigned firstElt = result->second;
2693+
return isFullyAvailable(baseTy, firstElt,
2694+
promotions.markDepBases.availableValues(index));
2695+
}
2696+
26552697
/// Return true if we can promote the given destroy.
26562698
bool OptimizeDeadAlloc::canPromoteTake(
26572699
SILInstruction *inst, PromotableInstructions &promotableInsts) {
@@ -2692,6 +2734,12 @@ bool OptimizeDeadAlloc::canPromoteTake(
26922734
}
26932735

26942736
void OptimizeDeadAlloc::removeDeadAllocation() {
2737+
for (auto idxVal : llvm::enumerate(promotions.markDepBases.instructions())) {
2738+
auto *md = cast<MarkDependenceInst>(idxVal.value());
2739+
auto vals = promotions.markDepBases.availableValues(idxVal.index());
2740+
promoteMarkDepBase(md, vals);
2741+
}
2742+
26952743
// If our memory is trivially typed, we can just remove it without needing to
26962744
// consider if the stored value needs to be destroyed. So at this point,
26972745
// delete the memory!
@@ -2798,6 +2846,23 @@ void OptimizeDeadAlloc::removeDeadAllocation() {
27982846
}
27992847
}
28002848

2849+
SILValue OptimizeDeadAlloc::promoteMarkDepBase(
2850+
MarkDependenceInst *md, ArrayRef<AvailableValue> availableValues) {
2851+
2852+
LLVM_DEBUG(llvm::dbgs() << " *** Promoting mark_dependence base: " << *md);
2853+
SILBuilderWithScope B(md);
2854+
SILValue dependentValue = md->getValue();
2855+
for (auto &availableValue : availableValues) {
2856+
dependentValue =
2857+
B.createMarkDependence(md->getLoc(), dependentValue,
2858+
availableValue.getValue(), md->dependenceKind());
2859+
}
2860+
LLVM_DEBUG(llvm::dbgs() << " To value: " << dependentValue);
2861+
md->replaceAllUsesWith(dependentValue);
2862+
deleter.deleteIfDead(md);
2863+
return dependentValue;
2864+
}
2865+
28012866
SILValue
28022867
OptimizeDeadAlloc::promoteLoadTake(LoadInst *li,
28032868
ArrayRef<AvailableValue> availableValues) {

0 commit comments

Comments
 (0)