Skip to content

Commit 9f4ce07

Browse files
authored
Merge pull request #81062 from atrick/62-rdar147500193-vector-expectEquals
[6.2] Fix LifetimeDependenceDiagnostics: handle address-only 'let's
2 parents da57f96 + 3674d08 commit 9f4ce07

File tree

3 files changed

+82
-23
lines changed

3 files changed

+82
-23
lines changed

SwiftCompilerSources/Sources/Optimizer/Utilities/LifetimeDependenceUtils.swift

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -279,10 +279,18 @@ extension LifetimeDependence.Scope {
279279
case let .box(projectBox):
280280
// Note: the box may be in a borrow scope.
281281
self.init(base: projectBox.operand.value, context)
282-
case .stack, .class, .tail, .pointer, .index:
282+
case .class, .tail, .pointer, .index:
283283
self = .unknown(accessBase.address!)
284284
case .unidentified:
285285
self = .unknown(address)
286+
case let .stack(allocStack):
287+
if let initializer = accessBase.findSingleInitializer(context) {
288+
if case let .store(store, _) = initializer {
289+
self = .initialized(.store(initializingStore: store, initialAddress: allocStack))
290+
return
291+
}
292+
}
293+
self = .unknown(allocStack)
286294
case .global:
287295
// TODO: When AccessBase directly stores GlobalAccessBase, we don't need a check here and don't need to pass
288296
// 'address' in to this function.
@@ -402,6 +410,17 @@ extension LifetimeDependence.Scope {
402410
///
403411
/// Returns nil if the dependence scope covers the entire function. Returns an empty range for an unknown scope.
404412
///
413+
/// Ignore the lifetime of temporary trivial values (with .initialized and .unknown scopes). Temporaries have an
414+
/// unknown Scope, which means that LifetimeDependence.Scope did not recognize a VariableScopeInstruction. This is
415+
/// important to promote mark_dependence instructions emitted by SILGen to [nonescaping] (e.g. unsafeAddressor). It
416+
/// also allows trivial value to be "extended" without actually tracking their scope, which is expected behavior. For
417+
/// example:
418+
///
419+
/// let span = Span(buffer.baseAddress)
420+
///
421+
/// If 'baseAddress' is an opaque getter, then the temporary pointer is effectively valid
422+
/// until the end of the function.
423+
///
405424
/// Note: The caller must deinitialize the returned range.
406425
func computeRange(_ context: Context) -> InstructionRange? {
407426
switch self {
@@ -439,18 +458,13 @@ extension LifetimeDependence.Scope {
439458
if case let .argument(arg) = initializer, arg.convention.isInout {
440459
return nil
441460
}
461+
let address = initializer.initialAddress
462+
if address.type.objectType.isTrivial(in: address.parentFunction) {
463+
return nil
464+
}
442465
return LifetimeDependence.Scope.computeInitializedRange(initializer: initializer, context)
443466
case let .unknown(value):
444-
// Ignore the lifetime of temporary trivial values. Temporaries have an unknown Scope, which means that
445-
// LifetimeDependence.Scope did not recognize a VariableScopeInstruction. This is important to promote
446-
// mark_dependence instructions emitted by SILGen to [nonescaping] (e.g. unsafeAddressor). It also allows trivial
447-
// value to be "extended" without actually tracking their scope, which is expected behavior. For example:
448-
//
449-
// let span = Span(buffer.baseAddress)
450-
//
451-
// If 'baseAddress' is an opaque getter, then the temporary pointer is effectively valid
452-
// until the end of the function.
453-
if value.type.isTrivial(in: value.parentFunction) {
467+
if value.type.objectType.isTrivial(in: value.parentFunction) {
454468
return nil
455469
}
456470
// Return an empty range.

test/Interop/Cxx/stdlib/use-std-vector.swift

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -194,15 +194,12 @@ StdVectorTestSuite.test("VectorOfInt to span").require(.stdlib_6_2).code {
194194
guard #available(SwiftStdlib 6.2, *) else { return }
195195

196196
let v = Vector([1, 2, 3])
197-
// FIXME: remove 'withExtendedLifetime' once lifetime analysis is fixed.
198-
withExtendedLifetime(v) {
199-
let s = $0.span
200-
expectEqual(s.count, 3)
201-
expectFalse(s.isEmpty)
202-
expectEqual(s[0], 1)
203-
expectEqual(s[1], 2)
204-
expectEqual(s[2], 3)
205-
}
197+
let s = v.span
198+
expectEqual(s.count, 3)
199+
expectFalse(s.isEmpty)
200+
expectEqual(s[0], 1)
201+
expectEqual(s[1], 2)
202+
expectEqual(s[2], 3)
206203
}
207204

208205
runAllTests()

test/SILOptimizer/lifetime_dependence/verify_diagnostics.sil

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ public struct Holder {
3333
var c: C
3434
}
3535

36+
public struct TrivialHolder {
37+
var p: Builtin.RawPointer
38+
}
39+
3640
struct A {}
3741

3842
struct NCWrapper : ~Copyable, ~Escapable {
@@ -44,7 +48,13 @@ sil @getNEPointer : $@convention(thin) (@guaranteed NE) -> Builtin.RawPointer
4448
sil @useA : $@convention(thin) (A) -> ()
4549
sil @makeNE : $@convention(thin) () -> @lifetime(immortal) @owned NE
4650
sil @makeNEObject : $@convention(thin) () -> @lifetime(immortal) @owned NEObject
47-
sil @useNE : $@convention(thin) (NE) -> ()
51+
sil @useNE : $@convention(thin) (@guaranteed NE) -> ()
52+
53+
sil @initHolder : $@convention(thin) () -> @out Holder
54+
sil @getNE : $@convention(thin) (@in_guaranteed Holder) -> @lifetime(borrow address_for_deps 0) @owned NE
55+
56+
sil @initTrivialHolder : $@convention(thin) () -> @out TrivialHolder
57+
sil @getTrivialNE : $@convention(thin) (@in_guaranteed TrivialHolder) -> @lifetime(borrow address_for_deps 0) @owned NE
4858

4959
// Test returning a owned dependence on a trivial value
5060
sil [ossa] @return_trivial_dependence : $@convention(thin) (@guaranteed C) -> @lifetime(borrow 0) @owned NE {
@@ -80,8 +90,8 @@ bb0(%0 : @owned $Holder):
8090
%c1 = apply %f1() : $@convention(thin) () -> @lifetime(immortal) @owned NE
8191
%md = mark_dependence [unresolved] %c1 on %sb
8292
%mv = move_value [var_decl] %md
83-
%f2 = function_ref @useNE : $@convention(thin) (NE) -> ()
84-
%c2 = apply %f2(%mv) : $@convention(thin) (NE) -> ()
93+
%f2 = function_ref @useNE : $@convention(thin) (@guaranteed NE) -> ()
94+
%c2 = apply %f2(%mv) : $@convention(thin) (@guaranteed NE) -> ()
8595
destroy_value %mv
8696
end_borrow %sb
8797
dealloc_stack %stk
@@ -115,3 +125,41 @@ bb0(%0 : @owned $NCWrapper):
115125
%17 = tuple ()
116126
return %17
117127
}
128+
129+
// Test that LifetimeDependence.Scope recognizes a singly-initialized alloc_stack.
130+
sil [ossa] @testStackInit : $@convention(thin) () -> () {
131+
bb0:
132+
%0 = alloc_stack [lexical] [var_decl] $Holder, let, name "v"
133+
%1 = function_ref @initHolder : $@convention(thin) () -> @out Holder
134+
%2 = apply %1(%0) : $@convention(thin) () -> @out Holder
135+
%3 = function_ref @getNE : $@convention(thin) (@in_guaranteed Holder) -> @lifetime(borrow address_for_deps 0) @owned NE
136+
%4 = apply %3(%0) : $@convention(thin) (@in_guaranteed Holder) -> @lifetime(borrow address_for_deps 0) @owned NE
137+
%5 = mark_dependence [unresolved] %4 on %0
138+
%6 = move_value [var_decl] %5
139+
%7 = function_ref @useNE : $@convention(thin) (@guaranteed NE) -> ()
140+
%8 = apply %7(%6) : $@convention(thin) (@guaranteed NE) -> ()
141+
destroy_value %6
142+
destroy_addr %0
143+
dealloc_stack %0
144+
%12 = tuple ()
145+
return %12
146+
}
147+
148+
// Test that LifetimeDependence.Scope.computeRange handles a singly-initialized alloc_stack of trivial type by treating
149+
// it as available for the entire function
150+
sil [ossa] @testTrivialStackInit : $@convention(thin) () -> () {
151+
bb0:
152+
%0 = alloc_stack [lexical] [var_decl] $TrivialHolder, let, name "v"
153+
%1 = function_ref @initTrivialHolder : $@convention(thin) () -> @out TrivialHolder
154+
%2 = apply %1(%0) : $@convention(thin) () -> @out TrivialHolder
155+
%3 = function_ref @getTrivialNE : $@convention(thin) (@in_guaranteed TrivialHolder) -> @lifetime(borrow 0) @owned NE
156+
%4 = apply %3(%0) : $@convention(thin) (@in_guaranteed TrivialHolder) -> @lifetime(borrow 0) @owned NE
157+
%5 = mark_dependence [unresolved] %4 on %0
158+
dealloc_stack %0
159+
%6 = move_value [var_decl] %5
160+
%7 = function_ref @useNE : $@convention(thin) (@guaranteed NE) -> ()
161+
%8 = apply %7(%6) : $@convention(thin) (@guaranteed NE) -> ()
162+
destroy_value %6
163+
%12 = tuple ()
164+
return %12
165+
}

0 commit comments

Comments
 (0)