Skip to content

Commit 4e61c56

Browse files
committed
MandatoryInlining: look through sendable function conversions
Allows inlining of sendable transparent functions rdar://124401627
1 parent bae6450 commit 4e61c56

File tree

4 files changed

+42
-24
lines changed

4 files changed

+42
-24
lines changed

include/swift/SIL/SILInstruction.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5740,6 +5740,9 @@ class ConvertFunctionInst final
57405740
/// argument and return types, as well as all other attributes, after substitution,
57415741
/// such as converting `$<A, B> in (A) -> B for <Int, String>` to `(Int) -> String`.
57425742
bool onlyConvertsSubstitutions() const;
5743+
5744+
/// Returns true if the source and destination types only differ by `@Sendable`.
5745+
bool onlyConvertsSendable() const;
57435746
};
57445747

57455748
/// ConvertEscapeToNoEscapeInst - Change the type of a escaping function value

lib/SIL/IR/SILInstructions.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2744,6 +2744,16 @@ bool ConvertFunctionInst::onlyConvertsSubstitutions() const {
27442744
return fromType->getUnsubstitutedType(M) == toType->getUnsubstitutedType(M);
27452745
}
27462746

2747+
static SILFunctionType *getNonSendableFuncType(SILType ty) {
2748+
auto fnTy = ty.castTo<SILFunctionType>();
2749+
return fnTy->getWithExtInfo(fnTy->getExtInfo().withConcurrent(false));
2750+
}
2751+
2752+
bool ConvertFunctionInst::onlyConvertsSendable() const {
2753+
return getNonSendableFuncType(getOperand()->getType()) ==
2754+
getNonSendableFuncType(getType());
2755+
}
2756+
27472757
ConvertEscapeToNoEscapeInst *ConvertEscapeToNoEscapeInst::create(
27482758
SILDebugLocation DebugLoc, SILValue Operand, SILType Ty, SILFunction &F,
27492759
bool isLifetimeGuaranteed) {

lib/SILOptimizer/Mandatory/MandatoryInlining.cpp

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,20 @@ static SILValue getLoadedCalleeValue(LoadInst *li) {
592592
return si->getSrc();
593593
}
594594

595+
static bool convertsThinEscapeToNoescape(ConvertFunctionInst *cv) {
596+
// Example:
597+
// %1 = function_ref @thin_closure_impl : $() -> ()
598+
// %2 = convert_function %1 : $() -> () to $@noescape () -> ()
599+
//
600+
auto fromTy = cv->getOperand()->getType().castTo<SILFunctionType>();
601+
if (fromTy->getExtInfo().hasContext())
602+
return false;
603+
604+
auto toTy = cv->getType().castTo<SILFunctionType>();
605+
auto escapeToTy = toTy->getWithExtInfo(toTy->getExtInfo().withNoEscape(false));
606+
return fromTy == escapeToTy;
607+
}
608+
595609
// PartialApply/ThinToThick -> ConvertFunction patterns are generated
596610
// by @noescape closures.
597611
//
@@ -602,32 +616,13 @@ static SILValue stripFunctionConversions(SILValue CalleeValue) {
602616
// Skip any copies that we see.
603617
CalleeValue = lookThroughOwnershipInsts(CalleeValue);
604618

605-
// We can also allow a thin @escape to noescape conversion as such:
606-
// %1 = function_ref @thin_closure_impl : $@convention(thin) () -> ()
607-
// %2 = convert_function %1 :
608-
// $@convention(thin) () -> () to $@convention(thin) @noescape () -> ()
609-
// %3 = thin_to_thick_function %2 :
610-
// $@convention(thin) @noescape () -> () to
611-
// $@noescape @callee_guaranteed () -> ()
612-
// %4 = apply %3() : $@noescape @callee_guaranteed () -> ()
613619
if (auto *ConvertFn = dyn_cast<ConvertFunctionInst>(CalleeValue)) {
614-
// If the conversion only changes the substitution level of the function,
615-
// we can also look through it.
616-
if (ConvertFn->onlyConvertsSubstitutions())
620+
if (ConvertFn->onlyConvertsSubstitutions() ||
621+
ConvertFn->onlyConvertsSendable() ||
622+
convertsThinEscapeToNoescape(ConvertFn)) {
617623
return stripFunctionConversions(ConvertFn->getOperand());
618-
619-
auto FromCalleeTy =
620-
ConvertFn->getOperand()->getType().castTo<SILFunctionType>();
621-
if (FromCalleeTy->getExtInfo().hasContext())
622-
return CalleeValue;
623-
624-
auto ToCalleeTy = ConvertFn->getType().castTo<SILFunctionType>();
625-
auto EscapingCalleeTy = ToCalleeTy->getWithExtInfo(
626-
ToCalleeTy->getExtInfo().withNoEscape(false));
627-
if (FromCalleeTy != EscapingCalleeTy)
628-
return CalleeValue;
629-
630-
return lookThroughOwnershipInsts(ConvertFn->getOperand());
624+
}
625+
return CalleeValue;
631626
}
632627

633628
// Ignore mark_dependence users. A partial_apply [stack] uses them to mark

test/SILOptimizer/diagnostic_constant_propagation.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,12 @@ func add<T : SignedInteger>(_ left: T, _ right: T) -> T {
347347
return left + right
348348
}
349349

350+
@Sendable
351+
@_transparent
352+
func sendableAdd<T : SignedInteger>(_ left: T, _ right: T) -> T {
353+
return left + right
354+
}
355+
350356
@_transparent
351357
func applyBinary<T : SignedInteger>(_ fn: (T, T) -> (T), _ left: T, _ right: T) -> T {
352358
return fn(left, right)
@@ -356,6 +362,10 @@ func testTransparentApply() -> Int8 {
356362
return applyBinary(add, Int8.max, Int8.max) // expected-error {{arithmetic operation '127 + 127' (on signed 8-bit integer type) results in an overflow}}
357363
}
358364

365+
func testTransparentApplySendable() -> Int8 {
366+
return applyBinary(sendableAdd, Int8.max, Int8.max) // expected-error {{arithmetic operation '127 + 127' (on signed 8-bit integer type) results in an overflow}}
367+
}
368+
359369
func testBuiltinGlobalStringTablePointerNoError() -> UnsafePointer<CChar> {
360370
return _getGlobalStringTablePointer("A literal")
361371
}

0 commit comments

Comments
 (0)