diff --git a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyLoad.swift b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyLoad.swift index bf14b180da542..76e703e964df8 100644 --- a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyLoad.swift +++ b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyLoad.swift @@ -281,7 +281,7 @@ private func transitivelyErase(load: LoadInst, _ context: SimplifyContext) { private extension Value { func canBeCopied(into function: Function, _ context: SimplifyContext) -> Bool { - if !function.isSerialized { + if !function.isAnySerialized { return true } @@ -297,7 +297,7 @@ private extension Value { while let value = worklist.pop() { if let fri = value as? FunctionRefInst { - if !fri.referencedFunction.hasValidLinkageForFragileRef { + if !fri.referencedFunction.hasValidLinkageForFragileRef(function.serializedKind) { return false } } diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift b/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift index 160b46f8fa8cd..2eec22f2b7c6c 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift +++ b/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift @@ -549,9 +549,8 @@ extension FullApplySite { return false } // Cannot inline a non-inlinable function it an inlinable function. - if parentFunction.isSerialized, - let calleeFunction = referencedFunction, - !calleeFunction.isSerialized { + if let calleeFunction = referencedFunction, + !calleeFunction.canBeInlinedIntoCaller(parentFunction.serializedKind) { return false } diff --git a/SwiftCompilerSources/Sources/SIL/Function.swift b/SwiftCompilerSources/Sources/SIL/Function.swift index 4eb55fcc62f67..ee2d650d5d3bf 100644 --- a/SwiftCompilerSources/Sources/SIL/Function.swift +++ b/SwiftCompilerSources/Sources/SIL/Function.swift @@ -122,7 +122,37 @@ final public class Function : CustomStringConvertible, HasShortDescription, Hash } public var isSerialized: Bool { bridged.isSerialized() } - public var hasValidLinkageForFragileRef: Bool { bridged.hasValidLinkageForFragileRef() } + public var isAnySerialized: Bool { bridged.isAnySerialized() } + + public enum SerializedKind { + case notSerialized, serialized, serializedForPackage + } + + public var serializedKind: SerializedKind { + switch bridged.getSerializedKind() { + case .IsNotSerialized: return .notSerialized + case .IsSerialized: return .serialized + case .IsSerializedForPackage: return .serializedForPackage + default: fatalError() + } + } + + private func serializedKindBridged(_ arg: SerializedKind) -> BridgedFunction.SerializedKind { + switch arg { + case .notSerialized: return .IsNotSerialized + case .serialized: return .IsSerialized + case .serializedForPackage: return .IsSerializedForPackage + default: fatalError() + } + } + + public func canBeInlinedIntoCaller(_ kind: SerializedKind) -> Bool { + bridged.canBeInlinedIntoCaller(serializedKindBridged(kind)) + } + + public func hasValidLinkageForFragileRef(_ kind: SerializedKind) -> Bool { + bridged.hasValidLinkageForFragileRef(serializedKindBridged(kind)) + } public enum ThunkKind { case noThunk, thunk, reabstractionThunk, signatureOptimizedThunk diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 22c1ade177cf7..497310fd9027d 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -697,7 +697,7 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated { HasAnyUnavailableDuringLoweringValues : 1 ); - SWIFT_INLINE_BITFIELD(ModuleDecl, TypeDecl, 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1, + SWIFT_INLINE_BITFIELD(ModuleDecl, TypeDecl, 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1, /// If the module is compiled as static library. StaticLibrary : 1, @@ -756,7 +756,10 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated { HasCxxInteroperability : 1, /// Whether this module has been built with -experimental-allow-non-resilient-access. - AllowNonResilientAccess : 1 + AllowNonResilientAccess : 1, + + /// Whether this module has been built with -experimental-package-cmo. + SerializePackageEnabled : 1 ); SWIFT_INLINE_BITFIELD(PrecedenceGroupDecl, Decl, 1+2, @@ -4148,6 +4151,13 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext { /// is built resiliently. bool isResilient() const; + /// True if the decl is resilient AND also its defining module does + /// _not_ allow non-resilient access; the module can allow such access + /// if package optimization is enabled so its client modules within the + /// same package can have a direct access to this decl even if it's + /// resilient. + bool isStrictlyResilient() const; + /// Returns whether this decl is accessed non/resiliently at the _use_ site /// in \p accessingModule, depending on \p expansion. /// @@ -5966,6 +5976,13 @@ class AbstractStorageDecl : public ValueDecl { /// property from the given module? bool isResilient(ModuleDecl *M, ResilienceExpansion expansion) const; + /// True if the decl is resilient AND also its defining module does + /// _not_ allow non-resilient access; the module can allow such access + /// if package optimization is enabled so its client modules within the + /// same package can have a direct access to this decl even if it's + /// resilient. + bool isStrictlyResilient() const; + /// True if the storage can be referenced by a keypath directly. /// Otherwise, its override must be referenced. bool isValidKeyPathComponent() const; diff --git a/include/swift/AST/Module.h b/include/swift/AST/Module.h index 7983b98edf459..42f4a27b669a3 100644 --- a/include/swift/AST/Module.h +++ b/include/swift/AST/Module.h @@ -736,6 +736,16 @@ class ModuleDecl Bits.ModuleDecl.AllowNonResilientAccess = flag; } + /// Returns true if -experimental-package-cmo was passed, which + /// enables serialization of package, public, and inlinable decls in a + /// package. This requires -experimental-allow-non-resilient-access. + bool serializePackageEnabled() const { + return Bits.ModuleDecl.SerializePackageEnabled; + } + void setSerializePackageEnabled(bool flag = true) { + Bits.ModuleDecl.SerializePackageEnabled = flag; + } + /// Returns true if this module is a non-Swift module that was imported into /// Swift. /// @@ -783,6 +793,15 @@ class ModuleDecl return getResilienceStrategy() != ResilienceStrategy::Default; } + /// True if this module is resilient AND also does _not_ allow + /// non-resilient access; the module can allow such access if + /// package optimization is enabled so its client modules within + /// the same package can have a direct access to decls in this + /// module even if it's built resiliently. + bool isStrictlyResilient() const { + return isResilient() && !allowNonResilientAccess(); + } + /// Look up a (possibly overloaded) value set at top-level scope /// (but with the specified access path, which may come from an import decl) /// within the current module. diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 53d8eacbcbc9f..8928132672605 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -6618,6 +6618,8 @@ enum class OpaqueSubstitutionKind { // Can be done if the underlying type is accessible from the context we // substitute into. Private types cannot be accessed from a different TU. SubstituteSameModuleMaximalResilience, + // Same as previous but with package and above visibility. + SubstituteSamePackageMaximalResilience, // Substitute in a different module from the opaque defining decl. Can only // be done if the underlying type is public. SubstituteNonResilientModule diff --git a/include/swift/SIL/GenericSpecializationMangler.h b/include/swift/SIL/GenericSpecializationMangler.h index caf68329fc0d1..e668d16f9eab7 100644 --- a/include/swift/SIL/GenericSpecializationMangler.h +++ b/include/swift/SIL/GenericSpecializationMangler.h @@ -37,7 +37,7 @@ class SpecializationMangler : public Mangle::ASTMangler { /// The specialization pass. SpecializationPass Pass; - IsSerialized_t Serialized; + swift::SerializedKind_t Serialized; /// The original function which is specialized. SILFunction *Function; @@ -50,12 +50,12 @@ class SpecializationMangler : public Mangle::ASTMangler { PossibleEffects RemovedEffects; protected: - SpecializationMangler(SpecializationPass P, IsSerialized_t Serialized, + SpecializationMangler(SpecializationPass P, swift::SerializedKind_t Serialized, SILFunction *F) : Pass(P), Serialized(Serialized), Function(F), ArgOpBuffer(ArgOpStorage) {} - SpecializationMangler(SpecializationPass P, IsSerialized_t Serialized, + SpecializationMangler(SpecializationPass P, swift::SerializedKind_t Serialized, std::string functionName) : Pass(P), Serialized(Serialized), Function(nullptr), FunctionName(functionName), ArgOpBuffer(ArgOpStorage) {} @@ -88,7 +88,7 @@ class GenericSpecializationMangler : public SpecializationMangler { SubstitutionMap subs); public: - GenericSpecializationMangler(SILFunction *F, IsSerialized_t Serialized) + GenericSpecializationMangler(SILFunction *F, swift::SerializedKind_t Serialized) : SpecializationMangler(SpecializationPass::GenericSpecializer, Serialized, F) {} diff --git a/include/swift/SIL/SILBridging.h b/include/swift/SIL/SILBridging.h index 4bdf1d76eb3fd..05a95e8c49556 100644 --- a/include/swift/SIL/SILBridging.h +++ b/include/swift/SIL/SILBridging.h @@ -529,6 +529,12 @@ struct BridgedFunction { IsSignatureOptimizedThunk }; + enum class SerializedKind { + IsNotSerialized, + IsSerialized, + IsSerializedForPackage + }; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE swift::SILFunction * _Nonnull getFunction() const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedStringRef getName() const; SWIFT_IMPORT_UNSAFE BridgedOwnedString getDebugDescription() const; @@ -558,7 +564,10 @@ struct BridgedFunction { BRIDGED_INLINE PerformanceConstraints getPerformanceConstraints() const; BRIDGED_INLINE InlineStrategy getInlineStrategy() const; BRIDGED_INLINE bool isSerialized() const; - BRIDGED_INLINE bool hasValidLinkageForFragileRef() const; + BRIDGED_INLINE bool isAnySerialized() const; + BRIDGED_INLINE SerializedKind getSerializedKind() const; + BRIDGED_INLINE bool canBeInlinedIntoCaller(SerializedKind) const; + BRIDGED_INLINE bool hasValidLinkageForFragileRef(SerializedKind) const; BRIDGED_INLINE ThunkKind isThunk() const; BRIDGED_INLINE void setThunk(ThunkKind) const; BRIDGED_INLINE bool needsStackProtection() const; diff --git a/include/swift/SIL/SILBridgingImpl.h b/include/swift/SIL/SILBridgingImpl.h index 54b205662878b..acf2f53bfb9d7 100644 --- a/include/swift/SIL/SILBridgingImpl.h +++ b/include/swift/SIL/SILBridgingImpl.h @@ -690,8 +690,20 @@ bool BridgedFunction::isSerialized() const { return getFunction()->isSerialized(); } -bool BridgedFunction::hasValidLinkageForFragileRef() const { - return getFunction()->hasValidLinkageForFragileRef(); +bool BridgedFunction::isAnySerialized() const { + return getFunction()->isAnySerialized(); +} + +BridgedFunction::SerializedKind BridgedFunction::getSerializedKind() const { + return (SerializedKind)getFunction()->getSerializedKind(); +} + +bool BridgedFunction::canBeInlinedIntoCaller(SerializedKind kind) const { + return getFunction()->canBeInlinedIntoCaller(swift::SerializedKind_t(kind)); +} + +bool BridgedFunction::hasValidLinkageForFragileRef(SerializedKind kind) const { + return getFunction()->hasValidLinkageForFragileRef(swift::SerializedKind_t(kind)); } bool BridgedFunction::needsStackProtection() const { diff --git a/include/swift/SIL/SILDeclRef.h b/include/swift/SIL/SILDeclRef.h index 60619ec108982..3eaef1aebe2db 100644 --- a/include/swift/SIL/SILDeclRef.h +++ b/include/swift/SIL/SILDeclRef.h @@ -46,7 +46,7 @@ namespace swift { class EffectsAttr; class FileUnit; class SILFunctionType; - enum IsSerialized_t : unsigned char; + enum SerializedKind_t : uint8_t; enum class SubclassScope : unsigned char; class SILModule; class SILLocation; @@ -384,7 +384,11 @@ struct SILDeclRef { /// True if the function should be treated as transparent. bool isTransparent() const; /// True if the function should have its body serialized. - IsSerialized_t isSerialized() const; + bool isSerialized() const; + /// True if this function is neither [serialized] or [serialized_for_package]. + bool isNotSerialized() const; + /// Returns IsNotSerialized, IsSerializedForPackage, or IsSerialized. + SerializedKind_t getSerializedKind() const; /// True if the function has noinline attribute. bool isNoinline() const; /// True if the function has __always inline attribute. diff --git a/include/swift/SIL/SILFunction.h b/include/swift/SIL/SILFunction.h index d990c41ab0358..660d3f3fa3f83 100644 --- a/include/swift/SIL/SILFunction.h +++ b/include/swift/SIL/SILFunction.h @@ -362,7 +362,7 @@ class SILFunction unsigned Transparent : 1; /// The function's serialized attribute. - bool Serialized : 1; + unsigned SerializedKind : 2; /// Specifies if this function is a thunk or a reabstraction thunk. /// @@ -502,7 +502,7 @@ class SILFunction SILFunction(SILModule &module, SILLinkage linkage, StringRef mangledName, CanSILFunctionType loweredType, GenericEnvironment *genericEnv, IsBare_t isBareSILFunction, IsTransparent_t isTrans, - IsSerialized_t isSerialized, ProfileCounter entryCount, + SerializedKind_t serializedKind, ProfileCounter entryCount, IsThunk_t isThunk, SubclassScope classSubclassScope, Inline_t inlineStrategy, EffectsKind E, const SILDebugScope *debugScope, @@ -515,7 +515,7 @@ class SILFunction create(SILModule &M, SILLinkage linkage, StringRef name, CanSILFunctionType loweredType, GenericEnvironment *genericEnv, std::optional loc, IsBare_t isBareSILFunction, - IsTransparent_t isTrans, IsSerialized_t isSerialized, + IsTransparent_t isTrans, SerializedKind_t serializedKind, ProfileCounter entryCount, IsDynamicallyReplaceable_t isDynamic, IsDistributed_t isDistributed, IsRuntimeAccessible_t isRuntimeAccessible, @@ -528,7 +528,7 @@ class SILFunction void init(SILLinkage Linkage, StringRef Name, CanSILFunctionType LoweredType, GenericEnvironment *genericEnv, IsBare_t isBareSILFunction, - IsTransparent_t isTrans, IsSerialized_t isSerialized, + IsTransparent_t isTrans, SerializedKind_t serializedKind, ProfileCounter entryCount, IsThunk_t isThunk, SubclassScope classSubclassScope, Inline_t inlineStrategy, EffectsKind E, const SILDebugScope *DebugScope, @@ -780,11 +780,7 @@ class SILFunction return getLoweredFunctionType()->getRepresentation(); } - ResilienceExpansion getResilienceExpansion() const { - return (isSerialized() - ? ResilienceExpansion::Minimal - : ResilienceExpansion::Maximal); - } + ResilienceExpansion getResilienceExpansion() const; // Returns the type expansion context to be used inside this function. TypeExpansionContext getTypeExpansionContext() const { @@ -875,13 +871,32 @@ class SILFunction /// Set the function's linkage attribute. void setLinkage(SILLinkage linkage) { Linkage = unsigned(linkage); } - /// Returns true if this function can be inlined into a fragile function - /// body. - bool hasValidLinkageForFragileInline() const { return isSerialized(); } +/// Checks if this (callee) function body can be inlined into the caller +/// by comparing their `SerializedKind_t` values. +/// +/// If both callee and caller are `not_serialized`, the callee can be inlined +/// into the caller during SIL inlining passes even if it (and the caller) +/// might contain private symbols. If this callee is `serialized_for_pkg`, +/// it can only be referenced by a serialized caller but not inlined into +/// it. +/// +/// ``` +/// canInlineInto: Caller +/// | not_serialized | serialized_for_pkg | serialized +/// not_serialized | ok | no | no +/// Callee serialized_for_pkg | ok | ok | no +/// serialized | ok | ok | ok +/// +/// ``` +/// +/// \p callerSerializedKind The caller's SerializedKind. + bool canBeInlinedIntoCaller(SerializedKind_t callerSerializedKind) const; /// Returns true if this function can be referenced from a fragile function /// body. - bool hasValidLinkageForFragileRef() const; + /// \p callerSerializedKind The caller's SerializedKind. Used to be passed to + /// \c canBeInlinedIntoCaller. + bool hasValidLinkageForFragileRef(SerializedKind_t callerSerializedKind) const; /// Get's the effective linkage which is used to derive the llvm linkage. /// Usually this is the same as getLinkage(), except in one case: if this @@ -1135,11 +1150,21 @@ class SILFunction assert(!Transparent || !IsDynamicReplaceable); } + bool isSerialized() const { + return SerializedKind_t(SerializedKind) == IsSerialized; + } + bool isAnySerialized() const { + return SerializedKind_t(SerializedKind) == IsSerialized || + SerializedKind_t(SerializedKind) == IsSerializedForPackage; + } + /// Get this function's serialized attribute. - IsSerialized_t isSerialized() const { return IsSerialized_t(Serialized); } - void setSerialized(IsSerialized_t isSerialized) { - Serialized = isSerialized; - assert(this->isSerialized() == isSerialized && + SerializedKind_t getSerializedKind() const { + return SerializedKind_t(SerializedKind); + } + void setSerializedKind(SerializedKind_t serializedKind) { + SerializedKind = serializedKind; + assert(this->getSerializedKind() == serializedKind && "too few bits for Serialized storage"); } diff --git a/include/swift/SIL/SILFunctionBuilder.h b/include/swift/SIL/SILFunctionBuilder.h index 37b75853e9974..a4d28b953d0f0 100644 --- a/include/swift/SIL/SILFunctionBuilder.h +++ b/include/swift/SIL/SILFunctionBuilder.h @@ -60,24 +60,19 @@ class SILFunctionBuilder { /// Return the declaration of a utility function that can, but needn't, be /// shared between different parts of a program. - SILFunction *getOrCreateSharedFunction(SILLocation loc, StringRef name, - CanSILFunctionType type, - IsBare_t isBareSILFunction, - IsTransparent_t isTransparent, - IsSerialized_t isSerialized, - ProfileCounter entryCount, - IsThunk_t isThunk, - IsDynamicallyReplaceable_t isDynamic, - IsDistributed_t isDistributed, - IsRuntimeAccessible_t isRuntimeAccessible); + SILFunction *getOrCreateSharedFunction( + SILLocation loc, StringRef name, CanSILFunctionType type, + IsBare_t isBareSILFunction, IsTransparent_t isTransparent, + SerializedKind_t serializedKind, ProfileCounter entryCount, + IsThunk_t isThunk, IsDynamicallyReplaceable_t isDynamic, + IsDistributed_t isDistributed, IsRuntimeAccessible_t isRuntimeAccessible); /// Return the declaration of a function, or create it if it doesn't exist. SILFunction *getOrCreateFunction( SILLocation loc, StringRef name, SILLinkage linkage, CanSILFunctionType type, IsBare_t isBareSILFunction, - IsTransparent_t isTransparent, IsSerialized_t isSerialized, - IsDynamicallyReplaceable_t isDynamic, - IsDistributed_t isDistributed, + IsTransparent_t isTransparent, SerializedKind_t serializedKind, + IsDynamicallyReplaceable_t isDynamic, IsDistributed_t isDistributed, IsRuntimeAccessible_t isRuntimeAccessible, ProfileCounter entryCount = ProfileCounter(), IsThunk_t isThunk = IsNotThunk, @@ -104,7 +99,7 @@ class SILFunctionBuilder { SILLinkage linkage, StringRef name, CanSILFunctionType loweredType, GenericEnvironment *genericEnv, std::optional loc, IsBare_t isBareSILFunction, IsTransparent_t isTrans, - IsSerialized_t isSerialized, IsDynamicallyReplaceable_t isDynamic, + SerializedKind_t serializedKind, IsDynamicallyReplaceable_t isDynamic, IsDistributed_t isDistributed, IsRuntimeAccessible_t isRuntimeAccessible, ProfileCounter entryCount = ProfileCounter(), IsThunk_t isThunk = IsNotThunk, diff --git a/include/swift/SIL/SILGlobalVariable.h b/include/swift/SIL/SILGlobalVariable.h index f788a40210c97..2b507d465d722 100644 --- a/include/swift/SIL/SILGlobalVariable.h +++ b/include/swift/SIL/SILGlobalVariable.h @@ -69,7 +69,7 @@ class SILGlobalVariable /// The global variable's serialized attribute. /// Serialized means that the variable can be "inlined" into another module. /// Currently this flag is set for all global variables in the stdlib. - unsigned Serialized : 1; + unsigned Serialized : 2; /// Whether this is a 'let' property, which can only be initialized /// once (either in its declaration, or once later), making it immutable. @@ -97,7 +97,7 @@ class SILGlobalVariable SILBasicBlock StaticInitializerBlock; SILGlobalVariable(SILModule &M, SILLinkage linkage, - IsSerialized_t IsSerialized, StringRef mangledName, + SerializedKind_t serializedKind, StringRef mangledName, SILType loweredType, std::optional loc, VarDecl *decl); @@ -107,7 +107,7 @@ class SILGlobalVariable } static SILGlobalVariable * - create(SILModule &Module, SILLinkage Linkage, IsSerialized_t IsSerialized, + create(SILModule &Module, SILLinkage Linkage, SerializedKind_t serializedKind, StringRef MangledName, SILType LoweredType, std::optional Loc = std::nullopt, VarDecl *Decl = nullptr); @@ -151,10 +151,17 @@ class SILGlobalVariable /// potentially be inspected by the debugger. bool shouldBePreservedForDebugger() const; + /// Check if this global variable is [serialized]. This does not check + /// if it's [serialized_for_package]. + bool isSerialized() const; + + /// Check if this global variable is [serialized] or [serialized_for_package]. + bool isAnySerialized() const; + /// Get this global variable's serialized attribute. - IsSerialized_t isSerialized() const; - void setSerialized(IsSerialized_t isSerialized); - + SerializedKind_t getSerializedKind() const; + void setSerializedKind(SerializedKind_t isSerialized); + /// Is this an immutable 'let' property? bool isLet() const { return IsLet; } void setLet(bool isLet) { IsLet = isLet; } diff --git a/include/swift/SIL/SILLinkage.h b/include/swift/SIL/SILLinkage.h index adcac4737bc88..ee238d86f8fe4 100644 --- a/include/swift/SIL/SILLinkage.h +++ b/include/swift/SIL/SILLinkage.h @@ -141,7 +141,7 @@ enum { /// After the swiftmodule file is written, the IsSerialized flag is cleared from /// all functions. This means that optimizations after the serialization point /// are not limited anymore regarding serialized functions. -enum IsSerialized_t : unsigned char { +enum SerializedKind_t : uint8_t { /// The function is not inlinable and will not be serialized. IsNotSerialized, @@ -151,15 +151,30 @@ enum IsSerialized_t : unsigned char { /// This flag is only valid for Public, PublicNonABI, PublicExternal, /// HiddenExternal and Shared functions. /// Functions with external linkage (PublicExternal, HiddenExternal) will not - /// be serialized, because they are available in a different module (from which - /// they were de-serialized). + /// be serialized, because they are available in a different module (from + /// which they were de-serialized). /// - /// Functions with Shared linkage will only be serialized if they are referenced - /// from another serialized function (or table). + /// Functions with Shared linkage will only be serialized if they are + /// referenced from another serialized function (or table). /// /// This flag is removed from all functions after the serialization point in /// the optimizer pipeline. - IsSerialized + IsSerialized, + + /// This flag is valid for all linkages applicable to IsSerialized as well as + /// Package, PackageNonABI, and PackageExternal, if package-wide + /// serialization is enabled with Package-CMO optimization. + /// + /// The [serialized_for_package] attribute is used to indicate that a function + /// is serialized because of Package CMO, which allows loadable types in a + /// serialized function in a resiliently built module, which is otherwise illegal. + /// It's also used to determine during SIL deserialization whether loadable + /// types in a serialized function can be allowed in the client module that + /// imports the module built with Package CMO. If the client contains a [serialized] + /// function due to `@inlinable`, funtions with [serialized_for_package] from + /// the imported module are not allowed being inlined into the client function, + /// which is the correct behavior. + IsSerializedForPackage }; /// The scope in which a subclassable class can be subclassed. @@ -394,12 +409,16 @@ inline SILLinkage effectiveLinkageForClassMember(SILLinkage linkage, // protocol requirement, even if the extended type is not public; // then SILGen gives the member private linkage, ignoring the more // visible access level it was given in the AST. -inline bool -fixmeWitnessHasLinkageThatNeedsToBePublic(SILDeclRef witness) { +// +// Despite the FIXME above, this is still used to determine the linkage +// for witness thunks. In case package serialization is enabled, we need +// to take the package linkage into account so we can set a proper final +// linkage to the thunks in the witness table with a package linkage. +inline bool fixmeWitnessHasLinkageThatNeedsToBePublic(SILDeclRef witness, + bool isPackageVisible) { auto witnessLinkage = witness.getLinkage(ForDefinition); - return !hasPublicVisibility(witnessLinkage) - && (!hasSharedVisibility(witnessLinkage) - || !witness.isSerialized()); + return !hasPublicOrPackageVisibility(witnessLinkage, isPackageVisible) && + (!hasSharedVisibility(witnessLinkage) || !witness.isSerialized()); } } // end swift namespace diff --git a/include/swift/SIL/SILMoveOnlyDeinit.h b/include/swift/SIL/SILMoveOnlyDeinit.h index 203045800c13b..538a0d56272f3 100644 --- a/include/swift/SIL/SILMoveOnlyDeinit.h +++ b/include/swift/SIL/SILMoveOnlyDeinit.h @@ -29,7 +29,7 @@ namespace swift { -enum IsSerialized_t : unsigned char; +enum SerializedKind_t : uint8_t; class SILFunction; class SILModule; @@ -45,18 +45,18 @@ class SILMoveOnlyDeinit final : public SILAllocated { /// Whether or not this deinit table is serialized. If a deinit is not /// serialized, then other modules can not consume directly a move only type /// since the deinit can not be called directly. - bool serialized : 1; + unsigned serialized : 2; SILMoveOnlyDeinit() - : nominalDecl(nullptr), funcImpl(nullptr), serialized(false) {} + : nominalDecl(nullptr), funcImpl(nullptr), serialized(unsigned(IsNotSerialized)) {} SILMoveOnlyDeinit(NominalTypeDecl *nominaldecl, SILFunction *implementation, - bool serialized); + unsigned serialized); ~SILMoveOnlyDeinit(); public: static SILMoveOnlyDeinit *create(SILModule &mod, NominalTypeDecl *nominalDecl, - IsSerialized_t serialized, + SerializedKind_t serialized, SILFunction *funcImpl); NominalTypeDecl *getNominalDecl() const { return nominalDecl; } @@ -66,11 +66,15 @@ class SILMoveOnlyDeinit final : public SILAllocated { return funcImpl; } - IsSerialized_t isSerialized() const { - return serialized ? IsSerialized : IsNotSerialized; + bool isAnySerialized() const { + return SerializedKind_t(serialized) == IsSerialized || + SerializedKind_t(serialized) == IsSerializedForPackage; } - void setSerialized(IsSerialized_t inputSerialized) { - serialized = inputSerialized ? 1 : 0; + SerializedKind_t getSerializedKind() const { + return SerializedKind_t(serialized); + } + void setSerializedKind(SerializedKind_t inputSerialized) { + serialized = unsigned(inputSerialized); } void print(llvm::raw_ostream &os, bool verbose) const; diff --git a/include/swift/SIL/SILProperty.h b/include/swift/SIL/SILProperty.h index 52b3a89ee5d41..f89e8c0e4a2ef 100644 --- a/include/swift/SIL/SILProperty.h +++ b/include/swift/SIL/SILProperty.h @@ -36,7 +36,7 @@ class SILProperty : public llvm::ilist_node, { private: /// True if serialized. - bool Serialized; + unsigned Serialized : 2; /// The declaration the descriptor represents. AbstractStorageDecl *Decl; @@ -44,17 +44,23 @@ class SILProperty : public llvm::ilist_node, /// The key path component that represents its implementation. std::optional Component; - SILProperty(bool Serialized, AbstractStorageDecl *Decl, + SILProperty(unsigned Serialized, AbstractStorageDecl *Decl, std::optional Component) : Serialized(Serialized), Decl(Decl), Component(Component) {} public: - static SILProperty *create(SILModule &M, bool Serialized, + static SILProperty *create(SILModule &M, unsigned Serialized, AbstractStorageDecl *Decl, std::optional Component); - bool isSerialized() const { return Serialized; } - + bool isAnySerialized() const { + return SerializedKind_t(Serialized) == IsSerialized || + SerializedKind_t(Serialized) == IsSerializedForPackage; + } + SerializedKind_t getSerializedKind() const { + return SerializedKind_t(Serialized); + } + AbstractStorageDecl *getDecl() const { return Decl; } bool isTrivial() const { diff --git a/include/swift/SIL/SILVTable.h b/include/swift/SIL/SILVTable.h index cc290c47321bb..aa012b743fdd0 100644 --- a/include/swift/SIL/SILVTable.h +++ b/include/swift/SIL/SILVTable.h @@ -35,7 +35,7 @@ namespace swift { class ClassDecl; -enum IsSerialized_t : unsigned char; +enum SerializedKind_t : uint8_t; class SILFunction; class SILModule; @@ -120,30 +120,30 @@ class SILVTable final : public SILAllocated, /// Whether or not this vtable is serialized, which allows /// devirtualization from another module. - bool Serialized : 1; + unsigned SerializedKind : 2; /// The number of SILVTables entries. unsigned NumEntries : 31; /// Private constructor. Create SILVTables by calling SILVTable::create. - SILVTable(ClassDecl *c, SILType classType, IsSerialized_t serialized, + SILVTable(ClassDecl *c, SILType classType, SerializedKind_t serialized, ArrayRef entries); - public: +public: ~SILVTable(); /// Create a new SILVTable with the given method-to-implementation mapping. /// The SILDeclRef keys should reference the most-overridden members available /// through the class. static SILVTable *create(SILModule &M, ClassDecl *Class, SILType classType, - IsSerialized_t Serialized, + SerializedKind_t Serialized, ArrayRef Entries); /// Create a new SILVTable with the given method-to-implementation mapping. /// The SILDeclRef keys should reference the most-overridden members available /// through the class. static SILVTable *create(SILModule &M, ClassDecl *Class, - IsSerialized_t Serialized, + SerializedKind_t Serialized, ArrayRef Entries); /// Return the class that the vtable represents. @@ -155,13 +155,21 @@ class SILVTable final : public SILAllocated, SILType getClassType() const { return classType; } /// Returns true if this vtable is going to be (or was) serialized. - IsSerialized_t isSerialized() const { - return Serialized ? IsSerialized : IsNotSerialized; + bool isSerialized() const { + return SerializedKind_t(SerializedKind) == IsSerialized; + } + + bool isAnySerialized() const { + return SerializedKind_t(SerializedKind) == IsSerialized || + SerializedKind_t(SerializedKind) == IsSerializedForPackage; } + SerializedKind_t getSerializedKind() const { + return SerializedKind_t(SerializedKind); + } /// Sets the serialized flag. - void setSerialized(IsSerialized_t serialized) { - Serialized = (serialized ? 1 : 0); + void setSerializedKind(SerializedKind_t serializedKind) { + SerializedKind = serializedKind; } /// Return all of the method entries. diff --git a/include/swift/SIL/SILWitnessTable.h b/include/swift/SIL/SILWitnessTable.h index 0c0d08f3b0794..45a5821262e99 100644 --- a/include/swift/SIL/SILWitnessTable.h +++ b/include/swift/SIL/SILWitnessTable.h @@ -35,7 +35,7 @@ class SILFunction; class SILModule; class ProtocolConformance; class RootProtocolConformance; -enum IsSerialized_t : unsigned char; +enum SerializedKind_t : uint8_t; /// A mapping from each requirement of a protocol to the SIL-level entity /// satisfying the requirement for a concrete type. @@ -197,10 +197,10 @@ class SILWitnessTable : public llvm::ilist_node, /// Whether or not this witness table is serialized, which allows /// devirtualization from another module. - bool Serialized; + unsigned SerializedKind : 2; /// Private constructor for making SILWitnessTable definitions. - SILWitnessTable(SILModule &M, SILLinkage Linkage, IsSerialized_t Serialized, + SILWitnessTable(SILModule &M, SILLinkage Linkage, SerializedKind_t Serialized, StringRef name, RootProtocolConformance *conformance, ArrayRef entries, ArrayRef conditionalConformances); @@ -214,7 +214,7 @@ class SILWitnessTable : public llvm::ilist_node, public: /// Create a new SILWitnessTable definition with the given entries. static SILWitnessTable * - create(SILModule &M, SILLinkage Linkage, IsSerialized_t Serialized, + create(SILModule &M, SILLinkage Linkage, SerializedKind_t SerializedKind, RootProtocolConformance *conformance, ArrayRef entries, ArrayRef conditionalConformances); @@ -252,13 +252,21 @@ class SILWitnessTable : public llvm::ilist_node, bool isDefinition() const { return !isDeclaration(); } /// Returns true if this witness table is going to be (or was) serialized. - IsSerialized_t isSerialized() const { - return Serialized ? IsSerialized : IsNotSerialized; + bool isSerialized() const { + return SerializedKind_t(SerializedKind) == IsSerialized; } + bool isAnySerialized() const { + return SerializedKind_t(SerializedKind) == IsSerialized || + SerializedKind_t(SerializedKind) == IsSerializedForPackage; + } + + SerializedKind_t getSerializedKind() const { + return SerializedKind_t(SerializedKind); + } /// Sets the serialized flag. - void setSerialized(IsSerialized_t serialized) { - Serialized = (serialized ? 1 : 0); + void setSerializedKind(SerializedKind_t serializedKind) { + SerializedKind = serializedKind; } /// Return all of the witness table entries. @@ -295,11 +303,11 @@ class SILWitnessTable : public llvm::ilist_node, void convertToDefinition(ArrayRef newEntries, ArrayRef conditionalConformances, - IsSerialized_t isSerialized); + SerializedKind_t serializedKind); - // Whether a conformance should be serialized. - static bool - conformanceIsSerialized(const RootProtocolConformance *conformance); + // Gets conformance serialized kind. + static SerializedKind_t + conformanceSerializedKind(const RootProtocolConformance *conformance); /// Call \c fn on each (split apart) conditional requirement of \c conformance /// that should appear in a witness table, i.e., conformance requirements that diff --git a/include/swift/SIL/TypeSubstCloner.h b/include/swift/SIL/TypeSubstCloner.h index 57783c0e2d643..450b62404f83e 100644 --- a/include/swift/SIL/TypeSubstCloner.h +++ b/include/swift/SIL/TypeSubstCloner.h @@ -446,7 +446,7 @@ class TypeSubstCloner : public SILClonerWithScopes { ParentFunction = FuncBuilder.getOrCreateFunction( ParentFunction->getLocation(), MangledName, SILLinkage::Shared, ParentFunction->getLoweredFunctionType(), ParentFunction->isBare(), - ParentFunction->isTransparent(), ParentFunction->isSerialized(), + ParentFunction->isTransparent(), ParentFunction->getSerializedKind(), IsNotDynamic, IsNotDistributed, IsNotRuntimeAccessible, 0, ParentFunction->isThunk(), ParentFunction->getClassSubclassScope()); // Increment the ref count for the inlined function, so it doesn't diff --git a/include/swift/SILOptimizer/Utils/GenericCloner.h b/include/swift/SILOptimizer/Utils/GenericCloner.h index 39deba38428ca..cc049f1bda00a 100644 --- a/include/swift/SILOptimizer/Utils/GenericCloner.h +++ b/include/swift/SILOptimizer/Utils/GenericCloner.h @@ -34,7 +34,7 @@ class GenericCloner using SuperTy = TypeSubstCloner; SILOptFunctionBuilder &FuncBuilder; - IsSerialized_t Serialized; + SerializedKind_t Serialized; const ReabstractionInfo &ReInfo; CloneCollector::CallbackType Callback; llvm::SmallDenseMap diff --git a/include/swift/SILOptimizer/Utils/Generics.h b/include/swift/SILOptimizer/Utils/Generics.h index 66f1f41c09c04..137b18a572153 100644 --- a/include/swift/SILOptimizer/Utils/Generics.h +++ b/include/swift/SILOptimizer/Utils/Generics.h @@ -156,8 +156,8 @@ class ReabstractionInfo { bool isPrespecialization = false; // Is the generated specialization going to be serialized? - IsSerialized_t Serialized = IsNotSerialized; - + SerializedKind_t Serialized = IsNotSerialized; + enum TypeCategory { NotLoadable, Loadable, @@ -201,13 +201,10 @@ class ReabstractionInfo { /// substitutions \p ParamSubs. /// If specialization is not possible getSpecializedType() will return an /// invalid type. - ReabstractionInfo(ModuleDecl *targetModule, - bool isModuleWholeModule, + ReabstractionInfo(ModuleDecl *targetModule, bool isModuleWholeModule, ApplySite Apply, SILFunction *Callee, - SubstitutionMap ParamSubs, - IsSerialized_t Serialized, - bool ConvertIndirectToDirect, - bool dropMetatypeArgs, + SubstitutionMap ParamSubs, SerializedKind_t Serialized, + bool ConvertIndirectToDirect, bool dropMetatypeArgs, OptRemark::Emitter *ORE = nullptr); /// Constructs the ReabstractionInfo for generic function \p Callee with @@ -226,9 +223,8 @@ class ReabstractionInfo { bool isPrespecialized() const { return isPrespecialization; } - IsSerialized_t isSerialized() const { - return Serialized; - } + bool isSerialized() const { return Serialized == IsSerialized; } + SerializedKind_t getSerializedKind() const { return Serialized; } unsigned param2ArgIndex(unsigned ParamIdx) const { return ParamIdx + NumFormalIndirectResults + (hasIndirectErrorResult ? 1: 0); diff --git a/include/swift/SILOptimizer/Utils/SpecializationMangler.h b/include/swift/SILOptimizer/Utils/SpecializationMangler.h index 87e3e6f82602f..70b45b2af42b7 100644 --- a/include/swift/SILOptimizer/Utils/SpecializationMangler.h +++ b/include/swift/SILOptimizer/Utils/SpecializationMangler.h @@ -34,7 +34,7 @@ class PartialSpecializationMangler : public SpecializationMangler { public: PartialSpecializationMangler(SILFunction *F, CanSILFunctionType SpecializedFnTy, - IsSerialized_t Serialized, bool isReAbstracted) + swift::SerializedKind_t Serialized, bool isReAbstracted) : SpecializationMangler(SpecializationPass::GenericSpecializer, Serialized, F), SpecializedFnTy(SpecializedFnTy), isReAbstracted(isReAbstracted) {} @@ -93,7 +93,7 @@ class FunctionSignatureSpecializationMangler : public SpecializationMangler { public: FunctionSignatureSpecializationMangler(SpecializationPass Pass, - IsSerialized_t Serialized, + swift::SerializedKind_t Serialized, SILFunction *F); // For arguments / return values void setArgumentConstantProp(unsigned OrigArgIdx, SILInstruction *constInst); diff --git a/include/swift/Serialization/Validation.h b/include/swift/Serialization/Validation.h index d7b95270e6530..1b0855c20d56e 100644 --- a/include/swift/Serialization/Validation.h +++ b/include/swift/Serialization/Validation.h @@ -141,6 +141,7 @@ class ExtendedValidationInfo { unsigned IsConcurrencyChecked : 1; unsigned HasCxxInteroperability : 1; unsigned AllowNonResilientAccess: 1; + unsigned SerializePackageEnabled: 1; } Bits; public: ExtendedValidationInfo() : Bits() {} @@ -209,6 +210,10 @@ class ExtendedValidationInfo { void setAllowNonResilientAccess(bool val) { Bits.AllowNonResilientAccess = val; } + bool serializePackageEnabled() const { return Bits.SerializePackageEnabled; } + void setSerializePackageEnabled(bool val) { + Bits.SerializePackageEnabled = val; + } bool isAllowModuleWithCompilerErrorsEnabled() { return Bits.IsAllowModuleWithCompilerErrorsEnabled; } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 4b83a4d0262d1..c59e8d0008c1a 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -3039,6 +3039,10 @@ bool Decl::isOutermostPrivateOrFilePrivateScope() const { !isInPrivateOrLocalContext(this); } +bool AbstractStorageDecl::isStrictlyResilient() const { + return isResilient() && !getModuleContext()->allowNonResilientAccess(); +} + bool AbstractStorageDecl::isResilient() const { // Check for an explicit @_fixed_layout attribute. if (getAttrs().hasAttribute()) @@ -3067,9 +3071,6 @@ bool AbstractStorageDecl::isResilient(ModuleDecl *M, case ResilienceExpansion::Maximal: if (M == getModuleContext()) return false; - // Non-resilient if bypass optimization in package is enabled - if (bypassResilienceInPackage(M)) - return false; return isResilient(); } llvm_unreachable("bad resilience expansion"); @@ -4278,13 +4279,23 @@ bool ValueDecl::hasOpenAccess(const DeclContext *useDC) const { } bool ValueDecl::bypassResilienceInPackage(ModuleDecl *accessingModule) const { - // Client needs to opt in to bypass resilience checks at the use site. - // Client and the loaded module both need to be in the same package. - // The loaded module needs to be built from source and opt in to allow - // non-resilient access. - return getASTContext().LangOpts.EnableBypassResilienceInPackage && - getModuleContext()->inSamePackage(accessingModule) && - getModuleContext()->allowNonResilientAccess(); + auto declModule = getModuleContext(); + if (declModule->inSamePackage(accessingModule) && + declModule->allowNonResilientAccess()) { + // If the defining module is built with package-cmo, + // allow direct access from the use site that belongs + // to accessingModule (client module). + if (declModule->isResilient() && + declModule->serializePackageEnabled()) + return true; + + // If not, check if the client can still opt in to + // have a direct access to this decl from the use + // site with a flag. + // FIXME: serialize this flag to Module and get it via accessingModule. + return getASTContext().LangOpts.EnableBypassResilienceInPackage; + } + return false; } /// Given the formal access level for using \p VD, compute the scope where @@ -5109,6 +5120,10 @@ bool NominalTypeDecl::isResilient() const { return getModuleContext()->isResilient(); } +bool NominalTypeDecl::isStrictlyResilient() const { + return isResilient() && !getModuleContext()->allowNonResilientAccess(); +} + DestructorDecl *NominalTypeDecl::getValueTypeDestructor() { if (!isa(this) && !isa(this)) { return nullptr; @@ -5139,7 +5154,7 @@ bool NominalTypeDecl::isResilient(ModuleDecl *M, // non-resiliently in a maximal context. if (M == getModuleContext()) return false; - // Non-resilient if bypass optimization in package is enabled + // Access non-resiliently if package optimization is enabled if (bypassResilienceInPackage(M)) return false; @@ -9896,6 +9911,11 @@ bool OpaqueTypeDecl::exportUnderlyingType() const { if (mod->getResilienceStrategy() != ResilienceStrategy::Resilient) return true; + // If we perform package CMO, in-package clients must have access to the + // underlying type. + if (mod->serializePackageEnabled()) + return true; + ValueDecl *namingDecl = getNamingDecl(); if (auto *AFD = dyn_cast(namingDecl)) return AFD->getResilienceExpansion() == ResilienceExpansion::Minimal; diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index 5fa3c01a071e9..b2e7259f75ff4 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -725,6 +725,7 @@ ModuleDecl::ModuleDecl(Identifier name, ASTContext &ctx, Bits.ModuleDecl.ObjCNameLookupCachePopulated = 0; Bits.ModuleDecl.HasCxxInteroperability = 0; Bits.ModuleDecl.AllowNonResilientAccess = 0; + Bits.ModuleDecl.SerializePackageEnabled = 0; } void ModuleDecl::setIsSystemModule(bool flag) { diff --git a/lib/AST/TypeSubstitution.cpp b/lib/AST/TypeSubstitution.cpp index 9f1f2d4a9b5ad..1d017f6d54a45 100644 --- a/lib/AST/TypeSubstitution.cpp +++ b/lib/AST/TypeSubstitution.cpp @@ -1003,6 +1003,14 @@ ReplaceOpaqueTypesWithUnderlyingTypes::shouldPerformSubstitution( module == contextModule) return OpaqueSubstitutionKind::SubstituteSameModuleMaximalResilience; + // Allow replacement of opaque result types in the context of maximal + // resilient expansion if the context's and the opaque type's module are in + // the same package. + if (contextExpansion == ResilienceExpansion::Maximal && + module->isResilient() && module->serializePackageEnabled() && + module->inSamePackage(contextModule)) + return OpaqueSubstitutionKind::SubstituteSamePackageMaximalResilience; + // Allow general replacement from non resilient modules. Otherwise, disallow. if (module->isResilient()) return OpaqueSubstitutionKind::DontSubstitute; @@ -1066,6 +1074,10 @@ static bool canSubstituteTypeInto(Type ty, const DeclContext *dc, return typeDecl->getEffectiveAccess() > AccessLevel::FilePrivate; + case OpaqueSubstitutionKind::SubstituteSamePackageMaximalResilience: { + return typeDecl->getEffectiveAccess() >= AccessLevel::Package; + } + case OpaqueSubstitutionKind::SubstituteNonResilientModule: // Can't access types that are not public from a different module. if (dc->getParentModule() == typeDecl->getDeclContext()->getParentModule() && diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 4beea4d7b512b..0a18793686152 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1568,6 +1568,7 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, static bool ParseTypeCheckerArgs(TypeCheckerOptions &Opts, ArgList &Args, DiagnosticEngine &Diags, + const LangOptions &LangOpts, const FrontendOptions &FrontendOpts) { using namespace options; @@ -1608,17 +1609,43 @@ static bool ParseTypeCheckerArgs(TypeCheckerOptions &Opts, ArgList &Args, // Check for SkipFunctionBodies arguments in order from skipping less to // skipping more. if (Args.hasArg( - OPT_experimental_skip_non_inlinable_function_bodies_without_types)) - Opts.SkipFunctionBodies = FunctionBodySkipping::NonInlinableWithoutTypes; + OPT_experimental_skip_non_inlinable_function_bodies_without_types)) { + if (LangOpts.AllowNonResilientAccess) + Diags.diagnose(SourceLoc(), diag::warn_ignore_option_overriden_by, + "-experimental-skip-non-inlinable-function-bodies-without-types", + "-experimental-allow-non-resilient-access"); + else + Opts.SkipFunctionBodies = FunctionBodySkipping::NonInlinableWithoutTypes; + } // If asked to perform InstallAPI, go ahead and enable non-inlinable function // body skipping. - if (Args.hasArg(OPT_experimental_skip_non_inlinable_function_bodies) || - Args.hasArg(OPT_tbd_is_installapi)) - Opts.SkipFunctionBodies = FunctionBodySkipping::NonInlinable; + if (Args.hasArg(OPT_experimental_skip_non_inlinable_function_bodies)) { + if (LangOpts.AllowNonResilientAccess) + Diags.diagnose(SourceLoc(), diag::warn_ignore_option_overriden_by, + "-experimental-skip-non-inlinable-function-bodies", + "-experimental-allow-non-resilient-access"); + else + Opts.SkipFunctionBodies = FunctionBodySkipping::NonInlinable; + } + + if (Args.hasArg(OPT_tbd_is_installapi)) { + if (LangOpts.AllowNonResilientAccess) + Diags.diagnose(SourceLoc(), diag::warn_ignore_option_overriden_by, + "-tbd-is-installapi", + "-experimental-allow-non-resilient-access"); + else + Opts.SkipFunctionBodies = FunctionBodySkipping::NonInlinable; + } - if (Args.hasArg(OPT_experimental_skip_all_function_bodies)) - Opts.SkipFunctionBodies = FunctionBodySkipping::All; + if (Args.hasArg(OPT_experimental_skip_all_function_bodies)) { + if (LangOpts.AllowNonResilientAccess) + Diags.diagnose(SourceLoc(), diag::warn_ignore_option_overriden_by, + "-experimental-skip-all-function-bodies", + "-experimental-allow-non-resilient-access"); + else + Opts.SkipFunctionBodies = FunctionBodySkipping::All; + } if (Opts.SkipFunctionBodies != FunctionBodySkipping::None && FrontendOpts.ModuleName == SWIFT_ONONE_SUPPORT) { @@ -1685,6 +1712,14 @@ static bool ParseTypeCheckerArgs(TypeCheckerOptions &Opts, ArgList &Args, } } + if (LangOpts.AllowNonResilientAccess && + Opts.EnableLazyTypecheck) { + Diags.diagnose(SourceLoc(), diag::warn_ignore_option_overriden_by, + "-experimental-lazy-typecheck", + "-experimental-allow-non-resilient-access"); + Opts.EnableLazyTypecheck = false; + } + // HACK: The driver currently erroneously passes all flags to module interface // verification jobs. -experimental-skip-non-exportable-decls is not // appropriate for verification tasks and should be ignored, though. @@ -3431,7 +3466,7 @@ bool CompilerInvocation::parseArgs( return true; } - if (ParseTypeCheckerArgs(TypeCheckerOpts, ParsedArgs, Diags, FrontendOpts)) { + if (ParseTypeCheckerArgs(TypeCheckerOpts, ParsedArgs, Diags, LangOpts, FrontendOpts)) { return true; } diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index 654fe864e5d40..bca4a3d95613c 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -1429,6 +1429,8 @@ ModuleDecl *CompilerInstance::getMainModule() const { MainModule->setHasCxxInteroperability(); if (Invocation.getLangOptions().AllowNonResilientAccess) MainModule->setAllowNonResilientAccess(); + if (Invocation.getSILOptions().EnableSerializePackage) + MainModule->setSerializePackageEnabled(); // Register the main module with the AST context. Context->addLoadedModule(MainModule); diff --git a/lib/SIL/IR/Linker.cpp b/lib/SIL/IR/Linker.cpp index db9bd14a2f7cd..f2d950585e2bf 100644 --- a/lib/SIL/IR/Linker.cpp +++ b/lib/SIL/IR/Linker.cpp @@ -87,7 +87,7 @@ void SILLinkerVisitor::deserializeAndPushToWorklist(SILFunction *F) { return; } - assert((bool)F->isSerialized() == !Mod.isSerialized() && + assert(!F->isAnySerialized() == Mod.isSerialized() && "the de-serializer did set the wrong serialized flag"); F->setBare(IsBare); @@ -98,21 +98,23 @@ void SILLinkerVisitor::deserializeAndPushToWorklist(SILFunction *F) { } /// Deserialize a function and add it to the worklist for processing. -void SILLinkerVisitor::maybeAddFunctionToWorklist(SILFunction *F, - bool setToSerializable) { +void SILLinkerVisitor::maybeAddFunctionToWorklist( + SILFunction *F, SerializedKind_t callerSerializedKind) { SILLinkage linkage = F->getLinkage(); - assert((!setToSerializable || F->hasValidLinkageForFragileRef() || + assert((callerSerializedKind == IsNotSerialized || + F->hasValidLinkageForFragileRef(callerSerializedKind) || hasSharedVisibility(linkage)) && "called function has wrong linkage for serialized function"); - if (!F->isExternalDeclaration()) { // The function is already in the module, so no need to de-serialized it. // But check if we need to set the IsSerialized flag. // See the top-level comment for SILLinkerVisitor for details. - if (setToSerializable && !Mod.isSerialized() && - hasSharedVisibility(linkage) && !F->isSerialized()) { - F->setSerialized(IsSerialized); - + if (callerSerializedKind == IsSerialized && + hasSharedVisibility(linkage) && + !Mod.isSerialized() && + !F->isAnySerialized()) { + F->setSerializedKind(IsSerialized); + // Push the function to the worklist so that all referenced shared functions // are also set to IsSerialized. Worklist.push_back(F); @@ -148,7 +150,7 @@ void SILLinkerVisitor::maybeAddFunctionToWorklist(SILFunction *F, bool SILLinkerVisitor::processFunction(SILFunction *F) { // If F is a declaration, first deserialize it. if (F->isExternalDeclaration()) { - maybeAddFunctionToWorklist(F, /*setToSerializable*/ false); + maybeAddFunctionToWorklist(F, /*serializedKind*/ IsNotSerialized); } else { Worklist.push_back(F); } @@ -183,10 +185,12 @@ void SILLinkerVisitor::linkInVTable(ClassDecl *D) { // for processing. for (auto &entry : Vtbl->getEntries()) { SILFunction *impl = entry.getImplementation(); - if (!Vtbl->isSerialized() || impl->hasValidLinkageForFragileRef()) { + if (!Vtbl->isAnySerialized() || + impl->hasValidLinkageForFragileRef(Vtbl->getSerializedKind())) { // Deserialize and recursively walk any vtable entries that do not have // bodies yet. - maybeAddFunctionToWorklist(impl, Vtbl->isSerialized()); + maybeAddFunctionToWorklist(impl, + Vtbl->getSerializedKind()); } } @@ -213,19 +217,19 @@ void SILLinkerVisitor::visitPartialApplyInst(PartialApplyInst *PAI) { void SILLinkerVisitor::visitFunctionRefInst(FunctionRefInst *FRI) { maybeAddFunctionToWorklist(FRI->getReferencedFunction(), - FRI->getFunction()->isSerialized()); + FRI->getFunction()->getSerializedKind()); } void SILLinkerVisitor::visitDynamicFunctionRefInst( DynamicFunctionRefInst *FRI) { maybeAddFunctionToWorklist(FRI->getInitiallyReferencedFunction(), - FRI->getFunction()->isSerialized()); + FRI->getFunction()->getSerializedKind()); } void SILLinkerVisitor::visitPreviousDynamicFunctionRefInst( PreviousDynamicFunctionRefInst *FRI) { maybeAddFunctionToWorklist(FRI->getInitiallyReferencedFunction(), - FRI->getFunction()->isSerialized()); + FRI->getFunction()->getSerializedKind()); } // Eagerly visiting all used conformances leads to a large blowup @@ -315,7 +319,8 @@ void SILLinkerVisitor::visitProtocolConformance(ProtocolConformanceRef ref) { // Otherwise, deserialize the witness if it has shared linkage, or if // we were asked to deserialize everything. maybeAddFunctionToWorklist(E.getMethodWitness().Witness, - WT->isSerialized() || isAvailableExternally(WT->getLinkage())); + (WT->isSerialized() || isAvailableExternally(WT->getLinkage()) ? + IsSerialized : WT->getSerializedKind())); break; } @@ -445,7 +450,7 @@ void SILLinkerVisitor::process() { // If the containing module has been serialized, // Remove The Serialized state (if any) // This allows for more optimizations - Fn->setSerialized(IsSerialized_t::IsNotSerialized); + Fn->setSerializedKind(SerializedKind_t::IsNotSerialized); } if (Fn->getModule().getASTContext().LangOpts.hasFeature(Feature::Embedded) && diff --git a/lib/SIL/IR/Linker.h b/lib/SIL/IR/Linker.h index 00d78abd72d23..46ec4f0366af1 100644 --- a/lib/SIL/IR/Linker.h +++ b/lib/SIL/IR/Linker.h @@ -139,9 +139,10 @@ class SILLinkerVisitor : public SILInstructionVisitor { /// Consider a function for deserialization if the current linking mode /// requires it. /// - /// If `setToSerializable` is true than all shared functions which are referenced - /// from `F` are set to - void maybeAddFunctionToWorklist(SILFunction *F, bool setToSerializable); + /// If `callerSerializedKind` is IsSerialized, then all shared + /// functions which are referenced from `F` are set to be serialized. + void maybeAddFunctionToWorklist(SILFunction *F, + SerializedKind_t callerSerializedKind); /// Is the current mode link all? Link all implies we should try and link /// everything, not just transparent/shared functions. diff --git a/lib/SIL/IR/SILDeclRef.cpp b/lib/SIL/IR/SILDeclRef.cpp index eef961f07b695..e6fc550504118 100644 --- a/lib/SIL/IR/SILDeclRef.cpp +++ b/lib/SIL/IR/SILDeclRef.cpp @@ -464,6 +464,8 @@ static LinkageLimit getLinkageLimit(SILDeclRef constant) { return Limit::OnDemand; case Kind::GlobalAccessor: + // global unsafeMutableAddressor should be kept hidden if its decl + // is resilient. return cast(d)->isResilient() ? Limit::NeverPublic : Limit::None; case Kind::DefaultArgGenerator: @@ -510,7 +512,7 @@ static LinkageLimit getLinkageLimit(SILDeclRef constant) { return Limit::AlwaysEmitIntoClient; // FIXME: This should always be true. - if (d->getModuleContext()->isResilient()) + if (d->getModuleContext()->isStrictlyResilient()) return Limit::NeverPublic; break; @@ -534,7 +536,7 @@ SILLinkage SILDeclRef::getDefinitionLinkage() const { auto privateLinkage = [&]() { // Private decls may still be serialized if they are e.g in an inlinable // function. In such a case, they receive shared linkage. - return isSerialized() ? SILLinkage::Shared : SILLinkage::Private; + return isNotSerialized() ? SILLinkage::Private : SILLinkage::Shared; }; // Prespecializations are public. @@ -624,7 +626,11 @@ SILLinkage SILDeclRef::getDefinitionLinkage() const { case Limit::None: return SILLinkage::Package; case Limit::AlwaysEmitIntoClient: - return SILLinkage::PackageNonABI; + // Drop the AEIC if the enclosing decl is not effectively public. + // This matches what we do in the `internal` case. + if (isSerialized()) + return SILLinkage::PackageNonABI; + else return SILLinkage::Package; case Limit::OnDemand: return SILLinkage::Shared; case Limit::NeverPublic: @@ -792,8 +798,16 @@ bool SILDeclRef::isTransparent() const { return false; } +bool SILDeclRef::isSerialized() const { + return getSerializedKind() == IsSerialized; +} + +bool SILDeclRef::isNotSerialized() const { + return getSerializedKind() == IsNotSerialized; +} + /// True if the function should have its body serialized. -IsSerialized_t SILDeclRef::isSerialized() const { +SerializedKind_t SILDeclRef::getSerializedKind() const { if (auto closure = getAbstractClosureExpr()) { // Ask the AST if we're inside an @inlinable context. if (closure->getResilienceExpansion() == ResilienceExpansion::Minimal) { @@ -1531,10 +1545,10 @@ SubclassScope SILDeclRef::getSubclassScope() const { // FIXME: This is too narrow. Any class with resilient metadata should // probably have this, at least for method overrides that don't add new // vtable entries. - bool isResilientClass = classType->isResilient(); + bool isStrictResilientClass = classType->isStrictlyResilient(); if (auto *CD = dyn_cast(decl)) { - if (isResilientClass) + if (isStrictResilientClass) return SubclassScope::NotApplicable; // Initializing entry points do not appear in the vtable. if (kind == SILDeclRef::Kind::Initializer) @@ -1565,14 +1579,14 @@ SubclassScope SILDeclRef::getSubclassScope() const { // In the resilient case, we're going to be making symbols _less_ // visible, so make sure we stop now; final methods can always be // called directly. - if (isResilientClass) + if (isStrictResilientClass) return SubclassScope::Internal; } assert(decl->getEffectiveAccess() <= classType->getEffectiveAccess() && "class must be as visible as its members"); - if (isResilientClass) { + if (isStrictResilientClass) { // The symbol should _only_ be reached via the vtable, so we're // going to make it hidden. return SubclassScope::Resilient; diff --git a/lib/SIL/IR/SILFunction.cpp b/lib/SIL/IR/SILFunction.cpp index 0dce131413b9a..6ca75bbc3725b 100644 --- a/lib/SIL/IR/SILFunction.cpp +++ b/lib/SIL/IR/SILFunction.cpp @@ -153,7 +153,7 @@ SILFunction *SILFunction::create( SILModule &M, SILLinkage linkage, StringRef name, CanSILFunctionType loweredType, GenericEnvironment *genericEnv, std::optional loc, IsBare_t isBareSILFunction, - IsTransparent_t isTrans, IsSerialized_t isSerialized, + IsTransparent_t isTrans, SerializedKind_t serializedKind, ProfileCounter entryCount, IsDynamicallyReplaceable_t isDynamic, IsDistributed_t isDistributed, IsRuntimeAccessible_t isRuntimeAccessible, IsExactSelfClass_t isExactSelfClass, IsThunk_t isThunk, @@ -175,14 +175,14 @@ SILFunction *SILFunction::create( // This happens for example if a specialized function gets dead and gets // deleted. And afterwards the same specialization is created again. fn->init(linkage, name, loweredType, genericEnv, isBareSILFunction, isTrans, - isSerialized, entryCount, isThunk, classSubclassScope, + serializedKind, entryCount, isThunk, classSubclassScope, inlineStrategy, E, debugScope, isDynamic, isExactSelfClass, isDistributed, isRuntimeAccessible); assert(fn->empty()); } else { fn = new (M) SILFunction( M, linkage, name, loweredType, genericEnv, isBareSILFunction, isTrans, - isSerialized, entryCount, isThunk, classSubclassScope, inlineStrategy, + serializedKind, entryCount, isThunk, classSubclassScope, inlineStrategy, E, debugScope, isDynamic, isExactSelfClass, isDistributed, isRuntimeAccessible); } @@ -210,7 +210,7 @@ SILFunction::SILFunction( SILModule &Module, SILLinkage Linkage, StringRef Name, CanSILFunctionType LoweredType, GenericEnvironment *genericEnv, IsBare_t isBareSILFunction, IsTransparent_t isTrans, - IsSerialized_t isSerialized, ProfileCounter entryCount, IsThunk_t isThunk, + SerializedKind_t serializedKind, ProfileCounter entryCount, IsThunk_t isThunk, SubclassScope classSubclassScope, Inline_t inlineStrategy, EffectsKind E, const SILDebugScope *DebugScope, IsDynamicallyReplaceable_t isDynamic, IsExactSelfClass_t isExactSelfClass, IsDistributed_t isDistributed, @@ -219,7 +219,7 @@ SILFunction::SILFunction( index(Module.getNewFunctionIndex()), Availability(AvailabilityContext::alwaysAvailable()) { init(Linkage, Name, LoweredType, genericEnv, isBareSILFunction, isTrans, - isSerialized, entryCount, isThunk, classSubclassScope, inlineStrategy, E, + serializedKind, entryCount, isThunk, classSubclassScope, inlineStrategy, E, DebugScope, isDynamic, isExactSelfClass, isDistributed, isRuntimeAccessible); @@ -233,7 +233,7 @@ SILFunction::SILFunction( void SILFunction::init( SILLinkage Linkage, StringRef Name, CanSILFunctionType LoweredType, GenericEnvironment *genericEnv, IsBare_t isBareSILFunction, - IsTransparent_t isTrans, IsSerialized_t isSerialized, + IsTransparent_t isTrans, SerializedKind_t serializedKind, ProfileCounter entryCount, IsThunk_t isThunk, SubclassScope classSubclassScope, Inline_t inlineStrategy, EffectsKind E, const SILDebugScope *DebugScope, IsDynamicallyReplaceable_t isDynamic, @@ -250,7 +250,7 @@ void SILFunction::init( this->Availability = AvailabilityContext::alwaysAvailable(); this->Bare = isBareSILFunction; this->Transparent = isTrans; - this->Serialized = isSerialized; + this->SerializedKind = serializedKind; this->Thunk = isThunk; this->ClassSubclassScope = unsigned(classSubclassScope); this->GlobalInitFlag = false; @@ -322,7 +322,7 @@ void SILFunction::createSnapshot(int id) { SILFunction *newSnapshot = new (Module) SILFunction( Module, getLinkage(), getName(), getLoweredFunctionType(), - getGenericEnvironment(), isBare(), isTransparent(), isSerialized(), + getGenericEnvironment(), isBare(), isTransparent(), getSerializedKind(), getEntryCount(), isThunk(), getClassSubclassScope(), getInlineStrategy(), getEffectsKind(), getDebugScope(), isDynamicallyReplaceable(), isExactSelfClass(), isDistributed(), isRuntimeAccessible()); @@ -545,6 +545,19 @@ bool SILFunction::isNoReturnFunction(TypeExpansionContext context) const { .isNoReturnFunction(getModule(), context); } +ResilienceExpansion SILFunction::getResilienceExpansion() const { + // If a function definition is in another module, and + // it was serialized due to package serialization opt, + // a new attribute [serialized_for_package] is added + // to the definition site. During deserialization, this + // attribute is preserved if the current module is in + // the same package, thus should be in the same resilience + // domain. + return (isSerialized() + ? ResilienceExpansion::Minimal + : ResilienceExpansion::Maximal); +} + const TypeLowering & SILFunction::getTypeLowering(AbstractionPattern orig, Type subst) { return getModule().Types.getTypeLowering(orig, subst, @@ -903,16 +916,62 @@ bool SILFunction::hasName(const char *Name) const { return getName() == Name; } +/* + Checks if this (callee) function body can be inlined into the caller + by comparing their SerializedKind_t values. + + If both callee and caller are not_serialized, the callee can be inlined + into the caller during SIL inlining passes even if it (and the caller) + might contain private symbols. If this callee is serialized_for_pkg, it + can only be referenced by a serialized caller but not inlined into it. + + canInlineInto: Caller + | not_serialized | serialized_for_pkg | serialized + not_serialized | ok | no | no +Callee serialized_for_pkg | ok | ok | no + serialized | ok | ok | ok + +*/ +bool SILFunction::canBeInlinedIntoCaller(SerializedKind_t callerSerializedKind) const { + switch (getSerializedKind()) { + // If both callee and caller are not_serialized, the callee + // can be inlined into the caller during SIL inlining passes + // even if it (and the caller) might contain private symbols. + case IsNotSerialized: + return callerSerializedKind == IsNotSerialized; + + // If Package-CMO is enabled, we serialize package, public, + // and @usableFromInline decls as [serialized_for_package]. + // Their bodies must not, however, leak into @inlinable + // functons (that are [serialized]) since they are inlined + // outside of their defining module. + // + // If this callee is [serialized_for_package], the caller + // must be either non-serialized or [serialized_for_package] + // for this callee's body to be inlined into the caller. + // It can however be referenced by [serialized] caller. + case IsSerializedForPackage: + return callerSerializedKind != IsSerialized; + case IsSerialized: + return true; + } + llvm_unreachable("Invalid serialized kind"); +} + /// Returns true if this function can be referenced from a fragile function /// body. -bool SILFunction::hasValidLinkageForFragileRef() const { +bool SILFunction::hasValidLinkageForFragileRef(SerializedKind_t callerSerializedKind) const { // Fragile functions can reference 'static inline' functions imported // from C. if (hasForeignBody()) return true; + // The call site of this function must have checked that + // caller.isAnySerialized() is true, as indicated by the + // function name itself (contains 'ForFragileRef'). + assert(callerSerializedKind != IsNotSerialized); // If we can inline it, we can reference it. - if (hasValidLinkageForFragileInline()) + if (canBeInlinedIntoCaller(callerSerializedKind)) return true; // If the containing module has been serialized already, we no longer diff --git a/lib/SIL/IR/SILFunctionBuilder.cpp b/lib/SIL/IR/SILFunctionBuilder.cpp index feb2db7927e52..7344864d2c3da 100644 --- a/lib/SIL/IR/SILFunctionBuilder.cpp +++ b/lib/SIL/IR/SILFunctionBuilder.cpp @@ -24,8 +24,9 @@ using namespace swift; SILFunction *SILFunctionBuilder::getOrCreateFunction( - SILLocation loc, StringRef name, SILLinkage linkage, CanSILFunctionType type, IsBare_t isBareSILFunction, - IsTransparent_t isTransparent, IsSerialized_t isSerialized, + SILLocation loc, StringRef name, SILLinkage linkage, + CanSILFunctionType type, IsBare_t isBareSILFunction, + IsTransparent_t isTransparent, SerializedKind_t serializedKind, IsDynamicallyReplaceable_t isDynamic, IsDistributed_t isDistributed, IsRuntimeAccessible_t isRuntimeAccessible, ProfileCounter entryCount, IsThunk_t isThunk, SubclassScope subclassScope) { @@ -38,7 +39,7 @@ SILFunction *SILFunctionBuilder::getOrCreateFunction( } auto fn = SILFunction::create(mod, linkage, name, type, nullptr, loc, - isBareSILFunction, isTransparent, isSerialized, + isBareSILFunction, isTransparent, serializedKind, entryCount, isDynamic, isDistributed, isRuntimeAccessible, IsNotExactSelfClass, isThunk, subclassScope); @@ -329,9 +330,9 @@ SILFunction *SILFunctionBuilder::getOrCreateFunction( IsTransparent_t IsTrans = constant.isTransparent() ? IsTransparent : IsNotTransparent; - IsSerialized_t IsSer = constant.isSerialized(); + SerializedKind_t IsSer = constant.getSerializedKind(); // Don't create a [serialized] function after serialization has happened. - if (IsSer == IsSerialized && mod.isSerialized()) + if (IsSer != IsNotSerialized && mod.isSerialized()) IsSer = IsNotSerialized; Inline_t inlineStrategy = InlineDefault; @@ -408,11 +409,11 @@ SILFunction *SILFunctionBuilder::getOrCreateFunction( SILFunction *SILFunctionBuilder::getOrCreateSharedFunction( SILLocation loc, StringRef name, CanSILFunctionType type, IsBare_t isBareSILFunction, IsTransparent_t isTransparent, - IsSerialized_t isSerialized, ProfileCounter entryCount, IsThunk_t isThunk, + SerializedKind_t serializedKind, ProfileCounter entryCount, IsThunk_t isThunk, IsDynamicallyReplaceable_t isDynamic, IsDistributed_t isDistributed, IsRuntimeAccessible_t isRuntimeAccessible) { return getOrCreateFunction(loc, name, SILLinkage::Shared, type, - isBareSILFunction, isTransparent, isSerialized, + isBareSILFunction, isTransparent, serializedKind, isDynamic, isDistributed, isRuntimeAccessible, entryCount, isThunk, SubclassScope::NotApplicable); } @@ -421,13 +422,13 @@ SILFunction *SILFunctionBuilder::createFunction( SILLinkage linkage, StringRef name, CanSILFunctionType loweredType, GenericEnvironment *genericEnv, std::optional loc, IsBare_t isBareSILFunction, IsTransparent_t isTrans, - IsSerialized_t isSerialized, IsDynamicallyReplaceable_t isDynamic, + SerializedKind_t serializedKind, IsDynamicallyReplaceable_t isDynamic, IsDistributed_t isDistributed, IsRuntimeAccessible_t isRuntimeAccessible, ProfileCounter entryCount, IsThunk_t isThunk, SubclassScope subclassScope, Inline_t inlineStrategy, EffectsKind EK, SILFunction *InsertBefore, const SILDebugScope *DebugScope) { return SILFunction::create(mod, linkage, name, loweredType, genericEnv, loc, - isBareSILFunction, isTrans, isSerialized, + isBareSILFunction, isTrans, serializedKind, entryCount, isDynamic, isDistributed, isRuntimeAccessible, IsNotExactSelfClass, isThunk, subclassScope, inlineStrategy, EK, InsertBefore, diff --git a/lib/SIL/IR/SILGlobalVariable.cpp b/lib/SIL/IR/SILGlobalVariable.cpp index 0131de8008149..ef4fc1388e8ae 100644 --- a/lib/SIL/IR/SILGlobalVariable.cpp +++ b/lib/SIL/IR/SILGlobalVariable.cpp @@ -22,7 +22,7 @@ using namespace swift; SwiftMetatype SILGlobalVariable::registeredMetatype; SILGlobalVariable *SILGlobalVariable::create(SILModule &M, SILLinkage linkage, - IsSerialized_t isSerialized, + SerializedKind_t serializedKind, StringRef name, SILType loweredType, std::optional loc, @@ -35,7 +35,7 @@ SILGlobalVariable *SILGlobalVariable::create(SILModule &M, SILLinkage linkage, assert(!entry->getValue() && "global variable already exists"); name = entry->getKey(); - auto var = new (M) SILGlobalVariable(M, linkage, isSerialized, name, + auto var = new (M) SILGlobalVariable(M, linkage, serializedKind, name, loweredType, loc, Decl); if (entry) entry->setValue(var); @@ -43,14 +43,14 @@ SILGlobalVariable *SILGlobalVariable::create(SILModule &M, SILLinkage linkage, } SILGlobalVariable::SILGlobalVariable(SILModule &Module, SILLinkage Linkage, - IsSerialized_t isSerialized, + SerializedKind_t serializedKind, StringRef Name, SILType LoweredType, std::optional Loc, VarDecl *Decl) : SwiftObjectHeader(registeredMetatype), Module(Module), Name(Name), LoweredType(LoweredType), Location(Loc.value_or(SILLocation::invalid())), Linkage(unsigned(Linkage)), HasLocation(Loc.has_value()), VDecl(Decl) { - setSerialized(isSerialized); + setSerializedKind(serializedKind); IsDeclaration = isAvailableExternally(Linkage); setLet(Decl ? Decl->isLet() : false); Module.silGlobals.push_back(this); @@ -75,12 +75,22 @@ bool SILGlobalVariable::shouldBePreservedForDebugger() const { return VDecl != nullptr; } +bool SILGlobalVariable::isSerialized() const { + return SerializedKind_t(Serialized) == IsSerialized; +} + +bool SILGlobalVariable::isAnySerialized() const { + return SerializedKind_t(Serialized) == IsSerialized || + SerializedKind_t(Serialized) == IsSerializedForPackage; +} + /// Get this global variable's fragile attribute. -IsSerialized_t SILGlobalVariable::isSerialized() const { - return Serialized ? IsSerialized : IsNotSerialized; +SerializedKind_t SILGlobalVariable::getSerializedKind() const { + return SerializedKind_t(Serialized); } -void SILGlobalVariable::setSerialized(IsSerialized_t isSerialized) { - Serialized = isSerialized ? 1 : 0; + +void SILGlobalVariable::setSerializedKind(SerializedKind_t serializedKind) { + Serialized = unsigned(serializedKind); } /// Return the value that is written into the global variable. diff --git a/lib/SIL/IR/SILModule.cpp b/lib/SIL/IR/SILModule.cpp index 6dca4a99de5ff..1432c5f3ffd72 100644 --- a/lib/SIL/IR/SILModule.cpp +++ b/lib/SIL/IR/SILModule.cpp @@ -936,7 +936,7 @@ void SILModule::performOnceForPrespecializedImportedExtensions( } SILProperty * -SILProperty::create(SILModule &M, bool Serialized, AbstractStorageDecl *Decl, +SILProperty::create(SILModule &M, unsigned Serialized, AbstractStorageDecl *Decl, std::optional Component) { auto prop = new (M) SILProperty(Serialized, Decl, Component); M.properties.push_back(prop); diff --git a/lib/SIL/IR/SILMoveOnlyDeinit.cpp b/lib/SIL/IR/SILMoveOnlyDeinit.cpp index 7a5cc6da36edd..4821871d0261b 100644 --- a/lib/SIL/IR/SILMoveOnlyDeinit.cpp +++ b/lib/SIL/IR/SILMoveOnlyDeinit.cpp @@ -18,12 +18,12 @@ using namespace swift; SILMoveOnlyDeinit *SILMoveOnlyDeinit::create(SILModule &mod, NominalTypeDecl *nominalDecl, - IsSerialized_t serialized, + SerializedKind_t serialized, SILFunction *funcImpl) { auto buf = mod.allocate(sizeof(SILMoveOnlyDeinit), alignof(SILMoveOnlyDeinit)); auto *table = - ::new (buf) SILMoveOnlyDeinit(nominalDecl, funcImpl, serialized); + ::new (buf) SILMoveOnlyDeinit(nominalDecl, funcImpl, unsigned(serialized)); mod.moveOnlyDeinits.push_back(table); mod.MoveOnlyDeinitMap[nominalDecl] = table; return table; @@ -31,7 +31,7 @@ SILMoveOnlyDeinit *SILMoveOnlyDeinit::create(SILModule &mod, SILMoveOnlyDeinit::SILMoveOnlyDeinit(NominalTypeDecl *nominalDecl, SILFunction *implementation, - bool serialized) + unsigned serialized) : nominalDecl(nominalDecl), funcImpl(implementation), serialized(serialized) { assert(funcImpl); diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp index 04f89d2f77219..54198c33aae2f 100644 --- a/lib/SIL/IR/SILPrinter.cpp +++ b/lib/SIL/IR/SILPrinter.cpp @@ -3281,6 +3281,20 @@ static void printLinkage(llvm::raw_ostream &OS, SILLinkage linkage, OS << getLinkageString(linkage); } + +static void printSerializedKind(llvm::raw_ostream &OS, SerializedKind_t kind) { + switch (kind) { + case IsNotSerialized: + break; + case IsSerializedForPackage: + OS << "[serialized_for_package] "; + break; + case IsSerialized: + OS << "[serialized] "; + break; + } +} + static void printClangQualifiedNameCommentIfPresent(llvm::raw_ostream &OS, const clang::Decl *decl) { if (decl) { @@ -3334,10 +3348,7 @@ void SILFunction::print(SILPrintContext &PrintCtx) const { if (isTransparent()) OS << "[transparent] "; - switch (isSerialized()) { - case IsNotSerialized: break; - case IsSerialized: OS << "[serialized] "; break; - } + printSerializedKind(OS, getSerializedKind()); switch (isThunk()) { case IsNotThunk: break; @@ -3523,10 +3534,8 @@ void SILGlobalVariable::print(llvm::raw_ostream &OS, bool Verbose) const { // Passing true for 'isDefinition' lets print the (external) linkage if it's // not a definition. printLinkage(OS, getLinkage(), /*isDefinition*/ true); + printSerializedKind(OS, getSerializedKind()); - if (isSerialized()) - OS << "[serialized] "; - if (isLet()) OS << "[let] "; @@ -3836,9 +3845,8 @@ void SILProperty::print(SILPrintContext &Ctx) const { auto &OS = Ctx.OS(); OS << "sil_property "; - if (isSerialized()) - OS << "[serialized] "; - + printSerializedKind(OS, getSerializedKind()); + OS << '#'; printValueDecl(getDecl(), OS); if (auto sig = getDecl()->getInnermostDeclContext() @@ -4015,8 +4023,8 @@ void SILVTableEntry::print(llvm::raw_ostream &OS) const { void SILVTable::print(llvm::raw_ostream &OS, bool Verbose) const { OS << "sil_vtable "; - if (isSerialized()) - OS << "[serialized] "; + printSerializedKind(OS, getSerializedKind()); + if (SILType classTy = getClassType()) { OS << classTy; } else { @@ -4036,8 +4044,7 @@ void SILVTable::dump() const { print(llvm::errs()); } void SILMoveOnlyDeinit::print(llvm::raw_ostream &OS, bool verbose) const { OS << "sil_moveonlydeinit "; - if (isSerialized()) - OS << "[serialized] "; + printSerializedKind(OS, getSerializedKind()); OS << getNominalDecl()->getName() << " {\n"; OS << " @" << getImplementation()->getName(); OS << "\t// " << demangleSymbol(getImplementation()->getName()); @@ -4127,8 +4134,7 @@ void SILWitnessTable::print(llvm::raw_ostream &OS, bool Verbose) const { PrintOptions QualifiedSILTypeOptions = PrintOptions::printQualifiedSILType(); OS << "sil_witness_table "; printLinkage(OS, getLinkage(), /*isDefinition*/ isDefinition()); - if (isSerialized()) - OS << "[serialized] "; + printSerializedKind(OS, getSerializedKind()); getConformance()->printName(OS, Options); Options.GenericSig = diff --git a/lib/SIL/IR/SILSymbolVisitor.cpp b/lib/SIL/IR/SILSymbolVisitor.cpp index 7cbc7d9a24136..9b8276d53352d 100644 --- a/lib/SIL/IR/SILSymbolVisitor.cpp +++ b/lib/SIL/IR/SILSymbolVisitor.cpp @@ -279,17 +279,19 @@ class SILSymbolVisitorImpl : public ASTVisitor { // FIXME: the logic around visibility in extensions is confusing, and // sometimes witness thunks need to be manually made public. - auto conformanceIsFixed = - SILWitnessTable::conformanceIsSerialized(rootConformance); + auto conformanceSeializedKind = + SILWitnessTable::conformanceSerializedKind(rootConformance); auto addSymbolIfNecessary = [&](ValueDecl *requirementDecl, ValueDecl *witnessDecl) { auto witnessRef = SILDeclRef(witnessDecl); if (Ctx.getOpts().PublicOrPackageSymbolsOnly) { - if (!conformanceIsFixed) + if (conformanceSeializedKind == IsNotSerialized) return; if (!isa(rootConformance) && - !fixmeWitnessHasLinkageThatNeedsToBePublic(witnessRef)) { + !fixmeWitnessHasLinkageThatNeedsToBePublic( + witnessRef, + witnessRef.getASTContext().SILOpts.EnableSerializePackage)) { return; } } @@ -577,7 +579,7 @@ class SILSymbolVisitorImpl : public ASTVisitor { void visitVarDecl(VarDecl *VD) { // Variables inside non-resilient modules have some additional symbols. - if (!VD->isResilient()) { + if (!VD->isStrictlyResilient()) { // Non-global variables might have an explicit initializer symbol in // non-resilient modules. if (VD->getAttrs().hasAttribute() && @@ -587,17 +589,14 @@ class SILSymbolVisitorImpl : public ASTVisitor { // Stored property initializers for public properties are public. addFunction(declRef); } - // Statically/globally stored variables have some special handling. if (VD->hasStorage() && isGlobalOrStaticVar(VD)) { if (!shouldSkipVisit(getDeclLinkage(VD))) { Visitor.addGlobalVar(VD); } - if (VD->isLazilyInitializedGlobal()) addFunction(SILDeclRef(VD, SILDeclRef::Kind::GlobalAccessor)); } - // Wrapped non-static member properties may have a backing initializer. auto initInfo = VD->getPropertyWrapperInitializerInfo(); if (initInfo.hasInitFromWrappedValue() && !VD->isStatic()) { @@ -605,7 +604,6 @@ class SILSymbolVisitorImpl : public ASTVisitor { VD, SILDeclRef::Kind::PropertyWrapperBackingInitializer)); } } - visitAbstractStorageDecl(VD); } diff --git a/lib/SIL/IR/SILVTable.cpp b/lib/SIL/IR/SILVTable.cpp index 29b0395f28b81..5a136476d9fa7 100644 --- a/lib/SIL/IR/SILVTable.cpp +++ b/lib/SIL/IR/SILVTable.cpp @@ -30,13 +30,13 @@ void SILVTableEntry::setImplementation(SILFunction *f) { } SILVTable *SILVTable::create(SILModule &M, ClassDecl *Class, - IsSerialized_t Serialized, - ArrayRef Entries) { + SerializedKind_t Serialized, + ArrayRef Entries) { return create(M, Class, SILType(), Serialized, Entries); } SILVTable *SILVTable::create(SILModule &M, ClassDecl *Class, SILType classType, - IsSerialized_t Serialized, + SerializedKind_t Serialized, ArrayRef Entries) { auto size = totalSizeToAlloc(Entries.size()); auto buf = M.allocate(size, alignof(SILVTable)); @@ -75,9 +75,10 @@ void SILVTable::updateVTableCache(const Entry &entry) { M.VTableEntryCache[{this, entry.getMethod()}] = entry; } -SILVTable::SILVTable(ClassDecl *c, SILType classType, IsSerialized_t serialized, - ArrayRef entries) - : Class(c), classType(classType), Serialized(serialized), NumEntries(entries.size()) { +SILVTable::SILVTable(ClassDecl *c, SILType classType, + SerializedKind_t serialized, ArrayRef entries) + : Class(c), classType(classType), SerializedKind(serialized), + NumEntries(entries.size()) { std::uninitialized_copy(entries.begin(), entries.end(), getTrailingObjects()); diff --git a/lib/SIL/IR/SILWitnessTable.cpp b/lib/SIL/IR/SILWitnessTable.cpp index d1b718340b694..cf090ba0c69ab 100644 --- a/lib/SIL/IR/SILWitnessTable.cpp +++ b/lib/SIL/IR/SILWitnessTable.cpp @@ -57,7 +57,7 @@ void SILWitnessTable::addWitnessTable() { } SILWitnessTable *SILWitnessTable::create( - SILModule &M, SILLinkage Linkage, IsSerialized_t Serialized, + SILModule &M, SILLinkage Linkage, SerializedKind_t SerializedKind, RootProtocolConformance *Conformance, ArrayRef entries, ArrayRef conditionalConformances) { @@ -72,7 +72,7 @@ SILWitnessTable *SILWitnessTable::create( // Allocate the witness table and initialize it. void *buf = M.allocate(sizeof(SILWitnessTable), alignof(SILWitnessTable)); SILWitnessTable *wt = ::new (buf) - SILWitnessTable(M, Linkage, Serialized, Name.str(), Conformance, entries, + SILWitnessTable(M, Linkage, SerializedKind, Name.str(), Conformance, entries, conditionalConformances); wt->addWitnessTable(); @@ -103,18 +103,20 @@ SILWitnessTable::create(SILModule &M, SILLinkage Linkage, } SILWitnessTable::SILWitnessTable( - SILModule &M, SILLinkage Linkage, IsSerialized_t Serialized, StringRef N, + SILModule &M, SILLinkage Linkage, SerializedKind_t SerializedKind, StringRef N, RootProtocolConformance *Conformance, ArrayRef entries, ArrayRef conditionalConformances) : Mod(M), Name(N), Linkage(Linkage), Conformance(Conformance), Entries(), - ConditionalConformances(), IsDeclaration(true), Serialized(false) { - convertToDefinition(entries, conditionalConformances, Serialized); + ConditionalConformances(), IsDeclaration(true), + SerializedKind(SerializedKind) { + convertToDefinition(entries, conditionalConformances, SerializedKind); } SILWitnessTable::SILWitnessTable(SILModule &M, SILLinkage Linkage, StringRef N, RootProtocolConformance *Conformance) : Mod(M), Name(N), Linkage(Linkage), Conformance(Conformance), Entries(), - ConditionalConformances(), IsDeclaration(true), Serialized(false) {} + ConditionalConformances(), IsDeclaration(true), + SerializedKind(IsNotSerialized) {} SILWitnessTable::~SILWitnessTable() { if (isDeclaration()) @@ -140,10 +142,10 @@ SILWitnessTable::~SILWitnessTable() { void SILWitnessTable::convertToDefinition( ArrayRef entries, ArrayRef conditionalConformances, - IsSerialized_t isSerialized) { + SerializedKind_t serializedKind) { assert(isDeclaration() && "Definitions should never call this method."); IsDeclaration = false; - Serialized = (isSerialized == IsSerialized); + SerializedKind = serializedKind; Entries = Mod.allocateCopy(entries); ConditionalConformances = Mod.allocateCopy(conditionalConformances); @@ -165,17 +167,25 @@ void SILWitnessTable::convertToDefinition( } } -bool SILWitnessTable::conformanceIsSerialized( - const RootProtocolConformance *conformance) { +SerializedKind_t SILWitnessTable::conformanceSerializedKind( + const RootProtocolConformance *conformance) { + + auto optInPackage = conformance->getDeclContext()->getParentModule()->serializePackageEnabled(); + auto accessLevelToCheck = + optInPackage ? AccessLevel::Package : AccessLevel::Public; + auto normalConformance = dyn_cast(conformance); - if (normalConformance && normalConformance->isResilient()) - return false; + if (normalConformance && normalConformance->isResilient() && !optInPackage) + return IsNotSerialized; - if (conformance->getProtocol()->getEffectiveAccess() < AccessLevel::Public) - return false; + if (conformance->getProtocol()->getEffectiveAccess() < accessLevelToCheck) + return IsNotSerialized; auto *nominal = conformance->getDeclContext()->getSelfNominalTypeDecl(); - return nominal->getEffectiveAccess() >= AccessLevel::Public; + if (nominal->getEffectiveAccess() >= accessLevelToCheck) + return IsSerialized; + + return IsNotSerialized; } bool SILWitnessTable::enumerateWitnessTableConditionalConformances( diff --git a/lib/SIL/IR/TypeLowering.cpp b/lib/SIL/IR/TypeLowering.cpp index 627c569c8a1a2..45b4588d6d9c1 100644 --- a/lib/SIL/IR/TypeLowering.cpp +++ b/lib/SIL/IR/TypeLowering.cpp @@ -2337,23 +2337,34 @@ namespace { if (D->isResilient()) { // If the type is resilient and defined in our module, make a note of // that, since our lowering now depends on the resilience expansion. - bool sameModule = (D->getModuleContext() == &TC.M); - if (sameModule) + // The same should happen if the type was resilient and serialized in + // another module in the same package with package-cmo enabled, which + // treats those modules to be in the same resilience domain. + auto declModule = D->getModuleContext(); + bool sameModule = (declModule == &TC.M); + bool serializedPackage = declModule != &TC.M && + declModule->inSamePackage(&TC.M) && + declModule->isResilient() && + declModule->serializePackageEnabled(); + auto inSameResilienceDomain = sameModule || serializedPackage; + if (inSameResilienceDomain) properties.addSubobject(RecursiveProperties::forResilient()); - // If the type is in a different module, or if we're using a minimal + // If the type is in a different module and not in the same package + // resilience domain (with package-cmo), or if we're using a minimal // expansion, the type is address only and completely opaque to us. // - // Note: if the type is in a different module, the lowering does - // not depend on the resilience expansion, so we do not need to set - // the isResilient() flag above. - if (!sameModule || Expansion.getResilienceExpansion() == + // Note: if the type is in a different module and not in the same + // package resilience domain, the lowering does not depend on the + // resilience expansion, so we do not need to set the isResilient() + // flag above. + if (!inSameResilienceDomain || + Expansion.getResilienceExpansion() == ResilienceExpansion::Minimal) { properties.addSubobject(RecursiveProperties::forOpaque()); return true; } } - return false; } diff --git a/lib/SIL/Parser/ParseSIL.cpp b/lib/SIL/Parser/ParseSIL.cpp index cb5071b93a95f..e6f242536b0fc 100644 --- a/lib/SIL/Parser/ParseSIL.cpp +++ b/lib/SIL/Parser/ParseSIL.cpp @@ -665,7 +665,7 @@ void SILParser::convertRequirements(ArrayRef From, } static bool parseDeclSILOptional( - bool *isTransparent, IsSerialized_t *isSerialized, bool *isCanonical, + bool *isTransparent, SerializedKind_t *serializedKind, bool *isCanonical, bool *hasOwnershipSSA, bool *hasResultDependsOnSelf, IsThunk_t *isThunk, IsDynamicallyReplaceable_t *isDynamic, IsDistributed_t *isDistributed, IsRuntimeAccessible_t *isRuntimeAccessible, @@ -676,10 +676,9 @@ static bool parseDeclSILOptional( SILFunction **usedAdHocRequirementWitness, Identifier *objCReplacementFor, SILFunction::Purpose *specialPurpose, Inline_t *inlineStrategy, OptimizationMode *optimizationMode, PerformanceConstraints *perfConstraints, - bool *isPerformanceConstraint, - bool *markedAsUsed, StringRef *section, bool *isLet, bool *isWeakImported, - bool *needStackProtection, AvailabilityContext *availability, - bool *isWithoutActuallyEscapingThunk, + bool *isPerformanceConstraint, bool *markedAsUsed, StringRef *section, + bool *isLet, bool *isWeakImported, bool *needStackProtection, + AvailabilityContext *availability, bool *isWithoutActuallyEscapingThunk, SmallVectorImpl *Semantics, SmallVectorImpl *SpecAttrs, ValueDecl **ClangDecl, EffectsKind *MRK, SILParser &SP, SILModule &M) { @@ -695,8 +694,10 @@ static bool parseDeclSILOptional( return true; } else if (isTransparent && SP.P.Tok.getText() == "transparent") *isTransparent = true; - else if (isSerialized && SP.P.Tok.getText() == "serialized") - *isSerialized = IsSerialized; + else if (serializedKind && SP.P.Tok.getText() == "serialized") + *serializedKind = IsSerialized; + else if (serializedKind && SP.P.Tok.getText() == "serialized_for_package") + *serializedKind = IsSerializedForPackage; else if (isDynamic && SP.P.Tok.getText() == "dynamically_replacable") *isDynamic = IsDynamic; else if (isDistributed && SP.P.Tok.getText() == "distributed") @@ -7073,7 +7074,7 @@ bool SILParserState::parseDeclSIL(Parser &P) { SourceLoc FnNameLoc; bool isTransparent = false; - IsSerialized_t isSerialized = IsNotSerialized; + SerializedKind_t isSerialized = IsNotSerialized; bool isCanonical = false; IsDynamicallyReplaceable_t isDynamic = IsNotDynamic; IsDistributed_t isDistributed = IsNotDistributed; @@ -7113,10 +7114,10 @@ bool SILParserState::parseDeclSIL(Parser &P) { &isExactSelfClass, &DynamicallyReplacedFunction, &AdHocWitnessFunction, &objCReplacementFor, &specialPurpose, &inlineStrategy, &optimizationMode, &perfConstr, - &isPerformanceConstraint, &markedAsUsed, - §ion, nullptr, &isWeakImported, &needStackProtection, - &availability, &isWithoutActuallyEscapingThunk, &Semantics, - &SpecAttrs, &ClangDecl, &MRK, FunctionState, M) || + &isPerformanceConstraint, &markedAsUsed, §ion, nullptr, + &isWeakImported, &needStackProtection, &availability, + &isWithoutActuallyEscapingThunk, &Semantics, &SpecAttrs, &ClangDecl, + &MRK, FunctionState, M) || P.parseToken(tok::at_sign, diag::expected_sil_function_name) || P.parseIdentifier(FnName, FnNameLoc, /*diagnoseDollarPrefix=*/false, diag::expected_sil_function_name) || @@ -7140,7 +7141,7 @@ bool SILParserState::parseDeclSIL(Parser &P) { FunctionState.getGlobalNameForDefinition(FnName, SILFnType, FnNameLoc); FunctionState.F->setBare(IsBare); FunctionState.F->setTransparent(IsTransparent_t(isTransparent)); - FunctionState.F->setSerialized(IsSerialized_t(isSerialized)); + FunctionState.F->setSerializedKind(SerializedKind_t(isSerialized)); FunctionState.F->setWasDeserializedCanonical(isCanonical); if (!hasOwnershipSSA) FunctionState.F->setOwnershipEliminated(); @@ -7359,7 +7360,7 @@ bool SILParserState::parseSILGlobal(Parser &P) { Identifier GlobalName; SILType GlobalType; SourceLoc NameLoc; - IsSerialized_t isSerialized = IsNotSerialized; + SerializedKind_t isSerialized = IsNotSerialized; bool isLet = false; SILParser State(P); @@ -7367,10 +7368,9 @@ bool SILParserState::parseSILGlobal(Parser &P) { parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, &isLet, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, State, M) || + &isLet, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, State, M) || P.parseToken(tok::at_sign, diag::expected_sil_value_name) || P.parseIdentifier(GlobalName, NameLoc, /*diagnoseDollarPrefix=*/false, diag::expected_sil_value_name) || @@ -7415,8 +7415,8 @@ bool SILParserState::parseSILProperty(Parser &P) { auto loc = P.consumeToken(tok::kw_sil_property); auto InstLoc = RegularLocation(loc); SILParser SP(P); - - IsSerialized_t Serialized = IsNotSerialized; + + SerializedKind_t Serialized = IsNotSerialized; if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, @@ -7486,7 +7486,7 @@ bool SILParserState::parseSILVTable(Parser &P) { P.consumeToken(tok::kw_sil_vtable); SILParser VTableState(P); - IsSerialized_t Serialized = IsNotSerialized; + SerializedKind_t Serialized = IsNotSerialized; if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, @@ -7609,13 +7609,13 @@ bool SILParserState::parseSILMoveOnlyDeinit(Parser &parser) { parser.consumeToken(tok::kw_sil_moveonlydeinit); SILParser moveOnlyDeinitTableState(parser); - IsSerialized_t Serialized = IsNotSerialized; - if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, moveOnlyDeinitTableState, M)) + SerializedKind_t Serialized = IsNotSerialized; + if (parseDeclSILOptional( + nullptr, &Serialized, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, moveOnlyDeinitTableState, M)) return true; // Parse the class name. @@ -8095,8 +8095,8 @@ bool SILParserState::parseSILWitnessTable(Parser &P) { // Parse the linkage. std::optional Linkage; parseSILLinkage(Linkage, P); - - IsSerialized_t isSerialized = IsNotSerialized; + + SerializedKind_t isSerialized = IsNotSerialized; if (parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, diff --git a/lib/SIL/Verifier/SILVerifier.cpp b/lib/SIL/Verifier/SILVerifier.cpp index 7196dd9b2160e..d6a0141a6f9bf 100644 --- a/lib/SIL/Verifier/SILVerifier.cpp +++ b/lib/SIL/Verifier/SILVerifier.cpp @@ -153,13 +153,38 @@ static bool isArchetypeValidInFunction(ArchetypeType *A, const SILFunction *F) { namespace { -/// When resilience is bypassed, direct access is legal, but the decls are still -/// resilient. +/// When resilience is bypassed for debugging or package serialization is enabled, +/// direct access is legal, but the decls are still resilient. template -bool checkResilience(DeclType *D, ModuleDecl *M, - ResilienceExpansion expansion) { - return !D->getModuleContext()->getBypassResilience() && - D->isResilient(M, expansion); +bool checkResilience(DeclType *D, ModuleDecl *accessingModule, + ResilienceExpansion expansion, + SerializedKind_t serializedKind) { + auto declModule = D->getModuleContext(); + + // For DEBUGGING: this check looks up + // `bypass-resilience-checks`, which is + // an old flag used for debugging, and + // has nothing to do with optimizations. + if (declModule->getBypassResilience()) + return false; + + // If the SIL function containing the decl D is + // [serialized_for_package], package-cmo had been + // enabled in its defining module, so direct access + // from a client module should be allowed. + if (accessingModule != declModule && + expansion == ResilienceExpansion::Maximal && + serializedKind == IsSerializedForPackage) + return false; + + return D->isResilient(accessingModule, expansion); +} + +template +bool checkResilience(DeclType *D, const SILFunction &f) { + return checkResilience(D, f.getModule().getSwiftModule(), + f.getResilienceExpansion(), + f.getSerializedKind()); } bool checkTypeABIAccessible(SILFunction const &F, SILType ty) { @@ -193,6 +218,7 @@ namespace { /// Verify invariants on a key path component. void verifyKeyPathComponent(SILModule &M, TypeExpansionContext typeExpansionContext, + SerializedKind_t serializedKind, llvm::function_ref require, CanType &baseTy, CanType leafTy, @@ -300,7 +326,8 @@ void verifyKeyPathComponent(SILModule &M, "property decl should be a member of the base with the same type " "as the component"); require(property->hasStorage(), "property must be stored"); - require(!checkResilience(property, M.getSwiftModule(), expansion), + require(!checkResilience(property, M.getSwiftModule(), + expansion, serializedKind), "cannot access storage of resilient property"); auto propertyTy = loweredBaseTy.getFieldType(property, M, typeExpansionContext); @@ -333,7 +360,8 @@ void verifyKeyPathComponent(SILModule &M, { auto getter = component.getComputedPropertyGetter(); if (expansion == ResilienceExpansion::Minimal) { - require(getter->hasValidLinkageForFragileRef(), + require(serializedKind != IsNotSerialized && + getter->hasValidLinkageForFragileRef(serializedKind), "Key path in serialized function should not reference " "less visible getters"); } @@ -379,7 +407,8 @@ void verifyKeyPathComponent(SILModule &M, auto setter = component.getComputedPropertySetter(); if (expansion == ResilienceExpansion::Minimal) { - require(setter->hasValidLinkageForFragileRef(), + require(serializedKind != IsNotSerialized && + setter->hasValidLinkageForFragileRef(serializedKind), "Key path in serialized function should not reference " "less visible setters"); } @@ -2449,9 +2478,9 @@ class SILVerifier : public SILVerifierBase { // A direct reference to a non-public or shared but not fragile function // from a fragile function is an error. - if (F.isSerialized()) { + if (F.isAnySerialized()) { require((SingleFunction && RefF->isExternalDeclaration()) || - RefF->hasValidLinkageForFragileRef(), + RefF->hasValidLinkageForFragileRef(F.getSerializedKind()), "function_ref inside fragile function cannot " "reference a private or hidden symbol"); } @@ -2474,8 +2503,7 @@ class SILVerifier : public SILVerifierBase { void checkAllocGlobalInst(AllocGlobalInst *AGI) { SILGlobalVariable *RefG = AGI->getReferencedGlobal(); if (auto *VD = RefG->getDecl()) { - require(!checkResilience(VD, F.getModule().getSwiftModule(), - F.getResilienceExpansion()), + require(!checkResilience(VD, F), "cannot access storage of resilient global"); } if (F.isSerialized()) { @@ -2495,10 +2523,10 @@ class SILVerifier : public SILVerifierBase { RefG->getLoweredTypeInContext(F.getTypeExpansionContext()), "global_addr/value must be the type of the variable it references"); if (auto *VD = RefG->getDecl()) { - require(!checkResilience(VD, F.getModule().getSwiftModule(), - F.getResilienceExpansion()), + require(!checkResilience(VD, F), "cannot access storage of resilient global"); } + // pcmo TODO: replace this with F.canInlineCalleeBody(RefG) if (F.isSerialized()) { // If it has a package linkage at this point, package CMO must // have been enabled, so opt in for visibility. @@ -3420,8 +3448,7 @@ class SILVerifier : public SILVerifierBase { require(!structDecl->hasUnreferenceableStorage(), "Cannot build a struct with unreferenceable storage from elements " "using StructInst"); - require(!checkResilience(structDecl, F.getModule().getSwiftModule(), - F.getResilienceExpansion()), + require(!checkResilience(structDecl, F), "cannot access storage of resilient struct"); require(SI->getType().isObject(), "StructInst must produce an object"); @@ -3657,8 +3684,7 @@ class SILVerifier : public SILVerifierBase { auto *cd = DI->getOperand()->getType().getClassOrBoundGenericClass(); require(cd, "Operand of dealloc_ref must be of class type"); - require(!checkResilience(cd, F.getModule().getSwiftModule(), - F.getResilienceExpansion()), + require(!checkResilience(cd, F), "cannot directly deallocate resilient class"); } void checkDeallocPartialRefInst(DeallocPartialRefInst *DPRI) { @@ -3785,8 +3811,7 @@ class SILVerifier : public SILVerifierBase { "result of struct_extract cannot be address"); StructDecl *sd = operandTy.getStructOrBoundGenericStruct(); require(sd, "must struct_extract from struct"); - require(!checkResilience(sd, F.getModule().getSwiftModule(), - F.getResilienceExpansion()), + require(!checkResilience(sd, F), "cannot access storage of resilient struct"); require(!EI->getField()->isStatic(), "cannot get address of static property with struct_element_addr"); @@ -3841,8 +3866,7 @@ class SILVerifier : public SILVerifierBase { "must derive struct_element_addr from address"); StructDecl *sd = operandTy.getStructOrBoundGenericStruct(); require(sd, "struct_element_addr operand must be struct address"); - require(!checkResilience(sd, F.getModule().getSwiftModule(), - F.getResilienceExpansion()), + require(!checkResilience(sd, F), "cannot access storage of resilient struct"); require(EI->getType().isAddress(), "result of struct_element_addr must be address"); @@ -3883,8 +3907,7 @@ class SILVerifier : public SILVerifierBase { SILType operandTy = EI->getOperand()->getType(); ClassDecl *cd = operandTy.getClassOrBoundGenericClass(); require(cd, "ref_element_addr operand must be a class instance"); - require(!checkResilience(cd, F.getModule().getSwiftModule(), - F.getResilienceExpansion()), + require(!checkResilience(cd, F), "cannot access storage of resilient class"); require(EI->getField()->getDeclContext() == @@ -3909,8 +3932,7 @@ class SILVerifier : public SILVerifierBase { SILType operandTy = RTAI->getOperand()->getType(); ClassDecl *cd = operandTy.getClassOrBoundGenericClass(); require(cd, "ref_tail_addr operand must be a class instance"); - require(!checkResilience(cd, F.getModule().getSwiftModule(), - F.getResilienceExpansion()), + require(!checkResilience(cd, F), "cannot access storage of resilient class"); require(cd, "ref_tail_addr operand must be a class instance"); checkAddressWalkerCanVisitAllTransitiveUses(RTAI); @@ -3920,8 +3942,7 @@ class SILVerifier : public SILVerifierBase { SILType operandTy = DSI->getOperand()->getType(); StructDecl *sd = operandTy.getStructOrBoundGenericStruct(); require(sd, "must struct_extract from struct"); - require(!checkResilience(sd, F.getModule().getSwiftModule(), - F.getResilienceExpansion()), + require(!checkResilience(sd, F), "cannot access storage of resilient struct"); if (F.hasOwnership()) { // Make sure that all of our destructure results ownership kinds are @@ -5738,7 +5759,9 @@ class SILVerifier : public SILVerifierBase { break; } - verifyKeyPathComponent(F.getModule(), F.getTypeExpansionContext(), + verifyKeyPathComponent(F.getModule(), + F.getTypeExpansionContext(), + F.getSerializedKind(), [&](bool reqt, StringRef message) { _require(reqt, message); }, baseTy, leafTy, @@ -7041,7 +7064,7 @@ class SILVerifier : public SILVerifierBase { SILModule &mod = F->getModule(); bool embedded = mod.getASTContext().LangOpts.hasFeature(Feature::Embedded); - require(!F->isSerialized() || !mod.isSerialized() || mod.isParsedAsSerializedSIL(), + require(!F->isAnySerialized() || !mod.isSerialized() || mod.isParsedAsSerializedSIL(), "cannot have a serialized function after the module has been serialized"); switch (F->getLinkage()) { @@ -7055,23 +7078,25 @@ class SILVerifier : public SILVerifierBase { case SILLinkage::PackageNonABI: require(F->isDefinition(), "alwaysEmitIntoClient function must have a body"); - require(F->isSerialized() || mod.isSerialized(), + require(F->isAnySerialized() || mod.isSerialized(), "alwaysEmitIntoClient function must be serialized"); break; case SILLinkage::Hidden: case SILLinkage::Private: require(F->isDefinition() || F->hasForeignBody(), "internal/private function must have a body"); - require(!F->isSerialized() || embedded, + require(!F->isAnySerialized() || embedded, "internal/private function cannot be serialized or serializable"); break; case SILLinkage::PublicExternal: - require(F->isExternalDeclaration() || F->isSerialized() || + require(F->isExternalDeclaration() || + F->isAnySerialized() || mod.isSerialized(), "public-external function definition must be serialized"); break; case SILLinkage::PackageExternal: - require(F->isExternalDeclaration() || F->isSerialized() || + require(F->isExternalDeclaration() || + F->isAnySerialized() || mod.isSerialized(), "package-external function definition must be serialized"); break; @@ -7246,6 +7271,7 @@ void SILProperty::verify(const SILModule &M) const { ResilienceExpansion::Maximal); verifyKeyPathComponent(const_cast(M), typeExpansionContext, + getSerializedKind(), require, baseTy, leafTy, @@ -7407,8 +7433,8 @@ void SILWitnessTable::verify(const SILModule &M) const { if (F) { // If a SILWitnessTable is going to be serialized, it must only // reference public or serializable functions. - if (isSerialized()) { - assert(F->hasValidLinkageForFragileRef() && + if (isAnySerialized()) { + assert(F->hasValidLinkageForFragileRef(getSerializedKind()) && "Fragile witness tables should not reference " "less visible functions."); } @@ -7434,7 +7460,7 @@ void SILDefaultWitnessTable::verify(const SILModule &M) const { #if 0 // FIXME: For now, all default witnesses are private. - assert(F->hasValidLinkageForFragileRef() && + assert(F->hasValidLinkageForFragileRef(IsSerialized) && "Default witness tables should not reference " "less visible functions."); #endif diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index 7a3d00d865cd2..3127fe022878c 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -821,7 +821,7 @@ void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) { if (constant.isForeignToNativeThunk()) { f->setThunk(IsThunk); if (constant.asForeign().isClangGenerated()) - f->setSerialized(IsSerialized); + f->setSerializedKind(IsSerialized); auto loc = constant.getAsRegularLocation(); loc.markAutoGenerated(); @@ -1981,7 +1981,7 @@ void SILGenModule::tryEmitPropertyDescriptor(AbstractStorageDecl *decl) { bool needsGenericContext = true; if (canStorageUseTrivialDescriptor(*this, decl)) { - (void)SILProperty::create(M, /*serialized*/ false, decl, std::nullopt); + (void)SILProperty::create(M, /*serializedKind*/ 0, decl, std::nullopt); return; } @@ -1998,7 +1998,7 @@ void SILGenModule::tryEmitPropertyDescriptor(AbstractStorageDecl *decl) { M.getSwiftModule(), /*property descriptor*/ true); - (void)SILProperty::create(M, /*serialized*/ false, decl, component); + (void)SILProperty::create(M, /*serializedKind*/ 0, decl, component); } void SILGenModule::visitIfConfigDecl(IfConfigDecl *ICD) { diff --git a/lib/SILGen/SILGen.h b/lib/SILGen/SILGen.h index 111b7521c0002..ac293ad7a6318 100644 --- a/lib/SILGen/SILGen.h +++ b/lib/SILGen/SILGen.h @@ -377,7 +377,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor { /// Emit a protocol witness entry point. SILFunction * emitProtocolWitness(ProtocolConformanceRef conformance, SILLinkage linkage, - IsSerialized_t isSerialized, SILDeclRef requirement, + SerializedKind_t serializedKind, SILDeclRef requirement, SILDeclRef witnessRef, IsFreeFunctionWitness_t isFree, Witness witness); diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp index 173c0cc2f5974..2654527ec85f7 100644 --- a/lib/SILGen/SILGenBridging.cpp +++ b/lib/SILGen/SILGenBridging.cpp @@ -1529,17 +1529,11 @@ SILFunction *SILGenFunction::emitNativeAsyncToForeignThunk(SILDeclRef thunk) { closureName.push_back(thunkSuffix[0]); SILGenFunctionBuilder fb(SGM); - auto closure = fb.getOrCreateSharedFunction(loc, closureName, - closureTy, - IsBare, - IsNotTransparent, - F.isSerialized(), - ProfileCounter(), - IsThunk, - IsNotDynamic, - IsNotDistributed, - IsNotRuntimeAccessible); - + auto closure = fb.getOrCreateSharedFunction( + loc, closureName, closureTy, IsBare, IsNotTransparent, + F.getSerializedKind(), ProfileCounter(), IsThunk, IsNotDynamic, + IsNotDistributed, IsNotRuntimeAccessible); + auto closureRef = B.createFunctionRef(loc, closure); auto closureVal = B.createPartialApply(loc, closureRef, subs, diff --git a/lib/SILGen/SILGenGlobalVariable.cpp b/lib/SILGen/SILGenGlobalVariable.cpp index 1026348ccdc8f..815efa5d5dd10 100644 --- a/lib/SILGen/SILGenGlobalVariable.cpp +++ b/lib/SILGen/SILGenGlobalVariable.cpp @@ -42,6 +42,7 @@ SILGlobalVariable *SILGenModule::getSILGlobalVariable(VarDecl *gDecl, // Get the linkage for SILGlobalVariable. FormalLinkage formalLinkage; + // sil_global linkage should be kept private if its decl is resilient. if (gDecl->isResilient()) formalLinkage = FormalLinkage::Private; else diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp index 27ba41934ebd7..09d95256b66fe 100644 --- a/lib/SILGen/SILGenPoly.cpp +++ b/lib/SILGen/SILGenPoly.cpp @@ -6281,7 +6281,7 @@ SILFunction *SILGenModule::getOrCreateCustomDerivativeThunk( auto linkage = stripExternalFromLinkage(originalFn->getLinkage()); auto *thunk = fb.getOrCreateFunction( loc, name, linkage, thunkFnTy, IsBare, IsNotTransparent, - customDerivativeFn->isSerialized(), + customDerivativeFn->getSerializedKind(), customDerivativeFn->isDynamicallyReplaceable(), customDerivativeFn->isDistributed(), customDerivativeFn->isRuntimeAccessible(), diff --git a/lib/SILGen/SILGenThunk.cpp b/lib/SILGen/SILGenThunk.cpp index f7d9e7377bb32..739ae7046b1fa 100644 --- a/lib/SILGen/SILGenThunk.cpp +++ b/lib/SILGen/SILGenThunk.cpp @@ -671,7 +671,7 @@ SILFunction *SILGenModule::getOrCreateDerivativeVTableThunk( /*isVTableThunk*/ true); auto *thunk = builder.getOrCreateFunction( derivativeFnDecl, name, SILLinkage::Private, constantTy, IsBare, - IsTransparent, derivativeFnDeclRef.isSerialized(), IsNotDynamic, + IsTransparent, derivativeFnDeclRef.getSerializedKind(), IsNotDynamic, IsNotDistributed, IsNotRuntimeAccessible, ProfileCounter(), IsThunk); if (!thunk->empty()) return thunk; diff --git a/lib/SILGen/SILGenType.cpp b/lib/SILGen/SILGenType.cpp index cbc7e2347a0c8..591a1d96cf8bf 100644 --- a/lib/SILGen/SILGenType.cpp +++ b/lib/SILGen/SILGenType.cpp @@ -306,7 +306,7 @@ class SILGenVTable : public SILVTableVisitor { false); } - IsSerialized_t serialized = IsNotSerialized; + SerializedKind_t serialized = IsNotSerialized; auto classIsPublic = theClass->getEffectiveAccess() >= AccessLevel::Public; // Only public, fixed-layout classes should have serialized vtables. if (classIsPublic && !isResilient) @@ -515,9 +515,8 @@ template class SILGenWitnessTable : public SILWitnessVisitor { } }; -static IsSerialized_t isConformanceSerialized(RootProtocolConformance *conf) { - return SILWitnessTable::conformanceIsSerialized(conf) - ? IsSerialized : IsNotSerialized; +static SerializedKind_t getConformanceSerializedKind(RootProtocolConformance *conf) { + return SILWitnessTable::conformanceSerializedKind(conf); } /// Emit a witness table for a protocol conformance. @@ -530,13 +529,13 @@ class SILGenConformance : public SILGenWitnessTable { std::vector Entries; std::vector ConditionalConformances; SILLinkage Linkage; - IsSerialized_t Serialized; + SerializedKind_t SerializedKind; SILGenConformance(SILGenModule &SGM, NormalProtocolConformance *C) : SGM(SGM), Conformance(C), Linkage(getLinkageForProtocolConformance(Conformance, ForDefinition)), - Serialized(isConformanceSerialized(Conformance)) + SerializedKind(getConformanceSerializedKind(Conformance)) { auto *proto = Conformance->getProtocol(); @@ -572,7 +571,7 @@ class SILGenConformance : public SILGenWitnessTable { // If we have a declaration, convert the witness table to a definition. if (wt->isDeclaration()) { - wt->convertToDefinition(Entries, ConditionalConformances, Serialized); + wt->convertToDefinition(Entries, ConditionalConformances, SerializedKind); // Since we had a declaration before, its linkage should be external, // ensure that we have a compatible linkage for soundness. *NOTE* we are ok @@ -589,7 +588,7 @@ class SILGenConformance : public SILGenWitnessTable { } // Otherwise if we have no witness table yet, create it. - return SILWitnessTable::create(SGM.M, Linkage, Serialized, Conformance, + return SILWitnessTable::create(SGM.M, Linkage, SerializedKind, Conformance, Entries, ConditionalConformances); } @@ -628,11 +627,16 @@ class SILGenConformance : public SILGenWitnessTable { Witness witness) { // Emit the witness thunk and add it to the table. auto witnessLinkage = witnessRef.getLinkage(ForDefinition); - auto witnessSerialized = Serialized; - if (witnessSerialized && - fixmeWitnessHasLinkageThatNeedsToBePublic(witnessRef)) { + auto witnessSerializedKind = SerializedKind; + if (witnessSerializedKind != IsNotSerialized && + // If package optimization is enabled, this is false; + // witness thunk should get a `shared` linkage in the + // else block below. + fixmeWitnessHasLinkageThatNeedsToBePublic( + witnessRef, + witnessRef.getASTContext().SILOpts.EnableSerializePackage)) { witnessLinkage = SILLinkage::Public; - witnessSerialized = IsNotSerialized; + witnessSerializedKind = IsNotSerialized; } else { // This is the "real" rule; the above case should go away once we // figure out what's going on. @@ -641,7 +645,7 @@ class SILGenConformance : public SILGenWitnessTable { witnessLinkage = SILLinkage::Private; // Unless the witness table is going to be serialized. - if (witnessSerialized) + if (witnessSerializedKind != IsNotSerialized) witnessLinkage = SILLinkage::Shared; // Or even if its not serialized, it might be for an imported @@ -655,7 +659,7 @@ class SILGenConformance : public SILGenWitnessTable { } SILFunction *witnessFn = SGM.emitProtocolWitness( - ProtocolConformanceRef(Conformance), witnessLinkage, witnessSerialized, + ProtocolConformanceRef(Conformance), witnessLinkage, witnessSerializedKind, requirementRef, witnessRef, isFree, witness); Entries.push_back( SILWitnessTable::MethodWitness{requirementRef, witnessFn}); @@ -717,8 +721,8 @@ SILGenModule::getWitnessTable(NormalProtocolConformance *conformance) { SILFunction *SILGenModule::emitProtocolWitness( ProtocolConformanceRef conformance, SILLinkage linkage, - IsSerialized_t isSerialized, SILDeclRef requirement, SILDeclRef witnessRef, - IsFreeFunctionWitness_t isFree, Witness witness) { + SerializedKind_t serializedKind, SILDeclRef requirement, + SILDeclRef witnessRef, IsFreeFunctionWitness_t isFree, Witness witness) { auto requirementInfo = Types.getConstantInfo(TypeExpansionContext::minimal(), requirement); @@ -844,7 +848,7 @@ SILFunction *SILGenModule::emitProtocolWitness( SILGenFunctionBuilder builder(*this); auto *f = builder.createFunction( linkage, nameBuffer, witnessSILFnType, genericEnv, - SILLocation(witnessRef.getDecl()), IsNotBare, IsTransparent, isSerialized, + SILLocation(witnessRef.getDecl()), IsNotBare, IsTransparent, serializedKind, IsNotDynamic, IsNotDistributed, IsNotRuntimeAccessible, ProfileCounter(), IsThunk, SubclassScope::NotApplicable, InlineStrategy); @@ -964,7 +968,7 @@ class SILGenSelfConformanceWitnessTable SILGenModule &SGM; SelfProtocolConformance *conformance; SILLinkage linkage; - IsSerialized_t serialized; + SerializedKind_t serialized; SmallVector entries; public: @@ -972,7 +976,7 @@ class SILGenSelfConformanceWitnessTable SelfProtocolConformance *conformance) : SGM(SGM), conformance(conformance), linkage(getLinkageForProtocolConformance(conformance, ForDefinition)), - serialized(isConformanceSerialized(conformance)) { + serialized(getConformanceSerializedKind(conformance)) { } void emit() { @@ -1116,7 +1120,7 @@ void SILGenModule::emitNonCopyableTypeDeinitTable(NominalTypeDecl *nom) { SILDeclRef constant(dd, SILDeclRef::Kind::Deallocator); SILFunction *f = getFunction(constant, NotForDefinition); - auto serialized = IsSerialized_t::IsNotSerialized; + auto serialized = SerializedKind_t::IsNotSerialized; bool nomIsPublic = nom->getEffectiveAccess() >= AccessLevel::Public; // We only serialize the deinit if the type is public and not resilient. if (nomIsPublic && !nom->isResilient()) diff --git a/lib/SILOptimizer/Differentiation/JVPCloner.cpp b/lib/SILOptimizer/Differentiation/JVPCloner.cpp index 226919e63b840..ff47a11f6d15f 100644 --- a/lib/SILOptimizer/Differentiation/JVPCloner.cpp +++ b/lib/SILOptimizer/Differentiation/JVPCloner.cpp @@ -1704,9 +1704,8 @@ void JVPCloner::Implementation::prepareForDifferentialGeneration() { auto *differential = fb.createFunction( linkage, context.getASTContext().getIdentifier(diffName).str(), diffType, diffGenericEnv, original->getLocation(), original->isBare(), - IsNotTransparent, jvp->isSerialized(), - original->isDynamicallyReplaceable(), - original->isDistributed(), + IsNotTransparent, jvp->getSerializedKind(), + original->isDynamicallyReplaceable(), original->isDistributed(), original->isRuntimeAccessible()); differential->setDebugScope( new (module) SILDebugScope(original->getLocation(), differential)); diff --git a/lib/SILOptimizer/Differentiation/Thunk.cpp b/lib/SILOptimizer/Differentiation/Thunk.cpp index 116ea3a2d228a..099d3b93d4a99 100644 --- a/lib/SILOptimizer/Differentiation/Thunk.cpp +++ b/lib/SILOptimizer/Differentiation/Thunk.cpp @@ -730,9 +730,9 @@ getOrCreateSubsetParametersThunkForDerivativeFunction( auto loc = origFnOperand.getLoc(); auto *thunk = fb.getOrCreateSharedFunction( - loc, thunkName, thunkType, IsBare, IsTransparent, caller->isSerialized(), - ProfileCounter(), IsThunk, IsNotDynamic, IsNotDistributed, - IsNotRuntimeAccessible); + loc, thunkName, thunkType, IsBare, IsTransparent, + caller->getSerializedKind(), ProfileCounter(), IsThunk, IsNotDynamic, + IsNotDistributed, IsNotRuntimeAccessible); if (!thunk->empty()) return {thunk, interfaceSubs}; diff --git a/lib/SILOptimizer/Differentiation/VJPCloner.cpp b/lib/SILOptimizer/Differentiation/VJPCloner.cpp index 86180ef170fcb..f5b1484c1d6a6 100644 --- a/lib/SILOptimizer/Differentiation/VJPCloner.cpp +++ b/lib/SILOptimizer/Differentiation/VJPCloner.cpp @@ -1001,7 +1001,7 @@ SILFunction *VJPCloner::Implementation::createEmptyPullback() { auto *pullback = fb.createFunction( linkage, context.getASTContext().getIdentifier(pbName).str(), pbType, pbGenericEnv, original->getLocation(), original->isBare(), - IsNotTransparent, vjp->isSerialized(), + IsNotTransparent, vjp->getSerializedKind(), original->isDynamicallyReplaceable(), original->isDistributed(), original->isRuntimeAccessible()); pullback->setDebugScope(new (module) diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialSpecializer.cpp b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialSpecializer.cpp index 3d836ff180587..0ce8079c26738 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialSpecializer.cpp +++ b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialSpecializer.cpp @@ -320,7 +320,7 @@ void ExistentialSpecializer::specializeExistentialArgsInAppliesWithinFunction( /// Name Mangler for naming the protocol constrained generic method. auto P = Demangle::SpecializationPass::FunctionSignatureOpts; Mangle::FunctionSignatureSpecializationMangler Mangler( - P, Callee->isSerialized(), Callee); + P, Callee->getSerializedKind(), Callee); /// Save the arguments in a descriptor. llvm::SpecificBumpPtrAllocator Allocator; diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp index 1d0b564ef0d5c..1ff1f0fcd1fc4 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp +++ b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp @@ -622,11 +622,11 @@ void ExistentialTransform::createExistentialSpecializedFunction() { SILLinkage linkage = getSpecializedLinkage(F, F->getLinkage()); NewF = FunctionBuilder.createFunction( - linkage, Name, NewFTy, NewFGenericEnv, F->getLocation(), F->isBare(), - F->isTransparent(), F->isSerialized(), IsNotDynamic, IsNotDistributed, - IsNotRuntimeAccessible, F->getEntryCount(), F->isThunk(), - F->getClassSubclassScope(), F->getInlineStrategy(), F->getEffectsKind(), - nullptr, F->getDebugScope()); + linkage, Name, NewFTy, NewFGenericEnv, F->getLocation(), F->isBare(), + F->isTransparent(), F->getSerializedKind(), IsNotDynamic, + IsNotDistributed, IsNotRuntimeAccessible, F->getEntryCount(), + F->isThunk(), F->getClassSubclassScope(), F->getInlineStrategy(), + F->getEffectsKind(), nullptr, F->getDebugScope()); /// Set the semantics attributes for the new function. for (auto &Attr : F->getSemanticsAttrs()) diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp index 26bff4018e92e..f3f360abae733 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp +++ b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp @@ -185,8 +185,8 @@ FunctionSignatureTransformDescriptor::createOptimizedSILFunctionName() { SILFunction *F = OriginalFunction; auto P = Demangle::SpecializationPass::FunctionSignatureOpts; - Mangle::FunctionSignatureSpecializationMangler Mangler(P, F->isSerialized(), - F); + Mangle::FunctionSignatureSpecializationMangler Mangler( + P, F->getSerializedKind(), F); // Handle arguments' changes. for (unsigned i : indices(ArgumentDescList)) { @@ -542,8 +542,9 @@ void FunctionSignatureTransform::createFunctionSignatureOptimizedFunction() { // classSubclassScope. TransformDescriptor.OptimizedFunction = FunctionBuilder.createFunction( linkage, Name, NewFTy, NewFGenericEnv, F->getLocation(), F->isBare(), - F->isTransparent(), F->isSerialized(), IsNotDynamic, IsNotDistributed, - IsNotRuntimeAccessible, F->getEntryCount(), F->isThunk(), + F->isTransparent(), F->getSerializedKind(), IsNotDynamic, + IsNotDistributed, IsNotRuntimeAccessible, F->getEntryCount(), + F->isThunk(), /*classSubclassScope=*/SubclassScope::NotApplicable, F->getInlineStrategy(), F->getEffectsKind(), nullptr, F->getDebugScope()); SILFunction *NewF = TransformDescriptor.OptimizedFunction.get(); @@ -856,8 +857,8 @@ class FunctionSignatureOpts : public SILFunctionTransform { // going to change, make sure the mangler is aware of all the changes done // to the function. auto P = Demangle::SpecializationPass::FunctionSignatureOpts; - Mangle::FunctionSignatureSpecializationMangler Mangler(P, - F->isSerialized(), F); + Mangle::FunctionSignatureSpecializationMangler Mangler( + P, F->getSerializedKind(), F); /// Keep a map between the exploded argument index and the original argument /// index. diff --git a/lib/SILOptimizer/IPO/CapturePropagation.cpp b/lib/SILOptimizer/IPO/CapturePropagation.cpp index a0b98715a3a43..aca26bdec24dc 100644 --- a/lib/SILOptimizer/IPO/CapturePropagation.cpp +++ b/lib/SILOptimizer/IPO/CapturePropagation.cpp @@ -84,8 +84,8 @@ static SILInstruction *getConstant(SILValue V) { return nullptr; } -static std::string getClonedName(PartialApplyInst *PAI, IsSerialized_t Serialized, - SILFunction *F) { +static std::string getClonedName(PartialApplyInst *PAI, + SerializedKind_t Serialized, SILFunction *F) { auto P = Demangle::SpecializationPass::CapturePropagation; Mangle::FunctionSignatureSpecializationMangler Mangler(P, Serialized, F); @@ -267,16 +267,13 @@ CanSILFunctionType getPartialApplyInterfaceResultType(PartialApplyInst *PAI) { /// function body. SILFunction *CapturePropagation::specializeConstClosure(PartialApplyInst *PAI, SILFunction *OrigF) { - IsSerialized_t Serialized = IsNotSerialized; - if (PAI->getFunction()->isSerialized()) - Serialized = IsSerialized; - - std::string Name = getClonedName(PAI, Serialized, OrigF); + SerializedKind_t serializedKind = PAI->getFunction()->getSerializedKind(); + std::string Name = getClonedName(PAI, serializedKind, OrigF); // See if we already have a version of this function in the module. If so, // just return it. if (auto *NewF = OrigF->getModule().lookUpFunction(Name)) { - assert(NewF->isSerialized() == Serialized); + assert(NewF->getSerializedKind() == serializedKind); LLVM_DEBUG(llvm::dbgs() << " Found an already specialized version of the callee: "; NewF->printName(llvm::dbgs()); llvm::dbgs() << "\n"); @@ -295,7 +292,7 @@ SILFunction *CapturePropagation::specializeConstClosure(PartialApplyInst *PAI, SILOptFunctionBuilder FuncBuilder(*this); SILFunction *NewF = FuncBuilder.createFunction( SILLinkage::Shared, Name, NewFTy, GenericEnv, OrigF->getLocation(), - OrigF->isBare(), OrigF->isTransparent(), Serialized, IsNotDynamic, + OrigF->isBare(), OrigF->isTransparent(), serializedKind, IsNotDynamic, IsNotDistributed, IsNotRuntimeAccessible, OrigF->getEntryCount(), OrigF->isThunk(), OrigF->getClassSubclassScope(), OrigF->getInlineStrategy(), OrigF->getEffectsKind(), @@ -491,8 +488,8 @@ static SILFunction *getSpecializedWithDeadParams( ReabstractionInfo ReInfo( FuncBuilder.getModule().getSwiftModule(), FuncBuilder.getModule().isWholeModule(), ApplySite(), Specialized, - PAI->getSubstitutionMap(), Specialized->isSerialized(), - /* ConvertIndirectToDirect */ false, /*dropMetatypeArgs=*/ false); + PAI->getSubstitutionMap(), Specialized->getSerializedKind(), + /* ConvertIndirectToDirect */ false, /*dropMetatypeArgs=*/false); GenericFuncSpecializer FuncSpecializer(FuncBuilder, Specialized, ReInfo.getClonerParamSubstitutionMap(), diff --git a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp index d70aca9525983..a9b1c9e0244f2 100644 --- a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp +++ b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp @@ -253,7 +253,8 @@ class CallSiteDescriptor { FullApplySite getApplyInst() const { return AI; } - IsSerialized_t isSerialized() const; + bool isSerialized() const; + SerializedKind_t getSerializedKind() const; std::string createName() const; @@ -500,16 +501,17 @@ static void rewriteApplyInst(const CallSiteDescriptor &CSDesc, // AI from parent? } -IsSerialized_t CallSiteDescriptor::isSerialized() const { - if (getClosure()->getFunction()->isSerialized()) - return IsSerialized; - return IsNotSerialized; +bool CallSiteDescriptor::isSerialized() const { + return getClosure()->getFunction()->getSerializedKind() == IsSerialized; +} +SerializedKind_t CallSiteDescriptor::getSerializedKind() const { + return getClosure()->getFunction()->getSerializedKind(); } std::string CallSiteDescriptor::createName() const { auto P = Demangle::SpecializationPass::ClosureSpecializer; - Mangle::FunctionSignatureSpecializationMangler Mangler(P, isSerialized(), - getApplyCallee()); + Mangle::FunctionSignatureSpecializationMangler Mangler(P, getSerializedKind(), + getApplyCallee()); if (auto *PAI = dyn_cast(getClosure())) { Mangler.setArgumentClosureProp(getClosureIndex(), PAI); @@ -712,7 +714,7 @@ ClosureSpecCloner::initCloned(SILOptFunctionBuilder &FunctionBuilder, getSpecializedLinkage(ClosureUser, ClosureUser->getLinkage()), ClonedName, ClonedTy, ClosureUser->getGenericEnvironment(), ClosureUser->getLocation(), IsBare, ClosureUser->isTransparent(), - CallSiteDesc.isSerialized(), IsNotDynamic, IsNotDistributed, + CallSiteDesc.getSerializedKind(), IsNotDynamic, IsNotDistributed, IsNotRuntimeAccessible, ClosureUser->getEntryCount(), ClosureUser->isThunk(), /*classSubclassScope=*/SubclassScope::NotApplicable, @@ -1295,8 +1297,7 @@ bool SILClosureSpecializerTransform::gatherCallSites( // Don't specialize non-fragile callees if the caller is fragile; // the specialized callee will have shared linkage, and thus cannot // be referenced from the fragile caller. - if (Caller->isSerialized() && - !ApplyCallee->hasValidLinkageForFragileInline()) + if (!ApplyCallee->canBeInlinedIntoCaller(Caller->getSerializedKind())) continue; // If the callee uses a dynamic Self, we cannot specialize it, diff --git a/lib/SILOptimizer/IPO/CrossModuleOptimization.cpp b/lib/SILOptimizer/IPO/CrossModuleOptimization.cpp index 1b789c21aa5dc..4bb799000a1f3 100644 --- a/lib/SILOptimizer/IPO/CrossModuleOptimization.cpp +++ b/lib/SILOptimizer/IPO/CrossModuleOptimization.cpp @@ -21,6 +21,8 @@ #include "swift/SIL/SILCloner.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILModule.h" +#include "swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h" +#include "swift/SILOptimizer/Analysis/FunctionOrder.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" #include "swift/SILOptimizer/Utils/InstOptUtils.h" @@ -65,14 +67,27 @@ class CrossModuleOptimization { bool everything; typedef llvm::DenseMap FunctionFlags; + FunctionFlags canSerializeFlags; public: CrossModuleOptimization(SILModule &M, bool conservative, bool everything) : M(M), conservative(conservative), everything(everything) { } - void serializeFunctionsInModule(); + void serializeFunctionsInModule(SILPassManager *manager); + void serializeWitnessTablesInModule(); + void serializeVTablesInModule(); private: + bool isReferenceSerializeCandidate(SILFunction *F, SILOptions options); + bool isReferenceSerializeCandidate(SILGlobalVariable *G, SILOptions options); + SerializedKind_t getRightSerializedKind(const SILModule &mod); + bool isSerializedWithRightKind(const SILModule &mod, SILFunction *f); + bool isSerializedWithRightKind(const SILModule &mod, SILGlobalVariable *g); + bool isPackageOrPublic(SILLinkage linkage); + bool isPackageOrPublic(AccessLevel accessLevel); + + void trySerializeFunctions(ArrayRef functions); + bool canSerializeFunction(SILFunction *function, FunctionFlags &canSerializeFlags, int maxDepth); @@ -161,29 +176,181 @@ class InstructionVisitor : public SILCloner { } }; -static bool isVisible(SILLinkage linkage, SILOptions options) { - if (options.EnableSerializePackage) +static bool isPackageCMOEnabled(ModuleDecl *mod) { + return mod->isResilient() && mod->serializePackageEnabled(); +} + +bool CrossModuleOptimization::isPackageOrPublic(SILLinkage linkage) { + if (isPackageCMOEnabled(M.getSwiftModule())) return linkage == SILLinkage::Public || linkage == SILLinkage::Package; return linkage == SILLinkage::Public; } -static bool isVisible(AccessLevel accessLevel, SILOptions options) { - if (options.EnableSerializePackage) + +bool CrossModuleOptimization::isPackageOrPublic(AccessLevel accessLevel) { + if (isPackageCMOEnabled(M.getSwiftModule())) return accessLevel == AccessLevel::Package || accessLevel == AccessLevel::Public; return accessLevel == AccessLevel::Public; } +/// Checks wither this function is [serialized_for_package] due to Package CMO +/// or [serialized] with non-package CMO. The [serialized_for_package] attribute +/// is used to indicate that a function is serialized because of Package CMO, which +/// allows loadable types in a serialized function in a resiliently built module, which +/// is otherwise illegal. It's also used to determine during SIL deserialization whether +/// loadable types in a serialized function can be allowed in the client module that +/// imports the module built with Package CMO. If the client contains a [serialized] +/// function due to `@inlinable`, funtions with [serialized_for_package] from +/// the imported module are not allowed being inlined into the client function, which +/// is the correct behavior. +bool CrossModuleOptimization::isSerializedWithRightKind(const SILModule &mod, + SILFunction *f) { + // If Package CMO is enabled in resilient mode, return + // true if the function is [serialized] due to @inlinable + // (or similar) or [serialized_for_package] due to this + // optimization. + return isPackageCMOEnabled(mod.getSwiftModule()) ? f->isAnySerialized() + : f->isSerialized(); +} +bool CrossModuleOptimization::isSerializedWithRightKind(const SILModule &mod, + SILGlobalVariable *g) { + return isPackageCMOEnabled(mod.getSwiftModule()) ? g->isAnySerialized() + : g->isSerialized(); +} +SerializedKind_t CrossModuleOptimization::getRightSerializedKind(const SILModule &mod) { + return isPackageCMOEnabled(mod.getSwiftModule()) ? IsSerializedForPackage + : IsSerialized; +} + +static bool isSerializeCandidate(SILFunction *F, SILOptions options) { + auto linkage = F->getLinkage(); + // If Package CMO is enabled, besides package/public definitions, + // we allow serializing private, hidden, or shared definitions + // that do not contain private or hidden symbol references (and + // their nested references). If private or internal definitions are + // serialized, they are set to a shared linkage. + // + // E.g. `public func foo() { print("") }` is a public function that + // references `print`, a shared definition which does not contain + // any private or internal symbols, thus is serialized, which in turn + // allows `foo` to be serialized. + // E.g. a protocol witness method for a package protocol member is + // set to a private linkage in SILGen. By allowing such private thunk + // to be serialized and set to shared linkage here, functions that + // reference the thunk can be serialized as well. + if (isPackageCMOEnabled(F->getModule().getSwiftModule())) + return linkage != SILLinkage::PublicExternal && + linkage != SILLinkage::PackageExternal && + linkage != SILLinkage::HiddenExternal; + return linkage == SILLinkage::Public; +} + +bool CrossModuleOptimization::isReferenceSerializeCandidate(SILFunction *F, + SILOptions options) { + if (isPackageCMOEnabled(F->getModule().getSwiftModule())) { + if (isSerializedWithRightKind(F->getModule(), F)) + return true; + return hasPublicOrPackageVisibility(F->getLinkage(), + /*includePackage*/ true); + } + return hasPublicVisibility(F->getLinkage()); +} + +bool CrossModuleOptimization::isReferenceSerializeCandidate(SILGlobalVariable *G, + SILOptions options) { + if (isPackageCMOEnabled(G->getModule().getSwiftModule())) { + if (isSerializedWithRightKind(G->getModule(), G)) + return true; + return hasPublicOrPackageVisibility(G->getLinkage(), + /*includePackage*/ true); + } + return hasPublicVisibility(G->getLinkage()); +} + /// Select functions in the module which should be serialized. -void CrossModuleOptimization::serializeFunctionsInModule() { +void CrossModuleOptimization::trySerializeFunctions( + ArrayRef functions) { + for (SILFunction *F : functions) { + if (isSerializeCandidate(F, M.getOptions()) || everything) { + if (canSerializeFunction(F, canSerializeFlags, /*maxDepth*/ 64)) { + serializeFunction(F, canSerializeFlags); + } + } + } +} - FunctionFlags canSerializeFlags; +void CrossModuleOptimization::serializeFunctionsInModule(SILPassManager *manager) { + // Reorder SIL funtions in the module bottom up so we can serialize + // the most nested referenced functions first and avoid unnecessary + // recursive checks. + BasicCalleeAnalysis *BCA = manager->getAnalysis(); + BottomUpFunctionOrder BottomUpOrder(M, BCA); + auto bottomUpFunctions = BottomUpOrder.getFunctions(); + trySerializeFunctions(bottomUpFunctions); +} - // Start with public functions. - for (SILFunction &F : M) { - if (isVisible(F.getLinkage(), M.getOptions()) || - everything) { - if (canSerializeFunction(&F, canSerializeFlags, /*maxDepth*/ 64)) { - serializeFunction(&F, canSerializeFlags); +void CrossModuleOptimization::serializeWitnessTablesInModule() { + if (!isPackageCMOEnabled(M.getSwiftModule())) + return; + + for (auto &wt : M.getWitnessTables()) { + if (wt.getSerializedKind() != getRightSerializedKind(M) && + hasPublicOrPackageVisibility(wt.getLinkage(), /*includePackage*/ true)) { + auto unserializedWTMethodRange = llvm::make_filter_range( + wt.getEntries(), [&](const SILWitnessTable::Entry &entry) { + return entry.getKind() == SILWitnessTable::Method && + entry.getMethodWitness().Witness->getSerializedKind() != + getRightSerializedKind(M); + }); + // In Package CMO, we try serializing witness thunks that + // are private if they don't contain hidden or private + // references. If they are serialized, they are set to + // a shared linkage. If they can't be serialized, we set + // the linkage to package so that the witness table itself + // can still be serialized, thus giving a chance for entires + // that _are_ serialized to be accessed directly. + for (const SILWitnessTable::Entry &entry: unserializedWTMethodRange) { + if (entry.getMethodWitness().Witness->getLinkage() == SILLinkage::Private) + entry.getMethodWitness().Witness->setLinkage(SILLinkage::Package); } + + bool containsInternal = llvm::any_of( + wt.getEntries(), [&](const SILWitnessTable::Entry &entry) { + return entry.getKind() == SILWitnessTable::Method && + !entry.getMethodWitness() + .Witness->hasValidLinkageForFragileRef( + getRightSerializedKind(M)); + }); + // FIXME: This check shouldn't be necessary but added as a caution + // to ensure we don't serialize witness table if it contains an + // internal entry. + if (!containsInternal) + wt.setSerializedKind(getRightSerializedKind(M)); + } + } +} + +void CrossModuleOptimization::serializeVTablesInModule() { + if (!isPackageCMOEnabled(M.getSwiftModule())) + return; + + for (const auto &vt : M.getVTables()) { + if (vt->getSerializedKind() != getRightSerializedKind(M) && + vt->getClass()->getEffectiveAccess() >= AccessLevel::Package) { + bool containsInternal = + llvm::any_of(vt->getEntries(), [&](const SILVTableEntry &entry) { + return !entry.getImplementation()->hasValidLinkageForFragileRef( + getRightSerializedKind(M)); + }); + + // If the entries are either serialized or have package/public + // visibility, the vtable can be serialized; the non-serialized + // entries can still be referenced as they have the visibility + // outside of their defining module, and the serialized entries + // can be directly accessed since the vtable is serialized. + // However, if it contains a private/internal entry, we don't + // serialize the vtable at all. + if (!containsInternal) + vt->setSerializedKind(getRightSerializedKind(M)); } } } @@ -206,8 +373,8 @@ bool CrossModuleOptimization::canSerializeFunction( canSerializeFlags[function] = false; if (everything) { - canSerializeFlags[function] = true; - return true; + canSerializeFlags[function] = true; + return true; } if (DeclContext *funcCtxt = function->getDeclContext()) { @@ -215,8 +382,10 @@ bool CrossModuleOptimization::canSerializeFunction( return false; } - if (function->isSerialized()) + if (function->isAnySerialized()) { + canSerializeFlags[function] = true; return true; + } if (!function->isDefinition() || function->isAvailableExternally()) return false; @@ -258,9 +427,8 @@ bool CrossModuleOptimization::canSerializeFunction( /// Returns true if \p inst can be serialized. /// /// If \p inst is a function_ref, recursively visits the referenced function. -bool CrossModuleOptimization::canSerializeInstruction(SILInstruction *inst, - FunctionFlags &canSerializeFlags, int maxDepth) { - +bool CrossModuleOptimization::canSerializeInstruction( + SILInstruction *inst, FunctionFlags &canSerializeFlags, int maxDepth) { // First check if any result or operand types prevent serialization. for (SILValue result : inst->getResults()) { if (!canSerializeType(result->getType())) @@ -280,9 +448,9 @@ bool CrossModuleOptimization::canSerializeInstruction(SILInstruction *inst, // public functions, because that can increase code size. E.g. if the // function is completely inlined afterwards. // Also, when emitting TBD files, we cannot introduce a new public symbol. - if ((conservative || M.getOptions().emitTBD) && - !hasPublicOrPackageVisibility(callee->getLinkage(), M.getOptions().EnableSerializePackage)) { - return false; + if (conservative || M.getOptions().emitTBD) { + if (!isReferenceSerializeCandidate(callee, M.getOptions())) + return false; } // In some project configurations imported C functions are not necessarily @@ -301,12 +469,13 @@ bool CrossModuleOptimization::canSerializeInstruction(SILInstruction *inst, // inline. if (!canUseFromInline(callee)) return false; + return true; } if (auto *GAI = dyn_cast(inst)) { SILGlobalVariable *global = GAI->getReferencedGlobal(); if ((conservative || M.getOptions().emitTBD) && - !hasPublicOrPackageVisibility(global->getLinkage(), M.getOptions().EnableSerializePackage)) { + !isReferenceSerializeCandidate(global, M.getOptions())) { return false; } @@ -327,11 +496,29 @@ bool CrossModuleOptimization::canSerializeInstruction(SILInstruction *inst, [&](SILDeclRef method) { if (method.isForeign) canUse = false; + else if (isPackageCMOEnabled(method.getModuleContext())) { + // If the referenced keypath is internal, do not + // serialize. + auto methodScope = method.getDecl()->getFormalAccessScope( + nullptr, + /*treatUsableFromInlineAsPublic*/ true); + canUse = methodScope.isPublicOrPackage(); + } }); return canUse; } if (auto *MI = dyn_cast(inst)) { - return !MI->getMember().isForeign; + // If a class_method or witness_method is internal, + // it can't be serialized. + auto member = MI->getMember(); + auto canUse = !member.isForeign; + if (canUse && isPackageCMOEnabled(member.getModuleContext())) { + auto methodScope = member.getDecl()->getFormalAccessScope( + nullptr, + /*treatUsableFromInlineAsPublic*/ true); + canUse = methodScope.isPublicOrPackage(); + } + return canUse; } if (auto *REAI = dyn_cast(inst)) { // In conservative mode, we don't support class field accesses of non-public @@ -348,13 +535,12 @@ bool CrossModuleOptimization::canSerializeGlobal(SILGlobalVariable *global) { for (const SILInstruction &initInst : *global) { if (auto *FRI = dyn_cast(&initInst)) { SILFunction *referencedFunc = FRI->getReferencedFunction(); - // In conservative mode we don't want to turn non-public functions into // public functions, because that can increase code size. E.g. if the // function is completely inlined afterwards. // Also, when emitting TBD files, we cannot introduce a new public symbol. if ((conservative || M.getOptions().emitTBD) && - !hasPublicOrPackageVisibility(referencedFunc->getLinkage(), M.getOptions().EnableSerializePackage)) { + !isReferenceSerializeCandidate(referencedFunc, M.getOptions())) { return false; } @@ -374,7 +560,7 @@ bool CrossModuleOptimization::canSerializeType(SILType type) { [this](Type rawSubType) { CanType subType = rawSubType->getCanonicalType(); if (NominalTypeDecl *subNT = subType->getNominalOrBoundGenericNominal()) { - + if (conservative && subNT->getEffectiveAccess() < AccessLevel::Package) { return true; } @@ -465,7 +651,7 @@ bool CrossModuleOptimization::canUseFromInline(SILFunction *function) { /// Decide whether to serialize a function. bool CrossModuleOptimization::shouldSerialize(SILFunction *function) { // Check if we already handled this function before. - if (function->isSerialized()) + if (isSerializedWithRightKind(M, function)) return false; if (everything) @@ -484,13 +670,17 @@ bool CrossModuleOptimization::shouldSerialize(SILFunction *function) { return true; } - // Also serialize "small" non-generic functions. - int size = 0; - for (SILBasicBlock &block : *function) { - for (SILInstruction &inst : block) { - size += (int)instructionInlineCost(inst); - if (size >= CMOFunctionSizeLimit) - return false; + // If package-cmo is enabled, we don't want to limit inlining + // or should at least increase the cap. + if (!M.getSwiftModule()->serializePackageEnabled()) { + // Also serialize "small" non-generic functions. + int size = 0; + for (SILBasicBlock &block : *function) { + for (SILInstruction &inst : block) { + size += (int)instructionInlineCost(inst); + if (size >= CMOFunctionSizeLimit) + return false; + } } } @@ -500,14 +690,24 @@ bool CrossModuleOptimization::shouldSerialize(SILFunction *function) { /// Serialize \p function and recursively all referenced functions which are /// marked in \p canSerializeFlags. void CrossModuleOptimization::serializeFunction(SILFunction *function, - const FunctionFlags &canSerializeFlags) { - if (function->isSerialized()) + const FunctionFlags &canSerializeFlags) { + if (isSerializedWithRightKind(M, function)) return; - + if (!canSerializeFlags.lookup(function)) return; - function->setSerialized(IsSerialized); + if (isPackageCMOEnabled(M.getSwiftModule())) { + // If a private thunk (such as a protocol witness method for + // a package protocol member) does not reference any private + // or internal symbols, thus is serialized, it's set to shared + // linkage, so that functions that reference the thunk can be + // serialized as well. + if (function->getLinkage() == SILLinkage::Private || + function->getLinkage() == SILLinkage::Hidden) + function->setLinkage(SILLinkage::Shared); + } + function->setSerializedKind(getRightSerializedKind(M)); for (SILBasicBlock &block : *function) { for (SILInstruction &inst : block) { @@ -552,15 +752,19 @@ void CrossModuleOptimization::serializeInstruction(SILInstruction *inst, } } serializeFunction(callee, canSerializeFlags); - assert(callee->isSerialized() || isVisible(callee->getLinkage(), M.getOptions())); + assert(isSerializedWithRightKind(M, callee) || + isPackageOrPublic(callee->getLinkage())); return; } + if (auto *GAI = dyn_cast(inst)) { SILGlobalVariable *global = GAI->getReferencedGlobal(); if (canSerializeGlobal(global)) { serializeGlobal(global); } - if (!hasPublicOrPackageVisibility(global->getLinkage(), M.getOptions().EnableSerializePackage)) { + if (!hasPublicOrPackageVisibility( + global->getLinkage(), + M.getSwiftModule()->serializePackageEnabled())) { global->setLinkage(SILLinkage::Public); } return; @@ -581,6 +785,8 @@ void CrossModuleOptimization::serializeInstruction(SILInstruction *inst, } void CrossModuleOptimization::serializeGlobal(SILGlobalVariable *global) { + if (isSerializedWithRightKind(M, global)) + return; for (const SILInstruction &initInst : *global) { if (auto *FRI = dyn_cast(&initInst)) { SILFunction *callee = FRI->getReferencedFunction(); @@ -588,7 +794,7 @@ void CrossModuleOptimization::serializeGlobal(SILGlobalVariable *global) { makeFunctionUsableFromInline(callee); } } - global->setSerialized(IsSerialized); + global->setSerializedKind(getRightSerializedKind(M)); } void CrossModuleOptimization::keepMethodAlive(SILDeclRef method) { @@ -602,7 +808,7 @@ void CrossModuleOptimization::keepMethodAlive(SILDeclRef method) { void CrossModuleOptimization::makeFunctionUsableFromInline(SILFunction *function) { assert(canUseFromInline(function)); if (!isAvailableExternally(function->getLinkage()) && - function->getLinkage() != SILLinkage::Public) { + !isPackageOrPublic(function->getLinkage())) { function->setLinkage(SILLinkage::Public); } } @@ -616,7 +822,7 @@ void CrossModuleOptimization::makeDeclUsableFromInline(ValueDecl *decl) { if (M.getSwiftModule() != decl->getDeclContext()->getParentModule()) return; - if (!isVisible(decl->getFormalAccess(), M.getOptions()) && + if (!isPackageOrPublic(decl->getFormalAccess()) && !decl->isUsableFromInline()) { // Mark the nominal type as "usableFromInline". // TODO: find a way to do this without modifying the AST. The AST should be @@ -626,11 +832,14 @@ void CrossModuleOptimization::makeDeclUsableFromInline(ValueDecl *decl) { decl->getAttrs().add(attr); if (everything) { - // Serialize vtables, their superclass vtables, and make all vfunctions - // usable from inline. + // The following does _not_ apply to the Package CMO as + // it is only supported for the conservative mode. + // + // With non-package CMO, serialize vtables, their superclass + // vtables, and make all vfunctions usable from inline. if (auto *classDecl = dyn_cast(decl)) { auto *vTable = M.lookUpVTable(classDecl); - vTable->setSerialized(IsSerialized); + vTable->setSerializedKind(IsSerialized); for (auto &entry : vTable->getEntries()) { makeFunctionUsableFromInline(entry.getImplementation()); } @@ -640,7 +849,7 @@ void CrossModuleOptimization::makeDeclUsableFromInline(ValueDecl *decl) { if (!vTable) { return TypeWalker::Action::Stop; } - vTable->setSerialized(IsSerialized); + vTable->setSerializedKind(IsSerialized); for (auto &entry : vTable->getEntries()) { makeFunctionUsableFromInline(entry.getImplementation()); } @@ -697,9 +906,9 @@ void CrossModuleOptimization::makeSubstUsableFromInline( class CrossModuleOptimizationPass: public SILModuleTransform { void run() override { - auto &M = *getModule(); - if (M.getSwiftModule()->isResilient()) + if (M.getSwiftModule()->isResilient() && + !M.getSwiftModule()->serializePackageEnabled()) return; if (!M.isWholeModule()) return; @@ -726,7 +935,11 @@ class CrossModuleOptimizationPass: public SILModuleTransform { } CrossModuleOptimization CMO(M, conservative, everything); - CMO.serializeFunctionsInModule(); + CMO.serializeFunctionsInModule(PM); + + // Serialize SIL v-tables and witness-tables if package-cmo is enabled. + CMO.serializeVTablesInModule(); + CMO.serializeWitnessTablesInModule(); } }; diff --git a/lib/SILOptimizer/Mandatory/CapturePromotion.cpp b/lib/SILOptimizer/Mandatory/CapturePromotion.cpp index 84360cc661b5c..a49dc2fbb146f 100644 --- a/lib/SILOptimizer/Mandatory/CapturePromotion.cpp +++ b/lib/SILOptimizer/Mandatory/CapturePromotion.cpp @@ -292,7 +292,7 @@ class ClosureCloner : public SILClonerWithScopes { friend class SILCloner; ClosureCloner(SILOptFunctionBuilder &funcBuilder, SILFunction *orig, - IsSerialized_t serialized, StringRef clonedName, + SerializedKind_t serialized, StringRef clonedName, IndicesSet &promotableIndices, ResilienceExpansion expansion); void populateCloned(); @@ -307,7 +307,7 @@ class ClosureCloner : public SILClonerWithScopes { private: static SILFunction *initCloned(SILOptFunctionBuilder &funcBuilder, - SILFunction *orig, IsSerialized_t serialized, + SILFunction *orig, SerializedKind_t serialized, StringRef clonedName, IndicesSet &promotableIndices, ResilienceExpansion expansion); @@ -334,7 +334,7 @@ class ClosureCloner : public SILClonerWithScopes { } // end anonymous namespace ClosureCloner::ClosureCloner(SILOptFunctionBuilder &funcBuilder, - SILFunction *orig, IsSerialized_t serialized, + SILFunction *orig, SerializedKind_t serialized, StringRef clonedName, IndicesSet &promotableIndices, ResilienceExpansion resilienceExpansion) @@ -410,7 +410,8 @@ computeNewArgInterfaceTypes(SILFunction *f, IndicesSet &promotableIndices, } } -static std::string getSpecializedName(SILFunction *f, IsSerialized_t serialized, +static std::string getSpecializedName(SILFunction *f, + SerializedKind_t serialized, IndicesSet &promotableIndices) { auto p = Demangle::SpecializationPass::CapturePromotion; Mangle::FunctionSignatureSpecializationMangler mangler(p, serialized, f); @@ -436,7 +437,7 @@ static std::string getSpecializedName(SILFunction *f, IsSerialized_t serialized, /// the address value. SILFunction * ClosureCloner::initCloned(SILOptFunctionBuilder &functionBuilder, - SILFunction *orig, IsSerialized_t serialized, + SILFunction *orig, SerializedKind_t serialized, StringRef clonedName, IndicesSet &promotableIndices, ResilienceExpansion resilienceExpansion) { SILModule &mod = orig->getModule(); @@ -546,20 +547,17 @@ SILFunction *ClosureCloner::constructClonedFunction( // Create the Cloned Name for the function. SILFunction *origF = fri->getReferencedFunction(); - IsSerialized_t isSerialized = IsNotSerialized; - if (f->isSerialized()) - isSerialized = IsSerialized_t::IsSerialized; - - auto clonedName = getSpecializedName(origF, isSerialized, promotableIndices); + SerializedKind_t serializedKind = f->getSerializedKind(); + auto clonedName = getSpecializedName(origF, serializedKind, promotableIndices); // If we already have such a cloned function in the module then just use it. if (auto *prevF = f->getModule().lookUpFunction(clonedName)) { - assert(prevF->isSerialized() == isSerialized); + assert(prevF->getSerializedKind() == serializedKind); return prevF; } // Otherwise, create a new clone. - ClosureCloner cloner(funcBuilder, origF, isSerialized, clonedName, + ClosureCloner cloner(funcBuilder, origF, serializedKind, clonedName, promotableIndices, resilienceExpansion); cloner.populateCloned(); return cloner.getCloned(); diff --git a/lib/SILOptimizer/Mandatory/ConsumeOperatorCopyableAddressesChecker.cpp b/lib/SILOptimizer/Mandatory/ConsumeOperatorCopyableAddressesChecker.cpp index 1554fde4c7be8..9bf2358b0039b 100644 --- a/lib/SILOptimizer/Mandatory/ConsumeOperatorCopyableAddressesChecker.cpp +++ b/lib/SILOptimizer/Mandatory/ConsumeOperatorCopyableAddressesChecker.cpp @@ -992,7 +992,7 @@ struct ClosureArgumentInOutToOutCloner public: ClosureArgumentInOutToOutCloner( SILOptFunctionBuilder &funcBuilder, SILFunction *orig, - IsSerialized_t isSerialized, + SerializedKind_t serializedKind, SmallBlotSetVector &postDominatingConsumingUsers, const SmallBitVector &argsToConvertIndices, StringRef name); @@ -1076,14 +1076,14 @@ struct ClosureArgumentInOutToOutCloner private: static SILFunction *initCloned( SILOptFunctionBuilder &funcBuilder, SILFunction *orig, - IsSerialized_t isSerialized, + SerializedKind_t serializedKind, SmallBlotSetVector &postDominatingConsumingUsers, const SmallBitVector &argsToConvertIndices, StringRef cloneName); }; } // namespace -static std::string getClonedName(SILFunction *func, IsSerialized_t serialized, +static std::string getClonedName(SILFunction *func, SerializedKind_t serialized, const SmallBitVector &argsToConvertIndices) { auto kind = Demangle::SpecializationPass::MoveDiagnosticInOutToOut; Mangle::FunctionSignatureSpecializationMangler Mangler(kind, serialized, @@ -1097,11 +1097,11 @@ static std::string getClonedName(SILFunction *func, IsSerialized_t serialized, ClosureArgumentInOutToOutCloner::ClosureArgumentInOutToOutCloner( SILOptFunctionBuilder &funcBuilder, SILFunction *orig, - IsSerialized_t isSerialized, + SerializedKind_t serializedKind, SmallBlotSetVector &postDominatingConsumingUsers, const SmallBitVector &argsToConvertIndices, StringRef name) : SILClonerWithScopes(*initCloned( - funcBuilder, orig, isSerialized, postDominatingConsumingUsers, + funcBuilder, orig, serializedKind, postDominatingConsumingUsers, argsToConvertIndices, name)), postDominatingConsumingUsers(postDominatingConsumingUsers), orig(orig), argsToConvertIndices(argsToConvertIndices) { @@ -1114,7 +1114,7 @@ ClosureArgumentInOutToOutCloner::ClosureArgumentInOutToOutCloner( /// parameters (which are specified by PromotedArgIndices). SILFunction *ClosureArgumentInOutToOutCloner::initCloned( SILOptFunctionBuilder &funcBuilder, SILFunction *orig, - IsSerialized_t serialized, + SerializedKind_t serialized, SmallBlotSetVector &postDominatingConsumingUsers, const SmallBitVector &argsToConvertIndices, StringRef clonedName) { SILModule &mod = orig->getModule(); @@ -1980,14 +1980,15 @@ void ConsumeOperatorCopyableAddressesChecker::cloneDeferCalleeAndRewriteUses( auto *origCallee = oldApplySite.getReferencedFunctionOrNull(); assert(origCallee); - auto name = getClonedName(origCallee, origCallee->isSerialized(), bitVector); + auto name = + getClonedName(origCallee, origCallee->getSerializedKind(), bitVector); SILFunction *newCallee = nullptr; if (auto *fn = origCallee->getModule().lookUpFunction(name)) { newCallee = fn; } else { ClosureArgumentInOutToOutCloner cloner( - funcBuilder, origCallee, origCallee->isSerialized(), + funcBuilder, origCallee, origCallee->getSerializedKind(), postDominatingConsumingUsers, bitVector, name); cloner.populateCloned(); newCallee = cloner.getCloned(); diff --git a/lib/SILOptimizer/Mandatory/DiagnosticDeadFunctionElimination.cpp b/lib/SILOptimizer/Mandatory/DiagnosticDeadFunctionElimination.cpp index 3d131c9a63dd6..70a56d6a6175e 100644 --- a/lib/SILOptimizer/Mandatory/DiagnosticDeadFunctionElimination.cpp +++ b/lib/SILOptimizer/Mandatory/DiagnosticDeadFunctionElimination.cpp @@ -72,7 +72,7 @@ struct DiagnosticDeadFunctionEliminator : SILFunctionTransform { // ODR shootouts. if (fn->getLinkage() == SILLinkage::Shared) { fn->setLinkage(SILLinkage::Private); - fn->setSerialized(IsNotSerialized); + fn->setSerializedKind(IsNotSerialized); } invalidateAnalysis(SILAnalysis::InvalidationKind::FunctionBody); diff --git a/lib/SILOptimizer/Mandatory/Differentiation.cpp b/lib/SILOptimizer/Mandatory/Differentiation.cpp index 51ff587a094ff..621a90321b0bb 100644 --- a/lib/SILOptimizer/Mandatory/Differentiation.cpp +++ b/lib/SILOptimizer/Mandatory/Differentiation.cpp @@ -110,9 +110,10 @@ class DifferentiationTransformer { /// /// \param serializeFunctions specifies whether generated functions should be /// serialized. - bool canonicalizeDifferentiabilityWitness( - SILDifferentiabilityWitness *witness, DifferentiationInvoker invoker, - IsSerialized_t serializeFunctions); + bool + canonicalizeDifferentiabilityWitness(SILDifferentiabilityWitness *witness, + DifferentiationInvoker invoker, + SerializedKind_t serializeFunctions); /// Process the given `differentiable_function` instruction, filling in /// missing derivative functions if necessary. @@ -749,7 +750,7 @@ emitDerivativeFunctionReference( static SILFunction *createEmptyVJP(ADContext &context, SILDifferentiabilityWitness *witness, - IsSerialized_t isSerialized) { + SerializedKind_t isSerialized) { auto original = witness->getOriginalFunction(); auto config = witness->getConfig(); LLVM_DEBUG({ @@ -794,7 +795,7 @@ static SILFunction *createEmptyVJP(ADContext &context, static SILFunction *createEmptyJVP(ADContext &context, SILDifferentiabilityWitness *witness, - IsSerialized_t isSerialized) { + SerializedKind_t isSerialized) { auto original = witness->getOriginalFunction(); auto config = witness->getConfig(); LLVM_DEBUG({ @@ -871,7 +872,7 @@ static void emitFatalError(ADContext &context, SILFunction *f, /// Returns true on error. bool DifferentiationTransformer::canonicalizeDifferentiabilityWitness( SILDifferentiabilityWitness *witness, DifferentiationInvoker invoker, - IsSerialized_t serializeFunctions) { + SerializedKind_t serializeFunctions) { std::string traceMessage; llvm::raw_string_ostream OS(traceMessage); OS << "processing "; @@ -1020,10 +1021,10 @@ static SILValue promoteCurryThunkApplicationToDifferentiableFunction( SILOptFunctionBuilder fb(dt.getTransform()); auto *newThunk = fb.getOrCreateFunction( loc, newThunkName, getSpecializedLinkage(thunk, thunk->getLinkage()), - thunkType, thunk->isBare(), thunk->isTransparent(), thunk->isSerialized(), - thunk->isDynamicallyReplaceable(), thunk->isDistributed(), - thunk->isRuntimeAccessible(), - ProfileCounter(), thunk->isThunk()); + thunkType, thunk->isBare(), thunk->isTransparent(), + thunk->getSerializedKind(), thunk->isDynamicallyReplaceable(), + thunk->isDistributed(), thunk->isRuntimeAccessible(), ProfileCounter(), + thunk->isThunk()); // If new thunk is newly created: clone the old thunk body, wrap the // returned function value with an `differentiable_function` // instruction, and process the `differentiable_function` instruction. @@ -1372,7 +1373,8 @@ void Differentiation::run() { auto *witness = invokerPair.first; auto invoker = invokerPair.second; if (transformer.canonicalizeDifferentiabilityWitness( - witness, invoker, witness->getOriginalFunction()->isSerialized())) + witness, invoker, + witness->getOriginalFunction()->getSerializedKind())) errorOccurred = true; } diff --git a/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp b/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp index f11e5abcf773b..dae66cea5e392 100644 --- a/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp +++ b/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp @@ -753,9 +753,9 @@ getCalleeFunction(SILFunction *F, FullApplySite AI, bool &IsThick, if (CalleeFunction->empty()) return nullptr; - if (F->isSerialized() && - !CalleeFunction->hasValidLinkageForFragileInline()) { - if (!CalleeFunction->hasValidLinkageForFragileRef()) { + if (!CalleeFunction->canBeInlinedIntoCaller(F->getSerializedKind())) { + if (F->isAnySerialized() && + !CalleeFunction->hasValidLinkageForFragileRef(F->getSerializedKind())) { llvm::errs() << "caller: " << F->getName() << "\n"; llvm::errs() << "callee: " << CalleeFunction->getName() << "\n"; llvm_unreachable("Should never be inlining a resilient function into " diff --git a/lib/SILOptimizer/PassManager/PassManager.cpp b/lib/SILOptimizer/PassManager/PassManager.cpp index 299e03351ce1d..fdfd4fb64b4ee 100644 --- a/lib/SILOptimizer/PassManager/PassManager.cpp +++ b/lib/SILOptimizer/PassManager/PassManager.cpp @@ -1711,8 +1711,8 @@ BridgedOwnedString BridgedPassContext::mangleAsyncRemoved(BridgedFunction functi // FIXME: hard assumption on what pass is requesting this. auto P = Demangle::SpecializationPass::AsyncDemotion; - Mangle::FunctionSignatureSpecializationMangler Mangler(P, F->isSerialized(), - F); + Mangle::FunctionSignatureSpecializationMangler Mangler( + P, F->getSerializedKind(), F); Mangler.setRemovedEffect(EffectKind::Async); return Mangler.mangle(); } @@ -1721,7 +1721,9 @@ BridgedOwnedString BridgedPassContext::mangleWithDeadArgs(const SwiftInt * _Null SwiftInt numDeadArgs, BridgedFunction function) const { SILFunction *f = function.getFunction(); - Mangle::FunctionSignatureSpecializationMangler Mangler(Demangle::SpecializationPass::FunctionSignatureOpts, f->isSerialized(), f); + Mangle::FunctionSignatureSpecializationMangler Mangler( + Demangle::SpecializationPass::FunctionSignatureOpts, + f->getSerializedKind(), f); for (SwiftInt idx = 0; idx < numDeadArgs; idx++) { Mangler.setArgumentDead((unsigned)idx); } @@ -1821,11 +1823,12 @@ createEmptyFunction(BridgedStringRef name, SILOptFunctionBuilder functionBuilder(*invocation->getTransform()); SILFunction *newF = functionBuilder.createFunction( - fromFn->getLinkage(), name.unbridged(), newTy, nullptr, fromFn->getLocation(), fromFn->isBare(), - fromFn->isTransparent(), fromFn->isSerialized(), IsNotDynamic, IsNotDistributed, - IsNotRuntimeAccessible, fromFn->getEntryCount(), fromFn->isThunk(), - fromFn->getClassSubclassScope(), fromFn->getInlineStrategy(), fromFn->getEffectsKind(), - nullptr, fromFn->getDebugScope()); + fromFn->getLinkage(), name.unbridged(), newTy, nullptr, + fromFn->getLocation(), fromFn->isBare(), fromFn->isTransparent(), + fromFn->getSerializedKind(), IsNotDynamic, IsNotDistributed, + IsNotRuntimeAccessible, fromFn->getEntryCount(), fromFn->isThunk(), + fromFn->getClassSubclassScope(), fromFn->getInlineStrategy(), + fromFn->getEffectsKind(), nullptr, fromFn->getDebugScope()); return {newF}; } diff --git a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp index c96e73bbf10c9..28c2ffce5d1b9 100644 --- a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp +++ b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp @@ -761,7 +761,7 @@ class PromotedParamCloner : public SILClonerWithScopes { public: PromotedParamCloner(SILOptFunctionBuilder &FuncBuilder, SILFunction *Orig, - IsSerialized_t Serialized, + SerializedKind_t Serialized, ArgIndexList &PromotedArgIndices, StringRef ClonedName); void populateCloned(); @@ -770,7 +770,7 @@ class PromotedParamCloner : public SILClonerWithScopes { private: static SILFunction *initCloned(SILOptFunctionBuilder &FuncBuilder, - SILFunction *Orig, IsSerialized_t Serialized, + SILFunction *Orig, SerializedKind_t Serialized, ArgIndexList &PromotedArgIndices, StringRef ClonedName); @@ -789,7 +789,7 @@ class PromotedParamCloner : public SILClonerWithScopes { PromotedParamCloner::PromotedParamCloner(SILOptFunctionBuilder &FuncBuilder, SILFunction *Orig, - IsSerialized_t Serialized, + SerializedKind_t Serialized, ArgIndexList &PromotedArgIndices, StringRef ClonedName) : SILClonerWithScopes(*initCloned( @@ -800,7 +800,7 @@ PromotedParamCloner::PromotedParamCloner(SILOptFunctionBuilder &FuncBuilder, getCloned()->getDebugScope()->getParentFunction()); } -static std::string getClonedName(SILFunction *F, IsSerialized_t Serialized, +static std::string getClonedName(SILFunction *F, SerializedKind_t Serialized, ArgIndexList &PromotedArgIndices) { auto P = Demangle::SpecializationPass::AllocBoxToStack; Mangle::FunctionSignatureSpecializationMangler Mangler(P, Serialized, F); @@ -815,7 +815,7 @@ static std::string getClonedName(SILFunction *F, IsSerialized_t Serialized, /// parameters (which are specified by PromotedArgIndices). SILFunction *PromotedParamCloner::initCloned(SILOptFunctionBuilder &FuncBuilder, SILFunction *Orig, - IsSerialized_t Serialized, + SerializedKind_t Serialized, ArgIndexList &PromotedArgIndices, StringRef ClonedName) { SILModule &M = Orig->getModule(); @@ -1041,22 +1041,19 @@ specializeApplySite(SILOptFunctionBuilder &FuncBuilder, ApplySite Apply, auto *F = FRI->getReferencedFunction(); assert(F && "Expected a referenced function!"); - IsSerialized_t Serialized = IsNotSerialized; - if (Apply.getFunction()->isSerialized()) - Serialized = IsSerialized; - + SerializedKind_t serializedKind = Apply.getFunction()->getSerializedKind(); std::string ClonedName = - getClonedName(F, Serialized, PromotedCalleeArgIndices); + getClonedName(F, serializedKind, PromotedCalleeArgIndices); auto &M = Apply.getModule(); SILFunction *ClonedFn; if (auto *PrevFn = M.lookUpFunction(ClonedName)) { - assert(PrevFn->isSerialized() == Serialized); + assert(PrevFn->getSerializedKind() == serializedKind); ClonedFn = PrevFn; } else { // Clone the function the existing ApplySite references. - PromotedParamCloner Cloner(FuncBuilder, F, Serialized, + PromotedParamCloner Cloner(FuncBuilder, F, serializedKind, PromotedCalleeArgIndices, ClonedName); Cloner.populateCloned(); diff --git a/lib/SILOptimizer/Transforms/VTableSpecializer.cpp b/lib/SILOptimizer/Transforms/VTableSpecializer.cpp index 027225e90ca8e..580da21a9056c 100644 --- a/lib/SILOptimizer/Transforms/VTableSpecializer.cpp +++ b/lib/SILOptimizer/Transforms/VTableSpecializer.cpp @@ -230,7 +230,7 @@ static SILFunction *specializeVTableMethod(SILFunction *origMethod, module.linkFunction(SpecializedF, SILModule::LinkingMode::LinkAll); SpecializedF->setLinkage(SILLinkage::Public); - SpecializedF->setSerialized(IsNotSerialized); + SpecializedF->setSerializedKind(IsNotSerialized); return SpecializedF; } diff --git a/lib/SILOptimizer/UtilityPasses/SILSkippingChecker.cpp b/lib/SILOptimizer/UtilityPasses/SILSkippingChecker.cpp index 84510ecddc80c..9481690f36cdf 100644 --- a/lib/SILOptimizer/UtilityPasses/SILSkippingChecker.cpp +++ b/lib/SILOptimizer/UtilityPasses/SILSkippingChecker.cpp @@ -32,7 +32,7 @@ static bool shouldHaveSkippedFunction(const SILFunction &F) { // First, we only care about functions that haven't been marked serialized. // If they've been marked serialized, they will end up in the final module // and we needed to SILGen them. - if (F.isSerialized()) + if (F.isAnySerialized()) return false; // Next, we're looking for functions that shouldn't have a body, but do. If diff --git a/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp b/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp index 3c1ba628ad2dc..29ee1ca0db6f4 100644 --- a/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp +++ b/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp @@ -459,8 +459,8 @@ class SerializeSILPass : public SILModuleTransform { /// optimizations and for a better dead function elimination. void removeSerializedFlagFromAllFunctions(SILModule &M) { for (auto &F : M) { - bool wasSerialized = F.isSerialized() != IsNotSerialized; - F.setSerialized(IsNotSerialized); + bool wasSerialized = F.isAnySerialized(); + F.setSerializedKind(IsNotSerialized); // We are removing [serialized] from the function. This will change how // opaque archetypes are lowered in SIL - they might lower to their @@ -492,15 +492,15 @@ class SerializeSILPass : public SILModuleTransform { } for (auto &WT : M.getWitnessTables()) { - WT.setSerialized(IsNotSerialized); + WT.setSerializedKind(IsNotSerialized); } for (auto &VT : M.getVTables()) { - VT->setSerialized(IsNotSerialized); + VT->setSerializedKind(IsNotSerialized); } for (auto &Deinit : M.getMoveOnlyDeinits()) { - Deinit->setSerialized(IsNotSerialized); + Deinit->setSerializedKind(IsNotSerialized); } } diff --git a/lib/SILOptimizer/Utils/CastOptimizer.cpp b/lib/SILOptimizer/Utils/CastOptimizer.cpp index e56ed4ff75c74..908feba5e5405 100644 --- a/lib/SILOptimizer/Utils/CastOptimizer.cpp +++ b/lib/SILOptimizer/Utils/CastOptimizer.cpp @@ -530,8 +530,8 @@ findBridgeToObjCFunc(SILOptFunctionBuilder &functionBuilder, bridgedFunc->setParentModule( resultDecl->getDeclContext()->getParentModule()); - if (dynamicCast.getFunction()->isSerialized() && - !bridgedFunc->hasValidLinkageForFragileRef()) + if (dynamicCast.getFunction()->isAnySerialized() && + !bridgedFunc->hasValidLinkageForFragileRef(dynamicCast.getFunction()->getSerializedKind())) return std::nullopt; if (bridgedFunc->getLoweredFunctionType() diff --git a/lib/SILOptimizer/Utils/Devirtualize.cpp b/lib/SILOptimizer/Utils/Devirtualize.cpp index 55731d538510b..09aa9ef17a484 100644 --- a/lib/SILOptimizer/Utils/Devirtualize.cpp +++ b/lib/SILOptimizer/Utils/Devirtualize.cpp @@ -721,10 +721,11 @@ bool swift::canDevirtualizeClassMethod(FullApplySite applySite, ClassDecl *cd, return false; } - if (applySite.getFunction()->isSerialized()) { + if (applySite.getFunction()->isAnySerialized()) { // function_ref inside fragile function cannot reference a private or // hidden symbol. - if (!f->hasValidLinkageForFragileRef()) + if (!f->hasValidLinkageForFragileRef( + applySite.getFunction()->getSerializedKind())) return false; } @@ -1171,12 +1172,11 @@ static bool canDevirtualizeWitnessMethod(ApplySite applySite, bool isMandatory) if (!f) return false; - if (applySite.getFunction()->isSerialized()) { - // function_ref inside fragile function cannot reference a private or - // hidden symbol. - if (!f->hasValidLinkageForFragileRef()) - return false; - } + // function_ref inside fragile function cannot reference a private or + // hidden symbol. + if (applySite.getFunction()->isAnySerialized() && + !f->hasValidLinkageForFragileRef(applySite.getFunction()->getSerializedKind())) + return false; // devirtualizeWitnessMethod below does not support this case. It currently // assumes it can try_apply call the target. diff --git a/lib/SILOptimizer/Utils/GenericCloner.cpp b/lib/SILOptimizer/Utils/GenericCloner.cpp index 3f40e9effc6e2..b3c39ee99764d 100644 --- a/lib/SILOptimizer/Utils/GenericCloner.cpp +++ b/lib/SILOptimizer/Utils/GenericCloner.cpp @@ -43,7 +43,7 @@ SILFunction *GenericCloner::createDeclaration( getSpecializedLinkage(Orig, Orig->getLinkage()), NewName, ReInfo.getSpecializedType(), ReInfo.getSpecializedGenericEnvironment(), Orig->getLocation(), Orig->isBare(), Orig->isTransparent(), - ReInfo.isSerialized(), IsNotDynamic, IsNotDistributed, + ReInfo.getSerializedKind(), IsNotDynamic, IsNotDistributed, IsNotRuntimeAccessible, Orig->getEntryCount(), Orig->isThunk(), Orig->getClassSubclassScope(), Orig->getInlineStrategy(), Orig->getEffectsKind(), Orig, Orig->getDebugScope()); diff --git a/lib/SILOptimizer/Utils/Generics.cpp b/lib/SILOptimizer/Utils/Generics.cpp index ec02377b9488d..93ec3842399c9 100644 --- a/lib/SILOptimizer/Utils/Generics.cpp +++ b/lib/SILOptimizer/Utils/Generics.cpp @@ -598,11 +598,11 @@ bool ReabstractionInfo::canBeSpecialized(ApplySite Apply, SILFunction *Callee, ReabstractionInfo::ReabstractionInfo( ModuleDecl *targetModule, bool isWholeModule, ApplySite Apply, - SILFunction *Callee, SubstitutionMap ParamSubs, IsSerialized_t Serialized, - bool ConvertIndirectToDirect, bool dropMetatypeArgs, OptRemark::Emitter *ORE) + SILFunction *Callee, SubstitutionMap ParamSubs, SerializedKind_t Serialized, + bool ConvertIndirectToDirect, bool dropMetatypeArgs, + OptRemark::Emitter *ORE) : ConvertIndirectToDirect(ConvertIndirectToDirect), - dropMetatypeArgs(dropMetatypeArgs), - M(&Callee->getModule()), + dropMetatypeArgs(dropMetatypeArgs), M(&Callee->getModule()), TargetModule(targetModule), isWholeModule(isWholeModule), Serialized(Serialized) { if (!prepareAndCheck(Apply, Callee, ParamSubs, ORE)) @@ -1948,7 +1948,7 @@ ReabstractionInfo::ReabstractionInfo(ModuleDecl *targetModule, : M(&Callee->getModule()), TargetModule(targetModule), isWholeModule(isWholeModule), isPrespecialization(isPrespecialization) { Serialized = - this->isPrespecialization ? IsNotSerialized : Callee->isSerialized(); + this->isPrespecialization ? IsNotSerialized : Callee->getSerializedKind(); if (shouldNotSpecialize(Callee, nullptr)) return; @@ -1987,11 +1987,11 @@ GenericFuncSpecializer::GenericFuncSpecializer( if (ReInfo.isPartialSpecialization()) { Mangle::PartialSpecializationMangler Mangler( - GenericFunc, FnTy, ReInfo.isSerialized(), /*isReAbstracted*/ true); + GenericFunc, FnTy, ReInfo.getSerializedKind(), /*isReAbstracted*/ true); ClonedName = Mangler.mangle(); } else { Mangle::GenericSpecializationMangler Mangler( - GenericFunc, ReInfo.isSerialized()); + GenericFunc, ReInfo.getSerializedKind()); if (ReInfo.isPrespecialized()) { ClonedName = Mangler.manglePrespecialized(ParamSubs); } else { @@ -2509,13 +2509,13 @@ class ReabstractionThunkGenerator { SpecializedFunc(SpecializedFunc), ReInfo(ReInfo), OrigPAI(OrigPAI), Loc(RegularLocation::getAutoGeneratedLocation()) { if (!ReInfo.isPartialSpecialization()) { - Mangle::GenericSpecializationMangler Mangler(OrigF, ReInfo.isSerialized()); + Mangle::GenericSpecializationMangler Mangler(OrigF, ReInfo.getSerializedKind()); ThunkName = Mangler.mangleNotReabstracted( ReInfo.getCalleeParamSubstitutionMap(), ReInfo.hasDroppedMetatypeArgs()); } else { Mangle::PartialSpecializationMangler Mangler( - OrigF, ReInfo.getSpecializedType(), ReInfo.isSerialized(), + OrigF, ReInfo.getSpecializedType(), ReInfo.getSerializedKind(), /*isReAbstracted*/ false); ThunkName = Mangler.mangle(); @@ -2544,7 +2544,7 @@ SILFunction *ReabstractionThunkGenerator::createThunk() { CanSILFunctionType thunkType = ReInfo.createThunkType(OrigPAI); SILFunction *Thunk = FunctionBuilder.getOrCreateSharedFunction( Loc, ThunkName, thunkType, IsBare, IsTransparent, - ReInfo.isSerialized(), ProfileCounter(), IsThunk, IsNotDynamic, + ReInfo.getSerializedKind(), ProfileCounter(), IsThunk, IsNotDynamic, IsNotDistributed, IsNotRuntimeAccessible); // Re-use an existing thunk. if (!Thunk->empty()) @@ -2808,7 +2808,7 @@ static bool createPrespecialized(StringRef UnspecializedName, M.linkFunction(SpecializedF, SILModule::LinkingMode::LinkAll); SpecializedF->setLinkage(SILLinkage::Public); - SpecializedF->setSerialized(IsNotSerialized); + SpecializedF->setSerializedKind(IsNotSerialized); return true; } @@ -3006,7 +3006,7 @@ bool usePrespecialized( ReabstractionInfo layoutReInfo = ReabstractionInfo( funcBuilder.getModule().getSwiftModule(), funcBuilder.getModule().isWholeModule(), apply, refF, newSubstMap, - apply.getFunction()->isSerialized() ? IsSerialized : IsNotSerialized, + apply.getFunction()->getSerializedKind(), /*ConvertIndirectToDirect=*/ true, /*dropMetatypeArgs=*/ false, nullptr); if (layoutReInfo.getSpecializedType() == reInfo.getSpecializedType()) { @@ -3018,7 +3018,7 @@ bool usePrespecialized( } SubstitutionMap subs = reInfo.getCalleeParamSubstitutionMap(); - Mangle::GenericSpecializationMangler mangler(refF, reInfo.isSerialized()); + Mangle::GenericSpecializationMangler mangler(refF, reInfo.getSerializedKind()); std::string name = reInfo.isPrespecialized() ? mangler.manglePrespecialized(subs) : mangler.mangleReabstracted(subs, reInfo.needAlternativeMangling()); @@ -3047,7 +3047,7 @@ bool usePrespecialized( // TODO: Deduplicate SubstitutionMap subs = reInfo.getCalleeParamSubstitutionMap(); - Mangle::GenericSpecializationMangler mangler(refF, reInfo.isSerialized()); + Mangle::GenericSpecializationMangler mangler(refF, reInfo.getSerializedKind()); std::string name = reInfo.isPrespecialized() ? mangler.manglePrespecialized(subs) : mangler.mangleReabstracted( @@ -3140,10 +3140,10 @@ void swift::trySpecializeApplyOfGeneric( // callee either. bool needSetLinkage = false; if (isMandatory) { - if (F->isSerialized() && !RefF->hasValidLinkageForFragileInline()) + if (!RefF->canBeInlinedIntoCaller(F->getSerializedKind())) needSetLinkage = true; } else { - if (F->isSerialized() && !RefF->hasValidLinkageForFragileInline()) + if (!RefF->canBeInlinedIntoCaller(F->getSerializedKind())) return; if (shouldNotSpecialize(RefF, F)) @@ -3153,9 +3153,7 @@ void swift::trySpecializeApplyOfGeneric( // If the caller and callee are both fragile, preserve the fragility when // cloning the callee. Otherwise, strip it off so that we can optimize // the body more. - IsSerialized_t Serialized = IsNotSerialized; - if (F->isSerialized()) - Serialized = IsSerialized; + SerializedKind_t serializedKind = F->getSerializedKind(); // If it is OnoneSupport consider all specializations as non-serialized // as we do not SIL serialize their bodies. @@ -3165,12 +3163,12 @@ void swift::trySpecializeApplyOfGeneric( if (createPrespecializations(Apply, RefF, FuncBuilder)) { return; } - Serialized = IsNotSerialized; + serializedKind = IsNotSerialized; } ReabstractionInfo ReInfo(FuncBuilder.getModule().getSwiftModule(), FuncBuilder.getModule().isWholeModule(), Apply, RefF, - Apply.getSubstitutionMap(), Serialized, + Apply.getSubstitutionMap(), serializedKind, /*ConvertIndirectToDirect=*/ true, /*dropMetatypeArgs=*/ canDropMetatypeArgs(Apply, RefF), &ORE); @@ -3266,19 +3264,21 @@ void swift::trySpecializeApplyOfGeneric( } if (needSetLinkage) { - assert(F->isSerialized() && !RefF->hasValidLinkageForFragileInline()); + assert(F->isAnySerialized() && + !RefF->canBeInlinedIntoCaller(F->getSerializedKind())); // If called from a serialized function we cannot make the specialized function // shared and non-serialized. The only other option is to keep the original // function's linkage. It's not great, because it can prevent dead code // elimination - usually the original function is a public function. SpecializedF->setLinkage(RefF->getLinkage()); - SpecializedF->setSerialized(IsNotSerialized); - } else if (F->isSerialized() && !SpecializedF->hasValidLinkageForFragileInline()) { + SpecializedF->setSerializedKind(IsNotSerialized); + } else if (F->isAnySerialized() && + !SpecializedF->canBeInlinedIntoCaller(F->getSerializedKind())) { // If the specialized function already exists as a "IsNotSerialized" function, - // but now it's called from a "IsSerialized" function, we need to mark it as - // IsSerialized. - SpecializedF->setSerialized(IsSerialized); - assert(SpecializedF->hasValidLinkageForFragileInline()); + // but now it's called from a serialized function, we need to mark it the + // same as its SerializedKind. + SpecializedF->setSerializedKind(F->getSerializedKind()); + assert(SpecializedF->canBeInlinedIntoCaller(F->getSerializedKind())); // ... including all referenced shared functions. FuncBuilder.getModule().linkFunction(SpecializedF.getFunction(), diff --git a/lib/SILOptimizer/Utils/InstOptUtils.cpp b/lib/SILOptimizer/Utils/InstOptUtils.cpp index 836b2807548fe..6ab9d12d599b4 100644 --- a/lib/SILOptimizer/Utils/InstOptUtils.cpp +++ b/lib/SILOptimizer/Utils/InstOptUtils.cpp @@ -554,7 +554,7 @@ TermInst *swift::addArgumentsToBranch(ArrayRef vals, } SILLinkage swift::getSpecializedLinkage(SILFunction *f, SILLinkage linkage) { - if (hasPrivateVisibility(linkage) && !f->isSerialized()) { + if (hasPrivateVisibility(linkage) && !f->isAnySerialized()) { // Specializations of private symbols should remain so, unless // they were serialized, which can only happen when specializing // definitions from a standard library built with -sil-serialize-all. diff --git a/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp b/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp index 7c7a586724a9c..fe177898f4a26 100644 --- a/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp +++ b/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp @@ -846,9 +846,9 @@ SILFunction *swift::getEligibleFunction(FullApplySite AI, } // A non-fragile function may not be inlined into a fragile function. - if (Caller->isSerialized() && - !Callee->hasValidLinkageForFragileInline()) { - if (!Callee->hasValidLinkageForFragileRef()) { + if (!Callee->canBeInlinedIntoCaller(Caller->getSerializedKind())) { + if (Caller->isAnySerialized() && + !Callee->hasValidLinkageForFragileRef(Caller->getSerializedKind())) { llvm::errs() << "caller: " << Caller->getName() << "\n"; llvm::errs() << "callee: " << Callee->getName() << "\n"; llvm_unreachable("Should never be inlining a resilient function into " diff --git a/lib/SILOptimizer/Utils/SpecializationMangler.cpp b/lib/SILOptimizer/Utils/SpecializationMangler.cpp index fbfb59f809a92..1c48581dda109 100644 --- a/lib/SILOptimizer/Utils/SpecializationMangler.cpp +++ b/lib/SILOptimizer/Utils/SpecializationMangler.cpp @@ -37,10 +37,9 @@ std::string PartialSpecializationMangler::mangle() { // Function Signature Optimizations //===----------------------------------------------------------------------===// -FunctionSignatureSpecializationMangler:: -FunctionSignatureSpecializationMangler(Demangle::SpecializationPass P, - IsSerialized_t Serialized, SILFunction *F) - : SpecializationMangler(P, Serialized, F) { +FunctionSignatureSpecializationMangler::FunctionSignatureSpecializationMangler( + Demangle::SpecializationPass P, SerializedKind_t Serialized, SILFunction *F) + : SpecializationMangler(P, Serialized, F) { for (unsigned i = 0, e = F->getConventions().getNumSILArguments(); i != e; ++i) { (void)i; diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index bdc1b9fb720e1..4e582feacc04f 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -563,7 +563,7 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, IdentifierID replacedFunctionID; IdentifierID usedAdHocWitnessFunctionID; GenericSignatureID genericSigID; - unsigned rawLinkage, isTransparent, isSerialized, isThunk, + unsigned rawLinkage, isTransparent, serializedKind, isThunk, isWithoutActuallyEscapingThunk, specialPurpose, inlineStrategy, optimizationMode, perfConstr, subclassScope, hasCReferences, effect, numAttrs, hasQualifiedOwnership, isWeakImported, @@ -571,7 +571,7 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, isDistributed, isRuntimeAccessible, forceEnableLexicalLifetimes; ArrayRef SemanticsIDs; SILFunctionLayout::readRecord( - scratch, rawLinkage, isTransparent, isSerialized, isThunk, + scratch, rawLinkage, isTransparent, serializedKind, isThunk, isWithoutActuallyEscapingThunk, specialPurpose, inlineStrategy, optimizationMode, perfConstr, subclassScope, hasCReferences, effect, numAttrs, hasQualifiedOwnership, isWeakImported, @@ -640,7 +640,7 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, // as serialized, since we no longer need to enforce resilience // boundaries. if (SILMod.isSerialized()) - isSerialized = IsNotSerialized; + serializedKind = IsNotSerialized; SILSerializationFunctionBuilder builder(SILMod); @@ -654,7 +654,7 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, return MF->diagnoseFatal(std::move(error)); } - fn->setSerialized(IsSerialized_t(isSerialized)); + fn->setSerializedKind(SerializedKind_t(serializedKind)); // If the serialized function comes from the same module, we're merging // modules, and can update the linkage directly. This is needed to @@ -702,7 +702,7 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, fn = builder.createDeclaration(name, ty, loc); fn->setLinkage(linkage); fn->setTransparent(IsTransparent_t(isTransparent == 1)); - fn->setSerialized(IsSerialized_t(isSerialized)); + fn->setSerializedKind(SerializedKind_t(serializedKind)); fn->setThunk(IsThunk_t(isThunk)); fn->setWithoutActuallyEscapingThunk(bool(isWithoutActuallyEscapingThunk)); fn->setInlineStrategy(Inline_t(inlineStrategy)); @@ -966,8 +966,8 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, Callback->didDeserializeFunctionBody(MF->getAssociatedModule(), fn); if (!MF->isSIB() && !SILMod.isSerialized()) { - assert((fn->isSerialized() || fn->empty()) && - "deserialized function must have the IsSerialized flag set"); + assert((fn->isAnySerialized() || fn->empty()) && + "deserialized function must have the IsSerialized or IsSerializedForPackage flag set"); } return fn; } @@ -3514,7 +3514,7 @@ bool SILDeserializer::hasSILFunction(StringRef Name, IdentifierID replacedFunctionID; IdentifierID usedAdHocWitnessFunctionID; GenericSignatureID genericSigID; - unsigned rawLinkage, isTransparent, isSerialized, isThunk, + unsigned rawLinkage, isTransparent, serializedKind, isThunk, isWithoutActuallyEscapingThunk, isGlobal, inlineStrategy, optimizationMode, perfConstr, subclassScope, hasCReferences, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, @@ -3522,7 +3522,7 @@ bool SILDeserializer::hasSILFunction(StringRef Name, isDistributed, isRuntimeAccessible, forceEnableLexicalLifetimes; ArrayRef SemanticsIDs; SILFunctionLayout::readRecord( - scratch, rawLinkage, isTransparent, isSerialized, isThunk, + scratch, rawLinkage, isTransparent, serializedKind, isThunk, isWithoutActuallyEscapingThunk, isGlobal, inlineStrategy, optimizationMode, perfConstr, subclassScope, hasCReferences, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, @@ -3617,8 +3617,8 @@ SILGlobalVariable *SILDeserializer::readGlobalVar(StringRef Name) { TypeID TyID; DeclID dID; - unsigned rawLinkage, isSerialized, IsDeclaration, IsLet; - SILGlobalVarLayout::readRecord(scratch, rawLinkage, isSerialized, + unsigned rawLinkage, serializedKind, IsDeclaration, IsLet; + SILGlobalVarLayout::readRecord(scratch, rawLinkage, serializedKind, IsDeclaration, IsLet, TyID, dID); if (TyID == 0) { LLVM_DEBUG(llvm::dbgs() << "SILGlobalVariable typeID is 0.\n"); @@ -3634,7 +3634,7 @@ SILGlobalVariable *SILDeserializer::readGlobalVar(StringRef Name) { auto Ty = MF->getType(TyID); SILGlobalVariable *v = SILGlobalVariable::create( - SILMod, linkage.value(), isSerialized ? IsSerialized : IsNotSerialized, + SILMod, linkage.value(), SerializedKind_t(serializedKind), Name.str(), getSILType(Ty, SILValueCategory::Object, nullptr), std::nullopt, dID ? cast(MF->getDecl(dID)) : nullptr); v->setLet(IsLet); @@ -3827,11 +3827,11 @@ SILVTable *SILDeserializer::readVTable(DeclID VId) { // as serialized, since we no longer need to enforce resilience // boundaries. if (SILMod.isSerialized()) - Serialized = 0; + Serialized = unsigned(SerializedKind_t::IsNotSerialized); SILVTable *vT = SILVTable::create( SILMod, theClass, - Serialized ? IsSerialized : IsNotSerialized, + SerializedKind_t(Serialized), vtableEntries); vTableOrOffset.set(vT, true /*isFullyDeserialized*/); @@ -3911,7 +3911,7 @@ SILMoveOnlyDeinit *SILDeserializer::readMoveOnlyDeinit(DeclID tableID) { rawSerialized = 0; auto *deinit = SILMoveOnlyDeinit::create( - SILMod, theNomDecl, rawSerialized ? IsSerialized : IsNotSerialized, + SILMod, theNomDecl, SerializedKind_t(rawSerialized), theFunc); moveOnlyDeinitOrOffset.set(deinit, true /*isFullyDeserialized*/); @@ -3975,7 +3975,7 @@ SILProperty *SILDeserializer::readProperty(DeclID PId) { DeclID StorageID; ArrayRef ComponentValues; PropertyLayout::readRecord(scratch, StorageID, Serialized, ComponentValues); - + auto decl = cast(MF->getDecl(StorageID)); unsigned ComponentValueIndex = 0; auto component = readKeyPathComponent(ComponentValues, ComponentValueIndex); @@ -4133,7 +4133,6 @@ llvm::Expected ProtocolConformanceID conformance; WitnessTableLayout::readRecord(scratch, RawLinkage, IsDeclaration, Serialized, conformance); - auto Linkage = fromStableSILLinkage(RawLinkage); if (!Linkage) { LLVM_DEBUG(llvm::dbgs() << "invalid linkage code " << RawLinkage @@ -4208,10 +4207,10 @@ llvm::Expected // as serialized, since we no longer need to enforce resilience // boundaries. if (SILMod.isSerialized()) - Serialized = 0; + Serialized = unsigned(SerializedKind_t::IsNotSerialized); wT->convertToDefinition(witnessEntries, conditionalConformances, - Serialized ? IsSerialized : IsNotSerialized); + SerializedKind_t(Serialized)); wTableOrOffset.set(wT, /*fully deserialized*/ true); if (Callback) Callback->didDeserializeWitnessTableEntries(MF->getAssociatedModule(), wT); diff --git a/lib/Serialization/ModuleFile.h b/lib/Serialization/ModuleFile.h index 4b53b80536dc1..bbc53f087daf7 100644 --- a/lib/Serialization/ModuleFile.h +++ b/lib/Serialization/ModuleFile.h @@ -659,6 +659,11 @@ class ModuleFile return Core->Bits.AllowNonResilientAccess; } + /// Whether this module was built with -experimental-package-cmo. + bool serializePackageEnabled() const { + return Core->Bits.SerializePackageEnabled; + } + /// Whether this module is compiled with implicit dynamic. bool isImplicitDynamicEnabled() const { return Core->Bits.IsImplicitDynamicEnabled; diff --git a/lib/Serialization/ModuleFileSharedCore.cpp b/lib/Serialization/ModuleFileSharedCore.cpp index fe6404ebd3ef0..26ff2ecc84ab1 100644 --- a/lib/Serialization/ModuleFileSharedCore.cpp +++ b/lib/Serialization/ModuleFileSharedCore.cpp @@ -200,6 +200,9 @@ static bool readOptionsBlock(llvm::BitstreamCursor &cursor, case options_block::ALLOW_NON_RESILIENT_ACCESS: extendedInfo.setAllowNonResilientAccess(true); break; + case options_block::SERIALIZE_PACKAGE_ENABLED: + extendedInfo.setSerializePackageEnabled(true); + break; default: // Unknown options record, possibly for use by a future version of the // module format. @@ -1448,6 +1451,7 @@ ModuleFileSharedCore::ModuleFileSharedCore( Bits.IsConcurrencyChecked = extInfo.isConcurrencyChecked(); Bits.HasCxxInteroperability = extInfo.hasCxxInteroperability(); Bits.AllowNonResilientAccess = extInfo.allowNonResilientAccess(); + Bits.SerializePackageEnabled = extInfo.serializePackageEnabled(); MiscVersion = info.miscVersion; ModuleABIName = extInfo.getModuleABIName(); ModulePackageName = extInfo.getModulePackageName(); diff --git a/lib/Serialization/ModuleFileSharedCore.h b/lib/Serialization/ModuleFileSharedCore.h index 24c3eaa5ceb86..dba0017ac0db9 100644 --- a/lib/Serialization/ModuleFileSharedCore.h +++ b/lib/Serialization/ModuleFileSharedCore.h @@ -391,6 +391,9 @@ class ModuleFileSharedCore { /// Whether this module is built with -experimental-allow-non-resilient-access. unsigned AllowNonResilientAccess : 1; + /// Whether this module is built with -experimental-package-cmo. + unsigned SerializePackageEnabled : 1; + // Explicitly pad out to the next word boundary. unsigned : 3; } Bits = {}; diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 27e74a19d2f4f..db7285ec211ce 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 = 869; // ~ for suppression +const uint16_t SWIFTMODULE_VERSION_MINOR = 870; // SerializePackageEnabled / [serialized_for_package] for SILFunctionLayout / package field in SerializedKind_t /// A standard hash seed used for all string hashes in a serialized module. /// @@ -941,6 +941,7 @@ namespace options_block { PLUGIN_SEARCH_OPTION, HAS_CXX_INTEROPERABILITY_ENABLED, ALLOW_NON_RESILIENT_ACCESS, + SERIALIZE_PACKAGE_ENABLED, }; using SDKPathLayout = BCRecordLayout< @@ -1027,6 +1028,10 @@ namespace options_block { using AllowNonResilientAccess = BCRecordLayout< ALLOW_NON_RESILIENT_ACCESS >; + + using SerializePackageEnabled = BCRecordLayout< + SERIALIZE_PACKAGE_ENABLED + >; } /// The record types within the input block. diff --git a/lib/Serialization/SILFormat.h b/lib/Serialization/SILFormat.h index c2fea45db31cd..38196e664fb3a 100644 --- a/lib/Serialization/SILFormat.h +++ b/lib/Serialization/SILFormat.h @@ -183,7 +183,7 @@ namespace sil_block { using VTableLayout = BCRecordLayout< SIL_VTABLE, DeclIDField, // Class Decl - BCFixed<1> // IsSerialized. + BCFixed<2> // SerializedKind. >; using VTableEntryLayout = BCRecordLayout< @@ -198,13 +198,13 @@ namespace sil_block { SIL_MOVEONLY_DEINIT, DeclIDField, // Class Decl DeclIDField, // SILFunction name - BCFixed<1> // IsSerialized. + BCFixed<2> // SerializedKind. >; using PropertyLayout = BCRecordLayout< SIL_PROPERTY, DeclIDField, // Property decl - BCFixed<1>, // Is serialized + BCFixed<2>, // SerializedKind BCArray // Encoded key path component // Any substitutions or conformances required for the key path component // follow. @@ -216,7 +216,7 @@ namespace sil_block { BCFixed<1>, // Is this a declaration. We represent this separately // from whether or not we have entries since we can // have empty witness tables. - BCFixed<1>, // IsSerialized. + BCFixed<2>, // SerializedKind. ProtocolConformanceIDField // conformance // Witness table entries will be serialized after. >; @@ -266,7 +266,7 @@ namespace sil_block { using SILGlobalVarLayout = BCRecordLayout< SIL_GLOBALVAR, SILLinkageField, - BCFixed<1>, // serialized + BCFixed<2>, // serialized BCFixed<1>, // Is this a declaration. BCFixed<1>, // Is this a let variable. TypeIDField, @@ -278,7 +278,7 @@ namespace sil_block { DeclIDField, // Original function name SILLinkageField, // Linkage BCFixed<1>, // Is declaration? - BCFixed<1>, // Is serialized? + BCFixed<2>, // Is serialized? DifferentiabilityKindField, // Differentiability kind GenericSignatureIDField, // Derivative function generic signature DeclIDField, // JVP function name @@ -291,7 +291,7 @@ namespace sil_block { using SILFunctionLayout = BCRecordLayout, // transparent - BCFixed<1>, // serialized + BCFixed<2>, // serializedKind BCFixed<2>, // thunks: signature optimized/reabstraction BCFixed<1>, // without_actually_escaping BCFixed<3>, // specialPurpose diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 628ffd0f6fea0..e3748581cab03 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -854,6 +854,7 @@ void Serializer::writeBlockInfoBlock() { BLOCK_RECORD(options_block, MODULE_EXPORT_AS_NAME); BLOCK_RECORD(options_block, PLUGIN_SEARCH_OPTION); BLOCK_RECORD(options_block, ALLOW_NON_RESILIENT_ACCESS); + BLOCK_RECORD(options_block, SERIALIZE_PACKAGE_ENABLED); BLOCK(INPUT_BLOCK); BLOCK_RECORD(input_block, IMPORTED_MODULE); @@ -1091,6 +1092,11 @@ void Serializer::writeHeader() { AllowNonResAcess.emit(ScratchRecord); } + if (M->serializePackageEnabled()) { + options_block::SerializePackageEnabled SerializePkgEnabled(Out); + SerializePkgEnabled.emit(ScratchRecord); + } + if (allowCompilerErrors()) { options_block::IsAllowModuleWithCompilerErrorsEnabledLayout AllowErrors(Out); diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index b51f7996b0a89..5c3edf7852ef6 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -277,7 +277,8 @@ namespace { void writeSILMoveOnlyDeinit(const SILMoveOnlyDeinit &deinit); void writeSILGlobalVar(const SILGlobalVariable &g); void writeSILWitnessTable(const SILWitnessTable &wt); - void writeSILWitnessTableEntry(const SILWitnessTable::Entry &entry); + void writeSILWitnessTableEntry(const SILWitnessTable::Entry &entry, + SerializedKind_t serializedKind); void writeSILDefaultWitnessTable(const SILDefaultWitnessTable &wt); void writeSILDifferentiabilityWitness(const SILDifferentiabilityWitness &dw); @@ -375,7 +376,7 @@ void SILSerializer::addReferencedSILFunction(const SILFunction *F, } if (F->getLinkage() == SILLinkage::Shared) { - assert(F->isSerialized() || F->hasForeignBody()); + assert(F->isAnySerialized() || F->hasForeignBody()); FuncsToEmit[F] = false; functionWorklist.push_back(F); @@ -493,7 +494,6 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) { } unsigned numAttrs = NoBody ? 0 : F.getSpecializeAttrs().size(); - auto resilience = F.getModule().getSwiftModule()->getResilienceStrategy(); bool serializeDerivedEffects = (resilience != ResilienceStrategy::Resilient) && !F.hasSemanticsAttr("optimize.no.crossmodule"); @@ -514,7 +514,7 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) { SILFunctionLayout::emitRecord( Out, ScratchRecord, abbrCode, toStableSILLinkage(Linkage), - (unsigned)F.isTransparent(), (unsigned)F.isSerialized(), + (unsigned)F.isTransparent(), (unsigned)F.getSerializedKind(), (unsigned)F.isThunk(), (unsigned)F.isWithoutActuallyEscapingThunk(), (unsigned)F.getSpecialPurpose(), (unsigned)F.getInlineStrategy(), (unsigned)F.getOptimizationMode(), (unsigned)F.getPerfConstraints(), @@ -2865,13 +2865,13 @@ void SILSerializer::writeSILGlobalVar(const SILGlobalVariable &g) { SILGlobalVarLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILGlobalVarLayout::Code], toStableSILLinkage(g.getLinkage()), - g.isSerialized() ? 1 : 0, + (unsigned)g.getSerializedKind(), (unsigned)!g.isDefinition(), (unsigned)g.isLet(), TyID, dID); // Don't emit the initializer instructions if not marked as "serialized". - if (!g.isSerialized()) + if (!g.isAnySerialized()) return; ValueIDs.clear(); @@ -2911,13 +2911,15 @@ void SILSerializer::writeSILVTable(const SILVTable &vt) { VTableOffset.push_back(Out.GetCurrentBitNo()); VTableLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[VTableLayout::Code], S.addDeclRef(vt.getClass()), - vt.isSerialized() == IsSerialized ? 1 : 0); + (unsigned)vt.getSerializedKind()); for (auto &entry : vt.getEntries()) { SmallVector ListOfValues; SILFunction *impl = entry.getImplementation(); - if (ShouldSerializeAll || impl->hasValidLinkageForFragileRef()) { + if (ShouldSerializeAll || + (vt.isAnySerialized() && + impl->hasValidLinkageForFragileRef(vt.getSerializedKind()))) { handleSILDeclRef(S, entry.getMethod(), ListOfValues); addReferencedSILFunction(impl, true); // Each entry is a pair of SILDeclRef and SILFunction. @@ -2940,7 +2942,11 @@ void SILSerializer::writeSILMoveOnlyDeinit(const SILMoveOnlyDeinit &deinit) { return; SILFunction *impl = deinit.getImplementation(); - if (!ShouldSerializeAll && !impl->hasValidLinkageForFragileRef()) + if (!ShouldSerializeAll && + // Package CMO for MoveOnlyDeinit is not supported so + // pass the IsSerialized argument to keep the behavior + // consistent with or without the optimization. + !impl->hasValidLinkageForFragileRef(IsSerialized)) return; // Use the mangled name of the class as a key to distinguish between classes @@ -2961,7 +2967,7 @@ void SILSerializer::writeSILMoveOnlyDeinit(const SILMoveOnlyDeinit &deinit) { Out, ScratchRecord, SILAbbrCodes[MoveOnlyDeinitLayout::Code], S.addDeclRef(deinit.getNominalDecl()), S.addUniquedStringRef(impl->getName()), - deinit.isSerialized() == IsSerialized ? 1 : 0); + deinit.getSerializedKind()); } void SILSerializer::writeSILProperty(const SILProperty &prop) { @@ -2979,7 +2985,7 @@ void SILSerializer::writeSILProperty(const SILProperty &prop) { Out, ScratchRecord, SILAbbrCodes[PropertyLayout::Code], S.addDeclRef(prop.getDecl()), - prop.isSerialized(), + prop.getSerializedKind(), componentValues); } @@ -2993,7 +2999,7 @@ void SILSerializer::writeSILWitnessTable(const SILWitnessTable &wt) { SILAbbrCodes[WitnessTableLayout::Code], toStableSILLinkage(wt.getLinkage()), unsigned(wt.isDeclaration()), - wt.isSerialized() == IsSerialized ? 1 : 0, + unsigned(wt.getSerializedKind()), conformanceID); // If we have a declaration, do not attempt to serialize entries. @@ -3001,7 +3007,7 @@ void SILSerializer::writeSILWitnessTable(const SILWitnessTable &wt) { return; for (auto &entry : wt.getEntries()) { - writeSILWitnessTableEntry(entry); + writeSILWitnessTableEntry(entry, wt.getSerializedKind()); } for (auto conditional : wt.getConditionalConformances()) { @@ -3015,7 +3021,8 @@ void SILSerializer::writeSILWitnessTable(const SILWitnessTable &wt) { } void SILSerializer::writeSILWitnessTableEntry( - const SILWitnessTable::Entry &entry) { + const SILWitnessTable::Entry &entry, + SerializedKind_t serializedKind) { if (entry.getKind() == SILWitnessTable::BaseProtocol) { auto &baseWitness = entry.getBaseProtocolWitness(); @@ -3056,7 +3063,9 @@ void SILSerializer::writeSILWitnessTableEntry( handleSILDeclRef(S, methodWitness.Requirement, ListOfValues); IdentifierID witnessID = 0; SILFunction *witness = methodWitness.Witness; - if (witness && witness->hasValidLinkageForFragileRef()) { + if (witness && + serializedKind != IsNotSerialized && + witness->hasValidLinkageForFragileRef(serializedKind)) { addReferencedSILFunction(witness, true); witnessID = S.addUniquedStringRef(witness->getName()); } @@ -3090,7 +3099,10 @@ writeSILDefaultWitnessTable(const SILDefaultWitnessTable &wt) { continue; } - writeSILWitnessTableEntry(entry); + // Default witness table is not serialized. The IsSerialized + // argument is passed here to call hasValidLinkageForFragileRef + // to keep the behavior consistent with or without any optimizations. + writeSILWitnessTableEntry(entry, IsSerialized); } } @@ -3162,7 +3174,7 @@ bool SILSerializer::shouldEmitFunctionBody(const SILFunction *F, // If F is serialized, we should always emit its body. // Shared functions are only serialized if they are referenced from another // serialized function. This is handled in `addReferencedSILFunction`. - if (F->isSerialized() && !hasSharedVisibility(F->getLinkage())) + if (F->isAnySerialized() && !hasSharedVisibility(F->getLinkage())) return true; return false; @@ -3224,13 +3236,13 @@ void SILSerializer::writeSILBlock(const SILModule *SILMod) { // serialize everything. // FIXME: Resilience: could write out vtable for fragile classes. for (const auto &vt : SILMod->getVTables()) { - if ((ShouldSerializeAll || vt->isSerialized()) && + if ((ShouldSerializeAll || vt->isAnySerialized()) && SILMod->shouldSerializeEntitiesAssociatedWithDeclContext(vt->getClass())) writeSILVTable(*vt); } for (const auto &deinit : SILMod->getMoveOnlyDeinits()) { - if ((ShouldSerializeAll || deinit->isSerialized()) && + if ((ShouldSerializeAll || deinit->isAnySerialized()) && SILMod->shouldSerializeEntitiesAssociatedWithDeclContext( deinit->getNominalDecl())) writeSILMoveOnlyDeinit(*deinit); @@ -3238,7 +3250,7 @@ void SILSerializer::writeSILBlock(const SILModule *SILMod) { // Write out property descriptors. for (const SILProperty &prop : SILMod->getPropertyList()) { - if ((ShouldSerializeAll || prop.isSerialized()) && + if ((ShouldSerializeAll || prop.isAnySerialized()) && SILMod->shouldSerializeEntitiesAssociatedWithDeclContext( prop.getDecl()->getInnermostDeclContext())) writeSILProperty(prop); @@ -3246,7 +3258,7 @@ void SILSerializer::writeSILBlock(const SILModule *SILMod) { // Write out fragile WitnessTables. for (const SILWitnessTable &wt : SILMod->getWitnessTables()) { - if ((ShouldSerializeAll || wt.isSerialized()) && + if ((ShouldSerializeAll || wt.isAnySerialized()) && SILMod->shouldSerializeEntitiesAssociatedWithDeclContext( wt.getConformance()->getDeclContext())) writeSILWitnessTable(wt); @@ -3263,7 +3275,7 @@ void SILSerializer::writeSILBlock(const SILModule *SILMod) { // Add global variables that must be emitted to the list. for (const SILGlobalVariable &g : SILMod->getSILGlobals()) { - if (g.isSerialized() || ShouldSerializeAll) + if (g.isAnySerialized() || ShouldSerializeAll) addReferencedGlobalVariable(&g); } diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index 1461b30f17567..6848215f73d34 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -924,6 +924,8 @@ LoadedFile *SerializedModuleLoaderBase::loadAST( M.setIsBuiltFromInterface(); if (loadedModuleFile->allowNonResilientAccess()) M.setAllowNonResilientAccess(); + if (loadedModuleFile->serializePackageEnabled()) + M.setSerializePackageEnabled(); if (!loadedModuleFile->getModuleABIName().empty()) M.setABIName(Ctx.getIdentifier(loadedModuleFile->getModuleABIName())); if (loadedModuleFile->isConcurrencyChecked()) diff --git a/test/AutoDiff/compiler_crashers/issue-54722-apply-opened-opened-existential-argument.swift b/test/AutoDiff/compiler_crashers/issue-54722-apply-opened-opened-existential-argument.swift index 8ef9080e3ec1a..e6d59341206b6 100644 --- a/test/AutoDiff/compiler_crashers/issue-54722-apply-opened-opened-existential-argument.swift +++ b/test/AutoDiff/compiler_crashers/issue-54722-apply-opened-opened-existential-argument.swift @@ -54,4 +54,4 @@ public func abs(_ x: T) -> T where T.Element: Numer // #13 0x0000000000f1a1e1 swift::autodiff::LinearMapInfo::addLinearMapToStruct(swift::autodiff::ADContext&, swift::ApplyInst*) (build/Ninja-ReleaseAssert/swift-linux-x86_64/bin/swift+0xf1a1e1) // #14 0x0000000000f17925 swift::autodiff::LinearMapInfo::generateDifferentiationDataStructures(swift::autodiff::ADContext&, swift::SILFunction*) (build/Ninja-ReleaseAssert/swift-linux-x86_64/bin/swift+0xf17925) // #15 0x0000000000f2615f swift::autodiff::VJPEmitter::VJPEmitter(swift::autodiff::ADContext&, swift::SILFunction*, swift::SILDifferentiabilityWitness*, swift::SILFunction*, swift::autodiff::DifferentiationInvoker) (build/Ninja-ReleaseAssert/swift-linux-x86_64/bin/swift+0xf2615f) -// #16 0x0000000000e7efff (anonymous namespace)::DifferentiationTransformer::canonicalizeDifferentiabilityWitness(swift::SILFunction*, swift::SILDifferentiabilityWitness*, swift::autodiff::DifferentiationInvoker, swift::IsSerialized_t) (build/Ninja-ReleaseAssert/swift-linux-x86_64/bin/swift+0xe7efff) +// #16 0x0000000000e7efff (anonymous namespace)::DifferentiationTransformer::canonicalizeDifferentiabilityWitness(swift::SILFunction*, swift::SILDifferentiabilityWitness*, swift::autodiff::DifferentiationInvoker, swift::SerializedKind_t) (build/Ninja-ReleaseAssert/swift-linux-x86_64/bin/swift+0xe7efff) diff --git a/test/AutoDiff/compiler_crashers_fixed/issue-55085-silgen-immutable-address-use-verification-failure.swift b/test/AutoDiff/compiler_crashers_fixed/issue-55085-silgen-immutable-address-use-verification-failure.swift index 24c46a1ccd413..ef35d0ae64916 100644 --- a/test/AutoDiff/compiler_crashers_fixed/issue-55085-silgen-immutable-address-use-verification-failure.swift +++ b/test/AutoDiff/compiler_crashers_fixed/issue-55085-silgen-immutable-address-use-verification-failure.swift @@ -67,5 +67,5 @@ func loadableOriginal(_ loadable: LoadableOriginal) -> // #10 0x0000000000f8248b swift::autodiff::PullbackEmitter::emitZeroDerivativesForNonvariedResult(swift::SILValue) // #11 0x0000000000f7fcae swift::autodiff::PullbackEmitter::run() // #12 0x0000000000f3fba4 swift::autodiff::VJPEmitter::run() -// #13 0x0000000000eb1669 (anonymous namespace)::DifferentiationTransformer::canonicalizeDifferentiabilityWitness(swift::SILFunction*, swift::SILDifferentiabilityWitness*, swift::autodiff::DifferentiationInvoker, swift::IsSerialized_t) +// #13 0x0000000000eb1669 (anonymous namespace)::DifferentiationTransformer::canonicalizeDifferentiabilityWitness(swift::SILFunction*, swift::SILDifferentiabilityWitness*, swift::autodiff::DifferentiationInvoker, swift::SerializedKind_t) // #14 0x0000000000eaea5e (anonymous namespace)::Differentiation::run() diff --git a/test/AutoDiff/compiler_crashers_fixed/issue-56263-library-evolution-mode-crasher-property-differentiation.swift b/test/AutoDiff/compiler_crashers_fixed/issue-56263-library-evolution-mode-crasher-property-differentiation.swift index 6b4eb9e96d42e..79e527c820858 100644 --- a/test/AutoDiff/compiler_crashers_fixed/issue-56263-library-evolution-mode-crasher-property-differentiation.swift +++ b/test/AutoDiff/compiler_crashers_fixed/issue-56263-library-evolution-mode-crasher-property-differentiation.swift @@ -57,7 +57,7 @@ public struct Struct: Differentiable { // 11 swift-frontend 0x0000000109ae8196 swift::autodiff::PullbackCloner::Implementation::visitSILBasicBlock(swift::SILBasicBlock*) + 838 // 12 swift-frontend 0x0000000109ae5504 swift::autodiff::PullbackCloner::Implementation::run() + 7268 // 13 swift-frontend 0x0000000109b077d3 swift::autodiff::VJPCloner::Implementation::run() + 1539 -// 14 swift-frontend 0x0000000109c4e0b4 (anonymous namespace)::DifferentiationTransformer::canonicalizeDifferentiabilityWitness(swift::SILFunction*, swift::SILDifferentiabilityWitness*, swift::autodiff::DifferentiationInvoker, swift::IsSerialized_t) + 7172 +// 14 swift-frontend 0x0000000109c4e0b4 (anonymous namespace)::DifferentiationTransformer::canonicalizeDifferentiabilityWitness(swift::SILFunction*, swift::SILDifferentiabilityWitness*, swift::autodiff::DifferentiationInvoker, swift::SerializedKind_t) + 7172 // 15 swift-frontend 0x0000000109c4bafa (anonymous namespace)::Differentiation::run() + 1530 // 16 swift-frontend 0x0000000109c9c86e swift::SILPassManager::runModulePass(unsigned int) + 558 // 17 swift-frontend 0x0000000109ca144a swift::SILPassManager::execute() + 666 diff --git a/test/IRGen/package_bypass_resilience_class.swift b/test/IRGen/package_bypass_resilience_class.swift new file mode 100644 index 0000000000000..16f1776f81c06 --- /dev/null +++ b/test/IRGen/package_bypass_resilience_class.swift @@ -0,0 +1,243 @@ +// RUN: %empty-directory(%t) +// RUN: split-file %s %t + +/// Build with -experimental-allow-non-resilient-access +// RUN: %target-build-swift %t/Core.swift \ +// RUN: -module-name=Core -package-name Pkg \ +// RUN: -Xfrontend -experimental-allow-non-resilient-access \ +// RUN: -enable-library-evolution -O -wmo \ +// RUN: -emit-ir -o %t/Core.ir \ +// RUN: -emit-tbd -emit-tbd-path %t/libCore.tbd \ +// RUN: -Xfrontend -tbd-install_name=libCore.dylib -Xfrontend -validate-tbd-against-ir=all + +/// Build without -experimental-allow-non-resilient-access +// RUN: %target-build-swift %t/Core.swift \ +// RUN: -module-name=Core -package-name Pkg \ +// RUN: -enable-library-evolution -O -wmo \ +// RUN: -emit-ir -o %t/CoreRes.ir \ +// RUN: -emit-tbd -emit-tbd-path %t/libCoreRes.tbd \ +// RUN: -Xfrontend -tbd-install_name=libCoreRes.dylib -Xfrontend -validate-tbd-against-ir=all + +// RUN: %FileCheck %s --check-prefixes=CHECK-COMMON,CHECK-OPT < %t/Core.ir +// RUN: %FileCheck %s --check-prefixes=CHECK-TBD-COMMON,CHECK-TBD-OPT < %t/libCore.tbd +// RUN: %FileCheck %s --check-prefixes=CHECK-COMMON,CHECK-RES < %t/CoreRes.ir +// RUN: %FileCheck %s --check-prefixes=CHECK-TBD-COMMON,CHECK-TBD-RES < %t/libCoreRes.tbd + +//--- Core.swift + +// CHECK-RES-NOT: s4Core8UFIKlassC6varUfiSSSgvpfi +// CHECK-RES-NOT: s4Core3FooC02myB0AA3PubCSgvpfi + +final public class Pub { + // type metadata accessor for Core.Pub + // CHECK-COMMON-DAG: define {{(dllexport |protected )?}}swiftcc %swift.metadata_response @"$s4Core3PubCMa"({{i32|i64}} %0) + + // method lookup function for Core.Pub + // CHECK-COMMON-DAG: define {{(dllexport |protected )?}}swiftcc ptr @"$s4Core3PubCMu"(ptr %0, ptr %1) + + // CHECK-COMMON-DAG: define {{(dllexport |protected )?}}swiftcc ptr @"$s4Core3PubCfd"(ptr readnone returned swiftself %0) + // CHECK-COMMON-DAG: define {{(dllexport |protected )?}}swiftcc void @"$s4Core3PubCfD"(ptr swiftself %0) +} + +package class Foo { + // key path getter for Core.Foo.myFoo + // CHECK-COMMON-DAG: define linkonce_odr hidden swiftcc void @"$s4Core3FooC02myB0AA3PubCSgvpACTK" + + // key path setter for Core.Foo.myFoo + // CHECK-COMMON-DAG: define linkonce_odr hidden swiftcc void @"$s4Core3FooC02myB0AA3PubCSgvpACTk" + + // variable initialization expression of Core.Foo.myFoo + // CHECK-OPT-DAG: define {{(dllexport |protected )?}}swiftcc {{i32|i64}} @"$s4Core3FooC02myB0AA3PubCSgvpfi"() #0 { + + // Core.Foo.myFoo.getter + // CHECK-RES-DAG: define hidden {{.*}}swiftcc {{i32|i64}} @"$s4Core3FooC02myB0AA3PubCSgvg"(ptr swiftself %0) + // CHECK-OPT-DAG: define {{(dllexport |protected )?}}swiftcc {{i32|i64}} @"$s4Core3FooC02myB0AA3PubCSgvg"(ptr swiftself %0) + + // merged Core.Foo.myFoo.getter + // CHECK-COMMON-DAG: define internal swiftcc {{i32|i64}} @"$s4Core3FooC02myB0AA3PubCSgvgTm"(ptr swiftself %0) + + // Core.Foo.myFoo.setter + // CHECK-RES-DAG: define hidden {{.*}}swiftcc void @"$s4Core3FooC02myB0AA3PubCSgvs"({{i32|i64}} %0, ptr swiftself %1) #1 { + // CHECK-OPT-DAG: define {{(dllexport |protected )?}}swiftcc void @"$s4Core3FooC02myB0AA3PubCSgvs"({{i32|i64}} %0, ptr swiftself %1) #1 { + + // merged Core.Foo.myFoo.setter + // CHECK-COMMON-DAG: define internal swiftcc void @"$s4Core3FooC02myB0AA3PubCSgvsTm"({{i32|i64}} %0, ptr swiftself %1) + + // Core.Foo.myFoo.modify + // CHECK-RES-DAG: define hidden {{.*}}swiftcc { ptr, ptr } @"$s4Core3FooC02myB0AA3PubCSgvM" + // CHECK-OPT-DAG: define {{(dllexport |protected )?}}swiftcc { ptr, ptr } @"$s4Core3FooC02myB0AA3PubCSgvM" + + // Core.Foo.myFoo.modify + // CHECK-COMMON-DAG: define internal swiftcc void @"$s4Core3FooC02myB0AA3PubCSgvM.resume.0" + + // type metadata accessor for Core.Foo + // CHECK-COMMON-DAG: define {{(dllexport |protected )?}}swiftcc %swift.metadata_response @"$s4Core3FooCMa" + + // method lookup function for Core.Foo + // CHECK-COMMON-DAG: define {{(dllexport |protected )?}}swiftcc ptr @"$s4Core3FooCMu"(ptr %0, ptr %1) + + // dispatch thunk of Core.Foo.myFoo.getter + // CHECK-COMMON-DAG: define {{(dllexport |protected )?}}swiftcc {{i32|i64}} @"$s4Core3FooC02myB0AA3PubCSgvgTj"(ptr swiftself %0) + + // dispatch thunk of Core.Foo.myFoo.setter + // CHECK-COMMON-DAG: define {{(dllexport |protected )?}}swiftcc void @"$s4Core3FooC02myB0AA3PubCSgvsTj"({{i32|i64}} %0, ptr swiftself %1) + + // dispatch thunk of Core.Foo.myFoo.modify + // CHECK-COMMON-DAG: define {{(dllexport |protected )?}}swiftcc { ptr, ptr } @"$s4Core3FooC02myB0AA3PubCSgvMTj" + + // Core.Foo.deinit + // CHECK-COMMON-DAG: define {{(dllexport |protected )?}}swiftcc ptr @"$s4Core3FooCfd"(ptr readonly returned swiftself %0) + + // Core.Foo.__deallocating_deinit + // CHECK-COMMON-DAG: define {{(dllexport |protected )?}}swiftcc void @"$s4Core3FooCfD"(ptr swiftself %0) + + package var myFoo: Pub? +} + +final package class Bar { + + // CHECK-OPT-DAG: define {{(dllexport |protected )?}}swiftcc {{i32|i64}} @"$s4Core3BarC02myB0AA3PubCSgvpfi"() + // CHECK-COMMON-DAG: define {{(dllexport |protected )?}}swiftcc {{i32|i64}} @"$s4Core3BarC02myB0AA3PubCSgvg"(ptr swiftself %0) + // CHECK-COMMON-DAG: define {{(dllexport |protected )?}}swiftcc void @"$s4Core3BarC02myB0AA3PubCSgvs"({{i32|i64}} %0, ptr swiftself %1) + // CHECK-COMMON-DAG: define {{(dllexport |protected )?}}swiftcc { ptr, ptr } @"$s4Core3BarC02myB0AA3PubCSgvM" + // CHECK-COMMON-DAG: define internal swiftcc void @"$s4Core3BarC02myB0AA3PubCSgvM.resume.0" + + // type metadata accessor for Core.Bar + // CHECK-COMMON-DAG: define {{(dllexport |protected )?}}swiftcc %swift.metadata_response @"$s4Core3BarCMa"({{i32|i64}} %0) + + // method lookup function for Core.Bar + // CHECK-COMMON-DAG: define {{(dllexport |protected )?}}swiftcc ptr @"$s4Core3BarCMu"(ptr %0, ptr %1) + + // CHECK-COMMON-DAG: define {{(dllexport |protected )?}}swiftcc ptr @"$s4Core3BarCfd"(ptr readonly returned swiftself %0) + // CHECK-COMMON-DAG: define {{(dllexport |protected )?}}swiftcc void @"$s4Core3BarCfD"(ptr swiftself %0) + + package var myBar: Pub? +} + +@usableFromInline +class UFIKlass { + var varNonUfi: String? + + // variable initialization expression of Core.UFIKlass.varUfi + // CHECK-OPT-DAG: define {{(dllexport |protected )?}}swiftcc {{.*}} @"$s4Core8UFIKlassC6varUfiSSSgvpfi"() + + // key path getter for Core.UFIKlass.varUfi + // CHECK-COMMON-DAG: define linkonce_odr hidden swiftcc void @"$s4Core8UFIKlassC6varUfiSSSgvpACTK" + + // key path setter for Core.UFIKlass.varUfi + // CHECK-COMMON-DAG: define linkonce_odr hidden swiftcc void @"$s4Core8UFIKlassC6varUfiSSSgvpACTk" + + // dispatch thunk of Core.UFIKlass.varUfi.getter + // CHECK-COMMON-DAG: define {{(dllexport |protected )?}}swiftcc {{.*}} @"$s4Core8UFIKlassC6varUfiSSSgvgTj" + + // dispatch thunk of Core.UFIKlass.varUfi.setter + // CHECK-COMMON-DAG: define {{(dllexport |protected )?}}swiftcc void @"$s4Core8UFIKlassC6varUfiSSSgvsTj" + + // dispatch thunk of Core.UFIKlass.varUfi.modify + // CHECK-COMMON-DAG: define {{(dllexport |protected )?}}swiftcc { ptr, ptr } @"$s4Core8UFIKlassC6varUfiSSSgvMTj" + + // Core.UFIKlass.varUfi.getter + // CHECK-RES-DAG: define hidden {{.*}}swiftcc {{.*}} @"$s4Core8UFIKlassC6varUfiSSSgvg" + // CHECK-OPT-DAG: define {{(dllexport |protected )?}}swiftcc {{.*}} @"$s4Core8UFIKlassC6varUfiSSSgvg" + + // Core.UFIKlass.varUfi.setter + // CHECK-RES-DAG: define hidden {{.*}}swiftcc void @"$s4Core8UFIKlassC6varUfiSSSgvs" + // CHECK-OPT-DAG: define {{(dllexport |protected )?}}swiftcc void @"$s4Core8UFIKlassC6varUfiSSSgvs" + + // Core.UFIKlass.varUfi.modify + // CHECK-RES-DAG: define hidden {{.*}}swiftcc { ptr, ptr } @"$s4Core8UFIKlassC6varUfiSSSgvM" + // CHECK-OPT-DAG: define {{(dllexport |protected )?}}swiftcc { ptr, ptr } @"$s4Core8UFIKlassC6varUfiSSSgvM" + + @usableFromInline + var varUfi: String? +} + +class InternalKlass { + var varInternal: String? +} + +/// TBD +/// +/// Core.Foo +// property descriptor for Core.Foo.myFoo +// CHECK-TBD-COMMON-DAG: s4Core3FooC02myB0AA3PubCSgvpMV +// method descriptor for Core.Foo.myFoo.getter +// CHECK-TBD-COMMON-DAG: s4Core3FooC02myB0AA3PubCSgvgTq +// method descriptor for Core.Foo.myFoo.setter +// CHECK-TBD-COMMON-DAG: s4Core3FooC02myB0AA3PubCSgvsTq +// method descriptor for Core.Foo.myFoo.modify +// CHECK-TBD-COMMON-DAG: s4Core3FooC02myB0AA3PubCSgvMTq +// type metadata accessor for Core.Foo +// CHECK-TBD-COMMON-DAG: s4Core3FooCMa +// nominal type descriptor for Core.Foo +// CHECK-TBD-COMMON-DAG: s4Core3FooCMn + +// dispatch thunk of Core.Foo.myFoo.getter +// CHECK-TBD-COMMON-DAG: s4Core3FooC02myB0AA3PubCSgvgTj +// dispatch thunk of Core.Foo.myFoo.setter +// CHECK-TBD-COMMON-DAG: s4Core3FooC02myB0AA3PubCSgvsTj +// dispatch thunk of Core.Foo.myFoo.modify +// CHECK-TBD-COMMON-DAG: s4Core3FooC02myB0AA3PubCSgvMTj +// method lookup function for Core.Foo +// CHECK-TBD-COMMON-DAG: s4Core3FooCMu +// class metadata base offset for Core.Foo +// CHECK-TBD-COMMON-DAG: s4Core3FooCMo + +// CHECK-TBD-OPT-DAG: s4Core3FooC02myB0AA3PubCSgvpfi +// CHECK-TBD-OPT-DAG: s4Core3FooC02myB0AA3PubCSgvg +// CHECK-TBD-OPT-DAG: s4Core3FooC02myB0AA3PubCSgvs +// CHECK-TBD-COMMON-DAG: s4Core3FooCfd +// CHECK-TBD-COMMON-DAG: s4Core3FooCfD + +/// Core.UFIKlass +// property descriptor for Core.UFIKlass.varUfi +// CHECK-TBD-COMMON-DAG: s4Core8UFIKlassC6varUfiSSSgvpMV +// method descriptor for Core.UFIKlass.varUfi.getter +// CHECK-TBD-COMMON-DAG: s4Core8UFIKlassC6varUfiSSSgvgTq +// method descriptor for Core.UFIKlass.varUfi.setter +// CHECK-TBD-COMMON-DAG: s4Core8UFIKlassC6varUfiSSSgvsTq +// method descriptor for Core.UFIKlass.varUfi.modify +// CHECK-TBD-COMMON-DAG: s4Core8UFIKlassC6varUfiSSSgvMTq +// type metadata accessor for Core.UFIKlass +// CHECK-TBD-COMMON-DAG: s4Core8UFIKlassCMa +// nominal type descriptor for Core.UFIKlass +// CHECK-TBD-COMMON-DAG: s4Core8UFIKlassCMn + +// dispatch thunk of Core.UFIKlass.varUfi.getter +// CHECK-TBD-COMMON-DAG: s4Core8UFIKlassC6varUfiSSSgvgTj +// dispatch thunk of Core.UFIKlass.varUfi.setter +// CHECK-TBD-COMMON-DAG: s4Core8UFIKlassC6varUfiSSSgvsTj +// dispatch thunk of Core.UFIKlass.varUfi.modify +// CHECK-TBD-COMMON-DAG: s4Core8UFIKlassC6varUfiSSSgvMTj +// method lookup function for Core.UFIKlass +// CHECK-TBD-COMMON-DAG: s4Core8UFIKlassCMu +// class metadata base offset for Core.UFIKlass +// CHECK-TBD-COMMON-DAG: s4Core8UFIKlassCMo + +// CHECK-TBD-OPT-DAG: s4Core8UFIKlassC6varUfiSSSgvpfi +// CHECK-TBD-OPT-DAG: s4Core8UFIKlassC9varNonUfiSSSgvpfi +// CHECK-TBD-OPT-DAG: s4Core8UFIKlassC6varUfiSSSgvg +// CHECK-TBD-OPT-DAG: s4Core8UFIKlassC6varUfiSSSgvs +// CHECK-TBD-COMMON-DAG: s4Core8UFIKlassCfd +// CHECK-TBD-COMMON-DAG: s4Core8UFIKlassCfD + +/// Core.Bar is a final class so no dispatch thunks for its methods +// CHECK-TBD-OPT-DAG: s4Core3BarC02myB0AA3PubCSgvpfi +// CHECK-TBD-OPT-DAG: s4Core3BarC02myB0AA3PubCSgvg +// CHECK-TBD-OPT-DAG: s4Core3BarC02myB0AA3PubCSgvs +// CHECK-TBD-OPT-DAG: s4Core3BarC02myB0AA3PubCSgvM +// CHECK-TBD-COMMON-DAG: s4Core3BarC02myB0AA3PubCSgvpMV +// CHECK-TBD-COMMON-DAG: s4Core3BarCMa +// CHECK-TBD-COMMON-DAG: s4Core3BarCMn +// CHECK-TBD-COMMON-DAG: s4Core3BarCfd +// CHECK-TBD-COMMON-DAG: s4Core3BarCfD +// CHECK-TBD-COMMON-DAG: s4Core3BarCMu +// CHECK-TBD-COMMON-DAG: s4Core3BarCMo + +/// Core.Pub is a final empty class +// CHECK-TBD-COMMON-DAG: s4Core3PubCMa +// CHECK-TBD-COMMON-DAG: s4Core3PubCMn +// CHECK-TBD-COMMON-DAG: s4Core3PubCfd +// CHECK-TBD-COMMON-DAG: s4Core3PubCfD +// CHECK-TBD-COMMON-DAG: s4Core3PubCMu +// CHECK-TBD-COMMON-DAG: s4Core3PubCMo diff --git a/test/IRGen/package_global_accessor.swift b/test/IRGen/package_global_accessor.swift new file mode 100644 index 0000000000000..e7402ae800153 --- /dev/null +++ b/test/IRGen/package_global_accessor.swift @@ -0,0 +1,13 @@ + // RUN: %empty-directory(%t) + +// RUN: %target-build-swift -module-name=File -package-name Pkg -I%t -emit-ir %s | %FileCheck %s --check-prefix=CHECK-IR-NONRES +// RUN: %target-build-swift -module-name=File -package-name Pkg -I%t -emit-ir %s -enable-library-evolution | %FileCheck %s --check-prefix=CHECK-IR-RES +// RUN: %target-build-swift -module-name=File -package-name Pkg -I%t -emit-ir %s -enable-library-evolution -Xfrontend -experimental-allow-non-resilient-access -Xfrontend -experimental-package-cmo | %FileCheck %s --check-prefix=CHECK-IR-RES + +public struct S { + public static var x = "hello world" +} + +// CHECK-IR-NONRES: define{{( dllexport)?}}{{( protected)?}} swiftcc ptr @"$s4File1SV1xSSvau"() +// CHECK-IR-RES: define hidden swiftcc ptr @"$s4File1SV1xSSvau"() + diff --git a/test/SILGen/always_emit_into_client_attribute.swift b/test/SILGen/always_emit_into_client_attribute.swift index ca075c1e424ff..1b74cef3bd874 100644 --- a/test/SILGen/always_emit_into_client_attribute.swift +++ b/test/SILGen/always_emit_into_client_attribute.swift @@ -58,3 +58,21 @@ public final class C { @_alwaysEmitIntoClient deinit {} } + + +// We drop AEIC if the containing context does not have effective public +// visibility. +internal struct InternalContext { +// CHECK-LABEL: sil hidden [ossa] @$s33always_emit_into_client_attribute15InternalContextV1vSivgZ + @_alwaysEmitIntoClient + internal static var v : Int { 1 } +} + +// We drop AEIC if the containing context does not have effective public +// visibility. +package struct PackageContext { +// CHECK-LABEL: sil package [ossa] @$s33always_emit_into_client_attribute14PackageContextV1vSivgZ + + @_alwaysEmitIntoClient + package static var v : Int { 1 } +} diff --git a/test/SILGen/package_bypass_resilience.swift b/test/SILGen/package_allow_non_resilient_access.swift similarity index 56% rename from test/SILGen/package_bypass_resilience.swift rename to test/SILGen/package_allow_non_resilient_access.swift index b53f698e23b6c..ce15b4b9ec617 100644 --- a/test/SILGen/package_bypass_resilience.swift +++ b/test/SILGen/package_allow_non_resilient_access.swift @@ -17,8 +17,8 @@ /// To bypass resilience at use site, Client needs to be in the same package as its /// loaded module and also opt in with -experimental-package-bypass-resilience. -// RUN: %target-swift-frontend -emit-silgen %t/Client.swift -I %t -module-name Client -package-name mypkg -experimental-package-bypass-resilience | %FileCheck %s --check-prefixes=CHECK,CHECK-BYPASS -// RUN: %target-swift-frontend -emit-silgen %t/Client.swift -I %t -module-name Client -package-name mypkg -experimental-package-bypass-resilience -enable-library-evolution | %FileCheck %s --check-prefixes=CHECK,CHECK-BYPASS +// RUN: %target-swift-frontend -emit-silgen %t/Client.swift -I %t -module-name Client -package-name mypkg -experimental-package-bypass-resilience | %FileCheck %s --check-prefixes=CHECK,CHECK-ACCESS +// RUN: %target-swift-frontend -emit-silgen %t/Client.swift -I %t -module-name Client -package-name mypkg -experimental-package-bypass-resilience -enable-library-evolution | %FileCheck %s --check-prefixes=CHECK,CHECK-ACCESS /// Utils can be built with both -enable-testing and -experimental-allow-non-resilient-access. // RUN: rm -rf %t/Utils.swiftmodule @@ -43,8 +43,73 @@ // RUN: -experimental-skip-non-exportable-decls \ // RUN: -experimental-allow-non-resilient-access \ // RUN: -emit-module -emit-module-path %t/Utils.swiftmodule \ -// RUN: 2>&1 | %FileCheck %s --check-prefix=CHECK-DIAG-EXP -// CHECK-DIAG-EXP: warning: ignoring -experimental-skip-non-exportable-decls (overriden by -experimental-allow-non-resilient-access) +// RUN: 2>&1 | %FileCheck %s --check-prefix=CHECK-DIAG-1 +// CHECK-DIAG-1: warning: ignoring -experimental-skip-non-exportable-decls (overriden by -experimental-allow-non-resilient-access) +// RUN: llvm-bcanalyzer --dump %t/Utils.swiftmodule | %FileCheck %s --check-prefix=CHECK-ON + +/// Override -experimental-skip-non-inlinable-function-bodies-without-types with warning +// RUN: rm -rf %t/Utils.swiftmodule +// RUN: %target-swift-frontend %t/Utils.swift \ +// RUN: -module-name Utils -swift-version 5 -I %t \ +// RUN: -package-name mypkg \ +// RUN: -enable-library-evolution \ +// RUN: -experimental-skip-non-inlinable-function-bodies-without-types \ +// RUN: -experimental-allow-non-resilient-access \ +// RUN: -emit-module -emit-module-path %t/Utils.swiftmodule \ +// RUN: 2>&1 | %FileCheck %s --check-prefix=CHECK-DIAG-2 +// CHECK-DIAG-2: warning: ignoring -experimental-skip-non-inlinable-function-bodies-without-types (overriden by -experimental-allow-non-resilient-access) +// RUN: llvm-bcanalyzer --dump %t/Utils.swiftmodule | %FileCheck %s --check-prefix=CHECK-ON + +/// Override -experimental-skip-non-inlinable-function-bodies with warning +// RUN: rm -rf %t/Utils.swiftmodule +// RUN: %target-swift-frontend %t/Utils.swift \ +// RUN: -module-name Utils -swift-version 5 -I %t \ +// RUN: -package-name mypkg \ +// RUN: -enable-library-evolution \ +// RUN: -experimental-skip-non-inlinable-function-bodies \ +// RUN: -experimental-allow-non-resilient-access \ +// RUN: -emit-module -emit-module-path %t/Utils.swiftmodule \ +// RUN: 2>&1 | %FileCheck %s --check-prefix=CHECK-DIAG-3 +// CHECK-DIAG-3: warning: ignoring -experimental-skip-non-inlinable-function-bodies (overriden by -experimental-allow-non-resilient-access) +// RUN: llvm-bcanalyzer --dump %t/Utils.swiftmodule | %FileCheck %s --check-prefix=CHECK-ON + +/// Override -experimental-skip-all-function-bodies with warning +// RUN: rm -rf %t/Utils.swiftmodule +// RUN: %target-swift-frontend %t/Utils.swift \ +// RUN: -module-name Utils -swift-version 5 -I %t \ +// RUN: -package-name mypkg \ +// RUN: -enable-library-evolution \ +// RUN: -experimental-skip-all-function-bodies \ +// RUN: -experimental-allow-non-resilient-access \ +// RUN: -emit-module -emit-module-path %t/Utils.swiftmodule \ +// RUN: 2>&1 | %FileCheck %s --check-prefix=CHECK-DIAG-4 +// CHECK-DIAG-4: warning: ignoring -experimental-skip-all-function-bodies (overriden by -experimental-allow-non-resilient-access) +// RUN: llvm-bcanalyzer --dump %t/Utils.swiftmodule | %FileCheck %s --check-prefix=CHECK-ON + +/// Override -experimental-lazy-typecheck with warning +// RUN: rm -rf %t/Utils.swiftmodule +// RUN: %target-swift-frontend %t/Utils.swift \ +// RUN: -module-name Utils -swift-version 5 -I %t \ +// RUN: -package-name mypkg \ +// RUN: -enable-library-evolution \ +// RUN: -experimental-lazy-typecheck \ +// RUN: -experimental-allow-non-resilient-access \ +// RUN: -emit-module -emit-module-path %t/Utils.swiftmodule \ +// RUN: 2>&1 | %FileCheck %s --check-prefix=CHECK-DIAG-5 +// CHECK-DIAG-5: warning: ignoring -experimental-lazy-typecheck (overriden by -experimental-allow-non-resilient-access) +// RUN: llvm-bcanalyzer --dump %t/Utils.swiftmodule | %FileCheck %s --check-prefix=CHECK-ON + +/// Override -tbd-is-installapi with warning +// RUN: rm -rf %t/Utils.swiftmodule +// RUN: %target-swift-frontend %t/Utils.swift \ +// RUN: -module-name Utils -swift-version 5 -I %t \ +// RUN: -package-name mypkg \ +// RUN: -enable-library-evolution \ +// RUN: -tbd-is-installapi \ +// RUN: -experimental-allow-non-resilient-access \ +// RUN: -emit-module -emit-module-path %t/Utils.swiftmodule \ +// RUN: 2>&1 | %FileCheck %s --check-prefix=CHECK-DIAG-TBD +// CHECK-DIAG-TBD: warning: ignoring -tbd-is-installapi (overriden by -experimental-allow-non-resilient-access) // RUN: llvm-bcanalyzer --dump %t/Utils.swiftmodule | %FileCheck %s --check-prefix=CHECK-ON /// Build Utils interface files. @@ -93,7 +158,7 @@ func foo() { // CHECK: sil hidden [ossa] @$s6Client3fooyyF : $@convention(thin) () -> () { // CHECK-DEFAULT: function_ref @$s5Utils9PkgStructV6pkgVarSivg : $@convention(method) (@in_guaranteed PkgStruct) -> Int // CHECK-DEFAULT: sil package_external @$s5Utils9PkgStructV6pkgVarSivg : $@convention(method) (@in_guaranteed PkgStruct) -> Int -// CHECK-BYPASS: struct_element_addr {{.*}} : $*PkgStruct, #PkgStruct.pkgVar +// CHECK-ACCESS: function_ref @$s5Utils9PkgStructV6pkgVarSivg // CHECK-NONRES: struct_extract {{.*}} : $PkgStruct, #PkgStruct.pkgVar func bar() { @@ -103,5 +168,5 @@ func bar() { // CHECK: sil hidden [ossa] @$s6Client3baryyF : $@convention(thin) () -> () { // CHECK-DEFAULT: function_ref @$s5Utils9PubStructV6pubVarSivg : $@convention(method) (@in_guaranteed PubStruct) -> Int // CHECK-DEFAULT: sil @$s5Utils9PubStructV6pubVarSivg : $@convention(method) (@in_guaranteed PubStruct) -> Int -// CHECK-BYPASS: struct_element_addr {{.*}} : $*PubStruct, #PubStruct.pubVar +// CHECK-ACCESS: function_ref @$s5Utils9PubStructV6pubVarSivg // CHECK-NONRES: struct_extract {{.*}} : $PubStruct, #PubStruct.pubVar diff --git a/test/SILGen/package_global_accessor.swift b/test/SILGen/package_global_accessor.swift new file mode 100644 index 0000000000000..99ce73482ef0c --- /dev/null +++ b/test/SILGen/package_global_accessor.swift @@ -0,0 +1,54 @@ +// RUN: %empty-directory(%t) +// RUN: split-file %s %t + +// RUN: %target-build-swift -module-name=Lib -package-name Pkg -I%t -emit-silgen %t/Lib.swift -o %t/Lib-nonres.sil +// RUN: %FileCheck %s --check-prefix=CHECK-NONRES < %t/Lib-nonres.sil +// RUN: %target-build-swift -module-name=Lib -package-name Pkg -I%t -emit-silgen -O -wmo %t/Lib.swift | %FileCheck %s --check-prefix=CHECK-NONRES +// RUN: %target-build-swift -module-name=Lib -package-name Pkg -I%t -emit-silgen %t/Lib.swift -enable-library-evolution -o %t/Lib-res.sil +// RUN: %FileCheck %s < %t/Lib-res.sil +// RUN: %target-build-swift -module-name=Lib -package-name Pkg -I%t -emit-silgen %t/Lib.swift -enable-library-evolution -O -wmo | %FileCheck %s +// RUN: %target-build-swift -module-name=Lib -package-name Pkg -I%t -emit-silgen %t/Lib.swift -enable-library-evolution -Xfrontend -experimental-allow-non-resilient-access -Xfrontend -experimental-package-cmo -O -wmo | %FileCheck %s + +// RUN: %target-build-swift -module-name=Lib -package-name Pkg -I%t -emit-module %t/Lib.swift -enable-library-evolution -Xfrontend -experimental-allow-non-resilient-access -Xfrontend -experimental-package-cmo -O -wmo -o %t/Lib.swiftmodule +// RUN: %target-build-swift -module-name=Client -package-name Pkg -I%t -emit-silgen %t/Client.swift -I %t | %FileCheck %s --check-prefix=CHECK-CLIENT + +//--- Client.swift +import Lib +public func client() { + /// Should not be calling S.x.unsafeMutableAddressor when accessing resilient global var; + /// instead, should be calling the opaque getter. + // CHECK-CLIENT-NOT: s3Lib1SV1xSSvau + // CHECK-CLIENT: function_ref @$s3Lib1SV1xSSvgZ + print(S.x) +} + +//--- Lib.swift +public struct S { + public static var x = "hello world" +} + +// one-time initialization token for x +// CHECK-NONRES: sil_global private @$s3Lib1SV1x_Wz : $Builtin.Word +// CHECK: sil_global private @$s3Lib1SV1x_Wz : $Builtin.Word + +// static S.x +// CHECK-NONRES: sil_global @$s3Lib1SV1xSSvpZ : $String +// CHECK: sil_global private @$s3Lib1SV1xSSvpZ : $String + +// one-time initialization function for x +// CHECK-NONRES: sil private [global_init_once_fn] [ossa] @$s3Lib1SV1x_WZ : $@convention(c) (Builtin.RawPointer) -> () { +// CHECK: sil private [global_init_once_fn] [ossa] @$s3Lib1SV1x_WZ : $@convention(c) (Builtin.RawPointer) -> () { + +// S.x.unsafeMutableAddressor +// CHECK-NONRES: sil [global_init] [ossa] @$s3Lib1SV1xSSvau : $@convention(thin) () -> Builtin.RawPointer { +// CHECK: sil hidden [global_init] [ossa] @$s3Lib1SV1xSSvau : $@convention(thin) () -> Builtin.RawPointer { +// CHECK: global_addr @$s3Lib1SV1x_Wz +// CHECK: address_to_pointer +// function_ref one-time initialization function for x +// CHECK: function_ref @$s3Lib1SV1x_WZ +// CHECK: global_addr @$s3Lib1SV1xSSvpZ +// CHECK: address_to_pointer + +// static S.x.getter +// CHECK-NONRES: sil [transparent] [serialized] [ossa] @$s3Lib1SV1xSSvgZ : $@convention(method) (@thin S.Type) -> @owned String { +// CHECK: sil [ossa] @$s3Lib1SV1xSSvgZ : $@convention(method) (@thin S.Type) -> @owned String { diff --git a/test/SILOptimizer/package-cmo-closure.swift b/test/SILOptimizer/package-cmo-closure.swift new file mode 100644 index 0000000000000..08d027b464ea1 --- /dev/null +++ b/test/SILOptimizer/package-cmo-closure.swift @@ -0,0 +1,64 @@ +// RUN: %empty-directory(%t) + +// RUN: %target-build-swift %s \ +// RUN: -module-name=Lib -package-name Pkg \ +// RUN: -parse-as-library -emit-module -emit-module-path %t/Lib.swiftmodule -I%t \ +// RUN: -Xfrontend -experimental-package-cmo -Xfrontend -experimental-allow-non-resilient-access \ +// RUN: -O -wmo -enable-library-evolution + +// RUN: %target-sil-opt %t/Lib.swiftmodule -sil-verify-all -o %t/Lib.sil +// RUN: %FileCheck %s --check-prefix=CHECK < %t/Lib.sil + +// REQUIRES: swift_in_compiler + +public struct Something { + public init() {} + + public func f() -> Int { + return 7 + } +} + + +@usableFromInline +func use(_ c: () -> Int) { } + +// Don't crash on this example +@inlinable +public func reproduce(_ e: Something) { + use { + return e.f() + } +} + +// use(_:) +// CHECK: sil [serialized_for_package] [canonical] @$s3Lib3useyySiyXEF : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> Int) -> () { +// CHECK: bb0(%0 : $@noescape @callee_guaranteed () -> Int): +// CHECK: [[RESULT:%.*]] = tuple () +// CHECK: return [[RESULT]] : $() +// CHECK: } // end sil function '$s3Lib3useyySiyXEF' + +// closure #1 in reproduce(_:) +// CHECK: sil shared [serialized] [canonical] @$s3Lib9reproduceyyAA9SomethingVFSiyXEfU_ : $@convention(thin) (@in_guaranteed Something) -> Int { + // function_ref Something.f() +// CHECK: bb0(%0 : @closureCapture $*Something): +// CHECK: [[REF:%.*]] = function_ref @$s3Lib9SomethingV1fSiyF : $@convention(method) (@in_guaranteed Something) -> Int +// CHECK: [[VAL:%.*]] = apply [[REF]](%0) : $@convention(method) (@in_guaranteed Something) -> Int +// CHECK: return [[VAL]] : $Int +// CHECK: } // end sil function '$s3Lib9reproduceyyAA9SomethingVFSiyXEfU_' + +// Something.f() +// CHECK: sil [serialized_for_package] [canonical] @$s3Lib9SomethingV1fSiyF : $@convention(method) (@in_guaranteed Something) -> Int { + +// Something.init() +// CHECK: sil [serialized_for_package] [canonical] @$s3Lib9SomethingVACycfC : $@convention(method) (@thin Something.Type) -> @out Something { + +// reproduce(_:) +// CHECK: sil [serialized] [canonical] @$s3Lib9reproduceyyAA9SomethingVF : $@convention(thin) (@in_guaranteed Something) -> () { +// CHECK: bb0(%0 : $*Something): +// CHECK: [[CLOSURE_PTR:%.*]] = function_ref @$s3Lib9reproduceyyAA9SomethingVFSiyXEfU_ : $@convention(thin) (@in_guaranteed Something) -> Int +// CHECK: [[CLOSURE_W_ARG:%.*]] = partial_apply [callee_guaranteed] [on_stack] [[CLOSURE_PTR]](%0) : $@convention(thin) (@in_guaranteed Something) -> Int +// CHECK: [[MARKED:%.*]] = mark_dependence [nonescaping] [[CLOSURE_W_ARG]] : $@noescape @callee_guaranteed () -> Int on %0 : $*Something +// CHECK: [[USE_REF:%.*]] = function_ref @$s3Lib3useyySiyXEF : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> Int) -> () +// CHECK: [[RESULT:%.*]] = apply [[USE_REF]]([[MARKED]]) : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> Int) -> () + diff --git a/test/SILOptimizer/package-cmo-inlinable-ufi.swift b/test/SILOptimizer/package-cmo-inlinable-ufi.swift new file mode 100644 index 0000000000000..e8d2952360a55 --- /dev/null +++ b/test/SILOptimizer/package-cmo-inlinable-ufi.swift @@ -0,0 +1,205 @@ +// RUN: %empty-directory(%t) +// RUN: split-file %s %t + +// RUN: %target-build-swift %t/Lib.swift \ +// RUN: -module-name=Lib -package-name Pkg \ +// RUN: -parse-as-library -emit-module -emit-module-path %t/Lib.swiftmodule -I%t \ +// RUN: -Xfrontend -experimental-package-cmo -Xfrontend -experimental-allow-non-resilient-access \ +// RUN: -O -wmo -enable-library-evolution +// RUN: %target-sil-opt %t/Lib.swiftmodule -sil-verify-all -o %t/Lib.sil + +// RUN: %target-build-swift -module-name=Main -package-name Pkg -I%t -emit-silgen %t/main.swift -o %t/MAIN.sil +// RUN: %target-build-swift -module-name=Main -package-name Pkg -I%t -emit-sil -O %t/main.swift -o %t/Main-opt.sil + +// RUN: %FileCheck %s --check-prefix=CHECK < %t/Lib.sil +// RUN: %FileCheck %s --check-prefix=CHECK-MAIN-OPT < %t/Main-opt.sil +// RUN: %FileCheck %s --check-prefix=CHECK-MAIN < %t/MAIN.sil + +// REQUIRES: swift_in_compiler + +//--- main.swift + +import Lib + +// CHECK-MAIN-OPT-NOT: function_ref +// CHECK-MAIN-OPT: struct $PubStruct +// CHECK-MAIN-OPT: store {{.*}} to %0 : $*PubStruct +// CHECK-MAIN-OPT: struct $UfiPkgStruct +// CHECK-MAIN-OPT: store {{.*}} to %0 : $*UfiPkgStruct +// CHECK-MAIN-OPT: struct $PkgStruct +// CHECK-MAIN-OPT: store {{.*}} to %0 : $*PkgStruct + +// CHECK-MAIN: sil [serialized] [ossa] @$s4Main14inUsePubStructy3Lib0dE0VSiF : $@convention(thin) (Int) -> @out PubStruct { +@inlinable +public func inUsePubStruct(_ arg: Int) -> PubStruct { + var p = PubStruct(1) + // CHECK-MAIN: function_ref @$s3Lib9PubStructV3pubSivM : $@yield_once @convention(method) (@inout PubStruct) -> @yields @inout Int + p.pub += arg + return p +} + +// CHECK-MAIN: sil [ossa] @$s4Main12usePubStructy3Lib0cD0VSiF : $@convention(thin) (Int) -> @out PubStruct { +public func usePubStruct(_ arg: Int) -> PubStruct { + var p = PubStruct(1) + // CHECK-MAIN: function_ref @$s3Lib9PubStructVyACSicfC + // CHECK-MAIN: function_ref @$s3Lib9PubStructV3pubSivM + p.pub += arg + return p +} + +// CHECK-MAIN: sil [serialized] [ossa] @$s4Main17inUseUfiPkgStructy3Lib0deF0VSiF : $@convention(thin) (Int) -> @out UfiPkgStruct { +@inlinable +package func inUseUfiPkgStruct(_ arg: Int) -> UfiPkgStruct { + var p = UfiPkgStruct(1) + // CHECK-MAIN: function_ref @$s3Lib12UfiPkgStructV03ufiC0SivM : $@yield_once @convention(method) (@inout UfiPkgStruct) -> @yields @inout Int + p.ufiPkg += arg + return p +} + +// CHECK-MAIN: sil package [ossa] @$s4Main15useUfiPkgStructy3Lib0cdE0VSiF : $@convention(thin) (Int) -> @out UfiPkgStruct { +package func useUfiPkgStruct(_ arg: Int) -> UfiPkgStruct { + var p = UfiPkgStruct(1) + // CHECK-MAIN: function_ref @$s3Lib12UfiPkgStructVyACSicfC + // CHECK-MAIN: function_ref @$s3Lib12UfiPkgStructV03ufiC0SivM + p.ufiPkg += arg + return p +} + +// CHECK-MAIN: sil package [ossa] @$s4Main12usePkgStructy3Lib0cD0VSiF : $@convention(thin) (Int) -> @out PkgStruct { +package func usePkgStruct(_ arg: Int) -> PkgStruct { + var p = PkgStruct(1) + // CHECK-MAIN: function_ref @$s3Lib9PkgStructVyACSicfC + // CHECK-MAIN: function_ref @$s3Lib9PkgStructV3pkgSivM + p.pkg += arg + return p +} + +//--- Lib.swift + +// CHECK: sil package [serialized_for_package] [canonical] @$s3Lib6libPkgyAA0C6StructVSiF : $@convention(thin) (Int) -> @out PkgStruct { + // CHECK: struct $PkgStruct + // CHECK: store {{.*}} to %0 : $*PkgStruct + +// CHECK: sil [serialized_for_package] [canonical] @$s3Lib6libPubyAA0C6StructVSiF : $@convention(thin) (Int) -> @out PubStruct { + // CHECK: struct $PubStruct + // CHECK: store {{.*}} to %0 : $*PubStruct + +// CHECK: sil package [serialized_for_package] [canonical] @$s3Lib9libUfiPkgyAA0cD6StructVSiF : $@convention(thin) (Int) -> @out UfiPkgStruct { + // CHECK: struct $UfiPkgStruct + // CHECK: store {{.*}} to %0 : $*UfiPkgStruct + +/// @inlinable package func inLibUfiPkg(_ arg: Int) -> UfiPkgStruct +// CHECK: sil [serialized] [canonical] @$s3Lib02inA6UfiPkgyAA0cD6StructVSiF : $@convention(thin) (Int) -> @out UfiPkgStruct { + // CHECK: function_ref @$s3Lib12UfiPkgStructVyACSicfC : $@convention(method) (Int, @thin UfiPkgStruct.Type) -> @out UfiPkgStruct + // CHECK: function_ref @$s3Lib12UfiPkgStructV03ufiC0SivM : $@yield_once @convention(method) (@inout UfiPkgStruct) -> @yields @inout Int + +/// @inlinable func inLibUfiHid(_ arg: Int) -> UfiHidStruct +// CHECK: sil [serialized] [canonical] @$s3Lib02inA6UfiHidyAA0cD6StructVSiF : $@convention(thin) (Int) -> @out UfiHidStruct { + // CHECK: function_ref @$s3Lib12UfiHidStructVyACSicfC : $@convention(method) (Int, @thin UfiHidStruct.Type) -> @out UfiHidStruct + // CHECK: function_ref @$s3Lib12UfiHidStructV03ufiC0SivM : $@yield_once @convention(method) (@inout UfiHidStruct) -> @yields @inout Int + +/// @inlinable public func inLibPub(_ arg: Int) -> PubStruct +// CHECK: sil [serialized] [canonical] @$s3Lib02inA3PubyAA0C6StructVSiF : $@convention(thin) (Int) -> @out PubStruct { + // CHECK: function_ref @$s3Lib9PubStructVyACSicfC : $@convention(method) (Int, @thin PubStruct.Type) -> @out PubStruct + // CHECK: function_ref @$s3Lib9PubStructV3pubSivM : $@yield_once @convention(method) (@inout PubStruct) -> @yields @inout Int + +@inlinable +public func inLibPub(_ arg: Int) -> PubStruct { + var p = PubStruct(1) + p.pub += arg + return p +} + +public func libPub(_ arg: Int) -> PubStruct { + var p = PubStruct(1) + p.pub += arg + return p +} + +@inlinable +package func inLibUfiPkg(_ arg: Int) -> UfiPkgStruct { + var p = UfiPkgStruct(1) + p.ufiPkg += arg + return p +} + +package func libUfiPkg(_ arg: Int) -> UfiPkgStruct { + var p = UfiPkgStruct(1) + p.ufiPkg += arg + return p +} + +package func libPkg(_ arg: Int) -> PkgStruct { + var p = PkgStruct(1) + p.pkg += arg + return p +} + +@inlinable +func inLibUfiHid(_ arg: Int) -> UfiHidStruct { + var p = UfiHidStruct(1) + p.ufiHid += arg + return p +} + +func libUfiHid(_ arg: Int) -> UfiHidStruct { + var p = UfiHidStruct(1) + p.ufiHid += arg + return p +} + +public struct PubStruct { + // PubStruct.pub.getter + // sil [serialized_for_package] [canonical] @$s3Lib9PubStructV3pubSivg : $@convention(method) (@in_guaranteed PubStruct) -> Int { + public var pub: Int + public init(_ arg: Int) { + pub = arg + } + public func pubFunc(_ arg: Int) -> Int { + return arg > 0 ? arg : arg + 11 + } +} + +package struct PkgStruct { + // PkgStruct.pkg.modify + // sil package [serialized_for_package] [canonical] @$s3Lib9PkgStructV3pkgSivM : $@yield_once @convention(method) (@inout PkgStruct) -> @yields @inout Int { + package var pkg: Int + package init(_ arg: Int) { + pkg = arg + } + package func pkgFunc(_ arg: Int) -> Int { + return arg > 0 ? arg : 11 + } +} + +@usableFromInline +package struct UfiPkgStruct { + // UfiPkgStruct.ufiPkg.getter + // sil [serialized_for_package] [canonical] @$s3Lib12UfiPkgStructV03ufiC0Sivg : $@convention(method) (@in_guaranteed UfiPkgStruct) -> Int { + @usableFromInline + package var ufiPkg: Int + @usableFromInline + package init(_ arg: Int) { + ufiPkg = arg + } + @usableFromInline + package func ufiPkgFunc(_ arg: Int) -> Int { + return arg > 0 ? arg : 11 + } +} + +@usableFromInline +struct UfiHidStruct { + // UfiHidStruct.ufiHid.setter + // sil [serialized_for_package] [canonical] @$s3Lib12UfiHidStructV03ufiC0Sivs : $@convention(method) (Int, @inout UfiHidStruct) -> () { + @usableFromInline + var ufiHid: Int + @usableFromInline + init(_ arg: Int) { + ufiHid = arg + } + @usableFromInline + func ufiFunc(_ arg: Int) -> Int { + return arg > 0 ? arg : 11 + } +} diff --git a/test/SILOptimizer/package-cmo.swift b/test/SILOptimizer/package-cmo-non-resilient-mode.swift similarity index 75% rename from test/SILOptimizer/package-cmo.swift rename to test/SILOptimizer/package-cmo-non-resilient-mode.swift index 7f46c97c4a667..d55cc354ef9bf 100644 --- a/test/SILOptimizer/package-cmo.swift +++ b/test/SILOptimizer/package-cmo-non-resilient-mode.swift @@ -11,27 +11,34 @@ import Module import ModuleTBD +// static ModuleStruct.privateFunctionPointer // CHECK-LABEL: sil_global public_external @$s6Module0A6StructV22privateFunctionPointeryS2icvpZ : $@callee_guaranteed (Int) -> Int{{$}} + +// static ModuleStruct.publicFunctionPointer +// CHECK-LABEL: sil_global public_external [serialized] @$s6Module0A6StructV21publicFunctionPointeryS2icvpZ : $@callee_guaranteed (Int) -> Int + + +// CHECK-LABEL: sil @$s4Main26callPrivateFunctionPointeryS2iF : $@convention(thin) (Int) -> Int { +// CHECK: global_addr @$s6Module0A6StructV22privateFunctionPointeryS2icvpZ +// CHECK: load +// CHECK: apply public func callPrivateFunctionPointer(_ x: Int) -> Int { return Module.ModuleStruct.privateFunctionPointer(x) } -// CHECK-LABEL: sil_global package_external @$s6Module03PkgA6StructV14closurePointeryS2icvpZ : $@callee_guaranteed (Int) -> Int{{$}} +// CHECK-LABEL: sil package @$s4Main27callStaticPkgClosurePointeryS2iF : $@convention(thin) (Int) -> Int { +// CHECK: function_ref @$s6Module03PkgA6StructV14closurePointeryS2icvau +// CHECK: apply +// CHECK: pointer_to_address +// CHECK: load +// CHECK: apply + +// PkgModuleStruct.closurePointer.unsafeMutableAddressor +// CHECK: sil package_external [global_init] @$s6Module03PkgA6StructV14closurePointeryS2icvau : $@convention(thin) () -> Builtin.RawPointer package func callStaticPkgClosurePointer(_ x: Int) -> Int { return Module.PkgModuleStruct.closurePointer(x) } -// CHECK-LABEL: sil_global public_external [serialized] @$s6Module0A6StructV21publicFunctionPointeryS2icvpZ : $@callee_guaranteed (Int) -> Int = { - // function_ref incrementByThree(_:) -// CHECK: [[REF:%.*]] = function_ref @$s6Module16incrementByThreeyS2iF : $@convention(thin) (Int) -> Int -// CHECK-NEXT: [[INITVAL:%.*]] = thin_to_thick_function [[REF]] : $@convention(thin) (Int) -> Int to $@callee_guaranteed (Int) -> Int -// CHECK-NEXT: } - -// CHECK-LABEL: sil_global package_external [serialized] @$s6Module03PkgA6StructV11funcPointeryS2icvpZ : $@callee_guaranteed (Int) -> Int = { -// CHECK: [[REF:%.*]] = function_ref @$s6Module7pkgFuncyS2iF : $@convention(thin) (Int) -> Int -// CHECK-NEXT: [[INITVAL:%.*]] = thin_to_thick_function [[REF]] : $@convention(thin) (Int) -> Int to $@callee_guaranteed (Int) -> Int -// CHECK-NEXT: } - // CHECK-LABEL: sil @$s4Main25callPublicFunctionPointeryS2iF : $@convention(thin) (Int) -> Int { // CHECK: global_addr @$s6Module0A6StructV21publicFunctionPointeryS2icvpZ : $*@callee_guaranteed (Int) -> Int // CHECK: load @@ -42,10 +49,14 @@ public func callPublicFunctionPointer(_ x: Int) -> Int { } // CHECK-LABEL: sil package @$s4Main28callStaticPkgFunctionPointeryS2iF : $@convention(thin) (Int) -> Int { -// CHECK: global_addr @$s6Module03PkgA6StructV11funcPointeryS2icvpZ : $*@callee_guaranteed (Int) -> Int +// CHECK: function_ref @$s6Module03PkgA6StructV11funcPointeryS2icvau +// CHECK: pointer_to_address // CHECK: load // CHECK: apply // CHECK: } // end sil function '$s4Main28callStaticPkgFunctionPointeryS2iF' + +// PkgModuleStruct.funcPointer.unsafeMutableAddressor +// CHECK-LABEL: sil package_external [global_init] @$s6Module03PkgA6StructV11funcPointeryS2icvau : $@convention(thin) () -> Builtin.RawPointer package func callStaticPkgFunctionPointer(_ x: Int) -> Int { return Module.PkgModuleStruct.funcPointer(x) } @@ -68,16 +79,17 @@ public func usePrivateCVarInModule() -> Int { // CHECK-NOT: function_ref // CHECK-NOT: apply // CHECK: } // end sil function '$s4Main11doIncrementyS2iF' -// CHECK-LABEL: sil public_external @$s6Module16incrementByThreeyS2iF : $@convention(thin) (Int) -> Int { public func doIncrement(_ x: Int) -> Int { return Module.incrementByThree(x) } // CHECK-LABEL: sil package @$s4Main11callPkgFuncyS2iF : $@convention(thin) (Int) -> Int { -// CHECK-NOT: function_ref -// CHECK-NOT: apply +// CHECK: function_ref @$s6Module7pkgFuncyS2iF +// CHECK: apply // CHECK: } // end sil function '$s4Main11callPkgFuncyS2iF' -// CHECK-LABEL: sil public_external @$s6Module7pkgFuncyS2iF : $@convention(thin) (Int) -> Int { + +// pkgFunc(_:) +// CHECK-LABEL: sil package_external @$s6Module7pkgFuncyS2iF : $@convention(thin) (Int) -> Int package func callPkgFunc(_ x: Int) -> Int { return Module.pkgFunc(x) } @@ -90,8 +102,10 @@ public func doIncrementWithCall(_ x: Int) -> Int { } // CHECK-LABEL: sil package @$s4Main16callPkgFuncNoCMOyS2iF : $@convention(thin) (Int) -> Int { -// CHECK: function_ref @$s9Submodule15subPkgFuncNoCMOyS2iF +// CHECK: function_ref @$s6Module12pkgFuncNoCMOyS2iF // CHECK: } // end sil function '$s4Main16callPkgFuncNoCMOyS2iF' +// pkgFuncNoCMO(_:) +// CHECK-LABEL: sil package_external @$s6Module12pkgFuncNoCMOyS2iF : $@convention(thin) (Int) -> Int package func callPkgFuncNoCMO(_ x: Int) -> Int { return Module.pkgFuncNoCMO(x) } @@ -105,9 +119,11 @@ public func doIncrementTBD(_ x: Int) -> Int { } // CHECK-LABEL: sil package @$s4Main14callPkgFuncTBDyS2iF : $@convention(thin) (Int) -> Int { -// CHECK-NOT: function_ref -// CHECK-NOT: apply +// CHECK: function_ref @$s9ModuleTBD7pkgFuncyS2iF +// CHECK: apply // CHECK: } // end sil function '$s4Main14callPkgFuncTBDyS2iF' +// pkgFunc(_:) +// CHECK-LABEL: sil package_external @$s9ModuleTBD7pkgFuncyS2iF : $@convention(thin) (Int) -> Int package func callPkgFuncTBD(_ x: Int) -> Int { return ModuleTBD.pkgFunc(x) } @@ -123,7 +139,6 @@ public func doIncrementTBDWithCall(_ x: Int) -> Int { // CHECK-LABEL: sil package @$s4Main19callPkgFuncNoCMOTBDyS2iF : $@convention(thin) (Int) -> Int { // CHECK: function_ref @$s9ModuleTBD12pkgFuncNoCMOyS2iF // CHECK: } // end sil function '$s4Main19callPkgFuncNoCMOTBDyS2iF' -// FIXME: should package_external be package? // CHECK-LABEL: sil package_external @$s9ModuleTBD12pkgFuncNoCMOyS2iF : $@convention(thin) (Int) -> Int package func callPkgFuncNoCMOTBD(_ x: Int) -> Int { return ModuleTBD.pkgFuncNoCMO(x) @@ -138,9 +153,11 @@ public func getSubmoduleKlassMember() -> Int { } // CHECK-LABEL: sil package @$s4Main26getPkgSubmoduleKlassMemberSiyF : $@convention(thin) () -> Int { -// CHECK-NOT: function_ref -// CHECK-NOT: apply +// CHECK: function_ref @$s6Module23pkgSubmoduleKlassMemberSiyF +// CHECK: apply // CHECK: } // end sil function '$s4Main26getPkgSubmoduleKlassMemberSiyF' +// pkgSubmoduleKlassMember() +// CHECK-LABEL: sil package_external @$s6Module23pkgSubmoduleKlassMemberSiyF : $@convention(thin) () -> Int package func getPkgSubmoduleKlassMember() -> Int { return Module.pkgSubmoduleKlassMember() } @@ -154,10 +171,12 @@ public func getSubmoduleKlassMemberTBD() -> Int { } // CHECK-LABEL: sil package @$s4Main29getPkgSubmoduleKlassMemberTBDSiyF : $@convention(thin) () -> Int { -// FIXME: should not contain function_ref/apply -// CHECK: function_ref +// CHECK: function_ref @$s9ModuleTBD23pkgSubmoduleKlassMemberSiyF // CHECK: apply // CHECK: } // end sil function '$s4Main29getPkgSubmoduleKlassMemberTBDSiyF' + +// pkgSubmoduleKlassMember() +// CHECK-LABEL:sil package_external @$s9ModuleTBD23pkgSubmoduleKlassMemberSiyF : $@convention(thin) () -> Int package func getPkgSubmoduleKlassMemberTBD() -> Int { return ModuleTBD.pkgSubmoduleKlassMember() } @@ -171,9 +190,11 @@ public func getModuleKlassMember() -> Int { } // CHECK-LABEL: sil package @$s4Main23getPkgModuleKlassMemberSiyF : $@convention(thin) () -> Int { -// CHECK-NOT: function_ref -// CHECK-NOT: apply +// CHECK: function_ref @$s6Module03pkgA11KlassMemberSiyF +// CHECK: apply // CHECK: } // end sil function '$s4Main23getPkgModuleKlassMemberSiyF' +// pkgModuleKlassMember() +// CHECK-LABEL: sil package_external @$s6Module03pkgA11KlassMemberSiyF : $@convention(thin) () -> Int package func getPkgModuleKlassMember() -> Int { return Module.pkgModuleKlassMember() } @@ -187,14 +208,14 @@ public func getModuleKlassMemberTBD() -> Int { } // CHECK-LABEL: sil package @$s4Main26getPkgModuleKlassMemberTBDSiyF : $@convention(thin) () -> Int { -// CHECK-NOT: function_ref -// CHECK-NOT: apply +// CHECK: function_ref @$s9ModuleTBD03pkgA11KlassMemberSiyF +// CHECK: apply // CHECK: } // end sil function '$s4Main26getPkgModuleKlassMemberTBDSiyF' +// pkgModuleKlassMember() +// CHECK-LABEL: sil package_external @$s9ModuleTBD03pkgA11KlassMemberSiyF : $@convention(thin) () -> Int package func getPkgModuleKlassMemberTBD() -> Int { return ModuleTBD.pkgModuleKlassMember() } // CHECK-LABEL: sil [_semantics "optimize.no.crossmodule"] @$s9Submodule19incrementByOneNoCMOyS2iF : $@convention(thin) (Int) -> Int - -// CHECK-LABEL: sil package_external [_semantics "optimize.no.crossmodule"] @$s9Submodule15subPkgFuncNoCMOyS2iF : $@convention(thin) (Int) -> Int diff --git a/test/SILOptimizer/package-cmo-opaque-result.swift b/test/SILOptimizer/package-cmo-opaque-result.swift new file mode 100644 index 0000000000000..a6d398cfc360e --- /dev/null +++ b/test/SILOptimizer/package-cmo-opaque-result.swift @@ -0,0 +1,54 @@ +// RUN: %empty-directory(%t) +// RUN: split-file %s %t + +// RUN: %target-build-swift %t/Lib.swift \ +// RUN: -module-name=Lib -package-name Pkg \ +// RUN: -parse-as-library -emit-module -emit-module-path %t/Lib.swiftmodule -I%t \ +// RUN: -Xfrontend -experimental-package-cmo -Xfrontend -experimental-allow-non-resilient-access \ +// RUN: -O -wmo -enable-library-evolution -Xfrontend -disable-availability-checking + +// RUN: %target-build-swift -module-name=Main -package-name Pkg -I%t -emit-sil -O %t/main.swift -o %t/Main-res.sil +// RUN: %FileCheck %s --check-prefixes=CHECK-OPAQUE < %t/Main-res.sil + +// REQUIRES: swift_in_compiler + +//--- main.swift + +import Lib + +// CHECK-OPAQUE: sil @$s4Main023testPackageInSerializedC4FuncyyF : $@convention(thin) () -> () +// CHECK-OPAQUE: struct $Thing +// CHECK-OPAQUE: struct $Thing1 +// CHECK-OPAQUE: function_ref @$s3Lib13getSomeProto2QryF +// CHECK-OPAQUE: function_ref @$s3Lib13getSomeProto3QryF +// CHECK-OPAQUE: } // end sil function '$s4Main023testPackageInSerializedC4FuncyyF' + +public func testPackageInSerializedPackageFunc() { + print(getSomeProto()) + print(getSomeProto1()) + print(getSomeProto2()) + print(getSomeProto3()) +} + +//--- Lib.swift + +public protocol SomeProto {} + +public struct Thing : SomeProto {} +package struct Thing1 : SomeProto {} +internal struct Thing2 : SomeProto {} +private struct Thing3 : SomeProto {} + +// Don't crash on this example. +public func getSomeProto() -> some SomeProto { + return Thing() +} +public func getSomeProto1() -> some SomeProto { + return Thing1() +} +public func getSomeProto2() -> some SomeProto { + return Thing2() +} +public func getSomeProto3() -> some SomeProto { + return Thing3() +} diff --git a/test/SILOptimizer/package-cmo-resilient-mode.swift b/test/SILOptimizer/package-cmo-resilient-mode.swift new file mode 100644 index 0000000000000..bd0dfd9acaba4 --- /dev/null +++ b/test/SILOptimizer/package-cmo-resilient-mode.swift @@ -0,0 +1,569 @@ +// RUN: %empty-directory(%t) +// RUN: split-file %s %t + +// RUN: %target-build-swift %t/Lib.swift \ +// RUN: -module-name=Lib -package-name Pkg \ +// RUN: -parse-as-library -emit-module -emit-module-path %t/Lib.swiftmodule -I%t \ +// RUN: -Xfrontend -experimental-package-cmo -Xfrontend -experimental-allow-non-resilient-access \ +// RUN: -O -wmo -enable-library-evolution + +// RUN: %target-sil-opt %t/Lib.swiftmodule -sil-verify-all -o %t/Lib-res.sil +// RUN: %FileCheck %s --check-prefixes=CHECK-COMMON,CHECK-RES < %t/Lib-res.sil + +// RUN: %target-build-swift -module-name=Main -package-name Pkg -I%t -emit-sil -O %t/main.swift -o %t/Main-res.sil +// RUN: %FileCheck %s --check-prefixes=CHECK-MAIN-COMMON,CHECK-MAIN-RES < %t/Main-res.sil + +// RUN: llvm-bcanalyzer --dump %t/Lib.swiftmodule | %FileCheck %s --check-prefix=CHECK-BC +// CHECK-BC: SERIALIZE_PACKAGE_ENABLED + +// RUN: rm -rf %t/Lib.swiftmodule + +// RUN: %target-build-swift %t/Lib.swift \ +// RUN: -module-name=Lib -package-name Pkg \ +// RUN: -parse-as-library -emit-module -emit-module-path %t/Lib.swiftmodule -I%t \ +// RUN: -Xfrontend -experimental-package-cmo -Xfrontend -experimental-allow-non-resilient-access \ +// RUN: -O -wmo + +// RUN: %target-sil-opt %t/Lib.swiftmodule -sil-verify-all -o %t/Lib-non-res.sil +// RUN: %FileCheck %s --check-prefixes=CHECK-COMMON,CHECK-NONRES < %t/Lib-non-res.sil + +// RUN: %target-build-swift -module-name=Main -package-name Pkg -I%t -emit-sil -O %t/main.swift -o %t/Main-non-res.sil +// RUN: %FileCheck %s --check-prefixes=CHECK-MAIN-COMMON,CHECK-MAIN-NONRES < %t/Main-non-res.sil + +// REQUIRES: swift_in_compiler + +//--- main.swift + +import Lib + +// CHECK-MAIN-COMMON-NOT: s3Lib9PubStructVyACSicfC +// CHECK-MAIN-COMMON-NOT: s3Lib9PubStructV6fooVarSivg +// CHECK-MAIN-COMMON-NOT: s3Lib9PubStructV6fooVarSivs +// CHECK-MAIN-COMMON-NOT: s3Lib6runPubySiAA0C6StructVF +// CHECK-MAIN-COMMON-NOT: s3Lib9PkgStructVyACSicfC +// CHECK-MAIN-COMMON-NOT: s3Lib9PkgStructV6fooVarSivg +// CHECK-MAIN-COMMON-NOT: s3Lib9PkgStructV6fooVarSivs +// CHECK-MAIN-COMMON-NOT: s3Lib6runPkgySiAA0C6StructVF + +// CHECK-MAIN-COMMON: [[PUB_INIT:%.*]] = struct $PubStruct +// CHECK-MAIN-COMMON: store [[PUB_INIT]] to {{.*}} : $*PubStruct +// CHECK-MAIN-COMMON: [[PUB_ELEM_ADDR:%.*]] = struct_element_addr {{.*}} : $*PubStruct, #PubStruct.fooVar +// CHECK-MAIN-COMMON: [[PUB_GET:%.*]] = load [[PUB_ELEM_ADDR]] : $*Int +// CHECK-MAIN-COMMON: store [[PUB_GET]] to {{.*}} : $*Int + +// CHECK-MAIN-COMMON: [[FRPUB_INIT:%.*]] = struct $FrPubStruct +// CHECK-MAIN-COMMON: store [[FRPUB_INIT]] to {{.*}} : $*FrPubStruct +// CHECK-MAIN-COMMON: [[FRPUB_ELEM_ADDR:%.*]] = struct_element_addr {{.*}} : $*FrPubStruct, #FrPubStruct.fooVar +// CHECK-MAIN-COMMON: [[FRPUB_GET:%.*]] = load [[FRPUB_ELEM_ADDR]] : $*Int +// CHECK-MAIN-COMMON: store [[FRPUB_GET]] to {{.*}} : $*Int + +// CHECK-MAIN-RES: [[PKG_INIT:%.*]] = struct $PkgStruct +// CHECK-MAIN-RES: store [[PKG_INIT]] to {{.*}} : $*PkgStruct +// CHECK-MAIN-RES: [[PKG_ELEM_ADDR_RES:%.*]] = struct_element_addr {{.*}} : $*PkgStruct, #PkgStruct.fooVar +// CHECK-MAIN-RES: [[PKG_GET_RES:%.*]] = load [[PKG_ELEM_ADDR_RES]] : $*Int +// CHECK-MAIN-RES: store [[PKG_GET_RES]] to {{.*}} : $*Int +// CHECK-MAIN-RES: struct $PkgStruct +// CHECK-MAIN-RES: store +// CHECK-MAIN-RES: [[PKG_ELEM_ADDR_RES_ARG:%.*]] = struct_element_addr {{.*}} : $*PkgStruct, #PkgStruct.fooVar +// CHECK-MAIN-RES: load [[PKG_ELEM_ADDR_RES_ARG]] : $*Int +// CHECK-MAIN-NONRES: function_ref @$s3Lib9PkgStructVyACSicfC +// CHECK-MAIN-NONRES: [[PKG_ELEM_ADDR_NONRES:%.*]] = struct_element_addr {{.*}} : $*PkgStruct, #PkgStruct.fooVar +// CHECK-MAIN-NONRES: [[PKG_GET_NONRES:%.*]] = load [[PKG_ELEM_ADDR_NONRES]] : $*Int +// CHECK-MAIN-NONRES: store [[PKG_GET_NONRES]] to {{.*}} : $*Int +// CHECK-MAIN-NONRES: struct $PkgStruct +// CHECK-MAIN-NONRES: store +// CHECK-MAIN-NONRES: function_ref @$s3Lib6runPkgySiAA0C6StructVF + +// CHECK-MAIN-COMMON: [[PUB_ALLOC:%.*]] = alloc_ref $PubKlass +// CHECK-MAIN-COMMON-NEXT: [[PUB_INIT:%.*]] = end_init_let_ref [[PUB_ALLOC]] : $PubKlass +// CHECK-MAIN-COMMON-NEXT: [[PUB_REF_ELEM_ADDR:%.*]] = ref_element_addr [[PUB_INIT]] : $PubKlass, #PubKlass.data +// CHECK-MAIN-COMMON-NEXT: store {{.*}} to [[PUB_REF_ELEM_ADDR]] : $*Int +// CHECK-MAIN-COMMON-NEXT: store [[PUB_INIT]] to {{.*}} : $*PubKlass + +// CHECK-MAIN-COMMON: [[PUBK_GET:%.*]] = load {{.*}} : $*PubKlass +// CHECK-MAIN-COMMON: class_method [[PUBK_GET]] : $PubKlass, #PubKlass.data!getter : (PubKlass) -> () -> Int, $@convention(method) (@guaranteed PubKlass) -> Int +// CHECK-MAIN-COMMON: [[PUBK_SET:%.*]] = load {{.*}} : $*PubKlass +// CHECK-MAIN-COMMON: class_method [[PUBK_SET]] : $PubKlass, #PubKlass.data!setter : (PubKlass) -> (Int) -> (), $@convention(method) (Int, @guaranteed PubKlass) -> () + +// CHECK-MAIN-RES: [[PKG_ALLOC:%.*]] = alloc_ref $PkgKlass +// CHECK-MAIN-RES-NEXT: [[PKG_INIT:%.*]] = end_init_let_ref [[PKG_ALLOC]] : $PkgKlass +// CHECK-MAIN-RES-NEXT: [[PKG_REF_ELEM_ADDR:%.*]] = ref_element_addr [[PKG_INIT]] : $PkgKlass, #PkgKlass.data +// CHECK-MAIN-RES-NEXT: store {{.*}} to [[PKG_REF_ELEM_ADDR]] : $*Int +// CHECK-MAIN-RES-NEXT: store [[PKG_INIT]] to {{.*}} : $*PkgKlass +// CHECK-MAIN-NONRES: function_ref @$s3Lib8PkgKlassCyACSicfC + +// CHECK-MAIN-COMMON: [[PKGK_GET:%.*]] = load {{.*}} : $*PkgKlass +// CHECK-MAIN-COMMON: class_method [[PKGK_GET]] : $PkgKlass, #PkgKlass.data!getter : (PkgKlass) -> () -> Int, $@convention(method) (@guaranteed PkgKlass) -> Int + +// CHECK-MAIN-COMMON: [[PKGK_SET:%.*]] = load {{.*}} : $*PkgKlass +// CHECK-MAIN-COMMON: class_method [[PKGK_SET]] : $PkgKlass, #PkgKlass.data!setter : (PkgKlass) -> (Int) -> (), $@convention(method) (Int, @guaranteed PkgKlass) -> () + +// CHECK-MAIN-COMMON: [[FNL_PUB_ALLOC:%.*]] = alloc_ref $FinalPubKlass +// CHECK-MAIN-COMMON-NEXT: [[FNL_PUB_INIT:%.*]] = end_init_let_ref [[FNL_PUB_ALLOC]] : $FinalPubKlass +// CHECK-MAIN-COMMON-NEXT: [[FNL_PUB_REF_ELEM_ADDR:%.*]] = ref_element_addr [[FNL_PUB_INIT]] : $FinalPubKlass, #FinalPubKlass.data +// CHECK-MAIN-COMMON-NEXT: store {{.*}} to [[FNL_PUB_REF_ELEM_ADDR]] : $*Int +// CHECK-MAIN-COMMON: store [[FNL_PUB_INIT]] to {{.*}} : $*FinalPubKlass + +// CHECK-MAIN-COMMON: [[FNL_PUB_GET:%.*]] = load {{.*}} : $*FinalPubKlass +// CHECK-MAIN-COMMON: [[FNL_PUB_REF:%.*]] = ref_element_addr [[FNL_PUB_GET]] : $FinalPubKlass, #FinalPubKlass.data +// CHECK-MAIN-COMMON-NEXT: [[FNL_PUB_ACCESS:%.*]] = begin_access {{.*}} [[FNL_PUB_REF]] : $*Int +// CHECK-MAIN-COMMON-NEXT: [[FNL_PUB_LOAD:%.*]] = load [[FNL_PUB_ACCESS]] : $*Int +// CHECK-MAIN-COMMON: store [[FNL_PUB_LOAD]] to {{.*}} : $*Int + +// CHECK-MAIN-RES: [[FNL_PKG_ALLOC:%.*]] = alloc_ref $FinalPkgKlass +// CHECK-MAIN-RES-NEXT: [[FNL_PKG_INIT:%.*]] = end_init_let_ref [[FNL_PKG_ALLOC]] : $FinalPkgKlass +// CHECK-MAIN-RES-NEXT: [[FNL_PKG_REF_ELEM_ADDR:%.*]] = ref_element_addr [[FNL_PKG_INIT]] : $FinalPkgKlass, #FinalPkgKlass.data +// CHECK-MAIN-RES-NEXT: store {{.*}} to [[FNL_PKG_REF_ELEM_ADDR]] : $*Int +// CHECK-MAIN-RES: store [[FNL_PKG_INIT]] to {{.*}} : $*FinalPkgKlass +// CHECK-MAIN-NONRES: function_ref @$s3Lib13FinalPkgKlassCyACSicfC + +// CHECK-MAIN-COMMON: [[FNL_PKG_GET:%.*]] = load {{.*}} : $*FinalPkgKlass +// CHECK-MAIN-COMMON: [[FNL_PKG_REF:%.*]] = ref_element_addr [[FNL_PKG_GET]] : $FinalPkgKlass, #FinalPkgKlass.data +// CHECK-MAIN-COMMON-NEXT: [[FNL_PKG_ACCESS:%.*]] = begin_access {{.*}} [[FNL_PKG_REF]] : $*Int +// CHECK-MAIN-COMMON-NEXT: [[FNL_PKG_LOAD:%.*]] = load [[FNL_PKG_ACCESS]] : $*Int +// CHECK-MAIN-COMMON: store [[FNL_PKG_LOAD]] to {{.*}} : $*Int + +// CHECK-MAIN-RES-DAG: sil public_external @$s3Lib8PubKlassCyACSicfC : $@convention(method) (Int, @thick PubKlass.Type) -> @owned PubKlass { +// CHECK-MAIN-NONRES-DAG: sil public_external @$s3Lib8PubKlassCyACSicfC : $@convention(method) (Int, @thick PubKlass.Type) -> @owned PubKlass { + +// CHECK-MAIN-RES-DAG: sil package_external @$s3Lib8PkgKlassCyACSicfC : $@convention(method) (Int, @thick PkgKlass.Type) -> @owned PkgKlass { + +// CHECK-MAIN-RES-DAG: sil public_external @$s3Lib13FinalPubKlassCyACSicfC : $@convention(method) (Int, @thick FinalPubKlass.Type) -> @owned FinalPubKlass { +// CHECK-MAIN-NONRES-DAG: sil public_external @$s3Lib13FinalPubKlassCyACSicfC : $@convention(method) (Int, @thick FinalPubKlass.Type) -> @owned FinalPubKlass { + +// CHECK-MAIN-RES-DAG: sil public_external @$s3Lib8PubKlassC4dataSivs : $@convention(method) (Int, @guaranteed PubKlass) -> () { +// CHECK-MAIN-NONRES-DAG: sil public_external [transparent] @$s3Lib8PubKlassC4dataSivs : $@convention(method) (Int, @guaranteed PubKlass) -> () { + +// CHECK-MAIN-RES-DAG: sil package_external @$s3Lib13FinalPkgKlassCyACSicfC : $@convention(method) (Int, @thick FinalPkgKlass.Type) -> @owned FinalPkgKlass { + +// CHECK-MAIN-RES-DAG: sil package_external @$s3Lib8PkgKlassC4dataSivs : $@convention(method) (Int, @guaranteed PkgKlass) -> () { + +// CHECK-MAIN-COMMON: sil_vtable PubKlass { +// CHECK-MAIN-RES: sil_vtable PkgKlass { +// CHECK-MAIN-COMMON: sil_vtable FinalPubKlass { +// CHECK-MAIN-RES: sil_vtable FinalPkgKlass { + +var pub = PubStruct(1) +let prevPub = pub.fooVar +pub.fooVar = 3 +let a = runPub(pub) + +var frpub = FrPubStruct(1) +let prevFrPub = frpub.fooVar +frpub.fooVar = 3 +let b = runFrPub(frpub) + +var pkg = PkgStruct(1) +let prevPkg = pkg.fooVar +pkg.fooVar = 3 +let c = runPkg(pkg) + +var pubKlass = PubKlass(5) +let prevPubData = pubKlass.data +pubKlass.data = 7 +let x = runPubKlass(pubKlass) + +var pkgKlass = PkgKlass(7) +let prevPkgData = pkgKlass.data +pkgKlass.data = 7 +let y = runPkgKlass(pkgKlass) + +var fnlPubKlass = FinalPubKlass(9) +let prevPubDataFnl = fnlPubKlass.data +fnlPubKlass.data = 11 + +var fnlPkgKlass = FinalPkgKlass(9) +let prevPkgDataFnl = fnlPkgKlass.data +fnlPkgKlass.data = 11 + +print(a, b, c, x, y, + prevPub, prevFrPub, prevPkg, prevPubData, + prevPkgData, prevPubDataFnl, prevPkgDataFnl) + +public func mainPub() { + print(PubStruct(1)) +} + +//--- Lib.swift + +// static PubStruct.pubStaticSimpleFuncPtr +// CHECK-NONRES-DAG: sil_global [serialized] @$s3Lib9PubStructV22pubStaticSimpleFuncPtryS2icvpZ : $@callee_guaranteed (Int) -> Int = { + // function_ref runPubSimple(_:) +// CHECK-NONRES-DAG: [[PUB_FPTR:%.*]] = function_ref @$s3Lib12runPubSimpleyS2iF : $@convention(thin) (Int) -> Int +// CHECK-NONRES-DAG: thin_to_thick_function [[PUB_FPTR]] : $@convention(thin) (Int) -> Int to $@callee_guaranteed (Int) -> Int + +// static PubStruct.pubStaticFuncPtr +// CHECK-NONRES-DAG-DAG: sil_global [serialized] @$s3Lib9PubStructV16pubStaticFuncPtrySiACcvpZ : $@callee_guaranteed (PubStruct) -> Int = { + // function_ref runPub(_:) +// CHECK-NONRES-DAG: [[PTR:%.*]] = function_ref @$s3Lib6runPubySiAA0C6StructVF : $@convention(thin) (PubStruct) -> Int +// CHECK-NONRES-DAG: thin_to_thick_function [[PTR]] : $@convention(thin) (PubStruct) -> Int to $@callee_guaranteed (PubStruct) -> Int + +// static PubStruct.pubStaticSimpleClosurePtr +// CHECK-NONRES-DAG: sil_global @$s3Lib9PubStructV25pubStaticSimpleClosurePtryS2icvpZ : $@callee_guaranteed (Int) -> Int + +// static PubStruct.pubStaticClosurePtr +// CHECK-NONRES-DAG: sil_global @$s3Lib9PubStructV19pubStaticClosurePtrySiACcvpZ : $@callee_guaranteed (PubStruct) -> Int + +// static FrPubStruct.pubStaticSimpleFuncPtr +// CHECK-NONRES-DAG: sil_global [serialized] @$s3Lib11FrPubStructV22pubStaticSimpleFuncPtryS2icvpZ : $@callee_guaranteed (Int) -> Int = { + +// static FrPubStruct.pubStaticFuncPtr +// CHECK-NONRES-DAG: sil_global [serialized] @$s3Lib11FrPubStructV16pubStaticFuncPtrySiAA0cD0VcvpZ : $@callee_guaranteed (PubStruct) -> Int = { + +// static FrPubStruct.pubStaticSimpleClosurePtr +// CHECK-NONRES-DAG: sil_global @$s3Lib11FrPubStructV25pubStaticSimpleClosurePtryS2icvpZ : $@callee_guaranteed (Int) -> Int + +// static FrPubStruct.pubStaticClosurePtr +// CHECK-NONRES-DAG: sil_global @$s3Lib11FrPubStructV19pubStaticClosurePtrySiAA0cD0VcvpZ : $@callee_guaranteed (PubStruct) -> Int + +public struct PubStruct { + // PubStruct.foovar.getter + // CHECK-RES-DAG: sil [serialized_for_package] [canonical] @$s3Lib9PubStructV6fooVarSivg : $@convention(method) (@in_guaranteed PubStruct) -> Int { + // CHECK-NONRES-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib9PubStructV6fooVarSivg : $@convention(method) (PubStruct) -> Int + // CHECK-RES-DAG: [[PUB_GET:%.*]] = struct_element_addr {{.*}} : $*PubStruct, #PubStruct.fooVar + // CHECK-RES-DAG: load [[PUB_GET]] : $*Int + // CHECK-NONRES-DAG = struct_extract {{.*}} : $PubStruct, #PubStruct.fooVar + + // PubStruct.foovar.setter + // CHECK-RES-DAG: sil [serialized_for_package] [canonical] @$s3Lib9PubStructV6fooVarSivs : $@convention(method) (Int, @inout PubStruct) -> () { + // CHECK-NONRES-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib9PubStructV6fooVarSivs : $@convention(method) (Int, @inout PubStruct) -> () { + + /// NOTE: loadable types (e.g. load/store `struct $PubStruct`) can be only allowed + /// in a serialized function with `[serialized_for_package]` (if Package CMO is + /// enabled in a resiliently built module), otherwise illegal. + // CHECK-COMMON-DAG: [[PUB_SET:%.*]] = struct $PubStruct + // CHECK-RES-DAG: store [[PUB_SET]] to {{.*}} : $*PubStruct + // CHECK-NONRES-DAG: store [[PUB_SET]] to [trivial] {{.*}} : $*PubStruct + + // PubStruct.foovar.modify + // CHECK-RES-DAG: sil [serialized_for_package] [canonical] @$s3Lib9PubStructV6fooVarSivM : $@yield_once @convention(method) (@inout PubStruct) -> @yields @inout Int { + // CHECK-NONRES-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib9PubStructV6fooVarSivM : $@yield_once @convention(method) (@inout PubStruct) -> @yields @inout Int { + // CHECK-COMMON-DAG: [[PUB_MODIFY:%.*]] = struct_element_addr {{.*}} : $*PubStruct, #PubStruct.fooVar + // CHECK-COMMON-DAG: yield [[PUB_MODIFY]] + public var fooVar: Int + + public static var pubStaticVar: String { "StaticPubVar" } + + // static PubStruct.pubStaticSimpleFuncPtr.modify + // CHECK-NONRES-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib9PubStructV22pubStaticSimpleFuncPtryS2icvMZ : $@yield_once @convention(method) (@thin PubStruct.Type) -> @yields @inout @callee_guaranteed (Int) -> Int { + public static var pubStaticSimpleFuncPtr: (Int) -> (Int) = runPubSimple + + // static PubStruct.pubStaticFuncPtr.getter + // CHECK-NONRES-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib9PubStructV16pubStaticFuncPtrySiACcvgZ : $@convention(method) (@thin PubStruct.Type) -> @owned @callee_guaranteed (PubStruct) -> Int { + // function_ref PubStruct.pubStaticFuncPtr.unsafeMutableAddressor + // CHECK-NONRES-DAG: function_ref @$s3Lib9PubStructV16pubStaticFuncPtrySiACcvau : $@convention(thin) () -> Builtin.RawPointer + + // PubStruct.pubStaticFuncPtr.unsafeMutableAddressor + // CHECK-NONRES-DAG: sil [serialized] [global_init] [canonical] @$s3Lib9PubStructV16pubStaticFuncPtrySiACcvau : $@convention(thin) () -> Builtin.RawPointer { + // CHECK-NONRES-DAG: [[PUB_FADDR:%.*]] = global_addr @$s3Lib9PubStructV16pubStaticFuncPtrySiACcvpZ : $*@callee_guaranteed (PubStruct) -> Int + // CHECK-NONRES-DAG: address_to_pointer [[PUB_FADDR]] : $*@callee_guaranteed (PubStruct) -> Int to $Builtin.RawPointer + + public static var pubStaticFuncPtr: (PubStruct) -> (Int) = runPub + + // static PubStruct.pubStaticSimpleClosurePtr.setter + // CHECK-NONRES-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib9PubStructV25pubStaticSimpleClosurePtryS2icvsZ : $@convention(method) (@owned @callee_guaranteed (Int) -> Int, @thin PubStruct.Type) -> () { + // CHECK-NONRES-DAG: function_ref @$s3Lib9PubStructV25pubStaticSimpleClosurePtryS2icvau : $@convention(thin) () -> Builtin.RawPointer + + // PubStruct.pubStaticSimpleClosurePtr.unsafeMutableAddressor + // CHECK-NONRES-DAG: sil [serialized] [global_init] [canonical] @$s3Lib9PubStructV25pubStaticSimpleClosurePtryS2icvau : $@convention(thin) () -> Builtin.RawPointer { + // CHECK-NONRES-DAG: global_addr @$s3Lib9PubStructV25pubStaticSimpleClosurePtryS2icvpZ : $*@callee_guaranteed (Int) -> Int + public static var pubStaticSimpleClosurePtr: (Int) -> (Int) = { return $0 } + + // static PubStruct.pubStaticClosurePtr.getter + // CHECK-NONRES-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib9PubStructV19pubStaticClosurePtrySiACcvgZ : $@convention(method) (@thin PubStruct.Type) -> @owned @callee_guaranteed (PubStruct) -> Int { + // function_ref PubStruct.pubStaticClosurePtr.unsafeMutableAddressor + // CHECK-NONRES-DAG: function_ref @$s3Lib9PubStructV19pubStaticClosurePtrySiACcvau : $@convention(thin) + + // PubStruct.pubStaticClosurePtr.unsafeMutableAddressor + // CHECK-NONRES-DAG: sil [serialized] [global_init] [canonical] @$s3Lib9PubStructV19pubStaticClosurePtrySiACcvau : $@convention(thin) () -> Builtin.RawPointer { + // CHECK-NONRES-DAG: [[PUB_CADDR:%.*]] = global_addr @$s3Lib9PubStructV19pubStaticClosurePtrySiACcvpZ : $*@callee_guaranteed (PubStruct) -> Int + // CHECK-NONRES-DAG: address_to_pointer [[PUB_CADDR]] : $*@callee_guaranteed (PubStruct) -> Int to $Builtin.RawPointer + public static var pubStaticClosurePtr: (PubStruct) -> (Int) = { return $0.fooVar } + + // static PubStruct.pubStaticFunc() + // CHECK-RES-DAG: sil [serialized_for_package] [canonical] @$s3Lib9PubStructV13pubStaticFuncAA0B5KlassCyFZ : $@convention(method) (@thin PubStruct.Type) -> @owned PubKlass { + // CHECK-NONRES-DAG: sil [serialized] [canonical] @$s3Lib9PubStructV13pubStaticFuncAA0B5KlassCyFZ : $@convention(method) (@thin PubStruct.Type) -> @owned PubKlass { + public static func pubStaticFunc() -> PubKlass { return PubKlass() } + + public init(_ arg: Int) { + // CHECK-RES-DAG: sil [serialized_for_package] [canonical] @$s3Lib9PubStructVyACSicfC : $@convention(method) (Int, @thin PubStruct.Type) -> @out PubStruct { + // CHECK-NONRES-DAG: sil [serialized] [canonical] @$s3Lib9PubStructVyACSicfC : $@convention(method) (Int, @thin PubStruct.Type) -> PubStruct { + // CHECK-COMMON-DAG: [[PUB_INIT:%.*]] = struct $PubStruct + // CHECK-RES-DAG: store [[PUB_INIT]] to {{.*}} : $*PubStruct + // CHECK-NONRES-DAG: return [[PUB_INIT]] : $PubStruct + fooVar = arg + } + public func f() -> Int { + // CHECK-RES-DAG: sil [serialized_for_package] [canonical] @$s3Lib9PubStructV1fSiyF : $@convention(method) (@in_guaranteed PubStruct) -> Int { + // CHECK-NONRES-DAG: sil [serialized] [canonical] @$s3Lib9PubStructV1fSiyF : $@convention(method) (PubStruct) -> Int { + return fooVar > 7 ? fooVar : fooVar + 11 + } +} + +public func runPubSimple(_ arg: Int) -> Int { + return arg + 3 +} + +public func runPub(_ arg: PubStruct) -> Int { + // CHECK-RES-DAG: sil [serialized_for_package] [canonical] @$s3Lib6runPubySiAA0C6StructVF : $@convention(thin) (@in_guaranteed PubStruct) -> Int { + // CHECK-NONRES-DAG: sil [serialized] [canonical] @$s3Lib6runPubySiAA0C6StructVF : $@convention(thin) (PubStruct) -> Int { + return arg.f() > arg.fooVar ? arg.f() : arg.fooVar +} + +@frozen +public struct FrPubStruct { + // FrPubStruct.fooVar.getter + // CHECK-RES-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib11FrPubStructV6fooVarSivg : $@convention(method) (FrPubStruct) -> Int { + // CHECK-NONRES-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib11FrPubStructV6fooVarSivg : $@convention(method) (FrPubStruct) -> Int { + // CHECK-COMMON-DAG: [[FR_GET:%.*]] = struct_extract {{.*}} : $FrPubStruct, #FrPubStruct.fooVar + // CHECK-COMMON-DAG: return [[FR_GET]] : $Int + + // FrPubStruct.fooVar.setter + // CHECK-RES-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib11FrPubStructV6fooVarSivs : $@convention(method) (Int, @inout FrPubStruct) -> () { + // CHECK-NONRES-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib11FrPubStructV6fooVarSivs : $@convention(method) (Int, @inout FrPubStruct) -> () { + // CHECK-COMMON-DAG: [[FR_SET:%.*]] = struct $FrPubStruct + // CHECK-COMMON-DAG: store [[FR_SET]] to [trivial] {{.*}} : $*FrPubStruct + + // FrPubStruct.fooVar.modify + // CHECK-RES-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib11FrPubStructV6fooVarSivM : $@yield_once @convention(method) (@inout FrPubStruct) -> @yields @inout Int { + // CHECK-NONRES-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib11FrPubStructV6fooVarSivM : $@yield_once @convention(method) (@inout FrPubStruct) -> @yields @inout Int { + // CHECK-COMMON-DAG: [[FIELD:%.*]] = struct_element_addr {{.*}} : $*FrPubStruct, #FrPubStruct.fooVar + // CHECK-COMMON-DAG: yield [[FIELD]] + public var fooVar: Int + + public static var pubStaticVar: String { "FrStaticPubVar" } + public static var pubStaticSimpleFuncPtr: (Int) -> (Int) = runPubSimple + public static var pubStaticFuncPtr: (PubStruct) -> (Int) = runPub + // static FrPubStruct.pubStaticSimpleClosurePtr.setter + // CHECK-NONRES-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib11FrPubStructV25pubStaticSimpleClosurePtryS2icvsZ : $@convention(method) (@owned @callee_guaranteed (Int) -> Int, @thin FrPubStruct.Type) -> () { + public static var pubStaticSimpleClosurePtr: (Int) -> (Int) = { return $0 } + + // static FrPubStruct.pubStaticClosurePtr.setter + // CHECK-NONRES-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib11FrPubStructV19pubStaticClosurePtrySiAA0cD0VcvsZ : $@convention(method) (@owned @callee_guaranteed (PubStruct) -> Int, @thin FrPubStruct.Type) -> () { + public static var pubStaticClosurePtr: (PubStruct) -> (Int) = { return $0.fooVar } + + public init(_ arg: Int) { + // CHECK-RES-DAG: sil [serialized_for_package] [canonical] @$s3Lib11FrPubStructVyACSicfC : $@convention(method) (Int, @thin FrPubStruct.Type) -> FrPubStruct { + // CHECK-NONRES-DAG: sil [serialized] [canonical] @$s3Lib11FrPubStructVyACSicfC : $@convention(method) (Int, @thin FrPubStruct.Type) -> FrPubStruct { + // CHECK-COMMON-DAG: [[FR_MODIFY:%.*]] = struct $FrPubStruct + // CHECK-COMMON-DAG: return [[FR_MODIFY]] : $FrPubStruct + fooVar = arg + } + public func f() -> Int { + // CHECK-RES-DAG: sil [serialized_for_package] [canonical] @$s3Lib11FrPubStructV1fSiyF : $@convention(method) (FrPubStruct) -> Int { + // CHECK-NONRES-DAG: sil [serialized] [canonical] @$s3Lib11FrPubStructV1fSiyF : $@convention(method) (FrPubStruct) -> Int { + return fooVar > 13 ? fooVar : fooVar + 17 + } +} + +public func runFrPub(_ arg: FrPubStruct) -> Int { + // CHECK-RES-DAG: sil [serialized_for_package] [canonical] @$s3Lib8runFrPubySiAA0cD6StructVF : $@convention(thin) (FrPubStruct) -> Int { + // CHECK-NONRES-DAG: sil [serialized] [canonical] @$s3Lib8runFrPubySiAA0cD6StructVF : $@convention(thin) (FrPubStruct) -> Int { + return arg.f() > arg.fooVar ? arg.f() : arg.fooVar +} + +package struct PkgStruct { + // PkgStruct.fooVar.getter + // CHECK-RES-DAG: sil package [serialized_for_package] [canonical] @$s3Lib9PkgStructV6fooVarSivg : $@convention(method) (@in_guaranteed PkgStruct) -> Int { + // CHECK-RES-DAG: [[PKG_GET:%.*]] = struct_element_addr {{.*}} : $*PkgStruct, #PkgStruct.fooVar + // CHECK-RES-DAG: load [[PKG_GET]] : $*Int + + // PkgStruct.fooVar.setter + // CHECK-RES-DAG: sil package [serialized_for_package] [canonical] @$s3Lib9PkgStructV6fooVarSivs : $@convention(method) (Int, @inout PkgStruct) -> () { + // CHECK-RES-DAG: [[PKG_SET:%.*]] = struct $PkgStruct + // CHECK-RES-DAG: store [[PKG_SET]] to {{.*}} : $*PkgStruct + + // PkgStruct.fooVar.modify + // CHECK-RES-DAG: sil package [serialized_for_package] [canonical] @$s3Lib9PkgStructV6fooVarSivM : $@yield_once @convention(method) (@inout PkgStruct) -> @yields @inout Int { + package var fooVar: Int + + package static var pkgStaticVar: String { "StaticPkgVar" } + package static var pkgStaticSimpleFuncPtr: (Int) -> (Int) = runPubSimple + package static var pkgStaticFuncPtr: (PkgStruct) -> (Int) = runPkg + package static var pkgStaticSimpleClosurePtr: (Int) -> (Int) = { return $0 } + package static var pkgStaticClosurePtr: (PkgStruct) -> (Int) = { return $0.fooVar } + + package init(_ arg: Int) { + // CHECK-RES-DAG: sil package [serialized_for_package] [canonical] @$s3Lib9PkgStructVyACSicfC : $@convention(method) (Int, @thin PkgStruct.Type) -> @out PkgStruct { + // CHECK-RES-DAG: [[PKG_INIT:%.*]] = struct $PkgStruct + // CHECK-RES-DAG: store [[PKG_INIT]] to {{.*}} : $*PkgStruct + fooVar = arg + } + package func f() -> Int { + // CHECK-RES-DAG: sil package [serialized_for_package] [canonical] @$s3Lib9PkgStructV1fSiyF : $@convention(method) (@in_guaranteed PkgStruct) -> Int { + return fooVar > 19 ? fooVar : fooVar + 23 + } +} + +package func runPkg(_ arg: PkgStruct) -> Int { + // CHECK-RES-DAG: sil package [serialized_for_package] [canonical] @$s3Lib6runPkgySiAA0C6StructVF : $@convention(thin) (@in_guaranteed PkgStruct) -> Int { + return arg.f() > arg.fooVar ? arg.f() : arg.fooVar +} + +public protocol PubProto { + var data: Int { get set } + func pubfunc(_ arg: Int) -> Int +} + +public class PubKlass: PubProto { + // FIXME: rdar://130103572 witness thunks should get [serialized_for_package] in package-cmo. + // CHECK-RES-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib8PubKlassCAA0B5ProtoA2aDP4dataSivgTW : $@convention(witness_method: PubProto) (@in_guaranteed PubKlass) -> Int { + // CHECK-RES-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib8PubKlassCAA0B5ProtoA2aDP4dataSivMTW : $@yield_once @convention(witness_method: PubProto) @substituted <τ_0_0> (@inout τ_0_0) -> @yields @inout Int for { + // CHECK-RES-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib8PubKlassCAA0B5ProtoA2aDP4dataSivsTW : $@convention(witness_method: PubProto) (Int, @inout PubKlass) -> () { + // CHECK-NONRES-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib8PubKlassCAA0B5ProtoA2aDP4dataSivgTW : $@convention(witness_method: PubProto) (@in_guaranteed PubKlass) -> Int { + // CHECK-NONRES-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib8PubKlassCAA0B5ProtoA2aDP4dataSivMTW : $@yield_once @convention(witness_method: PubProto) @substituted <τ_0_0> (@inout τ_0_0) -> @yields @inout Int for { + // CHECK-NONRES-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib8PubKlassCAA0B5ProtoA2aDP4dataSivsTW : $@convention(witness_method: PubProto) (Int, @inout PubKlass) -> () { + // CHECK-RES-DAG: sil [serialized_for_package] [canonical] @$s3Lib8PubKlassC4dataSivg : $@convention(method) (@guaranteed PubKlass) -> Int + // CHECK-NONRES-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib8PubKlassC4dataSivg : $@convention(method) (@guaranteed PubKlass) -> Int { + // CHECK-RES-DAG: sil [serialized_for_package] [canonical] @$s3Lib8PubKlassC4dataSivs : $@convention(method) (Int, @guaranteed PubKlass) -> () { + // CHECK-NONRES-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib8PubKlassC4dataSivs : $@convention(method) (Int, @guaranteed PubKlass) -> () { + public var data: Int + public init(_ arg: Int = 1) { + // default argument 0 of PubKlass.init(_:) + // CHECK-RES-DAG: sil non_abi [serialized] [canonical] @$s3Lib8PubKlassCyACSicfcfA_ : $@convention(thin) () -> Int { + // CHECK-NONRES-DAG: sil non_abi [serialized] [canonical] @$s3Lib8PubKlassCyACSicfcfA_ : $@convention(thin) () -> Int { + + // CHECK-RES-DAG: sil [serialized_for_package] [canonical] @$s3Lib8PubKlassCyACSicfc : $@convention(method) (Int, @owned PubKlass) -> @owned PubKlass { + // CHECK-NONRES-DAG: sil [serialized] [canonical] @$s3Lib8PubKlassCyACSicfc : $@convention(method) (Int, @owned PubKlass) -> @owned PubKlass { + // CHECK-RES-DAG: sil [serialized] [exact_self_class] [canonical] @$s3Lib8PubKlassCyACSicfC : $@convention(method) (Int, @thick PubKlass.Type) -> @owned PubKlass { + // CHECK-NONRES-DAG: sil [serialized] [exact_self_class] [canonical] @$s3Lib8PubKlassCyACSicfC : $@convention(method) (Int, @thick PubKlass.Type) -> @owned PubKlass { + // CHECK-RES-DAG: sil [serialized_for_package] [canonical] @$s3Lib8PubKlassCfD : $@convention(method) (@owned PubKlass) -> () { + // CHECK-NONRES-DAG: sil [serialized] [canonical] @$s3Lib8PubKlassCfD : $@convention(method) (@owned PubKlass) -> () { + // CHECK-RES-DAG: sil [serialized_for_package] [canonical] @$s3Lib8PubKlassCfd : $@convention(method) (@guaranteed PubKlass) -> @owned Builtin.NativeObject { + // CHECK-NONRES-DAG: sil [serialized] [canonical] @$s3Lib8PubKlassCfd : $@convention(method) (@guaranteed PubKlass) -> @owned Builtin.NativeObject { + self.data = arg + } + public func pubfunc(_ arg: Int) -> Int { + // CHECK-RES-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib8PubKlassCAA0B5ProtoA2aDP7pubfuncyS2iFTW : $@convention(witness_method: PubProto) (Int, @in_guaranteed PubKlass) -> Int { + // CHECK-RES-DAG: sil [serialized_for_package] [canonical] @$s3Lib8PubKlassC7pubfuncyS2iF : $@convention(method) (Int, @guaranteed PubKlass) -> Int { + // CHECK-NONRES-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib8PubKlassCAA0B5ProtoA2aDP7pubfuncyS2iFTW : $@convention(witness_method: PubProto) (Int, @in_guaranteed PubKlass) -> Int { + // CHECK-NONRES-DAG: sil [serialized] [canonical] @$s3Lib8PubKlassC7pubfuncyS2iF : $@convention(method) (Int, @guaranteed PubKlass) -> Int { + return data + arg + } +} + +public func runPubKlass(_ arg: PubKlass) -> Int { + // CHECK-RES-DAG: sil [serialized_for_package] [canonical] @$s3Lib11runPubKlassySiAA0cD0CF : $@convention(thin) (@guaranteed PubKlass) -> Int + // CHECK-NONRES-DAG: sil [serialized] [canonical] @$s3Lib11runPubKlassySiAA0cD0CF : $@convention(thin) (@guaranteed PubKlass) -> Int { + arg.data += 29 + return arg.pubfunc(31) +} + +final public class FinalPubKlass { + // variable initialization expression of FinalPubKlass.data + // CHECK-RES-DAG: sil [transparent] [serialized_for_package] [canonical] [ossa] @$s3Lib13FinalPubKlassC4dataSivpfi : $@convention(thin) () -> Int { + public var data = 1 + // FinalPubKlass.__allocating_init(_:) + // CHECK-RES-DAG: sil [serialized] [exact_self_class] [canonical] @$s3Lib13FinalPubKlassCyACSicfC : $@convention(method) (Int, @thick FinalPubKlass.Type) -> @owned FinalPubKlass { + // FinalPubKlass.init(_:) + // CHECK-RES-DAG: sil [serialized_for_package] [canonical] @$s3Lib13FinalPubKlassCyACSicfc : $@convention(method) (Int, @owned FinalPubKlass) -> @owned FinalPubKlass { + // FinalPubKlass.__deallocating_deinit + // CHECK-RES-DAG: sil [serialized_for_package] [canonical] @$s3Lib13FinalPubKlassCfD : $@convention(method) (@owned FinalPubKlass) -> () { + // FinalPubKlass.deinit + // CHECK-RES-DAG: sil [serialized_for_package] [canonical] @$s3Lib13FinalPubKlassCfd : $@convention(method) (@guaranteed FinalPubKlass) -> @owned Builtin.NativeObject { + public init(_ arg: Int) { + data = arg + } + public func fnlPubFunc(_ arg: Int) -> Int { + data + arg + } +} + +package protocol PkgProto { + var data: Int { get set } + func pkgfunc(_ arg: Int) -> Int +} + +package class PkgKlass: PkgProto { + // CHECK-RES-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib8PkgKlassCAA0B5ProtoA2aDP4dataSivgTW : $@convention(witness_method: PkgProto) (@in_guaranteed PkgKlass) -> Int { + // CHECK-RES-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib8PkgKlassCAA0B5ProtoA2aDP4dataSivsTW : $@convention(witness_method: PkgProto) (Int, @inout PkgKlass) -> () { + // CHECK-RES-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib8PkgKlassCAA0B5ProtoA2aDP4dataSivMTW : $@yield_once @convention(witness_method: PkgProto) @substituted <τ_0_0> (@inout τ_0_0) -> @yields @inout Int for { + // CHECK-RES-DAG: sil package [serialized_for_package] [canonical] @$s3Lib8PkgKlassC4dataSivM : $@yield_once @convention(method) (@guaranteed PkgKlass) -> @yields @inout Int { + // CHECK-RES-DAG: sil package [serialized_for_package] [canonical] @$s3Lib8PkgKlassC4dataSivg : $@convention(method) (@guaranteed PkgKlass) -> Int { + // CHECK-RES-DAG: sil package [serialized_for_package] [canonical] @$s3Lib8PkgKlassC4dataSivs : $@convention(method) (Int, @guaranteed PkgKlass) -> () { + package var data: Int + + package init(_ arg: Int = 1) { + // default argument 0 of PkgKlass.init(_:) + // FIXME: package -> package_non_abi here? Also should this be [serialized] instead? + // CHECK-RES-DAG: sil package [serialized_for_package] [canonical] @$s3Lib8PkgKlassCyACSicfcfA_ : $@convention(thin) () -> Int { + + // CHECK-RES-DAG: sil package [serialized_for_package] [canonical] @$s3Lib8PkgKlassCyACSicfc : $@convention(method) (Int, @owned PkgKlass) -> @owned PkgKlass { + // CHECK-RES-DAG: sil package [serialized_for_package] [exact_self_class] [canonical] @$s3Lib8PkgKlassCyACSicfC : $@convention(method) (Int, @thick PkgKlass.Type) -> @owned PkgKlass { + // CHECK-RES-DAG: sil package [serialized_for_package] [canonical] @$s3Lib8PkgKlassCfd : $@convention(method) (@guaranteed PkgKlass) -> @owned Builtin.NativeObject { + // CHECK-RES-DAG: sil package [serialized_for_package] [canonical] @$s3Lib8PkgKlassCfD : $@convention(method) (@owned PkgKlass) -> () + self.data = arg + } + + package func pkgfunc(_ arg: Int) -> Int { + // CHECK-RES-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib8PkgKlassCAA0B5ProtoA2aDP7pkgfuncyS2iFTW : $@convention(witness_method: PkgProto) (Int, @in_guaranteed PkgKlass) -> Int { + // CHECK-RES-DAG: sil package [serialized_for_package] [canonical] @$s3Lib8PkgKlassC7pkgfuncyS2iF : $@convention(method) (Int, @guaranteed PkgKlass) -> Int { + return data + arg + } +} + +package func runPkgKlass(_ arg: PkgKlass) -> Int { + // CHECK-RES-DAG: sil package [serialized_for_package] [canonical] @$s3Lib11runPkgKlassySiAA0cD0CF : $@convention(thin) (@guaranteed PkgKlass) -> Int + arg.data += 37 + return arg.pkgfunc(41) +} + + +final package class FinalPkgKlass { + // variable initialization expression of FinalPkgKlass.data + // CHECK-RES-DAG: sil package [transparent] [serialized_for_package] [canonical] [ossa] @$s3Lib13FinalPkgKlassC4dataSivpfi : $@convention(thin) () -> Int { + package var data = 1 + package init(_ arg: Int) { + // FinalPkgKlass.__allocating_init(_:) + // CHECK-RES-DAG: sil package [serialized_for_package] [exact_self_class] [canonical] @$s3Lib13FinalPkgKlassCyACSicfC : $@convention(method) (Int, @thick FinalPkgKlass.Type) -> @owned FinalPkgKlass { + // FinalPkgKlass.init(_:) + // CHECK-RES-DAG: sil package [serialized_for_package] [canonical] @$s3Lib13FinalPkgKlassCyACSicfc : $@convention(method) (Int, @owned FinalPkgKlass) -> @owned FinalPkgKlass { + // FinalPkgKlass.__deallocating_deinit + // CHECK-RES-DAG: sil package [serialized_for_package] [canonical] @$s3Lib13FinalPkgKlassCfD : $@convention(method) (@owned FinalPkgKlass) -> () { + // FinalPkgKlass.deinit + // CHECK-RES-DAG: sil package [serialized_for_package] [canonical] @$s3Lib13FinalPkgKlassCfd : $@convention(method) (@guaranteed FinalPkgKlass) -> @owned Builtin.NativeObject { + data = arg + } + package func fnlPkgFunc(_ arg: Int) -> Int { + data + arg + } +} + +// CHECK-RES-LABEL: sil_vtable [serialized_for_package] PubKlass { +// CHECK-NONRES-LABEL: sil_vtable [serialized] PubKlass { +// CHECK-COMMON-NEXT: #PubKlass.data!getter: (PubKlass) -> () -> Int : @$s3Lib8PubKlassC4dataSivg +// CHECK-COMMON-NEXT: #PubKlass.data!setter: (PubKlass) -> (Int) -> () : @$s3Lib8PubKlassC4dataSivs +// CHECK-COMMON-NEXT: #PubKlass.data!modify: (PubKlass) -> () -> () : @$s3Lib8PubKlassC4dataSivM +// CHECK-COMMON-NEXT: #PubKlass.init!allocator: (PubKlass.Type) -> (Int) -> PubKlass : @$s3Lib8PubKlassCyACSicfC +// CHECK-COMMON-NEXT: #PubKlass.pubfunc: (PubKlass) -> (Int) -> Int : @$s3Lib8PubKlassC7pubfuncyS2iF +// CHECK-COMMON-NEXT: #PubKlass.deinit!deallocator: @$s3Lib8PubKlassCfD + +// CHECK-RES-LABEL: sil_vtable [serialized_for_package] FinalPubKlass { +// CHECK-NONRES-LABEL: sil_vtable [serialized] FinalPubKlass { +// CHECK-COMMON-NEXT: #FinalPubKlass.init!allocator: (FinalPubKlass.Type) -> (Int) -> FinalPubKlass : @$s3Lib13FinalPubKlassCyACSicfC +// CHECK-COMMON-NEXT: #FinalPubKlass.deinit!deallocator: @$s3Lib13FinalPubKlassCfD + +// CHECK-RES-LABEL: sil_vtable [serialized_for_package] PkgKlass { +// CHECK-RES-NEXT: #PkgKlass.data!getter: (PkgKlass) -> () -> Int : @$s3Lib8PkgKlassC4dataSivg +// CHECK-RES-NEXT: #PkgKlass.data!setter: (PkgKlass) -> (Int) -> () : @$s3Lib8PkgKlassC4dataSivs +// CHECK-RES-NEXT: #PkgKlass.data!modify: (PkgKlass) -> () -> () : @$s3Lib8PkgKlassC4dataSivM +// CHECK-RES-NEXT: #PkgKlass.init!allocator: (PkgKlass.Type) -> (Int) -> PkgKlass : @$s3Lib8PkgKlassCyACSicfC +// CHECK-RES-NEXT: #PkgKlass.pkgfunc: (PkgKlass) -> (Int) -> Int : @$s3Lib8PkgKlassC7pkgfuncyS2iF +// CHECK-RES-NEXT: #PkgKlass.deinit!deallocator: @$s3Lib8PkgKlassCfD + +// CHECK-RES-LABEL: sil_vtable [serialized_for_package] FinalPkgKlass { +// CHECK-RES-NEXT: #FinalPkgKlass.init!allocator: (FinalPkgKlass.Type) -> (Int) -> FinalPkgKlass : @$s3Lib13FinalPkgKlassCyACSicfC +// CHECK-RES-NEXT: #FinalPkgKlass.deinit!deallocator: @$s3Lib13FinalPkgKlassCfD + +// CHECK-RES-LABEL: sil_witness_table [serialized_for_package] PubKlass: PubProto module Lib { +// CHECK-NONRES-LABEL: sil_witness_table [serialized] PubKlass: PubProto module Lib { +// CHECK-COMMON-NEXT: method #PubProto.data!getter: (Self) -> () -> Int : @$s3Lib8PubKlassCAA0B5ProtoA2aDP4dataSivgTW +// CHECK-COMMON-NEXT: method #PubProto.data!setter: (inout Self) -> (Int) -> () : @$s3Lib8PubKlassCAA0B5ProtoA2aDP4dataSivsTW +// CHECK-COMMON-NEXT: method #PubProto.data!modify: (inout Self) -> () -> () : @$s3Lib8PubKlassCAA0B5ProtoA2aDP4dataSivMTW +// CHECK-COMMON-NEXT: method #PubProto.pubfunc: (Self) -> (Int) -> Int : @$s3Lib8PubKlassCAA0B5ProtoA2aDP7pubfuncyS2iFTW + +// CHECK-RES-LABEL: sil_witness_table package [serialized_for_package] PkgKlass: PkgProto module Lib { +// CHECK-RES-NEXT: method #PkgProto.data!getter: (Self) -> () -> Int : @$s3Lib8PkgKlassCAA0B5ProtoA2aDP4dataSivgTW +// CHECK-RES-NEXT: method #PkgProto.data!setter: (inout Self) -> (Int) -> () : @$s3Lib8PkgKlassCAA0B5ProtoA2aDP4dataSivsTW +// CHECK-RES-NEXT: method #PkgProto.data!modify: (inout Self) -> () -> () : @$s3Lib8PkgKlassCAA0B5ProtoA2aDP4dataSivMTW +// CHECK-RES-NEXT: method #PkgProto.pkgfunc: (Self) -> (Int) -> Int : @$s3Lib8PkgKlassCAA0B5ProtoA2aDP7pkgfuncyS2iFTW diff --git a/test/SILOptimizer/package-cmo-serialize-tables.swift b/test/SILOptimizer/package-cmo-serialize-tables.swift new file mode 100644 index 0000000000000..6b137d7ddfd80 --- /dev/null +++ b/test/SILOptimizer/package-cmo-serialize-tables.swift @@ -0,0 +1,577 @@ +/// This tests serializing v-table and witness-table with Package CMO in resilient mode. +/// +// RUN: %empty-directory(%t) +// RUN: split-file %s %t + +// RUN: %target-build-swift %t/Lib.swift \ +// RUN: -module-name=Lib -package-name Pkg \ +// RUN: -parse-as-library -emit-module -emit-module-path %t/Lib.swiftmodule -I%t \ +// RUN: -Xfrontend -experimental-package-cmo -Xfrontend -experimental-allow-non-resilient-access \ +// RUN: -enable-library-evolution -wmo + +// RUN: %target-sil-opt %t/Lib.swiftmodule -sil-verify-all -o %t/Lib.sil +// RUN: %FileCheck %s < %t/Lib.sil + +// RUN: %target-build-swift -module-name=Main -package-name Pkg -enable-library-evolution -I%t -emit-sil %t/main.swift -o %t/Main.sil +// RUN: %FileCheck %s --check-prefix=CHECK-MAIN < %t/Main.sil + +// REQUIRES: swift_in_compiler + + +//--- main.swift + +import Lib + +// CHECK-MAIN-NOT: witness_method +// CHECK-MAIN-NOT: class_method +runPub([PubStruct(rawValue: 2), PubKlassZ(rawValue: 3)]) +runPkg([PkgStruct(rawValue: 2), PkgKlassZ(rawValue: 3)]) + + +//--- Lib.swift + +public class ParentPubKlass { + public var parentPubVar: Int + public init(_ arg: Int) { + parentPubVar = arg + } + public func parentPubFunc() { + // CHECK-DAG: sil [serialized_for_package] [canonical] [ossa] @$s3Lib14ParentPubKlassC06parentC4FuncyyF + print(parentPubVar) + } +} + +public class PubKlass: ParentPubKlass { + public var pubVar: String = "publicVar" + public init(_ arg: String) { + super.init(1) + pubVar = arg + } + + public func pubFunc() { + // CHECK-DAG: sil [serialized_for_package] [canonical] [ossa] @$s3Lib8PubKlassC7pubFuncyyF + print(pubVar) + } + + override public func parentPubFunc() { + // CHECK-DAG: sil [serialized_for_package] [canonical] [ossa] @$s3Lib8PubKlassC06parentB4FuncyyF + print(pubVar) + } +} + +public class ParentPubKlassWithInternalMemberX { + public var parentPubVar: Int + var parentIntVar: Int + public init(_ arg: Int) { + // CHECK-DAG: sil [serialized] [exact_self_class] [canonical] [ossa] @$s3Lib33ParentPubKlassWithInternalMemberXCyACSicfC : $@convention(method) (Int, @thick ParentPubKlassWithInternalMemberX.Type) -> @owned ParentPubKlassWithInternalMemberX { + // CHECK-DAG: sil [canonical] @$s3Lib33ParentPubKlassWithInternalMemberXCyACSicfc : $@convention(method) (Int, @owned ParentPubKlassWithInternalMemberX) -> @owned ParentPubKlassWithInternalMemberX + parentPubVar = arg + parentIntVar = arg + } + public func parentPubFuncA() { + // CHECK-DAG: sil [serialized_for_package] [canonical] [ossa] @$s3Lib33ParentPubKlassWithInternalMemberXC06parentC5FuncAyyF + print(parentPubVar) + } + + public func parentPubFuncB() { + print(parentPubVar, parentIntVar) /// NOTE: parentPubFuncB() can't be serialized since it contains an internal var + } + + func parentIntFunc() { /// NOTE: internal, so not serialized + print(parentIntVar) + } +} + +public class PubKlassX: ParentPubKlassWithInternalMemberX { + public var pubVar: String = "publicVar" + + override public var parentPubVar: Int { + // CHECK-DAG: sil [serialized_for_package] [canonical] [ossa] @$s3Lib9PubKlassXC06parentB3VarSivg + didSet { print ("newValue") } + } + + public init() { + // CHECK-DAG: sil [serialized] [exact_self_class] [canonical] [ossa] @$s3Lib9PubKlassXCACycfC : $@convention(method) (@thick PubKlassX.Type) -> @owned PubKlassX { + // CHECK-DAG: sil [serialized_for_package] [canonical] [ossa] @$s3Lib9PubKlassXCACycfc : $@convention(method) (@owned PubKlassX) -> @owned PubKlassX { + super.init(1) + } + + override public func parentPubFuncA() { + print(pubVar, parentIntVar) /// NOTE: contains internal; not serialized + } + override public func parentPubFuncB() { + // CHECK-DAG: sil [serialized_for_package] [canonical] [ossa] @$s3Lib9PubKlassXC06parentB5FuncByyF + print(pubVar) + } + override func parentIntFunc() { /// NOTE: contains internal; not serialized + print(pubVar) + } + public func pubFunc() { + // CHECK-DAG: sil [serialized_for_package] [canonical] [ossa] @$s3Lib9PubKlassXC7pubFuncyyF + print(pubVar) + } +} + +public class ParentPubKlassWithInternalMemberY { + var parentIntVar: Int /// NOTE: internal; not serialized + public init(_ arg: Int) { /// NOTE: contains internal; not serialized + // CHECK-DAG: sil [serialized] [exact_self_class] [canonical] [ossa] @$s3Lib33ParentPubKlassWithInternalMemberYCyACSicfC : $@convention(method) (Int, @thick ParentPubKlassWithInternalMemberY.Type) -> @owned ParentPubKlassWithInternalMemberY { + // CHECK-DAG: sil [canonical] @$s3Lib33ParentPubKlassWithInternalMemberYCyACSicfc : $@convention(method) (Int, @owned ParentPubKlassWithInternalMemberY) -> @owned ParentPubKlassWithInternalMemberY + parentIntVar = arg + } + + func parentIntFunc() { /// NOTE: contains internal; not serialized + print(parentIntVar) + } +} + +public class PubKlassY: ParentPubKlassWithInternalMemberY { + public var pubVar: String = "publicVar" + public init() { super.init(1) } +} + +package class ParentPkgKlass { + package var parentPkgVar: Int + package init(_ arg: Int) { + // CHECK-DAG: sil package [serialized_for_package] [canonical] [ossa] @$s3Lib14ParentPkgKlassCyACSicfc : $@convention(method) (Int, @owned ParentPkgKlass) -> @owned ParentPkgKlass { + parentPkgVar = arg + } + package func parentPkgFunc() -> Int { + // CHECK-DAG: sil package [serialized_for_package] [canonical] [ossa] @$s3Lib14ParentPkgKlassC06parentC4FuncSiyF + parentPkgVar + } +} + +package class PkgKlass: ParentPkgKlass { + package var pkgVar: String = "pkgVar" + package init(_ arg: String) { + // CHECK-DAG: sil package [serialized_for_package] [canonical] [ossa] @$s3Lib8PkgKlassCyACSScfc + super.init(1) + pkgVar = arg + } + package func pkgFunc() { + // CHECK-DAG: sil package [serialized_for_package] [canonical] [ossa] @$s3Lib8PkgKlassC7pkgFuncyyF + print(pkgVar) + } + override package func parentPkgFunc() -> Int { + // CHECK-DAG: sil package [serialized_for_package] [canonical] [ossa] @$s3Lib8PkgKlassC06parentB4FuncSiyF + pkgVar.count + } +} + +package class ParentPkgKlassWithInternalMemberX { + package var parentPkgVar: Int + var parentIntVar: Int /// NOTE: internal so not serialized + + package init(_ arg: Int) { + // CHECK-DAG: sil package [serialized_for_package] [exact_self_class] [canonical] [ossa] @$s3Lib33ParentPkgKlassWithInternalMemberXCyACSicfC : $@convention(method) (Int, @thick ParentPkgKlassWithInternalMemberX.Type) -> @owned ParentPkgKlassWithInternalMemberX { + // CHECK-DAG: sil package_external [canonical] @$s3Lib33ParentPkgKlassWithInternalMemberXCyACSicfc : $@convention(method) (Int, @owned ParentPkgKlassWithInternalMemberX) -> @owned ParentPkgKlassWithInternalMemberX + parentPkgVar = arg + parentIntVar = arg + } + + package func parentPkgFuncA() { + // CHECK-DAG: sil package [serialized_for_package] [canonical] [ossa] @$s3Lib33ParentPkgKlassWithInternalMemberXC06parentC5FuncAyyF + print(parentPkgVar) + } + package func parentPkgFuncB() { /// NOTE: contains internal; not serialized + print(parentPkgVar, parentIntVar) + } + func parentIntFunc() { /// NOTE: internal so not serialized + print(parentIntVar) + } +} + +package class PkgKlassX: ParentPkgKlassWithInternalMemberX { + package var pkgVar: String = "pkgVar" + override package var parentPkgVar: Int { + // CHECK-DAG: sil package [serialized_for_package] [canonical] [ossa] @$s3Lib9PkgKlassXC06parentB3VarSivg + didSet { print ("newValue") } + } + package init() { + // CHECK-DAG: sil package [serialized_for_package] [exact_self_class] [canonical] [ossa] @$s3Lib9PkgKlassXCyACSicfC : $@convention(method) (Int, @thick PkgKlassX.Type) -> @owned PkgKlassX { + // CHECK-DAG: sil package [serialized_for_package] [canonical] [ossa] @$s3Lib9PkgKlassXCyACSicfc : $@convention(method) (Int, @owned PkgKlassX) -> @owned PkgKlassX { + super.init(1) + } + override package func parentPkgFuncA() { + print(pkgVar, parentIntVar) + } + override package func parentPkgFuncB() { + // CHECK-DAG: sil package [serialized_for_package] [canonical] [ossa] @$s3Lib9PkgKlassXC06parentB5FuncByyF + print(pkgVar) + } + override func parentIntFunc() { /// NOTE: contains internal; not serialized + print(pkgVar) + } + package func pubFunc() { + // CHECK-DAG: sil package [serialized_for_package] [canonical] [ossa] @$s3Lib9PkgKlassXC7pubFuncyyF + print(pkgVar) + } +} + +package class ParentPkgKlassWithInternalMemberY { + var parentIntVar: Int + package init(_ arg: Int) { + // CHECK-DAG: sil package [serialized_for_package] [exact_self_class] [canonical] [ossa] @$s3Lib33ParentPkgKlassWithInternalMemberYCyACSicfC : $@convention(method) (Int, @thick ParentPkgKlassWithInternalMemberY.Type) -> @owned ParentPkgKlassWithInternalMemberY { + // CHECK-DAG: sil package_external [canonical] @$s3Lib33ParentPkgKlassWithInternalMemberYCyACSicfc : $@convention(method) (Int, @owned ParentPkgKlassWithInternalMemberY) -> @owned ParentPkgKlassWithInternalMemberY + parentIntVar = arg + } + func parentIntFunc() { + print(parentIntVar) + } +} + +package class PkgKlassY: ParentPkgKlassWithInternalMemberY { + package var pkgVar: String = "pkgVar" + package init() { + // CHECK-DAG: sil package [serialized_for_package] [exact_self_class] [canonical] [ossa] @$s3Lib9PkgKlassYCACycfC : $@convention(method) (@thick PkgKlassY.Type) -> @owned PkgKlassY { + // CHECK-DAG: sil package [serialized_for_package] [canonical] [ossa] @$s3Lib9PkgKlassYCACycfc : $@convention(method) (@owned PkgKlassY) -> @owned PkgKlassY { + super.init(1) + } +} + +public protocol PubProto { + associatedtype Element = Self + static var root: UInt16 { get } + var env: UInt16 { get set } + init(rawValue: UInt16) + func pubFunc() +} + +/// NOTE: witness thunks get `shared` linkage +public class PubKlassZ: PubProto { + // FIXME: rdar://130103572 witness thunks should get [serialized_for_package] in package-cmo. + + // CHECK-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib9PubKlassZCAA0B5ProtoA2aDP4roots6UInt16VvgZTW + public static let root: UInt16 = 1 << 0 + + // CHECK-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib9PubKlassZCAA0B5ProtoA2aDP3envs6UInt16VvgTW + // CHECK-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib9PubKlassZCAA0B5ProtoA2aDP3envs6UInt16VvsTW + // CHECK-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib9PubKlassZCAA0B5ProtoA2aDP3envs6UInt16VvMTW + // CHECK-DAG: sil [serialized_for_package] [canonical] [ossa] @$s3Lib9PubKlassZC3envs6UInt16Vvg + // CHECK-DAG: sil [serialized_for_package] [canonical] [ossa] @$s3Lib9PubKlassZC3envs6UInt16Vvs + // CHECK-DAG: sil [serialized_for_package] [canonical] [ossa] @$s3Lib9PubKlassZC3envs6UInt16VvM + public var env: UInt16 + + // CHECK-DAG: sil [serialized_for_package] [canonical] [ossa] @$s3Lib9PubKlassZC8rawValues6UInt16Vvg + public let rawValue: UInt16 + + required public init(rawValue: UInt16) { + // CHECK-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib9PubKlassZCAA0B5ProtoA2aDP8rawValuexs6UInt16V_tcfCTW + // CHECK-DAG: sil [serialized_for_package] [canonical] [ossa] @$s3Lib9PubKlassZC8rawValueACs6UInt16V_tcfc + self.rawValue = rawValue + self.env = 1 << rawValue + } + public func pubFunc() { + // CHECK-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib9PubKlassZCAA0B5ProtoA2aDP7pubFuncyyFTW + // CHECK-DAG: sil [serialized_for_package] [canonical] [ossa] @$s3Lib9PubKlassZC7pubFuncyyF + print(env) + } +} + +public struct PubStruct: PubProto { + // protocol witness for static PubProto.root.getter in conformance PubStruct + // CHECK-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib9PubStructVAA0B5ProtoA2aDP4roots6UInt16VvgZTW : $@convention(witness_method: PubProto) (@thick PubStruct.Type) -> UInt16 { + // CHECK-DAG: function_ref @$s3Lib9PubStructV4roots6UInt16VvgZ : $@convention(method) (@thin PubStruct.Type) -> UInt16 + // CHECK-DAG: sil [canonical] @$s3Lib9PubStructV4roots6UInt16VvgZ : $@convention(method) (@thin PubStruct.Type) -> UInt16 + public static let root: UInt16 = 1 << 0 + + // CHECK-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib9PubStructVAA0B5ProtoA2aDP3envs6UInt16VvgTW : $@convention(witness_method: PubProto) (@in_guaranteed PubStruct) -> UInt16 { + // CHECK-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib9PubStructVAA0B5ProtoA2aDP3envs6UInt16VvsTW : $@convention(witness_method: PubProto) (UInt16, @inout PubStruct) -> () { + // CHECK-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib9PubStructVAA0B5ProtoA2aDP3envs6UInt16VvMTW : $@yield_once @convention(witness_method: PubProto) @substituted <τ_0_0> (@inout τ_0_0) -> @yields @inout UInt16 for { + // CHECK-DAG: sil [serialized_for_package] [canonical] [ossa] @$s3Lib9PubStructV3envs6UInt16Vvg + // CHECK-DAG: sil [serialized_for_package] [canonical] [ossa] @$s3Lib9PubStructV3envs6UInt16Vvs + public var env: UInt16 + + // CHECK-DAG: sil [serialized_for_package] [canonical] [ossa] @$s3Lib9PubStructV8rawValues6UInt16Vvg + public let rawValue: UInt16 + + public init(rawValue: UInt16) { + // CHECK-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib9PubStructVAA0B5ProtoA2aDP8rawValuexs6UInt16V_tcfCTW : $@convention(witness_method: PubProto) (UInt16, @thick PubStruct.Type) -> @out PubStruct { + // CHECK-DAG: sil [serialized_for_package] [canonical] [ossa] @$s3Lib9PubStructV8rawValueACs6UInt16V_tcfC + self.rawValue = rawValue + self.env = 1 << rawValue + } + + public func pubFunc() { + // CHECK-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib9PubStructVAA0B5ProtoA2aDP7pubFuncyyFTW + // CHECK-DAG: sil [serialized_for_package] [canonical] [ossa] @$s3Lib9PubStructV7pubFuncyyF + print(env) + } +} + +public protocol PubSimpleProto { + var pubVar: Int { get set } + func pubFunc() -> Int +} + +struct InternalStruct { + var name: String = "internalVar" +} + +protocol InternalProto { + var intVar: InternalStruct { get set } + func intFunc() -> InternalStruct +} + +public struct PubStructX: PubSimpleProto, InternalProto { /// NOTE: witness table serialized only for PubSimpleProto + + // CHECK-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib10PubStructXVAA0B11SimpleProtoA2aDP6pubVarSivgTW : $@convention(witness_method: PubSimpleProto) (@in_guaranteed PubStructX) -> Int { + // CHECK-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib10PubStructXVAA0B11SimpleProtoA2aDP6pubVarSivsTW : $@convention(witness_method: PubSimpleProto) (Int, @inout PubStructX) -> () { + // CHECK-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib10PubStructXVAA0B11SimpleProtoA2aDP6pubVarSivMTW : $@yield_once @convention(witness_method: PubSimpleProto) @substituted <τ_0_0> (@inout τ_0_0) -> @yields @inout Int for { + // CHECK-DAG: sil [serialized_for_package] [canonical] [ossa] @$s3Lib10PubStructXV6pubVarSivg + // CHECK-DAG: sil [serialized_for_package] [canonical] [ossa] @$s3Lib10PubStructXV6pubVarSivs + // CHECK-DAG: sil [serialized_for_package] [canonical] [ossa] @$s3Lib10PubStructXV6pubVarSivM + public var pubVar: Int + + var intVar: InternalStruct /// NOTE: internal; not serialized + + public init(_ arg: Int) { /// NOTE: contains internal; not serialized + self.intVar = InternalStruct(name: "foo") + self.pubVar = arg + } + public func pubFunc() -> Int { + // CHECK-DAG: sil [serialized_for_package] [canonical] [ossa] @$s3Lib10PubStructXV7pubFuncSiyF + return pubVar + } + + func intFunc() -> InternalStruct { /// NOTE: internal; not serialized + return intVar + } +} + +public struct PubStructY: InternalProto { /// NOTE: conforms to internal proto; not serialized + var intVar: InternalStruct + public init() { + self.intVar = InternalStruct(name: "foo") + } + func intFunc() -> InternalStruct { + return intVar + } +} + +package protocol PkgProto { + associatedtype Element = Self + static var root: UInt16 { get } + var env: UInt16 { get set } + init(rawValue: UInt16) + func pkgFunc() +} + +/// NOTE: witness thunks get `shared` linkage +package class PkgKlassZ: PkgProto { + // protocol witness for static PkgProto.root.getter in conformance PkgKlassZ + // CHECK-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib9PkgKlassZCAA0B5ProtoA2aDP4roots6UInt16VvgZTW : $@convention(witness_method: PkgProto) (@thick PkgKlassZ.Type) -> UInt16 { + // CHECK-DAG: function_ref @$s3Lib9PkgKlassZC4roots6UInt16VvgZ : $@convention(method) (@thick PkgKlassZ.Type) -> UInt16 + // CHECK-DAG: sil package_external [canonical] @$s3Lib9PkgKlassZC4roots6UInt16VvgZ : $@convention(method) (@thick PkgKlassZ.Type) -> UInt16 + package static let root: UInt16 = 1 << 0 + + // CHECK-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib9PkgKlassZCAA0B5ProtoA2aDP3envs6UInt16VvgTW : $@convention(witness_method: PkgProto) (@in_guaranteed PkgKlassZ) -> UInt16 { + // CHECK-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib9PkgKlassZCAA0B5ProtoA2aDP3envs6UInt16VvsTW : $@convention(witness_method: PkgProto) (UInt16, @inout PkgKlassZ) -> () { + // CHECK-DAG: sil package [serialized_for_package] [canonical] [ossa] @$s3Lib9PkgKlassZC3envs6UInt16Vvg + // CHECK-DAG: sil package [serialized_for_package] [canonical] [ossa] @$s3Lib9PkgKlassZC3envs6UInt16Vvs + // CHECK-DAG: sil package [serialized_for_package] [canonical] [ossa] @$s3Lib9PkgKlassZC3envs6UInt16VvM + package var env: UInt16 + + // CHECK-DAG: sil package [serialized_for_package] [canonical] [ossa] @$s3Lib9PkgKlassZC8rawValues6UInt16Vvg + package let rawValue: UInt16 + + required package init(rawValue: UInt16) { + // CHECK-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib9PkgKlassZCAA0B5ProtoA2aDP8rawValuexs6UInt16V_tcfCTW : $@convention(witness_method: PkgProto) (UInt16, @thick PkgKlassZ.Type) -> @out PkgKlassZ { + // CHECK-DAG: sil package [serialized_for_package] [canonical] [ossa] @$s3Lib9PkgKlassZC8rawValueACs6UInt16V_tcfc : $@convention(method) (UInt16, @owned PkgKlassZ) -> @owned PkgKlassZ { + self.rawValue = rawValue + self.env = 1 << rawValue + } + package func pkgFunc() { + // CHECK-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib9PkgKlassZCAA0B5ProtoA2aDP7pkgFuncyyFTW + // CHECK-DAG: sil package [serialized_for_package] [canonical] [ossa] @$s3Lib9PkgKlassZC7pkgFuncyyF + print(env) + } +} + +package struct PkgStruct: PkgProto { /// NOTE: witness thunks get `shared` linkage + // protocol witness for static PkgProto.root.getter in conformance PkgStruct + // CHECK-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib9PkgStructVAA0B5ProtoA2aDP4roots6UInt16VvgZTW : $@convention(witness_method: PkgProto) (@thick PkgStruct.Type) -> UInt16 { + // CHECK-DAG: function_ref @$s3Lib9PkgStructV4roots6UInt16VvgZ : $@convention(method) (@thin PkgStruct.Type) + // static PkgStruct.root.getter + // CHECK-DAG: sil package_external [canonical] @$s3Lib9PkgStructV4roots6UInt16VvgZ : $@convention(method) (@thin PkgStruct.Type) -> UInt16 + package static let root: UInt16 = 1 << 0 + + // CHECK-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib9PkgStructVAA0B5ProtoA2aDP3envs6UInt16VvsTW : $@convention(witness_method: PkgProto) (UInt16, @inout PkgStruct) -> () { + // CHECK-DAG: sil package [serialized_for_package] [canonical] [ossa] @$s3Lib9PkgStructV3envs6UInt16Vvs + package var env: UInt16 + + // CHECK-DAG: sil package [serialized_for_package] [canonical] [ossa] @$s3Lib9PkgStructV8rawValues6UInt16Vvg + package let rawValue: UInt16 + + package init(rawValue: UInt16) { + // CHECK-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib9PkgStructVAA0B5ProtoA2aDP8rawValuexs6UInt16V_tcfCTW : $@convention(witness_method: PkgProto) (UInt16, @thick PkgStruct.Type) -> @out PkgStruct { + // CHECK-DAG: sil package [serialized_for_package] [canonical] [ossa] @$s3Lib9PkgStructV8rawValueACs6UInt16V_tcfC + self.rawValue = rawValue + self.env = 1 << rawValue + } + package func pkgFunc() { + // CHECK-DAG: sil package [serialized_for_package] [canonical] [ossa] @$s3Lib9PkgStructV7pkgFuncyyF + print(env) + } +} + +package protocol PkgSimpleProto { + var pkgVar: Int { get set } + func pkgFunc() -> Int +} + +/// NOTE: only witness table of conformance to PkgSimpleProto is serialized. +package struct PkgStructX: PkgSimpleProto, InternalProto { + // CHECK-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib10PkgStructXVAA0B11SimpleProtoA2aDP6pkgVarSivgTW : $@convention(witness_method: PkgSimpleProto) (@in_guaranteed PkgStructX) -> Int { + // CHECK-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib10PkgStructXVAA0B11SimpleProtoA2aDP6pkgVarSivsTW : $@convention(witness_method: PkgSimpleProto) (Int, @inout PkgStructX) -> () { + // CHECK-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib10PkgStructXVAA0B11SimpleProtoA2aDP6pkgVarSivMTW : $@yield_once @convention(witness_method: PkgSimpleProto) @substituted <τ_0_0> (@inout τ_0_0) -> @yields @inout Int for { + // CHECK-DAG: sil package [serialized_for_package] [canonical] [ossa] @$s3Lib10PkgStructXV6pkgVarSivM + // CHECK-DAG: sil package [serialized_for_package] [canonical] [ossa] @$s3Lib10PkgStructXV6pkgVarSivg + // CHECK-DAG: sil package [serialized_for_package] [canonical] [ossa] @$s3Lib10PkgStructXV6pkgVarSivs + package var pkgVar: Int + var intVar: InternalStruct + package init(_ arg: Int) { + self.intVar = InternalStruct(name: "foo") + self.pkgVar = arg + } + package func pkgFunc() -> Int { + // CHECK-DAG: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s3Lib10PkgStructXVAA0B11SimpleProtoA2aDP7pkgFuncSiyFTW + // CHECK-DAG: sil package [serialized_for_package] [canonical] [ossa] @$s3Lib10PkgStructXV7pkgFuncSiyF + return pkgVar + } + func intFunc() -> InternalStruct { + return intVar + } +} + +/// NOTE: conforms to internal protocol, so not serialized +package struct PkgStructY: InternalProto { + var intVar: InternalStruct + package init() { + self.intVar = InternalStruct(name: "foo") + } + func intFunc() -> InternalStruct { + return intVar + } +} + +public func runPub(_ arg: [any PubProto]) { + print(arg) +} + +package func runPkg(_ arg: [any PkgProto]) { + print(arg) +} + + + +// CHECK-LABEL: sil_vtable [serialized_for_package] ParentPubKlass { +// CHECK-NEXT: #ParentPubKlass.parentPubVar!getter: (ParentPubKlass) -> () -> Int : @$s3Lib14ParentPubKlassC06parentC3VarSivg // ParentPubKlass.parentPubVar.getter +// CHECK-NEXT: #ParentPubKlass.parentPubVar!setter: (ParentPubKlass) -> (Int) -> () : @$s3Lib14ParentPubKlassC06parentC3VarSivs // ParentPubKlass.parentPubVar.setter +// CHECK-NEXT: #ParentPubKlass.parentPubVar!modify: (ParentPubKlass) -> () -> () : @$s3Lib14ParentPubKlassC06parentC3VarSivM // ParentPubKlass.parentPubVar.modify +// CHECK-NEXT: #ParentPubKlass.init!allocator: (ParentPubKlass.Type) -> (Int) -> ParentPubKlass : @$s3Lib14ParentPubKlassCyACSicfC // ParentPubKlass.__allocating_init(_:) +// CHECK-NEXT: #ParentPubKlass.parentPubFunc: (ParentPubKlass) -> () -> () : @$s3Lib14ParentPubKlassC06parentC4FuncyyF // ParentPubKlass.parentPubFunc() +// CHECK-NEXT: #ParentPubKlass.deinit!deallocator: @$s3Lib14ParentPubKlassCfD // ParentPubKlass.__deallocating_deinit + +// CHECK-LABEL: sil_vtable [serialized_for_package] PubKlass { +// CHECK-NEXT: #ParentPubKlass.parentPubVar!getter: (ParentPubKlass) -> () -> Int : @$s3Lib14ParentPubKlassC06parentC3VarSivg [inherited] // ParentPubKlass.parentPubVar.getter +// CHECK-NEXT: #ParentPubKlass.parentPubVar!setter: (ParentPubKlass) -> (Int) -> () : @$s3Lib14ParentPubKlassC06parentC3VarSivs [inherited] // ParentPubKlass.parentPubVar.setter +// CHECK-NEXT: #ParentPubKlass.parentPubVar!modify: (ParentPubKlass) -> () -> () : @$s3Lib14ParentPubKlassC06parentC3VarSivM [inherited] // ParentPubKlass.parentPubVar.modify +// CHECK-NEXT: #ParentPubKlass.init!allocator: (ParentPubKlass.Type) -> (Int) -> ParentPubKlass : @$s3Lib8PubKlassCyACSicfC [override] // PubKlass.__allocating_init(_:) +// CHECK-NEXT: #ParentPubKlass.parentPubFunc: (ParentPubKlass) -> () -> () : @$s3Lib8PubKlassC06parentB4FuncyyF [override] // PubKlass.parentPubFunc() +// CHECK-NEXT: #PubKlass.pubVar!getter: (PubKlass) -> () -> String : @$s3Lib8PubKlassC6pubVarSSvg // PubKlass.pubVar.getter +// CHECK-NEXT: #PubKlass.pubVar!setter: (PubKlass) -> (String) -> () : @$s3Lib8PubKlassC6pubVarSSvs // PubKlass.pubVar.setter +// CHECK-NEXT: #PubKlass.pubVar!modify: (PubKlass) -> () -> () : @$s3Lib8PubKlassC6pubVarSSvM // PubKlass.pubVar.modify +// CHECK-NEXT: #PubKlass.init!allocator: (PubKlass.Type) -> (String) -> PubKlass : @$s3Lib8PubKlassCyACSScfC // PubKlass.__allocating_init(_:) +// CHECK-NEXT: #PubKlass.pubFunc: (PubKlass) -> () -> () : @$s3Lib8PubKlassC7pubFuncyyF // PubKlass.pubFunc() +// CHECK-NEXT: #PubKlass.deinit!deallocator: @$s3Lib8PubKlassCfD // PubKlass.__deallocating_deinit +// CHECK-NEXT: #PubKlass!ivardestroyer: @$s3Lib8PubKlassCfE // PubKlass.__ivar_destroyer + +// CHECK-LABEL: sil_vtable [serialized_for_package] ParentPkgKlass { +// CHECK-NEXT: #ParentPkgKlass.parentPkgVar!getter: (ParentPkgKlass) -> () -> Int : @$s3Lib14ParentPkgKlassC06parentC3VarSivg // ParentPkgKlass.parentPkgVar.getter +// CHECK-NEXT: #ParentPkgKlass.parentPkgVar!setter: (ParentPkgKlass) -> (Int) -> () : @$s3Lib14ParentPkgKlassC06parentC3VarSivs // ParentPkgKlass.parentPkgVar.setter +// CHECK-NEXT: #ParentPkgKlass.parentPkgVar!modify: (ParentPkgKlass) -> () -> () : @$s3Lib14ParentPkgKlassC06parentC3VarSivM // ParentPkgKlass.parentPkgVar.modify +// CHECK-NEXT: #ParentPkgKlass.init!allocator: (ParentPkgKlass.Type) -> (Int) -> ParentPkgKlass : @$s3Lib14ParentPkgKlassCyACSicfC // ParentPkgKlass.__allocating_init(_:) +// CHECK-NEXT: #ParentPkgKlass.parentPkgFunc: (ParentPkgKlass) -> () -> Int : @$s3Lib14ParentPkgKlassC06parentC4FuncSiyF // ParentPkgKlass.parentPkgFunc() +// CHECK-NEXT: #ParentPkgKlass.deinit!deallocator: @$s3Lib14ParentPkgKlassCfD // ParentPkgKlass.__deallocating_deinit + +// CHECK-LABEL: sil_vtable [serialized_for_package] PkgKlass { +// CHECK-NEXT: #ParentPkgKlass.parentPkgVar!getter: (ParentPkgKlass) -> () -> Int : @$s3Lib14ParentPkgKlassC06parentC3VarSivg [inherited] // ParentPkgKlass.parentPkgVar.getter +// CHECK-NEXT: #ParentPkgKlass.parentPkgVar!setter: (ParentPkgKlass) -> (Int) -> () : @$s3Lib14ParentPkgKlassC06parentC3VarSivs [inherited] // ParentPkgKlass.parentPkgVar.setter +// CHECK-NEXT: #ParentPkgKlass.parentPkgVar!modify: (ParentPkgKlass) -> () -> () : @$s3Lib14ParentPkgKlassC06parentC3VarSivM [inherited] // ParentPkgKlass.parentPkgVar.modify +// CHECK-NEXT: #ParentPkgKlass.init!allocator: (ParentPkgKlass.Type) -> (Int) -> ParentPkgKlass : @$s3Lib8PkgKlassCyACSicfC [override] // PkgKlass.__allocating_init(_:) +// CHECK-NEXT: #ParentPkgKlass.parentPkgFunc: (ParentPkgKlass) -> () -> Int : @$s3Lib8PkgKlassC06parentB4FuncSiyF [override] // PkgKlass.parentPkgFunc() +// CHECK-NEXT: #PkgKlass.pkgVar!getter: (PkgKlass) -> () -> String : @$s3Lib8PkgKlassC6pkgVarSSvg // PkgKlass.pkgVar.getter +// CHECK-NEXT: #PkgKlass.pkgVar!setter: (PkgKlass) -> (String) -> () : @$s3Lib8PkgKlassC6pkgVarSSvs // PkgKlass.pkgVar.setter +// CHECK-NEXT: #PkgKlass.pkgVar!modify: (PkgKlass) -> () -> () : @$s3Lib8PkgKlassC6pkgVarSSvM // PkgKlass.pkgVar.modify +// CHECK-NEXT: #PkgKlass.init!allocator: (PkgKlass.Type) -> (String) -> PkgKlass : @$s3Lib8PkgKlassCyACSScfC // PkgKlass.__allocating_init(_:) +// CHECK-NEXT: #PkgKlass.pkgFunc: (PkgKlass) -> () -> () : @$s3Lib8PkgKlassC7pkgFuncyyF // PkgKlass.pkgFunc() +// CHECK-NEXT: #PkgKlass.deinit!deallocator: @$s3Lib8PkgKlassCfD // PkgKlass.__deallocating_deinit +// CHECK-NEXT: #PkgKlass!ivardestroyer: @$s3Lib8PkgKlassCfE // PkgKlass.__ivar_destroyer + +// CHECK-LABEL: sil_vtable [serialized_for_package] PubKlassZ { +// CHECK-NEXT: #PubKlassZ.env!getter: (PubKlassZ) -> () -> UInt16 : @$s3Lib9PubKlassZC3envs6UInt16Vvg // PubKlassZ.env.getter +// CHECK-NEXT: #PubKlassZ.env!setter: (PubKlassZ) -> (UInt16) -> () : @$s3Lib9PubKlassZC3envs6UInt16Vvs // PubKlassZ.env.setter +// CHECK-NEXT: #PubKlassZ.env!modify: (PubKlassZ) -> () -> () : @$s3Lib9PubKlassZC3envs6UInt16VvM // PubKlassZ.env.modify +// CHECK-NEXT: #PubKlassZ.init!allocator: (PubKlassZ.Type) -> (UInt16) -> PubKlassZ : @$s3Lib9PubKlassZC8rawValueACs6UInt16V_tcfC // PubKlassZ.__allocating_init(rawValue:) +// CHECK-NEXT: #PubKlassZ.pubFunc: (PubKlassZ) -> () -> () : @$s3Lib9PubKlassZC7pubFuncyyF // PubKlassZ.pubFunc() +// CHECK-NEXT: #PubKlassZ.deinit!deallocator: @$s3Lib9PubKlassZCfD // PubKlassZ.__deallocating_deinit + + +// CHECK-LABEL: sil_vtable [serialized_for_package] PkgKlassZ { +// CHECK-NEXT: #PkgKlassZ.env!getter: (PkgKlassZ) -> () -> UInt16 : @$s3Lib9PkgKlassZC3envs6UInt16Vvg // PkgKlassZ.env.getter +// CHECK-NEXT: #PkgKlassZ.env!setter: (PkgKlassZ) -> (UInt16) -> () : @$s3Lib9PkgKlassZC3envs6UInt16Vvs // PkgKlassZ.env.setter +// CHECK-NEXT: #PkgKlassZ.env!modify: (PkgKlassZ) -> () -> () : @$s3Lib9PkgKlassZC3envs6UInt16VvM // PkgKlassZ.env.modify +// CHECK-NEXT: #PkgKlassZ.init!allocator: (PkgKlassZ.Type) -> (UInt16) -> PkgKlassZ : @$s3Lib9PkgKlassZC8rawValueACs6UInt16V_tcfC // PkgKlassZ.__allocating_init(rawValue:) +// CHECK-NEXT: #PkgKlassZ.pkgFunc: (PkgKlassZ) -> () -> () : @$s3Lib9PkgKlassZC7pkgFuncyyF // PkgKlassZ.pkgFunc() +// CHECK-NEXT: #PkgKlassZ.deinit!deallocator: @$s3Lib9PkgKlassZCfD // PkgKlassZ.__deallocating_deinit + + +//CHECK-LABEL: sil_witness_table [serialized_for_package] PubKlassZ: PubProto module Lib { +//CHECK-NEXT: associated_type Element: PubKlassZ +//CHECK-NEXT: method #PubProto.root!getter: (Self.Type) -> () -> UInt16 : @$s3Lib9PubKlassZCAA0B5ProtoA2aDP4roots6UInt16VvgZTW +//CHECK-NEXT: method #PubProto.env!getter: (Self) -> () -> UInt16 : @$s3Lib9PubKlassZCAA0B5ProtoA2aDP3envs6UInt16VvgTW +//CHECK-NEXT: method #PubProto.env!setter: (inout Self) -> (UInt16) -> () : @$s3Lib9PubKlassZCAA0B5ProtoA2aDP3envs6UInt16VvsTW +//CHECK-NEXT: method #PubProto.env!modify: (inout Self) -> () -> () : @$s3Lib9PubKlassZCAA0B5ProtoA2aDP3envs6UInt16VvMTW +//CHECK-NEXT: method #PubProto.init!allocator: (Self.Type) -> (UInt16) -> Self : @$s3Lib9PubKlassZCAA0B5ProtoA2aDP8rawValuexs6UInt16V_tcfCTW +//CHECK-NEXT: method #PubProto.pubFunc: (Self) -> () -> () : @$s3Lib9PubKlassZCAA0B5ProtoA2aDP7pubFuncyyFTW + +//CHECK-LABEL: sil_witness_table [serialized_for_package] PubStruct: PubProto module Lib { +//CHECK-NEXT: associated_type Element: PubStruct +//CHECK-NEXT: method #PubProto.root!getter: (Self.Type) -> () -> UInt16 : @$s3Lib9PubStructVAA0B5ProtoA2aDP4roots6UInt16VvgZTW +//CHECK-NEXT: method #PubProto.env!getter: (Self) -> () -> UInt16 : @$s3Lib9PubStructVAA0B5ProtoA2aDP3envs6UInt16VvgTW +//CHECK-NEXT: method #PubProto.env!setter: (inout Self) -> (UInt16) -> () : @$s3Lib9PubStructVAA0B5ProtoA2aDP3envs6UInt16VvsTW +//CHECK-NEXT: method #PubProto.env!modify: (inout Self) -> () -> () : @$s3Lib9PubStructVAA0B5ProtoA2aDP3envs6UInt16VvMTW +//CHECK-NEXT: method #PubProto.init!allocator: (Self.Type) -> (UInt16) -> Self : @$s3Lib9PubStructVAA0B5ProtoA2aDP8rawValuexs6UInt16V_tcfCTW +//CHECK-NEXT: method #PubProto.pubFunc: (Self) -> () -> () : @$s3Lib9PubStructVAA0B5ProtoA2aDP7pubFuncyyFTW + +//CHECK-LABEL: sil_witness_table [serialized_for_package] PubStructX: PubSimpleProto module Lib { +//CHECK-NEXT: method #PubSimpleProto.pubVar!getter: (Self) -> () -> Int : @$s3Lib10PubStructXVAA0B11SimpleProtoA2aDP6pubVarSivgTW +//CHECK-NEXT: method #PubSimpleProto.pubVar!setter: (inout Self) -> (Int) -> () : @$s3Lib10PubStructXVAA0B11SimpleProtoA2aDP6pubVarSivsTW +//CHECK-NEXT: method #PubSimpleProto.pubVar!modify: (inout Self) -> () -> () : @$s3Lib10PubStructXVAA0B11SimpleProtoA2aDP6pubVarSivMTW +//CHECK-NEXT: method #PubSimpleProto.pubFunc: (Self) -> () -> Int : @$s3Lib10PubStructXVAA0B11SimpleProtoA2aDP7pubFuncSiyFTW + +//CHECK-LABEL: sil_witness_table package [serialized_for_package] PkgKlassZ: PkgProto module Lib { +//CHECK-NEXT: associated_type Element: PkgKlassZ +//CHECK-NEXT: method #PkgProto.root!getter: (Self.Type) -> () -> UInt16 : @$s3Lib9PkgKlassZCAA0B5ProtoA2aDP4roots6UInt16VvgZTW +//CHECK-NEXT: method #PkgProto.env!getter: (Self) -> () -> UInt16 : @$s3Lib9PkgKlassZCAA0B5ProtoA2aDP3envs6UInt16VvgTW +//CHECK-NEXT: method #PkgProto.env!setter: (inout Self) -> (UInt16) -> () : @$s3Lib9PkgKlassZCAA0B5ProtoA2aDP3envs6UInt16VvsTW +//CHECK-NEXT: method #PkgProto.env!modify: (inout Self) -> () -> () : @$s3Lib9PkgKlassZCAA0B5ProtoA2aDP3envs6UInt16VvMTW +//CHECK-NEXT: method #PkgProto.init!allocator: (Self.Type) -> (UInt16) -> Self : @$s3Lib9PkgKlassZCAA0B5ProtoA2aDP8rawValuexs6UInt16V_tcfCTW +//CHECK-NEXT: method #PkgProto.pkgFunc: (Self) -> () -> () : @$s3Lib9PkgKlassZCAA0B5ProtoA2aDP7pkgFuncyyFTW + +//CHECK-LABEL: sil_witness_table package [serialized_for_package] PkgStruct: PkgProto module Lib { +//CHECK-NEXT: associated_type Element: PkgStruct +//CHECK-NEXT: method #PkgProto.root!getter: (Self.Type) -> () -> UInt16 : @$s3Lib9PkgStructVAA0B5ProtoA2aDP4roots6UInt16VvgZTW +//CHECK-NEXT: method #PkgProto.env!getter: (Self) -> () -> UInt16 : @$s3Lib9PkgStructVAA0B5ProtoA2aDP3envs6UInt16VvgTW +//CHECK-NEXT: method #PkgProto.env!setter: (inout Self) -> (UInt16) -> () : @$s3Lib9PkgStructVAA0B5ProtoA2aDP3envs6UInt16VvsTW +//CHECK-NEXT: method #PkgProto.env!modify: (inout Self) -> () -> () : @$s3Lib9PkgStructVAA0B5ProtoA2aDP3envs6UInt16VvMTW +//CHECK-NEXT: method #PkgProto.init!allocator: (Self.Type) -> (UInt16) -> Self : @$s3Lib9PkgStructVAA0B5ProtoA2aDP8rawValuexs6UInt16V_tcfCTW +//CHECK-NEXT: method #PkgProto.pkgFunc: (Self) -> () -> () : @$s3Lib9PkgStructVAA0B5ProtoA2aDP7pkgFuncyyFTW + +//CHECK-LABEL: sil_witness_table package [serialized_for_package] PkgStructX: PkgSimpleProto module Lib { +//CHECK-NEXT: method #PkgSimpleProto.pkgVar!getter: (Self) -> () -> Int : @$s3Lib10PkgStructXVAA0B11SimpleProtoA2aDP6pkgVarSivgTW +//CHECK-NEXT: method #PkgSimpleProto.pkgVar!setter: (inout Self) -> (Int) -> () : @$s3Lib10PkgStructXVAA0B11SimpleProtoA2aDP6pkgVarSivsTW +//CHECK-NEXT: method #PkgSimpleProto.pkgVar!modify: (inout Self) -> () -> () : @$s3Lib10PkgStructXVAA0B11SimpleProtoA2aDP6pkgVarSivMTW +//CHECK-NEXT: method #PkgSimpleProto.pkgFunc: (Self) -> () -> Int : @$s3Lib10PkgStructXVAA0B11SimpleProtoA2aDP7pkgFuncSiyFTW diff --git a/test/SILOptimizer/package-cmo-skip-internal-generic.swift b/test/SILOptimizer/package-cmo-skip-internal-generic.swift new file mode 100644 index 0000000000000..14abeb5035e5a --- /dev/null +++ b/test/SILOptimizer/package-cmo-skip-internal-generic.swift @@ -0,0 +1,206 @@ +// RUN: %empty-directory(%t) +// RUN: split-file %s %t + +// RUN: %target-build-swift %t/Lib.swift \ +// RUN: -module-name=Lib -package-name Pkg \ +// RUN: -parse-as-library -emit-module -emit-module-path %t/Lib.swiftmodule -I%t \ +// RUN: -Xfrontend -experimental-package-cmo -Xfrontend -experimental-allow-non-resilient-access \ +// RUN: -O -wmo -enable-library-evolution +// RUN: %target-sil-opt %t/Lib.swiftmodule -sil-verify-all -o %t/Lib.sil + +// RUN: %target-build-swift -module-name=Main -package-name Pkg -I%t -emit-sil -O -wmo -Xllvm -sil-disable-pass=FunctionSignatureOpts %t/main.swift -o %t/Main.sil + +// RUN: %FileCheck %s --check-prefixes=CHECK < %t/Lib.sil +// RUN: %FileCheck %s --check-prefixes=CHECK-MAIN < %t/Main.sil + + +//--- main.swift +import Lib + +// CHECK-MAIN-NOT: s3Lib14createPubClassySixlF +// CHECK-MAIN-NOT: s3Lib19usePubStructKeypathySixlF + +func checkClasses() { + /// Inlined + print(createPubClass(0)) + + /// Not inlined as functions below contain private/internal symbols + // CHECK-MAIN-DAG: function_ref @$s3Lib20createPubClass_neverySixlF + // CHECK-MAIN-DAG: sil public_external [_semantics "optimize.sil.specialize.generic.never"] @$s3Lib20createPubClass_neverySixlF : $@convention(thin) (@in_guaranteed T) -> Int { + print(createPubClass_never(0)) + + // CHECK-MAIN-DAG: function_ref @$s3Lib14createPrvClassySixlF + // CHECK-MAIN-DAG: sil @$s3Lib14createPrvClassySixlF : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> Int + print(createPrvClass(0)) + + // CHECK-MAIN-DAG: function_ref @$s3Lib20createPrvClass_neverySixlF + // CHECK-MAIN-DAG: sil [_semantics "optimize.sil.specialize.generic.never"] @$s3Lib20createPrvClass_neverySixlF : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> Int + print(createPrvClass_never(0)) +} + +func checkNested() { + // PubContainer initializer is inlined. + // CHECK-MAIN-DAG: struct $PubContainer () + let c = PubContainer() + // CHECK-MAIN-DAG: function_ref @$s3Lib12PubContainerV9pubMemberyxxlF + // CHECK-MAIN-DAG: sil @$s3Lib12PubContainerV9pubMemberyxxlF : $@convention(method) <τ_0_0> (@in_guaranteed τ_0_0, @in_guaranteed PubContainer) -> @out τ_0_0 + print(c.pubMember(27)) +} + +func checkKeyPaths() { + /// Inlined + // CHECK-MAIN-DAG: function_ref @$s3Lib19getPubStructKeypathys7KeyPathCyAA0cD0VSiGxlF + print(usePubStructKeypath(0)) + + /// Not inlined as functions below contain private/internal symbols + // CHECK-MAIN-DAG: function_ref @$s3Lib24useInternalStructKeypathySixlF + // CHECK-MAIN-DAG: sil @$s3Lib24useInternalStructKeypathySixlF : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> Int + print(useInternalStructKeypath(0)) + + // CHECK-MAIN-DAG: function_ref @$s3Lib15useClassKeypathySixlF + // CHECK-MAIN-DAG: sil @$s3Lib15useClassKeypathySixlF : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> Int + print(useClassKeypath(0)) +} + +checkNested() +checkClasses() +checkKeyPaths() + + +//--- Lib.swift + +// createPubClass(_:) +// CHECK-DAG: sil [serialized_for_package] [canonical] @$s3Lib14createPubClassySixlF : $@convention(thin) (@in_guaranteed T) -> Int { +public func createPubClass(_ t: T) -> Int { + return getPubClass(t).foo() +} + +// CHECK-DAG: sil [serialized_for_package] [_semantics "optimize.sil.specialize.generic.never"] [canonical] @$s3Lib20createPubClass_neverySixlF : $@convention(thin) (@in_guaranteed T) -> Int { +@_semantics("optimize.sil.specialize.generic.never") +public func createPubClass_never(_ t: T) -> Int { + return getPubClass(t).foo() +} + +// CHECK-DAG: sil [serialized_for_package] [canonical] @$s3Lib11getPubClassyAA13PublicDerivedCyxGxlF : $@convention(thin) (@in_guaranteed T) -> @owned PublicDerived { +public func getPubClass(_ t : T) -> PublicDerived { + return PublicDerived(t) +} + +// Not serialized +public func createPrvClass(_ t: T) -> Int { + return getPrvClass(t).foo() +} + +// Not serialized +@_semantics("optimize.sil.specialize.generic.never") +public func createPrvClass_never(_ t: T) -> Int { + return getPrvClass(t).foo() +} + +// Not serialized +private func getPrvClass(_ t : T) -> PrivateBase { + return PrivateDerived(t) +} + +public class PublicBase { + public var t: T + public func foo() -> Int { return 27 } + public init(_ t: T) { self.t = t } +} + +public class PublicDerived : PublicBase { + override public func foo() -> Int { return 28 } +} + +private class PrivateBase { + var t: T + func foo() -> Int { return 27 } + init(_ t: T) { self.t = t } +} + +private class PrivateDerived : PrivateBase { + override func foo() -> Int { return 28 } +} + +public struct PubContainer { + private final class PrvBase {} + public init() {} + + // Not serialized; contains exported func + // but references a private class. + public func pubMember(_ t: T) -> T { + var arr = Array() + arr.append(PrvBase()) + print(arr) + exportedFunc(arr) + return t + } +} + +@_specialize(exported: true, where T == Int) +@inlinable +public func exportedFunc(_ t: T) { + print(t) +} + +public func pubFunc(_ t: T) -> Int { + return getPubClass(t).foo() +} + +@_semantics("optimize.sil.specialize.generic.never") +public func pubFuncNoSpecialize(_ t: T) -> Int { + return getPubClass(t).foo() +} + + +struct InternalStruct { + var x: Int { return 27 } + var y: Int { return 28 } +} + +public struct PubStruct { + public var x: Int { return 27 } + public var y: Int { return 28 } +} + +class Myclass { + var x: Int { return 27 } + var y: Int { return 28 } +} + +class Derived : Myclass { + override var x: Int { return 29 } + override var y: Int { return 30 } +} + + +func getInternalStructKeypath(_ t: T) -> KeyPath { + return \InternalStruct.x +} + +// CHECK-DAG: sil [canonical] @$s3Lib19getPubStructKeypathys7KeyPathCyAA0cD0VSiGxlF : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @owned KeyPath +public func getPubStructKeypath(_ t: T) -> KeyPath { + return \PubStruct.x +} + +public func useInternalStructKeypath(_ t: T) -> Int { + let s = InternalStruct() + return s[keyPath: getInternalStructKeypath(t)] +} + +// CHECK-DAG: sil [serialized_for_package] [canonical] @$s3Lib19usePubStructKeypathySixlF : $@convention(thin) (@in_guaranteed T) -> Int { +public func usePubStructKeypath(_ t: T) -> Int { + let p = PubStruct() + return p[keyPath: getPubStructKeypath(t)] +} + +func getClassKeypath(_ t: T) -> KeyPath { + return \Myclass.x +} + + +public func useClassKeypath(_ t: T) -> Int { + let c = Derived() + return c[keyPath: getClassKeypath(t)] +} + diff --git a/test/SILOptimizer/package-cmo-skip-internal.swift b/test/SILOptimizer/package-cmo-skip-internal.swift new file mode 100644 index 0000000000000..6e1c4a49f4aad --- /dev/null +++ b/test/SILOptimizer/package-cmo-skip-internal.swift @@ -0,0 +1,146 @@ +// RUN: %empty-directory(%t) +// RUN: split-file %s %t + +// RUN: %target-build-swift %t/Lib.swift \ +// RUN: -module-name=Lib -package-name Pkg \ +// RUN: -parse-as-library -emit-module -emit-module-path %t/Lib.swiftmodule -I%t \ +// RUN: -Xfrontend -experimental-package-cmo -Xfrontend -experimental-allow-non-resilient-access \ +// RUN: -O -wmo -enable-library-evolution +// RUN: %target-sil-opt %t/Lib.swiftmodule -sil-verify-all -o %t/Lib.sil + +// RUN: %target-build-swift -module-name=Main -package-name Pkg -I%t -emit-sil -O %t/main.swift -o %t/Main.sil + +// RUN: %FileCheck %s --check-prefixes=CHECK < %t/Lib.sil +// RUN: %FileCheck %s --check-prefixes=CHECK-MAIN < %t/Main.sil + + +//--- main.swift + +import Lib + +/// There should be no linker error on a public function +/// that contains symbols internal to Lib module. +// CHECK-MAIN: function_ref @$s3Lib11useInternalySiAA4BaseCF : $@convention(thin) (@guaranteed Base) -> Int +let x = useInternal(Base()) + +/// Since Base is not serialized, accessing its field should go +/// through `class_method`. +// CHECK-MAIN: class_method {{.*}} : $Base, #Base.baseVarPkg!getter : (Base) -> () -> Int, $@convention(method) (@guaranteed Base) -> Int +let y = usePkg(Base()) + +/// Since PubKlass is serialized, can access its field directly. +// CHECK-MAIN: struct $Int +// CHECK-MAIN-NEXT: store +let z = usePub(PubKlass()) + +/// PubKlassWithInternalMember is serialized but its initializer contains +/// an internal field. +// CHECK-MAIN: function_ref @$s3Lib26PubKlassWithInternalMemberCyACSicfc +let w = usePubWithInternalField(PubKlassWithInternalMember(1)) + +// useInternal(_:) +// CHECK-MAIN: sil @$s3Lib11useInternalySiAA4BaseCF : $@convention(thin) (@guaranteed Base) -> Int + +// PubKlassWithInternalMember.__allocating_init(_:) +// CHECK-MAIN: sil public_external @$s3Lib26PubKlassWithInternalMemberCyACSicfC : $@convention(method) (Int, @thick PubKlassWithInternalMember.Type) -> @owned PubKlassWithInternalMember { + + +//--- Lib.swift + +/// Package CMO does not serialize this function since +/// it references an internal symbol `baseVarInternal`. +/// If it were [serialized_for_package], it would leak +/// into client and client won't be able to find the +/// symbol `baseVarInternal` since its dispatch thunk +/// was not generated in the first place (due to it +/// being internal). +// CHECK-NOT: s3Lib11useInternalySiAA4BaseCF +public func useInternal(_ arg: Base) -> Int { + return PubKlass().pkgVar + arg.baseVarInternal.data +} + +// CHECK-DAG: sil package [serialized_for_package] [canonical] @$s3Lib6usePkgySiAA4BaseCF : $@convention(thin) (@guaranteed Base) -> Int { +package func usePkg(_ arg: Base) -> Int { + return arg.baseVarPkg +} + +// CHECK-DAG: sil [serialized_for_package] [canonical] @$s3Lib6usePubySiAA0C5KlassCF : $@convention(thin) (@guaranteed PubKlass) -> Int { +public func usePub(_ arg: PubKlass) -> Int { + return arg.pubVar + arg.pkgVar +} + +// CHECK-DAG: sil [serialized_for_package] [canonical] @$s3Lib23usePubWithInternalFieldySiAA0c5KlassdE6MemberCF : $@convention(thin) (@guaranteed PubKlassWithInternalMember) -> Int { +public func usePubWithInternalField(_ arg: PubKlassWithInternalMember) -> Int { + return arg.pubVar + arg.pkgVar +} + +struct InternalStruct { + var data: Int + init(_ arg: Int) { + data = arg + } +} + +/// This class is not serialized since it contains +/// a field of an internal type. +public class Base { + public init() {} + var baseVarInternal: InternalStruct { + return InternalStruct(1) + } + package var baseVarPkg: Int { + return 0 + } +} + +@usableFromInline +class UFIKlass: Base { + override init() {} + + var varInternal = 11 + + @usableFromInline + var varUfi = 12 + + override var baseVarInternal: InternalStruct { return InternalStruct(3) } + override var baseVarPkg: Int { return 2 } +} + +/// This class only contains package or public symbols, thus serialized. +public class PubKlass { + public init() {} + public var pubVar: Int { + return 1 + } + package var pkgVar: Int { + return 2 + } +} + +/// This class contains an internal field but its type is a public literal type, thus serialized. +public class PubKlassWithInternalMember { + var internalVar: Int + public init(_ arg: Int) { + internalVar = arg + } + public var pubVar: Int { + return 1 + } + package var pkgVar: Int { + return 2 + } +} + +/// PubKlass doesn't contain internal symbols so its vtable is serialized. +// CHECK-LABEL: sil_vtable [serialized_for_package] PubKlass { +// CHECK-NEXT: #PubKlass.init!allocator: (PubKlass.Type) -> () -> PubKlass : @$s3Lib8PubKlassCACycfC +// CHECK-NEXT: #PubKlass.pubVar!getter: (PubKlass) -> () -> Int : @$s3Lib8PubKlassC6pubVarSivg +// CHECK-NEXT: #PubKlass.pkgVar!getter: (PubKlass) -> () -> Int : @$s3Lib8PubKlassC6pkgVarSivg +// CHECK-NEXT: #PubKlass.deinit!deallocator: @$s3Lib8PubKlassCfD + +/// PubKlassWithInternalMember contains an internal field but its type is a literal public type, so the class is serialized. +// CHECK-LABEL: sil_vtable [serialized_for_package] PubKlassWithInternalMember { +// CHECK-NEXT: #PubKlassWithInternalMember.init!allocator: (PubKlassWithInternalMember.Type) -> (Int) -> PubKlassWithInternalMember : @$s3Lib26PubKlassWithInternalMemberCyACSicfC // PubKlassWithInternalMember.__allocating_init(_:) +// CHECK-NEXT: #PubKlassWithInternalMember.pubVar!getter: (PubKlassWithInternalMember) -> () -> Int : @$s3Lib26PubKlassWithInternalMemberC6pubVarSivg // PubKlassWithInternalMember.pubVar.getter +// CHECK-NEXT: #PubKlassWithInternalMember.pkgVar!getter: (PubKlassWithInternalMember) -> () -> Int : @$s3Lib26PubKlassWithInternalMemberC6pkgVarSivg // PubKlassWithInternalMember.pkgVar.getter +// CHECK-NEXT: #PubKlassWithInternalMember.deinit!deallocator: @$s3Lib26PubKlassWithInternalMemberCfD // PubKlassWithInternalMember.__deallocating_deinit