Skip to content

Commit be73bd5

Browse files
committed
AliasAnalysis: fix effect of end/abort_apply for read-only coroutines
The lifetime of yielded values always end at the end_apply. This is required because a yielded address is non-aliasing inside the begin/end_apply scope, but might be aliasing after the end_apply. For example, if the callee yields an `ref_element_addr` (which is encapsulated in a begin/end_access). Therefore, even if the callee does not write anything, the effects must be "read" and "write". Fixes a SIL verifier error rdar://147601749
1 parent 83db811 commit be73bd5

File tree

3 files changed

+72
-6
lines changed

3 files changed

+72
-6
lines changed

SwiftCompilerSources/Sources/Optimizer/Analysis/AliasAnalysis.swift

+15-2
Original file line numberDiff line numberDiff line change
@@ -275,10 +275,23 @@ struct AliasAnalysis {
275275
return getPartialApplyEffect(of: partialApply, on: memLoc)
276276

277277
case let endApply as EndApplyInst:
278-
return getApplyEffect(of: endApply.beginApply, on: memLoc)
278+
let beginApply = endApply.beginApply
279+
if case .yield(let addr) = memLoc.address.accessBase, addr.parentInstruction == beginApply {
280+
// The lifetime of yielded values always end at the end_apply. This is required because a yielded
281+
// address is non-aliasing inside the begin/end_apply scope, but might be aliasing after the end_apply.
282+
// For example, if the callee yields an `ref_element_addr` (which is encapsulated in a begin/end_access).
283+
// Therefore, even if the callee does not write anything, the effects must be "read" and "write".
284+
return .worstEffects
285+
}
286+
return getApplyEffect(of: beginApply, on: memLoc)
279287

280288
case let abortApply as AbortApplyInst:
281-
return getApplyEffect(of: abortApply.beginApply, on: memLoc)
289+
let beginApply = abortApply.beginApply
290+
if case .yield(let addr) = memLoc.address.accessBase, addr.parentInstruction == beginApply {
291+
// See the comment for `end_apply` above.
292+
return .worstEffects
293+
}
294+
return getApplyEffect(of: beginApply, on: memLoc)
282295

283296
case let builtin as BuiltinInst:
284297
return getBuiltinEffect(of: builtin, on: memLoc)

test/SILOptimizer/mem-behavior.sil

+36
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ sil @unknown_func : $@convention(thin) (Int32, @in_guaranteed Int32) -> ()
3232
sil @single_indirect_arg : $@convention(thin) (@in_guaranteed Int32) -> Int32
3333
sil @single_indirect_arg_and_error : $@convention(thin) (@in Int32) -> (Int32, @error Error)
3434
sil @single_indirect_arg_coroutine : $@yield_once @convention(thin) (@in Int32) -> @yields Int32
35+
sil [readnone] @read_none_coroutine : $@yield_once @convention(thin) () -> @yields @inout Int32
3536
sil @indirect_arg_and_ptr : $@convention(thin) (@in_guaranteed Int32, Builtin.RawPointer) -> Int32
3637
sil @single_reference : $@convention(thin) (@guaranteed X) -> Int32
3738
sil @indirect_yield_coroutine : $@yield_once @convention(thin) (@inout Int32) -> @yields @inout Int32
@@ -407,6 +408,41 @@ bb0(%0 : $Int32):
407408
return %9 : $()
408409
}
409410

411+
// CHECK-LABEL: @read_none_end_apply
412+
// CHECK: PAIR #0.
413+
// CHECK-NEXT: (%2, %3) = begin_apply %1() : $@yield_once @convention(thin) () -> @yields @inout Int32 // users: %8, %5
414+
// CHECK-NEXT: %0 = argument of bb0 : $*Int32
415+
// CHECK-NEXT: r=0,w=0
416+
// CHECK: PAIR #1.
417+
// CHECK-NEXT: %5 = end_apply %3 as $()
418+
// CHECK-NEXT: %0 = argument of bb0 : $*Int32
419+
// CHECK-NEXT: r=0,w=0
420+
// CHECK: PAIR #2.
421+
// CHECK-NEXT: %5 = end_apply %3 as $()
422+
// CHECK-NEXT: (**%2**, %3) = begin_apply %1() : $@yield_once @convention(thin) () -> @yields @inout Int32
423+
// CHECK-NEXT: r=1,w=1
424+
// CHECK: PAIR #3.
425+
// CHECK-NEXT: abort_apply %3
426+
// CHECK-NEXT: %0 = argument of bb0 : $*Int32
427+
// CHECK-NEXT: r=0,w=0
428+
// CHECK: PAIR #4.
429+
// CHECK-NEXT: abort_apply %3
430+
// CHECK-NEXT: (**%2**, %3) = begin_apply %1() : $@yield_once @convention(thin) () -> @yields @inout Int32
431+
// CHECK-NEXT: r=1,w=1
432+
sil [ossa] @read_none_end_apply : $@convention(thin) (@in Int32) -> () {
433+
bb0(%0 : $*Int32):
434+
%3 = function_ref @read_none_coroutine : $@yield_once @convention(thin) () -> @yields @inout Int32
435+
(%4, %5) = begin_apply %3() : $@yield_once @convention(thin) () -> @yields @inout Int32
436+
cond_br undef, bb1, bb2
437+
bb1:
438+
end_apply %5 as $()
439+
%r = tuple ()
440+
return %r
441+
bb2:
442+
abort_apply %5
443+
unreachable
444+
}
445+
410446
// CHECK-LABEL: @refelementaddr_and_reference
411447
// CHECK: PAIR #0.
412448
// CHECK-NEXT: %3 = apply %2(%0) : $@convention(thin) (@guaranteed X) -> Int32

test/SILOptimizer/temp_rvalue_opt_ossa.sil

+21-4
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,16 @@ public enum FakeOptional<T> {
4141

4242
struct MOS: ~Copyable {}
4343

44+
protocol P {
45+
func foo()
46+
}
47+
4448
sil [ossa] @getKlass : $@convention(thin) () -> @owned Klass
4549
sil [ossa] @getNonTrivialStruct : $@convention(thin) () -> @owned NonTrivialStruct
4650
sil [ossa] @getMOS : $@convention(thin) () -> @owned MOS
4751

4852
sil @unknown : $@convention(thin) () -> ()
53+
sil [readonly] [ossa] @read_only_coroutine : $@yield_once @convention(thin) () -> @yields @in_guaranteed P
4954

5055
sil [ossa] @guaranteed_user : $@convention(thin) (@guaranteed Klass) -> ()
5156
sil [ossa] @guaranteed_user_with_result : $@convention(thin) (@guaranteed Klass) -> @out Klass
@@ -634,10 +639,6 @@ bb0(%0 : $*Klass):
634639
return %12 : $()
635640
}
636641

637-
protocol P {
638-
func foo()
639-
}
640-
641642
sil [ossa] @getP : $@convention(thin) () -> @out Optional<P>
642643

643644
// CHECK-LABEL: sil [ossa] @handle_open_existential_addr : $@convention(thin) () -> () {
@@ -1876,3 +1877,19 @@ bb0(%0 : $*GS<B>, %1 : $*GS<B>):
18761877
return %10 : $()
18771878
}
18781879

1880+
// CHECK-LABEL: sil [ossa] @test_read_only_coroutine :
1881+
// CHECK: copy_addr
1882+
// CHECK: copy_addr
1883+
// CHECK-LABEL: } // end sil function 'test_read_only_coroutine'
1884+
sil [ossa] @test_read_only_coroutine : $@convention(thin) () -> @out P {
1885+
bb0(%0 : $*P):
1886+
%5 = function_ref @read_only_coroutine : $@yield_once @convention(thin) () -> @yields @in_guaranteed P
1887+
(%6, %7) = begin_apply %5() : $@yield_once @convention(thin) () -> @yields @in_guaranteed P
1888+
%8 = alloc_stack $P
1889+
copy_addr %6 to [init] %8
1890+
%10 = end_apply %7 as $()
1891+
copy_addr [take] %8 to [init] %0
1892+
dealloc_stack %8
1893+
%15 = tuple ()
1894+
return %15
1895+
}

0 commit comments

Comments
 (0)