Skip to content

Commit 0d76250

Browse files
Merge pull request #77908 from nate-chandler/rdar139840307
[BarrierAccessScopes] Handle end_access instructions' barrierness introduced during run.
2 parents 867cf28 + f79def4 commit 0d76250

File tree

5 files changed

+88
-25
lines changed

5 files changed

+88
-25
lines changed

include/swift/SILOptimizer/Analysis/VisitBarrierAccessScopes.h

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ class VisitBarrierAccessScopes {
156156
// whose successors are in the region) blocks in the region only the top
157157
// of which was already visited. Either way, the instructions between the
158158
// local gen and its kill have not yet been visited. Visit them now.
159-
auto foundLocalKill = visitBlockFromGenUntilBegin(instruction);
159+
auto foundLocalKill = visitBlockFromGenThroughKill(instruction);
160160
assert(foundLocalKill && "local gen without local kill?!");
161161
(void)foundLocalKill;
162162
}
@@ -165,13 +165,14 @@ class VisitBarrierAccessScopes {
165165
private:
166166
/// Entry points for visiting: they visit increasingly large portions of a
167167
/// block.
168-
/// - visitBlockFromGenUntilBegin: Instructions and phi until a kill.
168+
/// - visitBlockFromGenThroughKill: Instructions and phi through the first
169+
/// kill.
169170
/// - visitBlockFromGen: Instructions, phi, and begin.
170171
/// - visitBlock: End, instructions, phi, and begin.
171172

172173
/// Visit instructions and phis starting from the specified gen until a kill
173174
/// is found.
174-
bool visitBlockFromGenUntilBegin(SILInstruction *from) {
175+
bool visitBlockFromGenThroughKill(SILInstruction *from) {
175176
assert(effects.effectForInstruction(from) == Effects::Effect::Gen());
176177
for (auto *instruction = from; instruction;
177178
instruction = instruction->getPreviousInstruction()) {
@@ -198,9 +199,21 @@ class VisitBarrierAccessScopes {
198199
[&](SILBasicBlock *successor) { return visited.contains(successor); }));
199200

200201
visited.insert(block);
201-
bool foundLocalKill = visitBlockFromGenUntilBegin(from);
202-
assert(!foundLocalKill && "found local kill for non-local gen?!");
203-
(void)foundLocalKill;
202+
for (auto *instruction = from; instruction;
203+
instruction = instruction->getPreviousInstruction()) {
204+
if (visitInstruction(instruction)) {
205+
// New kills are incrementally added as access scopes are determined to
206+
// be barriers. For this reason, gens may newly be discovered to be
207+
// local. This can only happen when the kill which makes the gen local
208+
// ends an access scope (i.e. is an end_access).
209+
assert(isa<EndAccessInst>(instruction) &&
210+
"found preexisting local kill for initially-non-local gen?!");
211+
// Even so, the remainder of the block must still be visited.
212+
}
213+
}
214+
if (block->hasPhi()) {
215+
visitPhi(block);
216+
}
204217
visitBlockBegin(block);
205218
}
206219

@@ -259,8 +272,9 @@ class VisitBarrierAccessScopes {
259272
}
260273
}
261274
// If any of this block's predecessors haven't already been visited, it
262-
// means that they aren't in the region and consequently this block is a
263-
// barrier block.
275+
// means EITHER that those predecessors aren't in the region OR that a
276+
// barrier was encountered when visiting some (iterative) successor of that
277+
// predecessor. Either way, this block is a barrier block as a result.
264278
if (llvm::any_of(block->getSuccessorBlocks(), [&](SILBasicBlock *block) {
265279
return !visited.contains(block);
266280
})) {

lib/SILOptimizer/Utils/ShrinkBorrowScope.cpp

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -296,8 +296,8 @@ Dataflow::Effect Dataflow::effectForPhi(SILBasicBlock *block) {
296296
}
297297

298298
/// Finds end_access instructions which are barriers to hoisting because the
299-
/// access scopes they contain barriers to hoisting. Hoisting end_borrows into
300-
/// such access scopes could introduce exclusivity violations.
299+
/// access scopes they end contain barriers to hoisting. Hoisting end_borrows
300+
/// into such access scopes could introduce exclusivity violations.
301301
///
302302
/// Implements BarrierAccessScopeFinder::Visitor
303303
class BarrierAccessScopeFinder final {
@@ -501,35 +501,28 @@ bool swift::shrinkBorrowScope(
501501
namespace swift::test {
502502
// Arguments:
503503
// - BeginBorrowInst - the introducer for the scope to shrink
504-
// - bool - the expected return value of shrinkBorrowScope
505-
// - variadic list of values consisting of the copies expected to be rewritten
506504
// Dumps:
507505
// - DELETED: <<instruction deleted>>
508506
static FunctionTest ShrinkBorrowScopeTest(
509-
"shrink-borrow-scope", [](auto &function, auto &arguments, auto &test) {
507+
"shrink_borrow_scope", [](auto &function, auto &arguments, auto &test) {
510508
auto instruction = arguments.takeValue();
511-
auto expected = arguments.takeBool();
512509
auto *bbi = cast<BeginBorrowInst>(instruction);
513510
auto *analysis = test.template getAnalysis<BasicCalleeAnalysis>();
514511
SmallVector<CopyValueInst *, 4> modifiedCopyValueInsts;
515512
InstructionDeleter deleter(
516513
InstModCallbacks().onDelete([&](auto *instruction) {
517514
llvm::outs() << "DELETED:\n";
518515
instruction->print(llvm::outs());
516+
instruction->eraseFromParent();
517+
519518
}));
520519
auto shrunk =
521520
shrinkBorrowScope(*bbi, deleter, analysis, modifiedCopyValueInsts);
522-
unsigned index = 0;
521+
auto *shrunkString = shrunk ? "shrunk" : "did not shrink";
522+
llvm::outs() << "Result: " << shrunkString << "\n";
523+
llvm::outs() << "Rewrote the following copies:\n";
523524
for (auto *cvi : modifiedCopyValueInsts) {
524-
auto expectedCopy = arguments.takeValue();
525-
llvm::outs() << "rewritten copy " << index << ":\n";
526-
llvm::outs() << "expected:\n";
527-
expectedCopy->print(llvm::outs());
528-
llvm::outs() << "got:\n";
529525
cvi->print(llvm::outs());
530-
assert(cvi == expectedCopy);
531-
++index;
532526
}
533-
assert(expected == shrunk && "didn't shrink expectedly!?");
534527
});
535528
} // namespace swift::test

test/SILOptimizer/hoist_destroy_addr.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1174,7 +1174,7 @@ entry(%addr : $*X):
11741174
return %retval : $()
11751175
}
11761176

1177-
// Even though the apply of %empty is not a deinit barrier (c.f.
1177+
// Even though the apply of %empty is not a deinit barrier (cf.
11781178
// hoist_over_apply_of_non_barrier_fn), verify that the destroy_addr is not
11791179
// hoisted, because MoS is move-only.
11801180
// CHECK-LABEL: sil [ossa] @dont_move_destroy_addr_of_moveonly_struct : {{.*}} {

test/SILOptimizer/shrink_borrow_scope.unit.sil

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,21 @@ import Swift
55

66
class C {}
77

8+
struct X {}
9+
810
sil [ossa] @get_owned_c : $@convention(thin) () -> (@owned C)
911
sil [ossa] @callee_guaranteed: $@convention(thin) (@guaranteed C) -> ()
12+
sil [ossa] @barrier : $@convention(thin) () -> ()
13+
1014

1115
// CHECK-LABEL: begin running test 1 of {{[^,]+}} on nohoist_over_rewritten_copy
1216
// CHECK-NOT: DELETED:
1317
// CHECK-NOT: end_borrow
18+
// CHECK: Result: did not shrink
1419
// CHECK-LABEL: end running test 1 of {{[^,]+}} on nohoist_over_rewritten_copy
1520
sil [ossa] @nohoist_over_rewritten_copy : $@convention(thin) () -> (@owned C, @owned C) {
1621
entry:
17-
specify_test "shrink-borrow-scope @trace true @trace[1]"
22+
specify_test "shrink_borrow_scope %lifetime"
1823
%get_owned_c = function_ref @get_owned_c : $@convention(thin) () -> (@owned C)
1924
%instance = apply %get_owned_c() : $@convention(thin) () -> (@owned C)
2025
%lifetime = begin_borrow [lexical] %instance : $C
@@ -28,3 +33,37 @@ entry:
2833
return %retval : $(C, C)
2934
}
3035

36+
// CHECK-LABEL: begin running test {{.*}} on nohoist_over_access_scope_barrier_1
37+
// CHECK: Result: did not shrink
38+
// CHECK-LABEL: end running test {{.*}} on nohoist_over_access_scope_barrier_1
39+
sil [ossa] @nohoist_over_access_scope_barrier_1 : $@convention(thin) (@guaranteed C, @inout X) -> () {
40+
entry(%c : @guaranteed $C, %addr : $*X):
41+
%borrow = begin_borrow %c : $C
42+
specify_test "shrink_borrow_scope %borrow"
43+
%access = begin_access [modify] [dynamic] %addr : $*X
44+
cond_br undef, kill_introducer, newly_local_gen
45+
46+
kill_introducer:
47+
cond_br undef, left, right
48+
49+
left:
50+
%barrier = function_ref @barrier : $@convention(thin) () -> ()
51+
apply %barrier() : $@convention(thin) () -> ()
52+
end_access %access : $*X
53+
end_borrow %borrow : $C
54+
br exit
55+
56+
right:
57+
end_access %access : $*X
58+
end_borrow %borrow : $C
59+
br exit
60+
61+
newly_local_gen:
62+
end_access %access : $*X
63+
end_borrow %borrow : $C
64+
br exit
65+
66+
exit:
67+
%retval = tuple ()
68+
return %retval : $()
69+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %target-swift-frontend -c -O %s
2+
3+
protocol P {}
4+
enum E {
5+
case c(any P)
6+
var d: [String:String] { [:] }
7+
}
8+
9+
final class C {
10+
var o: [String:String]?
11+
}
12+
13+
func f(_ e: E?) {
14+
if let e {
15+
C().o?.merge(e.d) { c, _ in c }
16+
}
17+
}

0 commit comments

Comments
 (0)