diff --git a/include/swift/SIL/SILFunction.h b/include/swift/SIL/SILFunction.h index 660d3f3fa3f83..19d47184fe70a 100644 --- a/include/swift/SIL/SILFunction.h +++ b/include/swift/SIL/SILFunction.h @@ -56,7 +56,8 @@ enum IsThunk_t { IsNotThunk, IsThunk, IsReabstractionThunk, - IsSignatureOptimizedThunk + IsSignatureOptimizedThunk, + IsBackDeployedThunk, }; enum IsDynamicallyReplaceable_t { IsNotDynamic, @@ -368,7 +369,7 @@ class SILFunction /// /// The inliner uses this information to avoid inlining (non-trivial) /// functions into the thunk. - unsigned Thunk : 2; + unsigned Thunk : 3; /// The scope in which the parent class can be subclassed, if this is a method /// which is contained in the vtable of that class. @@ -488,6 +489,7 @@ class SILFunction break; case IsThunk: case IsReabstractionThunk: + case IsBackDeployedThunk: thunkCanHaveSubclassScope = false; break; } diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp index 7cf37b7424493..710d42db8107d 100644 --- a/lib/SIL/IR/SILPrinter.cpp +++ b/lib/SIL/IR/SILPrinter.cpp @@ -3355,6 +3355,7 @@ void SILFunction::print(SILPrintContext &PrintCtx) const { switch (isThunk()) { case IsNotThunk: break; + case IsBackDeployedThunk: // FIXME: Give this a distinct label case IsThunk: OS << "[thunk] "; break; case IsSignatureOptimizedThunk: OS << "[signature_optimized_thunk] "; diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index f056a95f72736..fe58fa3912bd9 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -909,7 +909,7 @@ void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) { preEmitFunction(constant, f, loc); PrettyStackTraceSILFunction X("silgen emitBackDeploymentThunk", f); f->setBare(IsBare); - f->setThunk(IsThunk); + f->setThunk(IsBackDeployedThunk); SILGenFunction(*this, *f, dc).emitBackDeploymentThunk(constant); diff --git a/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp b/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp index dae66cea5e392..7878dea403a6f 100644 --- a/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp +++ b/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp @@ -1027,10 +1027,22 @@ class MandatoryInlining : public SILModuleTransform { SILOptFunctionBuilder FuncBuilder(*this); for (auto &F : *M) { - // Don't inline into thunks, even transparent callees. - if (F.isThunk()) + switch (F.isThunk()) { + case IsThunk_t::IsThunk: + case IsThunk_t::IsReabstractionThunk: + case IsThunk_t::IsSignatureOptimizedThunk: + // Don't inline into most thunks, even transparent callees. continue; + case IsThunk_t::IsNotThunk: + case IsThunk_t::IsBackDeployedThunk: + // For correctness, inlining _stdlib_isOSVersionAtLeast() when it is + // declared transparent is mandatory in the thunks of @backDeployed + // functions. These thunks will not contain calls to other transparent + // functions. + break; + } + // Skip deserialized functions. if (F.wasDeserializedCanonical()) continue; diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 0ad6fcbc812c8..f3a62bb38efe9 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 870; // SerializePackageEnabled / [serialized_for_package] for SILFunctionLayout / package field in SerializedKind_t +const uint16_t SWIFTMODULE_VERSION_MINOR = 871; // SIL function thunk kind /// A standard hash seed used for all string hashes in a serialized module. /// diff --git a/lib/Serialization/SILFormat.h b/lib/Serialization/SILFormat.h index 38196e664fb3a..6f9aa35f661bb 100644 --- a/lib/Serialization/SILFormat.h +++ b/lib/Serialization/SILFormat.h @@ -292,7 +292,7 @@ namespace sil_block { BCRecordLayout, // transparent BCFixed<2>, // serializedKind - BCFixed<2>, // thunks: signature optimized/reabstraction + BCFixed<3>, // thunk kind BCFixed<1>, // without_actually_escaping BCFixed<3>, // specialPurpose BCFixed<2>, // inlineStrategy diff --git a/test/IRGen/Inputs/back_deployed.swift b/test/IRGen/Inputs/back_deployed.swift new file mode 100644 index 0000000000000..452a1e198def5 --- /dev/null +++ b/test/IRGen/Inputs/back_deployed.swift @@ -0,0 +1,6 @@ +@backDeployed(before: SwiftStdlib 6.0) +public func backDeployedFunc() { + otherFunc() +} + +@usableFromInline internal func otherFunc() {} diff --git a/test/IRGen/back_deployed_Onone.swift b/test/IRGen/back_deployed_Onone.swift new file mode 100644 index 0000000000000..4b0a4c6d5c74c --- /dev/null +++ b/test/IRGen/back_deployed_Onone.swift @@ -0,0 +1,17 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module %S/Inputs/back_deployed.swift -o %t/ -swift-version 5 -enable-library-evolution +// RUN: %target-swift-frontend -emit-ir %s -I %t -Onone | %FileCheck %s + +// _stdlib_isOSVersionAtLeast() is not @_transparent on macOS, watchOS, and tvOS +// REQUIRES: OS=macosx || OS=watchos || OS=tvos + +import back_deployed + +public func test() { + backDeployedFunc() +} + +// CHECK: define{{.*}} hidden swiftcc void @"$s13back_deployed0A12DeployedFuncyyFTwb" +// CHECK: call swiftcc i1 @"$ss26_stdlib_isOSVersionAtLeastyBi1_Bw_BwBwtF" +// CHECK: call swiftcc void @"$s13back_deployed0A12DeployedFuncyyFTwB" +// CHECK: call swiftcc void @"$s13back_deployed0A12DeployedFuncyyF" diff --git a/test/IRGen/back_deployed_Onone_transparent.swift b/test/IRGen/back_deployed_Onone_transparent.swift new file mode 100644 index 0000000000000..46016f80daa42 --- /dev/null +++ b/test/IRGen/back_deployed_Onone_transparent.swift @@ -0,0 +1,20 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module %S/Inputs/back_deployed.swift -o %t/ -swift-version 5 -enable-library-evolution +// RUN: %target-swift-frontend -emit-ir %s -I %t -Onone | %FileCheck %s + +// _stdlib_isOSVersionAtLeast() is @_transparent on iOS +// REQUIRES: OS=ios + +import back_deployed + +public func test() { + backDeployedFunc() +} + +// CHECK: define{{.*}} hidden swiftcc void @"$s13back_deployed0A12DeployedFuncyyFTwb" +// CHECK: call swiftcc i1 @"$ss31_stdlib_isOSVersionAtLeast_AEICyBi1_Bw_BwBwtF" +// CHECK: call swiftcc void @"$s13back_deployed0A12DeployedFuncyyFTwB" +// CHECK: call swiftcc void @"$s13back_deployed0A12DeployedFuncyyF" + +// CHECK: define{{.*}} hidden swiftcc i1 @"$ss31_stdlib_isOSVersionAtLeast_AEICyBi1_Bw_BwBwtF" +// CHECK: call i32 @__isPlatformVersionAtLeast