Skip to content

Commit ac5ae3c

Browse files
committed
[ClosureSpecializer] Bail on noncopyable argument.
The optimization currently always creates a retain of the argument. This isn't legal for noncopyable values. rdar://129622373
1 parent 55eb29a commit ac5ae3c

File tree

2 files changed

+43
-5
lines changed

2 files changed

+43
-5
lines changed

lib/SILOptimizer/IPO/ClosureSpecializer.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -675,24 +675,30 @@ static bool isSupportedClosure(const SILInstruction *Closure) {
675675
return false;
676676

677677
if (auto *PAI = dyn_cast<PartialApplyInst>(Closure)) {
678-
// Bail if any of the arguments are passed by address and
679-
// are not @inout.
680-
// This is a temporary limitation.
678+
// Check whether each argument is supported.
681679
auto ClosureCallee = FRI->getReferencedFunction();
682680
auto ClosureCalleeConv = ClosureCallee->getConventions();
683681
unsigned ClosureArgIdxBase =
684682
ClosureCalleeConv.getNumSILArguments() - PAI->getNumArguments();
685683
for (auto pair : llvm::enumerate(PAI->getArguments())) {
686684
auto Arg = pair.value();
687685
auto ClosureArgIdx = pair.index() + ClosureArgIdxBase;
686+
auto ArgConvention =
687+
ClosureCalleeConv.getSILArgumentConvention(ClosureArgIdx);
688+
688689
SILType ArgTy = Arg->getType();
690+
// Specializing (currently) always produces a retain in the caller.
691+
// That's not allowed for values of move-only type.
692+
if (ArgTy.isMoveOnly()) {
693+
return false;
694+
}
695+
696+
// Only @inout/@inout_aliasable addresses are (currently) supported.
689697
// If our argument is an object, continue...
690698
if (ArgTy.isObject()) {
691699
++ClosureArgIdx;
692700
continue;
693701
}
694-
auto ArgConvention =
695-
ClosureCalleeConv.getSILArgumentConvention(ClosureArgIdx);
696702
if (ArgConvention != SILArgumentConvention::Indirect_Inout &&
697703
ArgConvention != SILArgumentConvention::Indirect_InoutAliasable)
698704
return false;

test/SILOptimizer/closure_specialize.sil

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -938,3 +938,35 @@ bb0(%0 : $Int):
938938
%empty = tuple ()
939939
return %empty : $()
940940
}
941+
942+
struct NC : ~Copyable {
943+
deinit {}
944+
}
945+
946+
sil hidden [noinline] @noncopyable_arg_closure : $@convention(thin) (@guaranteed NC) -> () {
947+
bb0(%0 : $NC):
948+
%retval = tuple ()
949+
return %retval : $()
950+
}
951+
952+
sil hidden [noinline] @use_noncopyable_arg_closure : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> () {
953+
bb0(%0 : $@noescape @callee_guaranteed () -> ()):
954+
%2 = apply %0() : $@noescape @callee_guaranteed () -> ()
955+
%3 = tuple ()
956+
return %3 : $()
957+
}
958+
959+
// Ensure that a retain_value of a noncopyable value isn't created.
960+
// CHECK-LABEL: sil @dont_specialize_noncopyable_arg_closure : {{.*}} {
961+
// CHECK-NOT: retain_value {{%.*}} : $NC
962+
// CHECK-LABEL: } // end sil function 'dont_specialize_noncopyable_arg_closure'
963+
sil @dont_specialize_noncopyable_arg_closure : $@convention(thin) (@guaranteed NC) -> () {
964+
bb0(%nc : $NC):
965+
%closure_fn = function_ref @noncopyable_arg_closure : $@convention(thin) (@guaranteed NC) -> ()
966+
%closure = partial_apply [callee_guaranteed] [on_stack] %closure_fn(%nc) : $@convention(thin) (@guaranteed NC) -> ()
967+
%use = function_ref @use_noncopyable_arg_closure : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
968+
apply %use(%closure) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
969+
dealloc_stack %closure : $@noescape @callee_guaranteed () -> ()
970+
%11 = tuple ()
971+
return %11 : $()
972+
}

0 commit comments

Comments
 (0)