Skip to content

ReplaceOpaqueTypesWithUnderlyingTypes: Use resilience expansion instead of inlinable attribute #24478

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2484,9 +2484,18 @@ bool ReplaceOpaqueTypesWithUnderlyingTypes::shouldPerformSubstitution(

// Allow replacement of opaque result types of inlineable function regardless
// of resilience and in which context.
if (namingDecl->getAttrs().hasAttribute<InlinableAttr>()) {
return true;
if (auto *afd = dyn_cast<AbstractFunctionDecl>(namingDecl)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add some tests where either the property itself or just the getter is inlinable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok. A case you might want to test that the old logic definitely would have missed is an @_alwaysEmitIntoClient decl. These are the same as inlinable except they have different linkage -- but don't have an InlinableAttr.

if (afd->getResilienceExpansion() == ResilienceExpansion::Minimal) {
return true;
}
} else if (auto *asd = dyn_cast<AbstractStorageDecl>(namingDecl)) {
auto *getter = asd->getGetter();
if (getter &&
getter->getResilienceExpansion() == ResilienceExpansion::Minimal) {
return true;
}
}

// Allow replacement of opaque result types in the context of maximal
// resilient expansion if the context's and the opaque type's module are the
// same.
Expand Down
61 changes: 9 additions & 52 deletions test/SILOptimizer/Inputs/specialize_opaque_type_archetypes_3.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,36 +12,9 @@ public func externalResilient() -> some ExternalP2 {
return Int64(6)
}

@usableFromInline
@inline(never)
func preventInlining() {}

@inlinable
@inline(never)
public func inlinableExternalResilient() -> some ExternalP2 {
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
return Int64(6)
}

Expand All @@ -56,34 +29,18 @@ public struct ResilientContainer {
}

@inlinable
@inline(never)
public var inlineableProperty : some ExternalP2 {
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
return x
}

@_alwaysEmitIntoClient
@inline(never)
public var inlineableProperty2 : some ExternalP2 {
return x
}


@inlinable
public func inlineableContext() {
let x = computedProperty
Expand Down
104 changes: 4 additions & 100 deletions test/SILOptimizer/Inputs/specialize_opaque_type_archetypes_4.swift
Original file line number Diff line number Diff line change
@@ -1,67 +1,17 @@
import External2

@usableFromInline
@inline(never)
func preventInlining() {}

// When specializing the opaque result type for this function we should not
// specialize the opaque result type of the recursive invocation.
@inlinable
@inline(never)
public func inlinableExternalResilientCallsResilient() -> some ExternalP2 {
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
return externalResilient()
}

// In this case we should look through the recursion.
@inlinable
@inline(never)
public func inlinableExternalResilientCallsInlinableExternalResilient() -> some ExternalP2 {
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
return inlinableExternalResilient()
}

Expand All @@ -76,60 +26,14 @@ public struct ResilientContainer2 {
}

@inlinable
@inline(never)
public var inlineableProperty : some ExternalP2 {
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
return r.computedProperty
}

@inlinable
@inline(never)
public var inlineablePropertyCallsResilientInlineable : some ExternalP2 {
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
preventInlining()
return r.inlineableProperty
}
}
11 changes: 11 additions & 0 deletions test/SILOptimizer/specialize_opaque_type_archetypes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,17 @@ public func testResilientInlinableProperty() {
useP(r.inlineableProperty.myValue3())
}

// CHECK-LABEL: sil @$s1A31testResilientInlinableProperty3yyF
// CHECK: [[CONTAINER:%.*]] = alloc_stack $ResilientContainer
// CHECK: [[RES:%.*]] = alloc_stack $Int64
// CHECK: [[FUN:%.*]] = function_ref @$s9External218ResilientContainerV19inlineableProperty2Qrvg
// CHECK: [[RES2:%.*]] = unchecked_addr_cast [[RES]] : $*Int64 to $*@_opaqueReturnTypeOf("$s9External218ResilientContainerV19inlineableProperty2Qrvp", 0)
// CHECK: apply [[FUN]]([[RES2]], [[CONTAINER]])
public func testResilientInlinableProperty3() {
let r = ResilientContainer()
useP(r.inlineableProperty2.myValue3())
}

// CHECK-LABEL: sil @$s1A22testResilientProperty2yyF
// CHECK: [[CONTAINER:%.*]] = alloc_stack $ResilientContainer2
// CHECK: [[RES:%.*]] = alloc_stack $@_opaqueReturnTypeOf("$s9External319ResilientContainer2V16computedPropertyQrvp", 0)
Expand Down