Skip to content

Fix LifetimeDependenceInsertion: handle boxed indirect out arguments #81222

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
merged 1 commit into from
May 1, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -247,18 +247,21 @@ private func insertResultDependencies(for apply: LifetimeDependentApply, _ conte
insertMarkDependencies(value: dependentValue, initializer: nil, bases: sources.bases, builder: builder, context)
}
for resultOper in apply.applySite.indirectResultOperands {
let accessBase = resultOper.value.accessBase
guard case let .store(initializingStore, initialAddress) = accessBase.findSingleInitializer(context) else {
continue
guard let initialAddress = resultOper.value.accessBase.address else {
diagnoseUnknownDependenceSource(sourceLoc: apply.applySite.location.sourceLoc, context)
return
}
assert(initializingStore == resultOper.instruction, "an indirect result is a store")
Builder.insert(after: apply.applySite, context) { builder in
insertMarkDependencies(value: initialAddress, initializer: initializingStore, bases: sources.bases,
insertMarkDependencies(value: initialAddress, initializer: resultOper.instruction, bases: sources.bases,
builder: builder, context)
}
}
}

private func diagnoseUnknownDependenceSource(sourceLoc: SourceLoc?, _ context: FunctionPassContext) {
context.diagnosticEngine.diagnose(.lifetime_value_outside_scope, [], at: sourceLoc)
}

private func insertParameterDependencies(apply: LifetimeDependentApply, target: Operand,
_ context: FunctionPassContext ) {
guard var sources = apply.getParameterDependenceSources(target: target) else {
Expand Down
8 changes: 6 additions & 2 deletions test/ModuleInterface/Inputs/lifetime_dependence.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,17 @@ public func consumeAndCreate(_ view: consuming BufferView) -> BufferView {
return _overrideLifetime(bv, copying: view)
}

// FIXME: Filed rdar://150398673 ([nonescapable] allocbox-to-stack fails causing lifetime diagnostics to fail)
// Remove _overrideLifetime when this is fixed.
@inlinable
@lifetime(copy this, copy that)
public func deriveThisOrThat(_ this: consuming BufferView, _ that: consuming BufferView) -> BufferView {
if (Int.random(in: 1..<100) == 0) {
return BufferView(this._ptr, this._count)
let thisView = BufferView(this._ptr, this._count)
return _overrideLifetime(thisView, copying: this)
}
return BufferView(that._ptr, that._count)
let thatView = BufferView(that._ptr, that._count)
return _overrideLifetime(thatView, copying: that)
}

public struct Container {
Expand Down
33 changes: 33 additions & 0 deletions test/SILOptimizer/lifetime_dependence/dependence_insertion.sil
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,17 @@ struct Holder {
@_addressableForDependencies
struct AddressableForDeps {}

protocol PAny : ~Copyable, ~Escapable {}

sil @getPtr : $@convention(thin) () -> @out UnsafeRawPointer
sil @getSpan : $@convention(thin) (@in_guaranteed AnyObject) -> @lifetime(borrow 0) @out NE
sil @getInoutSpan : $@convention(thin) (@inout AnyObject) -> @lifetime(borrow 0) @out NCE

sil @useNE : $@convention(thin) (@guaranteed NE) -> ()

sil @getExistential : $@convention(thin) (@inout Holder) -> @lifetime(borrow 0) @out any PAny & ~Copyable & ~Escapable
sil @useExistential : $@convention(thin) (@in_guaranteed any PAny & ~Copyable & ~Escapable) -> ()

// Check that the inserted dependence is on the 'self' argument, not the temporary borrow.
//
// CHECK-LABEL: sil [available 9999] [ossa] @testSpanProp : $@convention(method) (@guaranteed AnyObject) -> @lifetime(borrow 0) @owned NE {
Expand Down Expand Up @@ -172,3 +177,31 @@ bb0(%0 : @guaranteed $Holder):
%99 = tuple ()
return %99 : $()
}

// Test that source of a dependency may be a project_box and the mark_dependence will be inserted.
//
// CHECK-LABEL: sil hidden [ossa] @testBoxDependenceSource : $@convention(thin) (@inout Holder) -> () {
// CHECK: [[BOX:%[0-9]+]] = project_box %2, 0
// CHECK: [[ARG:%[0-9]+]] = begin_access [modify] [unknown] %0
// CHECK: apply %{{.*}}([[BOX]], [[ARG]]) : $@convention(thin) (@inout Holder) -> @lifetime(borrow 0) @out any PAny & ~Copyable & ~Escapable
// CHECK: mark_dependence_addr [unresolved] [[BOX]] on [[ARG]]
// CHECK-LABEL: } // end sil function 'testBoxDependenceSource'
sil hidden [ossa] @testBoxDependenceSource : $@convention(thin) (@inout Holder) -> () {
bb0(%0 : $*Holder):
%1 = alloc_box ${ let any PAny & ~Copyable & ~Escapable }, let, name "span"
%2 = begin_borrow [lexical] [var_decl] %1
%3 = project_box %2, 0
%4 = begin_access [modify] [unknown] %0

%5 = function_ref @getExistential : $@convention(thin) (@inout Holder) -> @lifetime(borrow 0) @out any PAny & ~Copyable & ~Escapable
%6 = apply %5(%3, %4) : $@convention(thin) (@inout Holder) -> @lifetime(borrow 0) @out any PAny & ~Copyable & ~Escapable
end_access %4
%8 = mark_unresolved_non_copyable_value [no_consume_or_assign] %3

%9 = function_ref @useExistential : $@convention(thin) (@in_guaranteed any PAny & ~Copyable & ~Escapable) -> ()
%10 = apply %9(%8) : $@convention(thin) (@in_guaranteed any PAny & ~Copyable & ~Escapable) -> ()
end_borrow %2
destroy_value %1
%13 = tuple ()
return %13
}