Skip to content

Commit d1d6beb

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 8d83f0b commit d1d6beb

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
@@ -576,24 +576,30 @@ static bool isSupportedClosure(const SILInstruction *Closure) {
576576
return false;
577577

578578
if (auto *PAI = dyn_cast<PartialApplyInst>(Closure)) {
579-
// Bail if any of the arguments are passed by address and
580-
// are not @inout.
581-
// This is a temporary limitation.
579+
// Check whether each argument is supported.
582580
auto ClosureCallee = FRI->getReferencedFunction();
583581
auto ClosureCalleeConv = ClosureCallee->getConventions();
584582
unsigned ClosureArgIdxBase =
585583
ClosureCalleeConv.getNumSILArguments() - PAI->getNumArguments();
586584
for (auto pair : llvm::enumerate(PAI->getArguments())) {
587585
auto Arg = pair.value();
588586
auto ClosureArgIdx = pair.index() + ClosureArgIdxBase;
587+
auto ArgConvention =
588+
ClosureCalleeConv.getSILArgumentConvention(ClosureArgIdx);
589+
589590
SILType ArgTy = Arg->getType();
591+
// Specializing (currently) always produces a retain in the caller.
592+
// That's not allowed for values of move-only type.
593+
if (ArgTy.isMoveOnly()) {
594+
return false;
595+
}
596+
597+
// Only @inout/@inout_aliasable addresses are (currently) supported.
590598
// If our argument is an object, continue...
591599
if (ArgTy.isObject()) {
592600
++ClosureArgIdx;
593601
continue;
594602
}
595-
auto ArgConvention =
596-
ClosureCalleeConv.getSILArgumentConvention(ClosureArgIdx);
597603
if (ArgConvention != SILArgumentConvention::Indirect_Inout &&
598604
ArgConvention != SILArgumentConvention::Indirect_InoutAliasable)
599605
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)