blob: 932fab579f48d472a6b8e620b9af1b35fc2bd206 [file] [log] [blame]
// RUN: %target-sil-opt -sil-inline-generics -enable-sil-verify-all %s -O | %FileCheck %s
// RUN: %target-sil-opt -jumpthread-simplify-cfg -enable-sil-verify-all %s -O | %FileCheck --check-prefix=CHECK-SIMPLIFY-CFG %s
// Check some corner cases related to tracking of opened archetypes.
// For example, the compiler used to crash compiling the "process" function (rdar://28024272)
sil_stage canonical
import Builtin
import Swift
import SwiftShims
public protocol P {
}
extension P {
func invokeClosure(_ closure: () throws -> ()) rethrows
}
public func process(s: P)
sil [noinline] @invokeClosure : $@convention(method) <Self where Self : P> (@owned @callee_owned () -> @error Error, @in_guaranteed Self) -> @error Error {
bb0(%0 : $@callee_owned () -> @error Error, %1 : $*Self):
strong_release %0 : $@callee_owned () -> @error Error
%5 = tuple ()
return %5 : $()
}
sil @closure : $@convention(thin) () -> () {
bb0:
%0 = tuple ()
debug_value %0 : $()
%2 = tuple ()
return %2 : $()
}
// CHECK-LABEL: sil @process
// CHECK: bb0
// CHECK-NOT: try_apply
// CHECK-NOT: unreachable
// CHECK: apply
// CHECK-NOT: unreachable
// CHECK: return
sil @process : $@convention(thin) (@in P) -> () {
bb0(%0 : $*P):
%2 = open_existential_addr immutable_access %0 : $*P to $*@opened("4C22C24E-6BAA-11E6-B904-B8E856428C60") P
%3 = function_ref @invokeClosure : $@convention(method) _0_0 where τ_0_0 : P> (@owned @callee_owned () -> @error Error, @in_guaranteed τ_0_0) -> @error Error
// function_ref (process(s : P) -> ()).(closure #1)
%4 = function_ref @closure : $@convention(thin) () -> ()
%5 = thin_to_thick_function %4 : $@convention(thin) () -> () to $@callee_owned () -> ()
%6 = convert_function %5 : $@callee_owned () -> () to $@callee_owned () -> @error Error
try_apply %3<@opened("4C22C24E-6BAA-11E6-B904-B8E856428C60") P>(%6, %2) : $@convention(method) _0_0 where τ_0_0 : P> (@owned @callee_owned () -> @error Error, @in_guaranteed τ_0_0) -> @error Error, normal bb1, error bb2
bb1(%8 : $()):
destroy_addr %0 : $*P
%10 = tuple ()
return %10 : $()
bb2(%12 : $Error):
unreachable
}
sil_default_witness_table P {
}
public protocol View {
}
class DynamicStorage {
deinit
init()
}
final class ItemStorage<V> : DynamicStorage where V : View {
@_hasStorage final let content: V
init(content: V)
deinit
override init()
}
extension View {
func dynamicStorage() -> DynamicStorage
}
public struct DynamicItem {
@_hasStorage private var storage: DynamicStorage { get set }
public init(view: View)
}
sil @ItemStorage_alloc_init : $@convention(method) <V where V : View> (@in V, @thick ItemStorage<V>.Type) -> @owned ItemStorage<V> {
bb0(%0 : $*V, %1 : $@thick ItemStorage<V>.Type):
%2 = alloc_ref $ItemStorage<V>
%3 = function_ref @ItemStorage_init : $@convention(method) _0_0 where τ_0_0 : View> (@in τ_0_0, @owned ItemStorage_0_0>) -> @owned ItemStorage_0_0>
%4 = apply %3<V>(%0, %2) : $@convention(method) _0_0 where τ_0_0 : View> (@in τ_0_0, @owned ItemStorage_0_0>) -> @owned ItemStorage_0_0>
return %4 : $ItemStorage<V>
}
sil @ItemStorage_init : $@convention(method) <V where V : View> (@in V, @owned ItemStorage<V>) -> @owned ItemStorage<V>
sil @function_with_generic_alloc_ref : $@convention(method) <Self where Self : View> (@in_guaranteed Self) -> @owned DynamicStorage {
bb0(%0 : $*Self):
%2 = function_ref @ItemStorage_alloc_init : $@convention(method) _0_0 where τ_0_0 : View> (@in τ_0_0, @thick ItemStorage_0_0>.Type) -> @owned ItemStorage_0_0>
%3 = metatype $@thick ItemStorage<Self>.Type
%4 = alloc_stack $Self
copy_addr %0 to [initialization] %4 : $*Self
%6 = apply %2<Self>(%4, %3) : $@convention(method) _0_0 where τ_0_0 : View> (@in τ_0_0, @thick ItemStorage_0_0>.Type) -> @owned ItemStorage_0_0>
dealloc_stack %4 : $*Self
%8 = upcast %6 : $ItemStorage<Self> to $DynamicStorage
return %8 : $DynamicStorage
}
// Check that function calls with inlined properly and an alloc_ref
// with an opened archetype was created.
// CHECK-LABEL: sil @testAllocRefWithOpenArchetype
// CHECK: alloc_ref{{.*}}ItemStorage{{.*}}opened
sil @testAllocRefWithOpenArchetype: $@convention(method) (@in View, @thin DynamicItem.Type) -> @owned DynamicItem {
bb0(%0 : $*View, %1 : $@thin DynamicItem.Type):
%2 = alloc_stack $DynamicItem, var, name "self"
%4 = open_existential_addr immutable_access %0 : $*View to $*@opened("50960F66-26E4-11E7-BC37-A45E60E99281") View
%5 = function_ref @function_with_generic_alloc_ref : $@convention(method) _0_0 where τ_0_0 : View> (@in_guaranteed τ_0_0) -> @owned DynamicStorage
%6 = apply %5<@opened("50960F66-26E4-11E7-BC37-A45E60E99281") View>(%4) : $@convention(method) _0_0 where τ_0_0 : View> (@in_guaranteed τ_0_0) -> @owned DynamicStorage
%7 = struct_element_addr %2 : $*DynamicItem, #DynamicItem.storage
store %6 to %7 : $*DynamicStorage
%9 = struct $DynamicItem (%6 : $DynamicStorage)
retain_value %9 : $DynamicItem
destroy_addr %0 : $*View
%12 = struct $DynamicItem (%6 : $DynamicStorage)
release_value %12 : $DynamicItem
dealloc_stack %2 : $*DynamicItem
return %9 : $DynamicItem
}
func use<T>(_ t: T)
final class Foo<T> where T : P {
init(_ x: T)
@_hasStorage final var x: T { get set }
@_hasStorage final var y: T { get set }
deinit
}
extension P {
@inline(__always) func foo()
}
public func bar(_ p: P)
// Foo.__allocating_init(_:)
sil @Foo_alloc_init : $@convention(method) <T where T : P> (@in T, @thick Foo<T>.Type) -> @owned Foo<T> {
bb0(%0 : $*T, %1 : $@thick Foo<T>.Type):
%2 = alloc_ref $Foo<T>
// function_ref Foo.init(_:)
%3 = function_ref @Foo_init : $@convention(method) _0_0 where τ_0_0 : P> (@in τ_0_0, @owned Foo_0_0>) -> @owned Foo_0_0>
%4 = apply %3<T>(%0, %2) : $@convention(method) _0_0 where τ_0_0 : P> (@in τ_0_0, @owned Foo_0_0>) -> @owned Foo_0_0>
return %4 : $Foo<T>
} // end sil function 'Foo_alloc_init'
// Foo.init(_:)
sil @Foo_init : $@convention(method) <T where T : P> (@in T, @owned Foo<T>) -> @owned Foo<T> {
bb0(%0 : $*T, %1 : $Foo<T>):
%4 = alloc_stack $T
copy_addr %0 to [initialization] %4 : $*T
%6 = ref_element_addr %1 : $Foo<T>, #Foo.x
copy_addr [take] %4 to [initialization] %6 : $*T
dealloc_stack %4 : $*T
%9 = alloc_stack $T
copy_addr %0 to [initialization] %9 : $*T
%11 = ref_element_addr %1 : $Foo<T>, #Foo.y
copy_addr [take] %9 to [initialization] %11 : $*T
dealloc_stack %9 : $*T
destroy_addr %0 : $*T
return %1 : $Foo<T>
} // end sil function 'Foo_init'
// P.foo()
sil [always_inline] @P_foo : $@convention(method) <Self where Self : P> (@in_guaranteed Self) -> () {
bb0(%0 : $*Self):
// function_ref Foo.__allocating_init(_:)
%2 = function_ref @Foo_alloc_init : $@convention(method) _0_0 where τ_0_0 : P> (@in τ_0_0, @thick Foo_0_0>.Type) -> @owned Foo_0_0>
%3 = metatype $@thick Foo<Self>.Type
%4 = alloc_stack $Self
copy_addr %0 to [initialization] %4 : $*Self
%6 = apply %2<Self>(%4, %3) : $@convention(method) _0_0 where τ_0_0 : P> (@in τ_0_0, @thick Foo_0_0>.Type) -> @owned Foo_0_0>
dealloc_stack %4 : $*Self
// function_ref use
%9 = function_ref @use : $@convention(thin) _0_0> (@in τ_0_0) -> ()
%10 = ref_element_addr %6 : $Foo<Self>, #Foo.x
%11 = alloc_stack $Self
copy_addr %10 to [initialization] %11 : $*Self
%13 = apply %9<Self>(%11) : $@convention(thin) _0_0> (@in τ_0_0) -> ()
dealloc_stack %11 : $*Self
// function_ref use
%15 = function_ref @use : $@convention(thin) _0_0> (@in τ_0_0) -> ()
%16 = ref_element_addr %6 : $Foo<Self>, #Foo.y
%17 = alloc_stack $Self
copy_addr %16 to [initialization] %17 : $*Self
%19 = apply %15<Self>(%17) : $@convention(thin) _0_0> (@in τ_0_0) -> ()
dealloc_stack %17 : $*Self
strong_release %6 : $Foo<Self>
%22 = tuple ()
return %22 : $()
} // end sil function 'P_foo'
// use
sil hidden_external @use : $@convention(thin) _0_0> (@in τ_0_0) -> ()
// Check that everything besides the external function use is inlined into bar.
// It should contain alloc_ref and alloc_stack instructions using opened archetypes.
// CHECK-LABEL: sil @bar
// CHECK: open_existential{{.*}}C08045E0-2779-11E7-970E-A45E60E99281
// CHECK: alloc_stack{{.*}}C08045E0-2779-11E7-970E-A45E60E99281
// CHECK: alloc_ref{{.*}}C08045E0-2779-11E7-970E-A45E60E99281
// CHECK-NOT: function_ref @use
// CHECK: function_ref @use
// CHECK-NOT: function_ref
// CHECK: dealloc_stack{{.*}}C08045E0-2779-11E7-970E-A45E60E99281
// CHECK: strong_release{{.*}}C08045E0-2779-11E7-970E-A45E60E99281
// CHECK: dealloc_ref{{.*}}C08045E0-2779-11E7-970E-A45E60E99281
// CHECK: end sil function 'bar'
sil @bar : $@convention(thin) (@in P) -> () {
bb0(%0 : $*P):
%2 = open_existential_addr immutable_access %0 : $*P to $*@opened("C08045E0-2779-11E7-970E-A45E60E99281") P
// function_ref P.foo()
%3 = function_ref @P_foo : $@convention(method) _0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> ()
%4 = apply %3<@opened("C08045E0-2779-11E7-970E-A45E60E99281") P>(%2) : $@convention(method) _0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> ()
destroy_addr %0 : $*P
%6 = tuple ()
return %6 : $()
} // end sil function 'bar'
// A helper function that does not use its arguments at all
sil @dont_use_arguments: $@convention(thin) (Int32) -> () {
bb0(%0 : $Int32):
%1 = tuple ()
return %1 : $()
}
// Check that dont_use_arguments is inlined into check_removal_of_unregistered_archetype_def
// and this does not lead to an "Opened archetype definition is not registered in
// SILFunction" assertion failure, that used to happen because the apply instruction
// was not aware of the opened archetype definition that becomes unused and gets removed
// after the inlining.
//
// CHECK-LABEL: sil @check_removal_of_unregistered_archetype_def
// CHECK-NOT: init_existential
// CHECK-NOT: open_existential
// CHECK-NOT: function_ref
// CHECK-NOT: apply
// CHECK: strong_release
// CHECK: end sil function 'check_removal_of_unregistered_archetype_def'
sil @check_removal_of_unregistered_archetype_def : $@convention(thin) (AnyObject) -> () {
bb0(%0 : $AnyObject):
%1 = open_existential_ref %0 : $AnyObject to $@opened("2CAE06CE-5F10-11E4-AF13-C82A1428F987") AnyObject
%2 = integer_literal $Builtin.Int32, 1
%3 = struct $Int32(%2 : $Builtin.Int32)
%4 = mark_dependence %3 : $Int32 on %1 : $@opened("2CAE06CE-5F10-11E4-AF13-C82A1428F987") AnyObject
%5 = function_ref @dont_use_arguments : $@convention(thin) (Int32) -> ()
%6 = apply %5(%4) : $@convention(thin) (Int32) -> ()
strong_release %0 : $AnyObject
%8 = tuple ()
return %8 : $()
} // end sil function 'check_removal_of_unregistered_archetype_def'
// Check that even in case of unreacheable blocks the compiler does not hang
// in SILBuilder::addOpenedArchetypeOperands. rdar://problem/34602036
enum MyOptional<T> {
case none
case some(T)
}
class C {
var this : MyOptional<C>
init()
}
// CHECK-SIMPLIFY-CFG-LABEL: sil @test_infinite_loop_in_unreachable_block
// CHECK-SIMPLIFY-CFG: bb0
// CHECK-SIMPLIFY-CFG-NOT: bb1
// CHECK-SIMPLIFY-CFG: end sil function 'test_infinite_loop_in_unreachable_block'
sil @test_infinite_loop_in_unreachable_block : $@convention(method) (@guaranteed C) -> () {
bb0(%0 : $C):
%1 = enum $MyOptional<C>, #MyOptional.some!enumelt.1, %0 : $C
%2 = integer_literal $Builtin.Int64, 0
strong_retain %0 : $C
release_value %1 : $MyOptional<C>
%6 = integer_literal $Builtin.Int1, -1
cond_br %6, bb5, bb1
bb1:
%8 = enum $MyOptional<C>, #MyOptional.some!enumelt.1, %0 : $C
strong_retain %0 : $C
br bb2(%8 : $MyOptional<C>)
bb2(%11 : $MyOptional<C>):
%12 = unchecked_enum_data %11 : $MyOptional<C>, #MyOptional.some!enumelt.1
%13 = ref_element_addr %12 : $C, #C.this
%14 = load %13 : $*MyOptional<C>
switch_enum %14 : $MyOptional<C>, case #MyOptional.some!enumelt.1: bb3, case #MyOptional.none!enumelt: bb4
bb3(%16 : $C):
retain_value %14 : $MyOptional<C>
release_value %11 : $MyOptional<C>
br bb2(%14 : $MyOptional<C>)
bb4:
release_value %11 : $MyOptional<C>
br bb5
bb5:
%22 = tuple ()
return %22 : $()
} // end sil function 'test_infinite_loop_in_unreachable_block'