Skip to content

Commit 899a005

Browse files
Merge pull request #41519 from nate-chandler/lexical_lifetimes/lexical_destroy_addr_hoisting/avoid-second-dataflow
[SSADestroyHoisting] Avoid second per-var dataflow.
2 parents f124c2f + 2de9171 commit 899a005

File tree

2 files changed

+76
-14
lines changed

2 files changed

+76
-14
lines changed

lib/SILOptimizer/Transforms/SSADestroyHoisting.cpp

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@
9090
#define DEBUG_TYPE "ssa-destroy-hoisting"
9191

9292
#include "swift/Basic/GraphNodeWorklist.h"
93+
#include "swift/Basic/SmallPtrSetVector.h"
9394
#include "swift/SIL/BasicBlockDatastructures.h"
9495
#include "swift/SIL/MemAccessUtils.h"
9596
#include "swift/SIL/SILBasicBlock.h"
@@ -192,11 +193,11 @@ class DeinitBarriers {
192193
public:
193194
// Data flow state: blocks whose beginning is backward reachable from a
194195
// destroy without first reaching a barrier or storage use.
195-
BasicBlockSetVector destroyReachesBeginBlocks;
196+
SmallPtrSetVector<SILBasicBlock *, 4> destroyReachesBeginBlocks;
196197

197198
// Data flow state: blocks whose end is backward reachable from a destroy
198199
// without first reaching a barrier or storage use.
199-
BasicBlockSet destroyReachesEndBlocks;
200+
SmallPtrSet<SILBasicBlock *, 4> destroyReachesEndBlocks;
200201

201202
// Deinit barriers or storage uses within a block, reachable from a destroy.
202203
SmallVector<SILInstruction *, 4> barriers;
@@ -215,8 +216,7 @@ class DeinitBarriers {
215216
explicit DeinitBarriers(bool ignoreDeinitBarriers,
216217
const KnownStorageUses &knownUses,
217218
SILFunction *function)
218-
: destroyReachesBeginBlocks(function), destroyReachesEndBlocks(function),
219-
ignoreDeinitBarriers(ignoreDeinitBarriers), knownUses(knownUses) {
219+
: ignoreDeinitBarriers(ignoreDeinitBarriers), knownUses(knownUses) {
220220
auto rootValue = knownUses.getStorage().getRoot();
221221
assert(rootValue && "HoistDestroys requires a single storage root");
222222
// null for function args
@@ -225,6 +225,12 @@ class DeinitBarriers {
225225

226226
void compute() {
227227
FindBarrierAccessScopes(*this).solveBackward();
228+
if (barrierAccessScopes.size() == 0)
229+
return;
230+
destroyReachesBeginBlocks.clear();
231+
destroyReachesEndBlocks.clear();
232+
barriers.clear();
233+
deadUsers.clear();
228234
DestroyReachability(*this).solveBackward();
229235
}
230236

@@ -289,7 +295,6 @@ class DeinitBarriers {
289295
// open access scopes in the block's predecessors.
290296
class FindBarrierAccessScopes {
291297
DeinitBarriers &result;
292-
BasicBlockSetVector destroyReachesBeginBlocks;
293298
llvm::DenseMap<SILBasicBlock *, llvm::SmallPtrSet<BeginAccessInst *, 2>>
294299
liveInAccessScopes;
295300
llvm::SmallPtrSet<BeginAccessInst *, 2> runningLiveAccessScopes;
@@ -298,9 +303,7 @@ class DeinitBarriers {
298303

299304
public:
300305
FindBarrierAccessScopes(DeinitBarriers &result)
301-
: result(result),
302-
destroyReachesBeginBlocks(result.knownUses.getFunction()),
303-
reachability(result.knownUses.getFunction(), *this) {
306+
: result(result), reachability(result.knownUses.getFunction(), *this) {
304307
// Seed backward reachability with destroy points.
305308
for (SILInstruction *destroy : result.knownUses.originalDestroys) {
306309
reachability.initLastUse(destroy);
@@ -314,17 +317,18 @@ class DeinitBarriers {
314317
}
315318

316319
bool hasReachableBegin(SILBasicBlock *block) {
317-
return destroyReachesBeginBlocks.contains(block);
320+
return result.destroyReachesBeginBlocks.contains(block);
318321
}
319322

320323
void markReachableBegin(SILBasicBlock *block) {
321-
destroyReachesBeginBlocks.insert(block);
324+
result.destroyReachesBeginBlocks.insert(block);
322325
if (!runningLiveAccessScopes.empty()) {
323326
liveInAccessScopes[block] = runningLiveAccessScopes;
324327
}
325328
}
326329

327330
void markReachableEnd(SILBasicBlock *block) {
331+
result.destroyReachesEndBlocks.insert(block);
328332
runningLiveAccessScopes.clear();
329333
for (auto *predecessor : block->getPredecessorBlocks()) {
330334
auto iterator = liveInAccessScopes.find(predecessor);
@@ -347,7 +351,9 @@ class DeinitBarriers {
347351
} else if (auto *bai = dyn_cast<BeginAccessInst>(inst)) {
348352
runningLiveAccessScopes.erase(bai);
349353
}
350-
bool isBarrier = result.isBarrier(inst);
354+
auto classification = result.classifyInstruction(inst);
355+
result.visitedInstruction(inst, classification);
356+
auto isBarrier = result.classificationIsBarrier(classification);
351357
if (isBarrier) {
352358
markLiveAccessScopesAsBarriers();
353359
}
@@ -361,7 +367,7 @@ class DeinitBarriers {
361367
bool checkReachablePhiBarrier(SILBasicBlock *block) {
362368
bool isBarrier =
363369
llvm::any_of(block->getPredecessorBlocks(), [&](auto *predecessor) {
364-
return result.isBarrier(block->getTerminator());
370+
return result.isBarrier(predecessor->getTerminator());
365371
});
366372
if (isBarrier) {
367373
// If there's a barrier preventing us from hoisting out of this block,
@@ -484,8 +490,7 @@ bool DeinitBarriers::DestroyReachability::checkReachablePhiBarrier(
484490
assert(llvm::all_of(block->getArguments(),
485491
[&](auto argument) { return PhiValue(argument); }));
486492
return llvm::any_of(block->getPredecessorBlocks(), [&](auto *predecessor) {
487-
return result.classificationIsBarrier(
488-
result.classifyInstruction(predecessor->getTerminator()));
493+
return result.isBarrier(predecessor->getTerminator());
489494
});
490495
}
491496

test/SILOptimizer/hoist_destroy_addr.sil

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,22 @@ struct TrivialStruct {
4343
var e: E
4444
}
4545

46+
enum Change {
47+
case insert(offset: Int, element: X)
48+
case remove(offset: Int, element: X)
49+
}
50+
51+
struct Int {
52+
@_hasStorage var _value : Builtin.Int64
53+
}
54+
4655
sil @unknown : $@convention(thin) () -> ()
4756
sil @use_S : $@convention(thin) (@in_guaranteed S) -> ()
4857

4958
sil @f_out : $@convention(thin) <T> () -> @out T
5059
sil @f_bool : $@convention(thin) () -> Builtin.Int1
5160
sil [ossa] @take_trivial_struct : $@convention(thin) (TrivialStruct) -> ()
61+
sil [ossa] @get_change_out : $@convention(thin) () -> @out Change
5262

5363
// CHECK-LABEL: sil [ossa] @test_simple
5464
// CHECK: bb0(%0 : $*S):
@@ -270,6 +280,53 @@ entry(%addr : $*X):
270280
return %tuple : $()
271281
}
272282

283+
// Hoist a destroy_addr over a phi.
284+
//
285+
// CHECK-LABEL: sil [ossa] @hoist_over_undef_phi : {{.*}} {
286+
// CHECK: [[STACK1:%[^,]+]] = alloc_stack
287+
// CHECK-NEXT: apply undef
288+
// CHECK-NEXT: destroy_addr [[STACK1]]
289+
// CHECK-LABEL: } // end sil function 'hoist_over_undef_phi'
290+
sil [ossa] @hoist_over_undef_phi : $@convention(thin) () -> () {
291+
entry:
292+
br latch
293+
294+
latch:
295+
cond_br undef, top, exit
296+
297+
top:
298+
%stack1 = alloc_stack $Change
299+
apply undef(%stack1) : $@convention(thin) () -> @out Change
300+
%access = begin_access [static] [modify] %stack1 : $*Change
301+
br top2(undef : $())
302+
303+
top2(%66 : $()):
304+
end_access %access : $*Change
305+
destroy_addr %stack1 : $*Change
306+
dealloc_stack %stack1 : $*Change
307+
%stack2 = alloc_stack $Change
308+
apply undef(%stack2) : $@convention(thin) () -> @out Change
309+
switch_enum_addr %stack2 : $*Change, case #Change.insert!enumelt: left, case #Change.remove!enumelt: right
310+
311+
left:
312+
br bottom
313+
314+
right:
315+
br bottom
316+
317+
bottom:
318+
destroy_addr %stack2 : $*Change
319+
dealloc_stack %stack2 : $*Change
320+
br backedge
321+
322+
backedge:
323+
br latch
324+
325+
exit:
326+
%321 = tuple ()
327+
return %321 : $()
328+
}
329+
273330
// Fold destroy_addr and a load [copy] into a load [take] even when that
274331
// load [take] is guarded by an access scope.
275332
//

0 commit comments

Comments
 (0)