[SIL][PackageCMO] Allow optimizing [serialized_for_pkg] functions during SIL

inlining, generic/closure specialization, and devirtualization optimization passes.

SILFunction::canBeInlinedIntoCaller now exlicitly requires a caller's SerializedKind_t arg.
isAnySerialized() is added as a convenience function that checks if [serialized] or [serialized_for_pkg].

Resolves rdar://128704752
This commit is contained in:
Ellie Shin
2024-05-23 16:14:15 -07:00
parent 67e9df028e
commit 4ecfc96578
25 changed files with 123 additions and 178 deletions

View File

@@ -920,8 +920,6 @@ bool SILFunction::hasName(const char *Name) const {
Checks if this (callee) function body can be inlined into the caller
by comparing their SerializedKind_t values.
If the \p assumeFragileCaller is true, the caller must be serialized,
in which case the callee needs to be serialized also to be inlined.
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
@@ -934,22 +932,13 @@ Callee serialized_for_pkg | ok | ok | no
serialized | ok | ok | ok
*/
bool SILFunction::canBeInlinedIntoCaller(
std::optional<SerializedKind_t> callerSerializedKind,
bool assumeFragileCaller) const {
// If the \p assumeFragileCaller is true, the caller must
// be serialized, so return true only if the callee is also
// serialized.
if (assumeFragileCaller)
return isSerialized();
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.has_value() &&
callerSerializedKind.value() == IsNotSerialized;
return callerSerializedKind == IsNotSerialized;
// If Package-CMO is enabled, we serialize package, public,
// and @usableFromInline decls as [serialized_for_package].
@@ -962,8 +951,7 @@ bool SILFunction::canBeInlinedIntoCaller(
// for this callee's body to be inlined into the caller.
// It can however be referenced by [serialized] caller.
case IsSerializedForPackage:
return callerSerializedKind.has_value() &&
callerSerializedKind.value() != IsSerialized;
return callerSerializedKind != IsSerialized;
case IsSerialized:
return true;
}
@@ -972,16 +960,18 @@ bool SILFunction::canBeInlinedIntoCaller(
/// Returns true if this function can be referenced from a fragile function
/// body.
bool SILFunction::hasValidLinkageForFragileRef(
std::optional<SerializedKind_t> callerSerializedKind,
bool assumeFragileCaller) 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 (canBeInlinedIntoCaller(callerSerializedKind, assumeFragileCaller))
if (canBeInlinedIntoCaller(callerSerializedKind))
return true;
// If the containing module has been serialized already, we no longer