mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
602 lines
23 KiB
Plaintext
602 lines
23 KiB
Plaintext
// RUN: %target-sil-opt -enable-sil-verify-all %s -copy-forwarding -enable-copyforwarding -enable-destroyhoisting | FileCheck %s
|
|
|
|
sil_stage canonical
|
|
|
|
import Builtin
|
|
import Swift
|
|
|
|
class AClass {}
|
|
sil @f_in : $@convention(thin) <T> (@in T) -> ()
|
|
sil @f_in_guaranteed : $@convention(thin) <T> (@in_guaranteed T) -> ()
|
|
sil @f_out : $@convention(thin) <T> () -> @out T
|
|
sil @f_owned : $@convention(thin) <T> (@owned T) -> ()
|
|
|
|
protocol P {
|
|
init(_ i : Int32)
|
|
mutating func poke()
|
|
};
|
|
|
|
// CHECK-LABEL: nrvo
|
|
// CHECK-NOT: copy_addr
|
|
// CHECK: return
|
|
sil hidden @nrvo : $@convention(thin) <T where T : P> (Bool) -> @out T {
|
|
bb0(%0 : $*T, %1 : $Bool):
|
|
%2 = alloc_stack $T, var, name "ro" // users: %9, %15, %17, %19
|
|
debug_value_addr %0 : $*T
|
|
debug_value_addr %2 : $*T
|
|
%3 = struct_extract %1 : $Bool, #Bool._value // user: %4
|
|
cond_br %3, bb1, bb2 // id: %4
|
|
|
|
bb1: // Preds: bb0
|
|
%5 = metatype $@thick T.Type // user: %9
|
|
%6 = witness_method $T, #P.init!allocator.1 : $@convention(witness_method) <τ_0_0 where τ_0_0 : P> (Int32, @thick τ_0_0.Type) -> @out τ_0_0 // user: %9
|
|
%7 = integer_literal $Builtin.Int32, 10 // user: %8
|
|
%8 = struct $Int32 (%7 : $Builtin.Int32) // user: %9
|
|
%9 = apply %6<T>(%2, %8, %5) : $@convention(witness_method) <τ_0_0 where τ_0_0 : P> (Int32, @thick τ_0_0.Type) -> @out τ_0_0
|
|
br bb3 // id: %10
|
|
|
|
bb2: // Preds: bb0
|
|
%11 = metatype $@thick T.Type // user: %15
|
|
%12 = witness_method $T, #P.init!allocator.1 : $@convention(witness_method) <τ_0_0 where τ_0_0 : P> (Int32, @thick τ_0_0.Type) -> @out τ_0_0 // user: %15
|
|
%13 = integer_literal $Builtin.Int32, 1 // user: %14
|
|
%14 = struct $Int32 (%13 : $Builtin.Int32) // user: %15
|
|
%15 = apply %12<T>(%2, %14, %11) : $@convention(witness_method) <τ_0_0 where τ_0_0 : P> (Int32, @thick τ_0_0.Type) -> @out τ_0_0
|
|
br bb3 // id: %16
|
|
|
|
bb3: // Preds: bb1 bb2
|
|
copy_addr [take] %2 to [initialization] %0 : $*T // id: %17
|
|
%18 = tuple () // user: %20
|
|
debug_value_addr %0 : $*T
|
|
debug_value_addr %2 : $*T
|
|
dealloc_stack %2 : $*T // id: %19
|
|
return %18 : $() // id: %20
|
|
}
|
|
|
|
|
|
// CHECK-LABEL: dont_assert_nrvo
|
|
// CHECK: return
|
|
|
|
sil hidden @dont_assert_nrvo : $@convention(thin) <T where T : P> (Bool) -> @out T {
|
|
bb0(%0 : $*T, %1 : $Bool):
|
|
%2 = alloc_stack $T, var, name "ro" // users: %9, %15, %17, %19
|
|
debug_value_addr %0 : $*T
|
|
debug_value_addr %2 : $*T
|
|
%3 = struct_extract %1 : $Bool, #Bool._value // user: %4
|
|
%5 = metatype $@thick T.Type // user: %9
|
|
%6 = witness_method $T, #P.init!allocator.1 : $@convention(witness_method) <τ_0_0 where τ_0_0 : P> (Int32, @thick τ_0_0.Type) -> @out τ_0_0 // user: %9
|
|
%7 = integer_literal $Builtin.Int32, 10 // user: %8
|
|
%8 = struct $Int32 (%7 : $Builtin.Int32) // user: %9
|
|
%9 = apply %6<T>(%2, %8, %5) : $@convention(witness_method) <τ_0_0 where τ_0_0 : P> (Int32, @thick τ_0_0.Type) -> @out τ_0_0
|
|
br bb3(%0 : $*T)
|
|
|
|
bb3(%10 : $*T): // Preds: bb1 bb2
|
|
copy_addr [take] %2 to [initialization] %10 : $*T // id: %17
|
|
%18 = tuple () // user: %20
|
|
debug_value_addr %0 : $*T
|
|
debug_value_addr %2 : $*T
|
|
dealloc_stack %2 : $*T // id: %19
|
|
return %18 : $() // id: %20
|
|
}
|
|
|
|
//CHECK-LABEL: forward_init
|
|
//CHECK-NOT: copy_addr
|
|
//CHECK-NOT: destroy_addr
|
|
//CHECK: return
|
|
sil hidden @forward_init : $@convention(thin) <T> (@in T) -> () {
|
|
bb0(%0 : $*T):
|
|
debug_value_addr %0 : $*T
|
|
%l1 = alloc_stack $T
|
|
copy_addr %0 to [initialization] %l1 : $*T
|
|
%f1 = function_ref @f_in : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
|
|
%c1 = apply %f1<T>(%l1) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
|
|
debug_value_addr %l1 : $*T
|
|
dealloc_stack %l1 : $*T
|
|
debug_value_addr %0 : $*T
|
|
destroy_addr %0 : $*T
|
|
%r1 = tuple ()
|
|
return %r1 : $()
|
|
}
|
|
|
|
//CHECK-LABEL: dont_assert_on_basic_block_arg
|
|
//CHECK: return
|
|
sil hidden @dont_assert_on_basic_block_arg : $@convention(thin) <T> (@in T) -> () {
|
|
bb0(%0 : $*T):
|
|
debug_value_addr %0 : $*T
|
|
br bb1(%0: $*T)
|
|
|
|
bb1(%1 : $*T):
|
|
%l1 = alloc_stack $T
|
|
copy_addr %1 to [initialization] %l1 : $*T
|
|
%f1 = function_ref @f_in : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
|
|
%c1 = apply %f1<T>(%l1) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
|
|
debug_value_addr %l1 : $*T
|
|
dealloc_stack %l1 : $*T
|
|
debug_value_addr %0 : $*T
|
|
destroy_addr %0 : $*T
|
|
%r1 = tuple ()
|
|
return %r1 : $()
|
|
}
|
|
|
|
//CHECK-LABEL: forward_noinit
|
|
//CHECK-NOT: copy_addr
|
|
//CHECK: destroy_addr
|
|
//CHECK: return
|
|
sil hidden @forward_noinit : $@convention(thin) <T> (@in T) -> () {
|
|
bb0(%0 : $*T):
|
|
debug_value_addr %0 : $*T
|
|
%l1 = alloc_stack $T
|
|
%f1 = function_ref @f_out : $@convention(thin) <τ_0_0> () -> @out τ_0_0
|
|
%c1 = apply %f1<T>(%l1) : $@convention(thin) <τ_0_0> () -> @out τ_0_0
|
|
copy_addr %0 to %l1 : $*T
|
|
debug_value_addr %l1 : $*T
|
|
debug_value_addr %0 : $*T
|
|
%f2 = function_ref @f_in : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
|
|
%c2 = apply %f2<T>(%l1) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
|
|
dealloc_stack %l1 : $*T
|
|
destroy_addr %0 : $*T
|
|
%r1 = tuple ()
|
|
return %r1 : $()
|
|
}
|
|
|
|
//CHECK-LABEL: forward_takeinit
|
|
//CHECK-NOT: copy_addr
|
|
//CHECK-NOT: destroy_addr
|
|
//CHECK: return
|
|
sil hidden @forward_takeinit : $@convention(thin) <T> (@in T) -> () {
|
|
bb0(%0 : $*T):
|
|
debug_value_addr %0 : $*T
|
|
%l1 = alloc_stack $T
|
|
copy_addr [take] %0 to [initialization] %l1 : $*T
|
|
%f1 = function_ref @f_in : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
|
|
%c1 = apply %f1<T>(%l1) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
|
|
debug_value_addr %0 : $*T
|
|
debug_value_addr %l1 : $*T
|
|
dealloc_stack %l1 : $*T
|
|
%r1 = tuple ()
|
|
return %r1 : $()
|
|
}
|
|
|
|
//CHECK-LABEL: forward_takenoinit
|
|
//CHECK-NOT: copy_addr
|
|
//CHECK: destroy_addr
|
|
//CHECK: return
|
|
sil hidden @forward_takenoinit : $@convention(thin) <T> (@in T) -> () {
|
|
bb0(%0 : $*T):
|
|
debug_value_addr %0 : $*T
|
|
%l1 = alloc_stack $T
|
|
%f1 = function_ref @f_out : $@convention(thin) <τ_0_0> () -> @out τ_0_0
|
|
%c1 = apply %f1<T>(%l1) : $@convention(thin) <τ_0_0> () -> @out τ_0_0
|
|
copy_addr [take] %0 to %l1 : $*T
|
|
%f2 = function_ref @f_in : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
|
|
%c2 = apply %f2<T>(%l1) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
|
|
debug_value_addr %0 : $*T
|
|
debug_value_addr %l1 : $*T
|
|
dealloc_stack %l1 : $*T
|
|
%r1 = tuple ()
|
|
return %r1 : $()
|
|
}
|
|
|
|
//CHECK-LABEL: backward_init
|
|
//CHECK-NOT: copy_addr
|
|
//CHECK-NOT: destroy_addr
|
|
//CHECK: return
|
|
sil hidden @backward_init : $@convention(thin) <T> () -> @out T {
|
|
bb0(%0 : $*T):
|
|
%l1 = alloc_stack $T
|
|
%f1 = function_ref @f_out : $@convention(thin) <τ_0_0> () -> @out τ_0_0
|
|
%c1 = apply %f1<T>(%l1) : $@convention(thin) <τ_0_0> () -> @out τ_0_0
|
|
debug_value_addr %0 : $*T
|
|
debug_value_addr %l1 : $*T
|
|
copy_addr %l1 to [initialization] %0 : $*T
|
|
debug_value_addr %0 : $*T
|
|
debug_value_addr %l1 : $*T
|
|
destroy_addr %l1 : $*T
|
|
dealloc_stack %l1 : $*T
|
|
%t = tuple ()
|
|
return %t : $()
|
|
}
|
|
|
|
//CHECK-LABEL: dont_assert_backward_init
|
|
//CHECK: return
|
|
sil hidden @dont_assert_backward_init : $@convention(thin) <T> () -> @out T {
|
|
bb0(%0 : $*T):
|
|
%l1 = alloc_stack $T
|
|
br bb1(%0: $*T)
|
|
|
|
bb1(%1 : $*T):
|
|
%f1 = function_ref @f_out : $@convention(thin) <τ_0_0> () -> @out τ_0_0
|
|
%c1 = apply %f1<T>(%l1) : $@convention(thin) <τ_0_0> () -> @out τ_0_0
|
|
debug_value_addr %0 : $*T
|
|
debug_value_addr %l1 : $*T
|
|
copy_addr %l1 to [initialization] %0 : $*T
|
|
debug_value_addr %0 : $*T
|
|
debug_value_addr %l1 : $*T
|
|
destroy_addr %l1 : $*T
|
|
dealloc_stack %l1 : $*T
|
|
%t = tuple ()
|
|
return %t : $()
|
|
}
|
|
//CHECK-LABEL: backward_noinit
|
|
//CHECK: copy_addr
|
|
//CHECK: destroy_addr
|
|
//CHECK: return
|
|
sil hidden @backward_noinit : $@convention(thin) <T> () -> @out T {
|
|
bb0(%0 : $*T):
|
|
%l1 = alloc_stack $T
|
|
%f1 = function_ref @f_out : $@convention(thin) <τ_0_0> () -> @out τ_0_0
|
|
%c1 = apply %f1<T>(%0) : $@convention(thin) <τ_0_0> () -> @out τ_0_0
|
|
%c2 = apply %f1<T>(%l1) : $@convention(thin) <τ_0_0> () -> @out τ_0_0
|
|
copy_addr %l1 to %0 : $*T
|
|
destroy_addr %l1 : $*T
|
|
dealloc_stack %l1 : $*T
|
|
%t = tuple ()
|
|
return %t : $()
|
|
}
|
|
|
|
|
|
//CHECK-LABEL: backward_takeinit
|
|
//CHECK-NOT: copy_addr
|
|
//CHECK-NOT: destroy_addr
|
|
//CHECK: return
|
|
sil hidden @backward_takeinit : $@convention(thin) <T> () -> @out T {
|
|
bb0(%0 : $*T):
|
|
%l1 = alloc_stack $T
|
|
%f1 = function_ref @f_out : $@convention(thin) <τ_0_0> () -> @out τ_0_0
|
|
%c1 = apply %f1<T>(%l1) : $@convention(thin) <τ_0_0> () -> @out τ_0_0
|
|
debug_value_addr %0 : $*T
|
|
debug_value_addr %l1 : $*T
|
|
copy_addr [take] %l1 to [initialization] %0 : $*T
|
|
debug_value_addr %0 : $*T
|
|
debug_value_addr %l1 : $*T
|
|
dealloc_stack %l1 : $*T
|
|
%t = tuple ()
|
|
return %t : $()
|
|
}
|
|
|
|
//CHECK-LABEL: backward_takenoinit
|
|
//CHECK: copy_addr
|
|
//CHECK-NOT: destroy_addr
|
|
//CHECK: return
|
|
sil hidden @backward_takenoinit : $@convention(thin) <T> () -> @out T {
|
|
bb0(%0 : $*T):
|
|
%l1 = alloc_stack $T
|
|
%f1 = function_ref @f_out : $@convention(thin) <τ_0_0> () -> @out τ_0_0
|
|
%c1 = apply %f1<T>(%0) : $@convention(thin) <τ_0_0> () -> @out τ_0_0
|
|
%c2 = apply %f1<T>(%l1) : $@convention(thin) <τ_0_0> () -> @out τ_0_0
|
|
copy_addr [take] %l1 to %0 : $*T
|
|
dealloc_stack %l1 : $*T
|
|
%t = tuple ()
|
|
return %t : $()
|
|
}
|
|
|
|
//CHECK-LABEL: branch
|
|
//CHECK-NOT: copy_addr
|
|
//CHECK: return
|
|
sil hidden @branch : $@convention(thin) <T> (@in T, Bool) -> () {
|
|
bb0(%0 : $*T, %1 : $Bool):
|
|
%2 = struct_extract %1 : $Bool, #Bool._value // user: %3
|
|
cond_br %2, bb1, bb2 // id: %3
|
|
|
|
bb1: // Preds: bb0
|
|
%4 = function_ref @f_in : $@convention(thin) <τ_0_0> (@in τ_0_0) -> () // user: %7
|
|
%5 = alloc_stack $T // users: %6, %7, %8
|
|
copy_addr %0 to [initialization] %5 : $*T // id: %6
|
|
%7 = apply %4<T>(%5) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
|
|
dealloc_stack %5 : $*T // id: %8
|
|
br bb2 // id: %9
|
|
|
|
bb2: // Preds: bb0 bb1
|
|
destroy_addr %0 : $*T // id: %10
|
|
%11 = tuple () // user: %12
|
|
return %11 : $() // id: %12
|
|
}
|
|
|
|
enum A<T> {
|
|
case Val(T)
|
|
init(_ val: T)
|
|
}
|
|
|
|
sil [transparent] @_TFO8enuminit1A3ValU__fMGS0_Q__FQ_GS0_Q__ : $@convention(thin) <T> (@in T, @thin A<T>.Type) -> @out A<T>
|
|
|
|
//CHECK-LABEL: enuminit
|
|
//CHECK-NOT: copy_addr
|
|
//CHECK: return
|
|
sil @enuminit : $@convention(thin) <T> (@in T, @thin A<T>.Type) -> @out A<T> {
|
|
bb0(%0 : $*A<T>, %1 : $*T, %2 : $@thin A<T>.Type):
|
|
%3 = alloc_stack $A<T>, var, name "sf" // users: %10, %14, %16
|
|
// function_ref enuminit.A.Val <A>(enuminit.A<A>.Type)(A) -> enuminit.A<A>
|
|
%4 = function_ref @_TFO8enuminit1A3ValU__fMGS0_Q__FQ_GS0_Q__ : $@convention(thin) <τ_0_0> (@in τ_0_0, @thin A<τ_0_0>.Type) -> @out A<τ_0_0> // user: %9
|
|
%5 = metatype $@thin A<T>.Type // user: %9
|
|
%6 = alloc_stack $T // users: %7, %9, %12
|
|
copy_addr %1 to [initialization] %6 : $*T // id: %7
|
|
%8 = alloc_stack $A<T> // users: %9, %10, %11
|
|
%9 = apply %4<T>(%8, %6, %5) : $@convention(thin) <τ_0_0> (@in τ_0_0, @thin A<τ_0_0>.Type) -> @out A<τ_0_0>
|
|
copy_addr [take] %8 to [initialization] %3 : $*A<T> // id: %10
|
|
dealloc_stack %8 : $*A<T> // id: %11
|
|
dealloc_stack %6 : $*T // id: %12
|
|
destroy_addr %1 : $*T // id: %13
|
|
copy_addr [take] %3 to [initialization] %0 : $*A<T> // id: %14
|
|
%15 = tuple () // user: %17
|
|
dealloc_stack %3 : $*A<T> // id: %16
|
|
return %15 : $() // id: %17
|
|
}
|
|
|
|
//CHECK-LABEL: make_addronly
|
|
//CHECK-NOT: copy_addr
|
|
//CHECK: return
|
|
sil hidden @make_addronly : $@convention(thin) <T> () -> @out T {
|
|
bb0(%0 : $*T):
|
|
%1 = alloc_stack $T, let, name "t" // users: %3, %4, %5
|
|
%2 = function_ref @f_out : $@convention(thin) <τ_0_0> () -> @out τ_0_0 // user: %3
|
|
%3 = apply %2<T>(%1) : $@convention(thin) <τ_0_0> () -> @out τ_0_0
|
|
copy_addr [take] %1 to [initialization] %0 : $*T // id: %4
|
|
dealloc_stack %1 : $*T // id: %5
|
|
%6 = tuple () // user: %7
|
|
return %6 : $() // id: %7
|
|
}
|
|
|
|
sil @_TFSq4someU__fMGSqQ__FQ_GSqQ__ : $@convention(thin) <τ_0_0> (@in τ_0_0, @thin Optional<τ_0_0>.Type) -> @out Optional<τ_0_0>
|
|
|
|
sil @_TFsoi2neU__FTGSqQ__Vs26_OptionalNilComparisonType_Sb : $@convention(thin) <τ_0_0> (@in Optional<τ_0_0>, _OptionalNilComparisonType) -> Bool
|
|
|
|
//CHECK-LABEL: option_init
|
|
//CHECK: alloc_stack
|
|
//CHECK: alloc_stack
|
|
//CHECK: alloc_stack
|
|
//CHECK: copy_addr
|
|
//CHECK: copy_addr
|
|
//CHECK-NOT: copy_addr
|
|
//CHECK: alloc_stack
|
|
//CHECK: alloc_stack
|
|
//CHECK: copy_addr
|
|
//CHECK-NOT: copy_addr
|
|
//CHECK: alloc_stack
|
|
//CHECK-NOT: copy_addr
|
|
//CHECK: copy_addr
|
|
//CHECK-NOT: copy_addr
|
|
//CHECK: alloc_stack
|
|
//CHECK-NOT: copy_addr
|
|
//CHECK: return
|
|
sil hidden @option_init : $@convention(thin) <T> (@in AnyObject) -> () {
|
|
bb0(%0 : $*AnyObject):
|
|
%g0 = alloc_stack $IteratorOverOne<AnyObject> // 831
|
|
%s0 = struct_element_addr %g0 : $*IteratorOverOne<AnyObject>, #IteratorOverOne._elements
|
|
|
|
%l0 = alloc_stack $Optional<AnyObject>
|
|
// function_ref Swift.Optional.some <A>(Swift.Optional<A>.Type)(A) -> Swift.Optional<A>
|
|
%f0 = function_ref @_TFSq4someU__fMGSqQ__FQ_GSqQ__ : $@convention(thin) <τ_0_0> (@in τ_0_0, @thin Optional<τ_0_0>.Type) -> @out Optional<τ_0_0>
|
|
%t0 = metatype $@thin Optional<AnyObject>.Type
|
|
%i0 = apply %f0<AnyObject>(%l0, %0, %t0) : $@convention(thin) <τ_0_0> (@in τ_0_0, @thin Optional<τ_0_0>.Type) -> @out Optional<τ_0_0>
|
|
|
|
%g1 = alloc_stack $IteratorOverOne<AnyObject> // 850
|
|
%s1 = struct_element_addr %g1 : $*IteratorOverOne<AnyObject>, #IteratorOverOne._elements
|
|
// We can't backward propagate this yet because we can't analyze struct_element_addr copy dest.
|
|
copy_addr [take] %l0 to [initialization] %s1 : $*Optional<AnyObject>
|
|
// We ignore this copy because its Def is used by struct_element_addr
|
|
copy_addr [take] %g1 to [initialization] %g0 : $*IteratorOverOne<AnyObject>
|
|
|
|
%l1 = alloc_stack $Optional<AnyObject> // 869
|
|
|
|
%l2 = alloc_stack $Optional<AnyObject> // 873
|
|
// We ignore this copy because its Def is used by struct_element_addr
|
|
copy_addr %s0 to [initialization] %l2 : $*Optional<AnyObject>
|
|
|
|
%l3 = alloc_stack $Optional<AnyObject> // 877
|
|
%o1 = enum $Optional<AnyObject>, #Optional.none!enumelt
|
|
store %o1 to %l3 : $*Optional<AnyObject>
|
|
// We can't backward propagate this yet because we can't analyze struct_element_addr copy dest.
|
|
copy_addr [take] %l3 to %s0 : $*Optional<AnyObject>
|
|
dealloc_stack %l3 : $*Optional<AnyObject>
|
|
// We can't forward propagate this because l2 is deallocated, but we can backward propagate l1.
|
|
copy_addr [take] %l2 to [initialization] %l1 : $*Optional<AnyObject>
|
|
dealloc_stack %l2 : $*Optional<AnyObject>
|
|
%l4 = alloc_stack $Optional<AnyObject> // 889
|
|
%o2 = load %l1 : $*Optional<AnyObject>
|
|
store %o2 to %l4 : $*Optional<AnyObject>
|
|
%s5 = struct $_OptionalNilComparisonType ()
|
|
retain_value %o2 : $Optional<AnyObject>
|
|
|
|
%f1 = function_ref @_TFsoi2neU__FTGSqQ__Vs26_OptionalNilComparisonType_Sb : $@convention(thin) <τ_0_0> (@in Optional<τ_0_0>, _OptionalNilComparisonType) -> Bool
|
|
%c5 = apply %f1<AnyObject>(%l4, %s5) : $@convention(thin) <τ_0_0> (@in Optional<τ_0_0>, _OptionalNilComparisonType) -> Bool
|
|
dealloc_stack %l4 : $*Optional<AnyObject>
|
|
destroy_addr %l1 : $*Optional<AnyObject>
|
|
dealloc_stack %l1 : $*Optional<AnyObject>
|
|
dealloc_stack %g1 : $*IteratorOverOne<AnyObject>
|
|
dealloc_stack %l0 : $*Optional<AnyObject>
|
|
destroy_addr %g0 : $*IteratorOverOne<AnyObject>
|
|
dealloc_stack %g0 : $*IteratorOverOne<AnyObject>
|
|
%p0 = tuple ()
|
|
return %p0 : $()
|
|
}
|
|
|
|
// <rdar://problem/19779711> Premature release of optional NSData
|
|
// after optimization
|
|
//
|
|
// Check that destroy is not hoisted above a retain of a transitively
|
|
// referenced object.
|
|
//
|
|
// CHECK-LABEL: load_nontrivial
|
|
// CHECK: load %0 : $*Optional<AClass>
|
|
// CHECK-NOT: destroy_addr
|
|
// CHECK: unchecked_enum_data %{{.*}} : $Optional<AClass>
|
|
// CHECK-NOT: destroy_addr
|
|
// CHECK: strong_retain %{{.*}} : $AClass
|
|
// CHECK: destroy_addr %0
|
|
sil hidden @load_nontrivial : $@convention(thin) () -> () {
|
|
bb0:
|
|
%v0 = alloc_stack $Optional<AClass>
|
|
%v1 = alloc_stack $Optional<AClass>
|
|
|
|
%f0 = function_ref @f_out : $@convention(thin) <A> () -> @out A
|
|
%c0 = apply %f0<AClass?>(%v0) : $@convention(thin) <τ_0_0> () -> @out τ_0_0
|
|
|
|
copy_addr %v0 to [initialization] %v1 : $*Optional<AClass>
|
|
|
|
%f1 = function_ref @f_in : $@convention(thin) <A> (@in A) -> ()
|
|
%c1 = apply %f1<AClass?>(%v1) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
|
|
|
|
dealloc_stack %v1 : $*Optional<AClass>
|
|
%l1 = load %v0 : $*Optional<AClass>
|
|
%d1 = unchecked_enum_data %l1 : $Optional<AClass>, #Optional.some!enumelt.1
|
|
%f2 = function_ref @f_owned : $@convention(thin) <A> (@owned A) -> ()
|
|
%c2 = apply %f2<AClass>(%d1) : $@convention(thin) <τ_0_0> (@owned τ_0_0) -> ()
|
|
strong_retain %d1 : $AClass
|
|
destroy_addr %v0 : $*Optional<AClass>
|
|
%34 = tuple ()
|
|
dealloc_stack %v0 : $*Optional<AClass>
|
|
return %34 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @nil_comparison
|
|
// CHECK: alloc_stack
|
|
// CHECK-NOT: copy_addr
|
|
// CHECK-NOT destroy_addr
|
|
// CHECK: switch_enum_addr %0
|
|
// CHECK: [[D:%.*]] = unchecked_take_enum_data_addr %0
|
|
// CHECK: destroy_addr [[D]]
|
|
// CHECK: return
|
|
sil @nil_comparison : $@convention(thin) <T> (@in Optional<T>) -> Bool {
|
|
bb0(%0 : $*Optional<T>):
|
|
%2 = alloc_stack $Optional<T>
|
|
copy_addr %0 to [initialization] %2 : $*Optional<T>
|
|
destroy_addr %0 : $*Optional<T>
|
|
switch_enum_addr %2 : $*Optional<T>, case #Optional.some!enumelt.1: bb1, case #Optional.none!enumelt: bb2
|
|
|
|
bb1:
|
|
%6 = unchecked_take_enum_data_addr %2 : $*Optional<T>, #Optional.some!enumelt.1
|
|
destroy_addr %6 : $*T
|
|
%8 = integer_literal $Builtin.Int1, -1
|
|
br bb3(%8 : $Builtin.Int1)
|
|
|
|
bb2:
|
|
%10 = integer_literal $Builtin.Int1, 0
|
|
br bb3(%10 : $Builtin.Int1)
|
|
|
|
bb3(%12 : $Builtin.Int1):
|
|
%13 = struct $Bool (%12 : $Builtin.Int1)
|
|
dealloc_stack %2 : $*Optional<T>
|
|
return %13 : $Bool
|
|
}
|
|
|
|
sil @use: $@convention(thin) <T> (@inout T) -> ()
|
|
|
|
// We currently don't handle reasoning about multiple copy_addr instructions at
|
|
// once. With the current logic we must not optimize this case (we would have to
|
|
// prove that we can replace both copy_addr to be able to optimize).
|
|
|
|
// CHECK-LABEL: sil @not_dominated_uses
|
|
// CHECK: alloc_stack
|
|
// CHECK: cond_br
|
|
// CHECK: bb1
|
|
// CHECK: copy_addr
|
|
// CHECK: apply
|
|
// CHECK: br bb3
|
|
// CHECK: bb2
|
|
// CHECK: copy_addr
|
|
// CHECK: apply
|
|
// CHECK: br bb3
|
|
// CHECK: bb3
|
|
// CHECK: apply
|
|
// CHECK: destroy_addr
|
|
|
|
sil @not_dominated_uses: $@convention(thin) <T> (@in Optional<T>, @in Optional<T>, Bool) -> () {
|
|
bb0(%0 : $*Optional<T>, %1 : $*Optional<T>, %3 : $Bool):
|
|
%4 = alloc_stack $Optional<T>
|
|
%5 = struct_extract %3 : $Bool, #Bool._value
|
|
%f = function_ref @use : $@convention(thin) <T2> (@inout T2) -> ()
|
|
cond_br %5, bb1, bb2
|
|
|
|
bb1:
|
|
copy_addr [take] %0 to [initialization] %4 : $*Optional<T>
|
|
%r1 = apply %f<Optional<T>>(%4) : $@convention(thin) <T2> (@inout T2) -> ()
|
|
br bb3
|
|
|
|
bb2:
|
|
copy_addr [take] %1 to [initialization] %4 : $*Optional<T>
|
|
%r2 = apply %f<Optional<T>>(%4) : $@convention(thin) <T2> (@inout T2) -> ()
|
|
br bb3
|
|
|
|
bb3:
|
|
%r3 = apply %f<Optional<T>>(%4) : $@convention(thin) <T2> (@inout T2) -> ()
|
|
destroy_addr %4 : $*Optional<T>
|
|
dealloc_stack %4 : $*Optional<T>
|
|
%13 = tuple()
|
|
return %13 : $()
|
|
}
|
|
|
|
//CHECK-LABEL: test_in_guaranteed
|
|
//CHECK: copy_addr %1 to [initialization]
|
|
//CHECK-NOT: copy_addr
|
|
//CHECK-NOT: destroy_addr
|
|
//CHECK: return
|
|
sil hidden @test_in_guaranteed : $@convention(thin) <T> (@in T) -> @out T {
|
|
bb0(%0 : $*T, %1 : $*T):
|
|
%l1 = alloc_stack $T
|
|
copy_addr %1 to [initialization] %l1 : $*T
|
|
%f1 = function_ref @f_in_guaranteed : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> ()
|
|
%c2 = apply %f1<T>(%l1) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> ()
|
|
copy_addr %l1 to [initialization] %0 : $*T
|
|
destroy_addr %l1 : $*T
|
|
dealloc_stack %l1 : $*T
|
|
%t = tuple ()
|
|
return %t : $()
|
|
}
|
|
|
|
// CHECK-LABEL: forward_unchecked_ref_cast_addr
|
|
// CHECK: unchecked_ref_cast_addr
|
|
// CHECK-NOT: copy_addr
|
|
// CHECK: return
|
|
sil hidden @forward_unchecked_ref_cast_addr : $@convention(thin) (@in AnyObject) -> @out AClass {
|
|
bb0(%0 : $*AClass, %1 : $*AnyObject):
|
|
%3 = alloc_stack $AnyObject // user: %10
|
|
%4 = alloc_stack $AnyObject // user: %9
|
|
%5 = alloc_stack $AClass // users: %6, %7, %8
|
|
unchecked_ref_cast_addr AnyObject in %1 : $*AnyObject to AClass in %5 : $*AClass // id: %6
|
|
copy_addr [take] %5 to [initialization] %0 : $*AClass // id: %7
|
|
dealloc_stack %5 : $*AClass // id: %8
|
|
dealloc_stack %4 : $*AnyObject // id: %9
|
|
dealloc_stack %3 : $*AnyObject // id: %10
|
|
%11 = tuple () // user: %12
|
|
return %11 : $() // id: %12
|
|
}
|
|
|
|
sil @element_use : $@convention(thin) (@inout P) -> ()
|
|
|
|
// CHECK-LABEL: backward_propagate_enum_init
|
|
// CHECK-NOT: copy_addr
|
|
// CHECK: %[[TMP:.*]] = init_enum_data_addr %0 : $*Optional<P>
|
|
// CHECK: copy_addr %1 to [initialization] %[[TMP]]
|
|
// CHECK-NOT: copy_addr
|
|
sil @backward_propagate_enum_init : $@convention(thin) (@inout P) -> @out Optional<P> {
|
|
bb0(%0 : $*Optional<P>, %1 : $*P):
|
|
%2 = alloc_stack $P
|
|
copy_addr %1 to [initialization] %2 : $*P
|
|
%3 = function_ref @element_use : $@convention(thin) (@inout P) -> ()
|
|
%4 = apply %3(%1) : $@convention(thin) (@inout P) -> ()
|
|
%5 = init_enum_data_addr %0 : $*Optional<P>, #Optional.some!enumelt.1
|
|
copy_addr %2 to [initialization] %5 : $*P
|
|
inject_enum_addr %0 : $*Optional<P>, #Optional.some!enumelt.1
|
|
destroy_addr %2 : $*P
|
|
dealloc_stack %2 : $*P
|
|
%27 = tuple ()
|
|
return %27 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: backward_propagate_exi_init
|
|
// CHECK-NOT: copy_addr
|
|
// CHECK: %[[TMP:.*]] = init_existential_addr %0 : $*P, $T
|
|
// CHECK: copy_addr %1 to [initialization] %[[TMP]] : $*T
|
|
// CHECK-NOT: copy_addr
|
|
sil @backward_propagate_exi_init : $@convention(thin) <T where T : P>(@inout T) -> @out P {
|
|
bb0(%0 : $*P, %1 : $*T):
|
|
%2 = alloc_stack $T
|
|
copy_addr %1 to [initialization] %2 : $*T
|
|
%3 = witness_method $T, #P.poke!1 : $@convention(witness_method) <τ_0_0 where τ_0_0 : P> (@inout τ_0_0) -> ()
|
|
%4 = apply %3<T>(%1) : $@convention(witness_method) <τ_0_0 where τ_0_0 : P> (@inout τ_0_0) -> ()
|
|
%5 = init_existential_addr %0 : $*P, $T
|
|
copy_addr [take] %2 to [initialization] %5 : $*T
|
|
dealloc_stack %2 : $*T
|
|
%27 = tuple ()
|
|
return %27 : $()
|
|
}
|