Skip to content

Commit f423115

Browse files
Merge pull request #67218 from nate-chandler/rdar112078094
[AllocBoxToStack] Computing partial_apply frontier looks thru copies+moves.
2 parents adb842b + 6cf2bb4 commit f423115

File tree

2 files changed

+86
-1
lines changed

2 files changed

+86
-1
lines changed

lib/SILOptimizer/Transforms/AllocBoxToStack.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "swift/SIL/BasicBlockDatastructures.h"
2121
#include "swift/SIL/Dominance.h"
2222
#include "swift/SIL/MemAccessUtils.h"
23+
#include "swift/SIL/NodeDatastructures.h"
2324
#include "swift/SIL/SILArgument.h"
2425
#include "swift/SIL/SILBuilder.h"
2526
#include "swift/SIL/SILCloner.h"
@@ -1101,7 +1102,31 @@ specializeApplySite(SILOptFunctionBuilder &FuncBuilder, ApplySite Apply,
11011102
// borrows its captures, and we don't need to adjust capture lifetimes.
11021103
if (!PAI->isOnStack()) {
11031104
if (PAFrontier.empty()) {
1104-
ValueLifetimeAnalysis VLA(PAI, PAI->getUses());
1105+
SmallVector<SILInstruction *, 8> users;
1106+
InstructionWorklist worklist(PAI->getFunction());
1107+
worklist.push(PAI);
1108+
while (auto *inst = worklist.pop()) {
1109+
auto *svi = cast<SingleValueInstruction>(inst);
1110+
for (auto *use : svi->getUses()) {
1111+
auto *user = use->getUser();
1112+
SingleValueInstruction *svi;
1113+
// A copy_value produces a value with a new lifetime on which the
1114+
// captured alloc_box's lifetime depends. If the transformation
1115+
// were only to create a destroy_value of the alloc_box (and to
1116+
// rewrite the closure not to consume it), the alloc_box would be
1117+
// kept alive by the copy_value. The transformation does more,
1118+
// however: it rewrites the alloc_box as an alloc_stack, creating
1119+
// the alloc_stack/dealloc_stack instructions where the alloc_box/
1120+
// destroy_value instructions are respectively. The copy_value
1121+
// can't keep the alloc_stack alive.
1122+
if ((svi = dyn_cast<CopyValueInst>(user)) ||
1123+
(svi = dyn_cast<MoveValueInst>(user))) {
1124+
worklist.push(svi);
1125+
}
1126+
users.push_back(user);
1127+
}
1128+
}
1129+
ValueLifetimeAnalysis VLA(PAI, users);
11051130
pass.CFGChanged |= !VLA.computeFrontier(
11061131
PAFrontier, ValueLifetimeAnalysis::AllowToModifyCFG);
11071132
assert(!PAFrontier.empty() &&

test/SILOptimizer/allocboxtostack_localapply_ossa.sil

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,3 +488,63 @@ bb0(%0 : @guaranteed ${ var Int }, %1 : @guaranteed ${ var Int }):
488488
%8 = apply %7(%0, %1) : $@convention(thin) (@guaranteed { var Int }, @guaranteed { var Int }) -> Int
489489
return %8 : $Int
490490
}
491+
492+
class C {}
493+
494+
sil @getC : $@convention(thin) () -> (@owned C)
495+
496+
sil [ossa] @borrow_c_box : $@convention(thin) (@guaranteed { var C }) -> () {
497+
entry(%box : @guaranteed ${var C}):
498+
%retval = tuple ()
499+
return %retval : $()
500+
}
501+
502+
// CHECK-LABEL: sil [ossa] @test_copy_applied : {{.*}} {
503+
// CHECK: [[CLOSURE:%[^,]+]] = partial_apply
504+
// CHECK: [[COPY:%[^,]+]] = copy_value [[CLOSURE]]
505+
// CHECK: destroy_value [[CLOSURE]]
506+
// CHECK: apply [[COPY]]()
507+
// CHECK: destroy_addr
508+
// CHECK: dealloc_stack
509+
// CHECK-LABEL: } // end sil function 'test_copy_applied'
510+
sil [ossa] @test_copy_applied : $@convention(thin) () -> () {
511+
bb0:
512+
%box = alloc_box ${ var C }, var, name "x"
513+
%addr = project_box %box : ${ var C }, 0
514+
%getC = function_ref @getC : $@convention(thin) () -> (@owned C)
515+
%c = apply %getC() : $@convention(thin) () -> (@owned C)
516+
store %c to [init] %addr : $*C
517+
518+
%borrow_int_box = function_ref @borrow_c_box : $@convention(thin) (@guaranteed { var C }) -> ()
519+
%closure = partial_apply [callee_guaranteed] %borrow_int_box(%box) : $@convention(thin) (@guaranteed { var C }) -> ()
520+
%copy = copy_value %closure : $@callee_guaranteed () -> ()
521+
destroy_value %closure : $@callee_guaranteed () -> ()
522+
apply %copy() : $@callee_guaranteed () -> ()
523+
destroy_value %copy : $@callee_guaranteed () -> ()
524+
%retval = tuple ()
525+
return %retval : $()
526+
}
527+
528+
// CHECK-LABEL: sil [ossa] @test_move_applied : {{.*}} {
529+
// CHECK: [[CLOSURE:%[^,]+]] = partial_apply
530+
// CHECK: [[MOVE:%[^,]+]] = move_value [[CLOSURE]]
531+
// CHECK: apply [[MOVE]]()
532+
// CHECK: destroy_addr
533+
// CHECK: dealloc_stack
534+
// CHECK-LABEL: } // end sil function 'test_move_applied'
535+
sil [ossa] @test_move_applied : $@convention(thin) () -> () {
536+
bb0:
537+
%box = alloc_box ${ var C }, var, name "x"
538+
%addr = project_box %box : ${ var C }, 0
539+
%getC = function_ref @getC : $@convention(thin) () -> (@owned C)
540+
%c = apply %getC() : $@convention(thin) () -> (@owned C)
541+
store %c to [init] %addr : $*C
542+
543+
%borrow_int_box = function_ref @borrow_c_box : $@convention(thin) (@guaranteed { var C }) -> ()
544+
%closure = partial_apply [callee_guaranteed] %borrow_int_box(%box) : $@convention(thin) (@guaranteed { var C }) -> ()
545+
%move = move_value %closure : $@callee_guaranteed () -> ()
546+
apply %move() : $@callee_guaranteed () -> ()
547+
destroy_value %move : $@callee_guaranteed () -> ()
548+
%retval = tuple ()
549+
return %retval : $()
550+
}

0 commit comments

Comments
 (0)