Skip to content

Commit

Permalink
Package CMO containing the following PRs.
Browse files Browse the repository at this point in the history
  • Loading branch information
elsh committed Jun 19, 2024
1 parent ed21303 commit 4908327
Show file tree
Hide file tree
Showing 101 changed files with 3,499 additions and 641 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand All @@ -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
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
32 changes: 31 additions & 1 deletion SwiftCompilerSources/Sources/SIL/Function.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 19 additions & 2 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,7 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
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,

Expand Down Expand Up @@ -756,7 +756,10 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
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,
Expand Down Expand Up @@ -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.
///
Expand Down Expand Up @@ -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;
Expand Down
19 changes: 19 additions & 0 deletions include/swift/AST/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down Expand Up @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions include/swift/SIL/GenericSpecializationMangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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) {}
Expand Down Expand Up @@ -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) {}

Expand Down
11 changes: 10 additions & 1 deletion include/swift/SIL/SILBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
16 changes: 14 additions & 2 deletions include/swift/SIL/SILBridgingImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
8 changes: 6 additions & 2 deletions include/swift/SIL/SILDeclRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down
59 changes: 42 additions & 17 deletions include/swift/SIL/SILFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down Expand Up @@ -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,
Expand All @@ -515,7 +515,7 @@ class SILFunction
create(SILModule &M, SILLinkage linkage, StringRef name,
CanSILFunctionType loweredType, GenericEnvironment *genericEnv,
std::optional<SILLocation> 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,
Expand All @@ -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,
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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");
}

Expand Down
Loading

0 comments on commit 4908327

Please sign in to comment.