Skip to content

Commit 180b3bd

Browse files
committed
Add reborrow dependencies to DCE
A reborrow's base value may change if the base value is also passed as an operand on a branch. Record reborrow dependencies so that we can mark the base value as live, if the reborrow was also live. This ensures we do not insert destroy_value on the base value prematurely before the lifetime of the reborrow ends.
1 parent 9dd3ce5 commit 180b3bd

File tree

2 files changed

+121
-1
lines changed

2 files changed

+121
-1
lines changed

lib/SILOptimizer/Transforms/DeadCodeElimination.cpp

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@
1212

1313
#define DEBUG_TYPE "sil-dce"
1414
#include "swift/SIL/DebugUtils.h"
15+
#include "swift/SIL/OwnershipUtils.h"
1516
#include "swift/SIL/SILArgument.h"
1617
#include "swift/SIL/SILBasicBlock.h"
18+
#include "swift/SIL/SILBitfield.h"
1719
#include "swift/SIL/SILBuilder.h"
1820
#include "swift/SIL/SILFunction.h"
1921
#include "swift/SIL/SILUndef.h"
20-
#include "swift/SIL/SILBitfield.h"
2122
#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h"
2223
#include "swift/SILOptimizer/PassManager/Passes.h"
2324
#include "swift/SILOptimizer/PassManager/Transforms.h"
@@ -118,6 +119,14 @@ class DCE {
118119
llvm::DenseMap<SILValue, SmallPtrSet<SILInstruction *, 4>>
119120
ReverseDependencies;
120121

122+
// reborrowDependencies tracks the dependency of a reborrowed phiArg with its
123+
// renamed base value.
124+
// A reborrowed phiArg may have a new base value, if it's original base value
125+
// was also passed as a branch operand. The renamed base value should then be
126+
// live if the reborrow phiArg was also live.
127+
using BaseValueSet = SmallPtrSet<SILValue, 8>;
128+
llvm::DenseMap<SILPhiArgument *, BaseValueSet> reborrowDependencies;
129+
121130
/// Tracks if the pass changed branches.
122131
bool BranchesChanged = false;
123132
/// Tracks if the pass changed ApplyInsts.
@@ -128,6 +137,9 @@ class DCE {
128137
/// Record a reverse dependency from \p from to \p to meaning \p to is live
129138
/// if \p from is also live.
130139
void addReverseDependency(SILValue from, SILInstruction *to);
140+
/// Starting from \p borrowInst find all reborrow dependency of its reborrows
141+
/// with their renamed base values.
142+
void findReborrowDependencies(BeginBorrowInst *borrowInst);
131143
bool removeDead();
132144

133145
void computeLevelNumbers(PostDomTreeNode *root);
@@ -253,6 +265,10 @@ void DCE::markLive() {
253265
addReverseDependency(I.getOperand(0), &I);
254266
break;
255267
}
268+
case SILInstructionKind::BeginBorrowInst: {
269+
findReborrowDependencies(cast<BeginBorrowInst>(&I));
270+
break;
271+
}
256272
default:
257273
if (seemsUseful(&I))
258274
markInstructionLive(&I);
@@ -275,6 +291,21 @@ void DCE::addReverseDependency(SILValue from, SILInstruction *to) {
275291
ReverseDependencies[from].insert(to);
276292
}
277293

294+
void DCE::findReborrowDependencies(BeginBorrowInst *borrowInst) {
295+
LLVM_DEBUG(llvm::dbgs() << "Finding reborrow dependencies of " << borrowInst
296+
<< "\n");
297+
BorrowingOperand initialScopedOperand(&borrowInst->getOperandRef());
298+
auto visitReborrowBaseValuePair = [&](SILPhiArgument *phiArg,
299+
SILValue baseValue) {
300+
reborrowDependencies[phiArg].insert(baseValue);
301+
};
302+
// Find all reborrow dependencies starting from \p borrowInst and populate
303+
// them in reborrowDependencies
304+
findTransitiveReborrowBaseValuePairs(initialScopedOperand,
305+
borrowInst->getOperand(),
306+
visitReborrowBaseValuePair);
307+
}
308+
278309
// Mark as live the terminator argument at index ArgIndex in Pred that
279310
// targets Succ.
280311
void DCE::markTerminatorArgsLive(SILBasicBlock *Pred,
@@ -352,6 +383,12 @@ void DCE::propagateLiveBlockArgument(SILArgument *Arg) {
352383
markInstructionLive(depInst);
353384
}
354385

386+
if (auto *phi = dyn_cast<SILPhiArgument>(Arg)) {
387+
for (auto depVal : reborrowDependencies.lookup(phi)) {
388+
markValueLive(depVal);
389+
}
390+
}
391+
355392
auto *Block = Arg->getParent();
356393
auto ArgIndex = Arg->getIndex();
357394

test/SILOptimizer/dead_code_elimination_nontrivial_ossa.sil

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,3 +339,86 @@ bb4:
339339
return %res : $()
340340
}
341341

342+
struct TestStruct {
343+
var val:Klass
344+
var index:Int
345+
}
346+
347+
// CHECK-LABEL: sil [ossa] @dce_destructurenotfullydead :
348+
// CHECK-NOT: copy_value
349+
// CHECK-LABEL: } // end sil function 'dce_destructurenotfullydead'
350+
sil [ossa] @dce_destructurenotfullydead : $@convention(thin) (@owned TestStruct) -> Int {
351+
bb0(%0 : @owned $TestStruct):
352+
%stk = alloc_stack $TestStruct
353+
store %0 to [init] %stk : $*TestStruct
354+
%copy = load [take] %stk : $*TestStruct
355+
(%2, %3) = destructure_struct %copy : $TestStruct
356+
%4 = struct $TestStruct (%2 : $Klass, %3 : $Int)
357+
destroy_value %4 : $TestStruct
358+
dealloc_stack %stk : $*TestStruct
359+
return %3 : $Int
360+
}
361+
362+
// CHECK-LABEL: sil [ossa] @dce_borrowlifetime1 :
363+
// CHECK: bb1([[ARG1:%.*]] : @owned $NonTrivialStruct, [[ARG2:%.*]] : @guaranteed $NonTrivialStruct):
364+
// CHECK-LABEL: } // end sil function 'dce_borrowlifetime1'
365+
sil [ossa] @dce_borrowlifetime1 : $@convention(thin) (@guaranteed NonTrivialStruct) -> @owned NonTrivialStruct {
366+
bb0(%0 : @guaranteed $NonTrivialStruct):
367+
%copy = copy_value %0 : $NonTrivialStruct
368+
%borrow = begin_borrow %copy : $NonTrivialStruct
369+
br bb1(%copy : $NonTrivialStruct, %borrow : $NonTrivialStruct)
370+
371+
bb1(%copy2 : @owned $NonTrivialStruct, %borrow2 : @guaranteed $NonTrivialStruct):
372+
%newcopy = copy_value %borrow2 : $NonTrivialStruct
373+
end_borrow %borrow2 : $NonTrivialStruct
374+
destroy_value %copy2 : $NonTrivialStruct
375+
return %newcopy : $NonTrivialStruct
376+
}
377+
378+
// CHECK-LABEL: sil [ossa] @infinite_loop :
379+
// CHECK-NOT: copy_value
380+
// CHECK-LABEL: } // end sil function 'infinite_loop'
381+
sil [ossa] @infinite_loop : $@convention(thin) (@guaranteed NonTrivialStruct, @guaranteed NonTrivialStruct) -> () {
382+
bb0(%0 : @guaranteed $NonTrivialStruct, %1 : @guaranteed $NonTrivialStruct):
383+
cond_br undef, bb1, bb4
384+
385+
bb1:
386+
%copy0 = copy_value %0 : $NonTrivialStruct
387+
%borrow0 = begin_borrow %copy0 : $NonTrivialStruct
388+
br bb3(%borrow0 : $NonTrivialStruct, %copy0 : $NonTrivialStruct)
389+
390+
bb3(%newborrow : @guaranteed $NonTrivialStruct, %newowned : @owned $NonTrivialStruct):
391+
br bb3(%newborrow : $NonTrivialStruct, %newowned : $NonTrivialStruct)
392+
393+
bb4:
394+
%ret = tuple ()
395+
return %ret : $()
396+
}
397+
398+
// CHECK-LABEL: sil [ossa] @dce_reborrow_with_different_basevalues :
399+
// CHECK: bb3([[ARG1:%.*]] : @guaranteed $NonTrivialStruct, [[ARG2:%.*]] : @owned $NonTrivialStruct, [[ARG3:%.*]] : @owned $NonTrivialStruct):
400+
// CHECK-LABEL: } // end sil function 'dce_reborrow_with_different_basevalues'
401+
sil [ossa] @dce_reborrow_with_different_basevalues : $@convention(thin) (@guaranteed NonTrivialStruct, @guaranteed NonTrivialStruct) -> @owned NonTrivialStruct {
402+
bb0(%0 : @guaranteed $NonTrivialStruct, %1 : @guaranteed $NonTrivialStruct):
403+
cond_br undef, bb1, bb2
404+
405+
bb1:
406+
%copy0a = copy_value %0 : $NonTrivialStruct
407+
%borrow0a = begin_borrow %copy0a : $NonTrivialStruct
408+
%copy1a = copy_value %1 : $NonTrivialStruct
409+
br bb3(%borrow0a : $NonTrivialStruct, %copy0a : $NonTrivialStruct, %copy1a : $NonTrivialStruct)
410+
411+
bb2:
412+
%copy1b = copy_value %1 : $NonTrivialStruct
413+
%borrow0b = begin_borrow %copy1b : $NonTrivialStruct
414+
%copy0b = copy_value %0 : $NonTrivialStruct
415+
br bb3(%borrow0b : $NonTrivialStruct, %copy0b : $NonTrivialStruct, %copy1b : $NonTrivialStruct)
416+
417+
bb3(%newborrow : @guaranteed $NonTrivialStruct, %newowned1 : @owned $NonTrivialStruct, %newowned2 : @owned $NonTrivialStruct):
418+
%res = copy_value %newborrow : $NonTrivialStruct
419+
end_borrow %newborrow : $NonTrivialStruct
420+
destroy_value %newowned1 : $NonTrivialStruct
421+
destroy_value %newowned2 : $NonTrivialStruct
422+
return %res : $NonTrivialStruct
423+
}
424+

0 commit comments

Comments
 (0)