// RUN: %target-sil-opt %s -simplification -simplify-instruction=alloc_stack | %FileCheck %s import Swift import Builtin public class C {} public struct S {} protocol P { } protocol Q { associatedtype A } public class C2: P {} public struct T: P { let c: C let s: S struct A { var y: String } } public struct U: Q { let s: String struct A { var y: String } } public struct T1: P { let x: Int } public struct T2: P { let x: Int } enum MP { case A(S) case B(S) case C(T1) } enum MP2 { case A(T1) case B(T) } public enum X { case none case some(T) } sil [ossa] @take_s : $@convention(thin) (@in S) -> () sil [ossa] @take_t : $@convention(thin) (@in T) -> () sil [ossa] @use_mp : $@convention(thin) (@in_guaranteed MP) -> () sil [ossa] @use_c2 : $@convention(thin) (@in_guaranteed C2) -> () // CHECK-LABEL: sil [ossa] @expand_alloc_stack_of_enum1 : // CHECK: [[A:%[0-9]+]] = alloc_stack [lexical] $S // CHECK: bb1: // CHECK-NEXT: store %0 to [trivial] [[A]] // CHECK: bb2: // CHECK-NEXT: store %0 to [trivial] [[A]] // CHECK: bb3: // CHECK: apply {{%[0-9]+}}([[A]]) // CHECK: } // end sil function 'expand_alloc_stack_of_enum1' sil [ossa] @expand_alloc_stack_of_enum1 : $@convention(method) (S) -> () { bb0(%0 : $S): %1 = alloc_stack [lexical] $MP cond_br undef, bb1, bb2 bb1: %2 = init_enum_data_addr %1 : $*MP, #MP.A!enumelt store %0 to [trivial] %2 : $*S inject_enum_addr %1 : $*MP, #MP.A!enumelt br bb3 bb2: %3 = init_enum_data_addr %1 : $*MP, #MP.A!enumelt store %0 to [trivial] %3 : $*S inject_enum_addr %1 : $*MP, #MP.A!enumelt br bb3 bb3: %7 = unchecked_take_enum_data_addr %1 : $*MP, #MP.A!enumelt %8 = function_ref @take_s : $@convention(thin) (@in S) -> () %9 = apply %8(%7) : $@convention(thin) (@in S) -> () dealloc_stack %1 : $*MP %11 = tuple () return %11 : $() } // CHECK-LABEL: sil [ossa] @expand_alloc_stack_of_enum_without_take : // CHECK: [[A:%[0-9]+]] = alloc_stack $S // CHECK: bb1: // CHECK-NEXT: store %0 to [trivial] [[A]] // CHECK: bb2: // CHECK-NEXT: store %0 to [trivial] [[A]] // CHECK: bb3: // CHECK: destroy_addr [[A]] // CHECK: } // end sil function 'expand_alloc_stack_of_enum_without_take' sil [ossa] @expand_alloc_stack_of_enum_without_take : $@convention(method) (S) -> () { bb0(%0 : $S): %1 = alloc_stack $MP cond_br undef, bb1, bb2 bb1: %2 = init_enum_data_addr %1 : $*MP, #MP.A!enumelt store %0 to [trivial] %2 : $*S inject_enum_addr %1 : $*MP, #MP.A!enumelt br bb3 bb2: %3 = init_enum_data_addr %1 : $*MP, #MP.A!enumelt store %0 to [trivial] %3 : $*S inject_enum_addr %1 : $*MP, #MP.A!enumelt br bb3 bb3: destroy_addr %1 : $*MP dealloc_stack %1 : $*MP %11 = tuple () return %11 : $() } // CHECK-LABEL: sil [ossa] @expand_alloc_stack_of_enum_multiple_cases : // CHECK: [[A:%[0-9]+]] = alloc_stack $T // CHECK: bb1: // CHECK-NEXT: [[COPY_ARG:%.*]] = copy_value %0 // CHECK-NEXT: store [[COPY_ARG]] to [init] [[A]] // CHECK: apply {{%[0-9]+}}([[A]]) // CHECK: bb2: // CHECK-NEXT: br bb3 // CHECK: bb3: // CHECK: } // end sil function 'expand_alloc_stack_of_enum_multiple_cases' sil [ossa] @expand_alloc_stack_of_enum_multiple_cases : $@convention(method) (@guaranteed T) -> () { bb0(%0 : @guaranteed $T): %1 = alloc_stack $X cond_br undef, bb1, bb2 bb1: %2 = init_enum_data_addr %1 : $*X, #X.some!enumelt %0a = copy_value %0 : $T store %0a to [init] %2 : $*T inject_enum_addr %1 : $*X, #X.some!enumelt %7 = unchecked_take_enum_data_addr %1 : $*X, #X.some!enumelt %8 = function_ref @take_t : $@convention(thin) (@in T) -> () %9 = apply %8(%7) : $@convention(thin) (@in T) -> () br bb3 bb2: inject_enum_addr %1 : $*X, #X.none!enumelt destroy_addr %1 : $*X br bb3 bb3: dealloc_stack %1 : $*X %11 = tuple () return %11 : $() } // CHECK-LABEL: sil [ossa] @expand_alloc_stack_of_enum_multiple_cases2 : // CHECK: [[A:%[0-9]+]] = alloc_stack $Optional // CHECK: } // end sil function 'expand_alloc_stack_of_enum_multiple_cases2' sil [ossa] @expand_alloc_stack_of_enum_multiple_cases2 : $@convention(method) (@owned T) -> () { bb0(%0 : @owned $T): %1 = alloc_stack $Optional cond_br undef, bb1, bb2 bb1: %2 = init_enum_data_addr %1, #Optional.some!enumelt store %0 to [init] %2 inject_enum_addr %1, #Optional.some!enumelt %7 = unchecked_take_enum_data_addr %1, #Optional.some!enumelt %9 = apply undef(%7) : $@convention(thin) (@in_guaranteed T) -> () br bb3 bb2: inject_enum_addr %1, #Optional.none!enumelt destroy_value %0 br bb3 bb3: destroy_addr %1 dealloc_stack %1 %11 = tuple () return %11 : $() } // CHECK-LABEL: sil [ossa] @different_cases_same_payload_type : // CHECK: alloc_stack $S // CHECK: } // end sil function 'different_cases_same_payload_type' sil [ossa] @different_cases_same_payload_type : $@convention(method) (S) -> () { bb0(%0 : $S): %1 = alloc_stack $MP cond_br undef, bb1, bb2 bb1: %2 = init_enum_data_addr %1 : $*MP, #MP.A!enumelt store %0 to [trivial] %2 : $*S inject_enum_addr %1 : $*MP, #MP.A!enumelt br bb3 bb2: %3 = init_enum_data_addr %1 : $*MP, #MP.B!enumelt store %0 to [trivial] %3 : $*S inject_enum_addr %1 : $*MP, #MP.B!enumelt br bb3 bb3: destroy_addr %1 : $*MP dealloc_stack %1 : $*MP %11 = tuple () return %11 : $() } // CHECK-LABEL: sil [ossa] @different_case_different_payload_type : // CHECK: alloc_stack $MP // CHECK: } // end sil function 'different_case_different_payload_type' sil [ossa] @different_case_different_payload_type : $@convention(method) (S, T1) -> () { bb0(%0 : $S, %t : $T1): %1 = alloc_stack $MP cond_br undef, bb1, bb2 bb1: %2 = init_enum_data_addr %1 : $*MP, #MP.A!enumelt store %0 to [trivial] %2 inject_enum_addr %1, #MP.A!enumelt br bb3 bb2: %3 = init_enum_data_addr %1 : $*MP, #MP.C!enumelt store %t to [trivial] %3 inject_enum_addr %1, #MP.C!enumelt br bb3 bb3: destroy_addr %1 dealloc_stack %1 %11 = tuple () return %11 : $() } // CHECK-LABEL: sil [ossa] @dont_expand_alloc_stack_of_enum_multiple_cases2 : // CHECK: alloc_stack $X // CHECK: } // end sil function 'dont_expand_alloc_stack_of_enum_multiple_cases2' sil [ossa] @dont_expand_alloc_stack_of_enum_multiple_cases2 : $@convention(method) (@guaranteed T) -> () { bb0(%0 : @guaranteed $T): %1 = alloc_stack $X cond_br undef, bb1, bb2 bb1: %2 = init_enum_data_addr %1 : $*X, #X.some!enumelt %0a = copy_value %0 : $T store %0a to [init] %2 : $*T inject_enum_addr %1 : $*X, #X.some!enumelt br bb3 bb2: inject_enum_addr %1 : $*X, #X.none!enumelt br bb3 bb3: destroy_addr %1 : $*X dealloc_stack %1 : $*X %11 = tuple () return %11 : $() } // CHECK-LABEL: sil [ossa] @dont_expand_alloc_stack_of_enum_unknown_use : // CHECK: alloc_stack $MP // CHECK: } // end sil function 'dont_expand_alloc_stack_of_enum_unknown_use' sil [ossa] @dont_expand_alloc_stack_of_enum_unknown_use : $@convention(method) (S) -> () { bb0(%0 : $S): %1 = alloc_stack $MP %2 = init_enum_data_addr %1 : $*MP, #MP.A!enumelt store %0 to [trivial] %2 : $*S inject_enum_addr %1 : $*MP, #MP.A!enumelt %8 = function_ref @use_mp : $@convention(thin) (@in_guaranteed MP) -> () %9 = apply %8(%1) : $@convention(thin) (@in_guaranteed MP) -> () destroy_addr %1 : $*MP dealloc_stack %1 : $*MP %11 = tuple () return %11 : $() } // CHECK-LABEL: sil [ossa] @enum_with_store : // CHECK: %1 = alloc_stack $C // CHECK: %2 = unchecked_enum_data %0, #Optional.some // CHECK: store %2 to [init] %1 // CHECK: load [take] %1 // CHECK: } // end sil function 'enum_with_store' sil [ossa] @enum_with_store : $@convention(thin) (@owned Optional) -> @owned C { bb0(%0 : @owned $Optional): %1 = alloc_stack $Optional store %0 to [init] %1 %3 = unchecked_take_enum_data_addr %1, #Optional.some!enumelt %4 = load [take] %3 dealloc_stack %1 return %4 } // CHECK-LABEL: sil [ossa] @store_and_overlapping_inject : // CHECK: %1 = alloc_stack $Optional // CHECK: } // end sil function 'store_and_overlapping_inject' sil [ossa] @store_and_overlapping_inject : $@convention(thin) (@guaranteed Optional) -> () { bb0(%0 : @guaranteed $Optional): %1 = alloc_stack $Optional cond_br undef, bb1, bb2 bb1: %2 = copy_value %0 store %2 to [init] %1 %3 = unchecked_take_enum_data_addr %1, #Optional.some!enumelt %4 = load [copy] %3 destroy_value %4 br bb3 bb2: inject_enum_addr %1, #Optional.none!enumelt br bb3 bb3: destroy_addr %1 dealloc_stack %1 %r = tuple () return %r } // CHECK-LABEL: sil [ossa] @inject_diamond : // CHECK: %1 = alloc_stack $Optional // CHECK: } // end sil function 'inject_diamond' sil [ossa] @inject_diamond : $@convention(thin) () -> @out C { bb0(%0 : $*C): %1 = alloc_stack $Optional cond_br undef, bb1, bb3 bb1: inject_enum_addr %1, #Optional.none!enumelt %4 = integer_literal $Builtin.Int32, 0 %5 = integer_literal $Builtin.Int32, 1 switch_value %5, case %4: bb2, case %5: bb5 bb2: br bb4 bb3: %8 = init_enum_data_addr %1, #Optional.some!enumelt %9 = apply undef(%8) : $@convention(thin) () -> @out C inject_enum_addr %1, #Optional.some!enumelt br bb4 bb4: %12 = unchecked_take_enum_data_addr %1, #Optional.some!enumelt copy_addr [take] %12 to [init] %0 br bb6 bb5: %15 = apply undef(%0) : $@convention(thin) () -> @out C destroy_addr %1 br bb6 bb6: dealloc_stack %1 %19 = tuple () return %19 } // CHECK-LABEL: sil [ossa] @trivial_case_of_nontrivial_enum : // CHECK: %1 = alloc_stack $T1 // CHECK: %2 = unchecked_enum_data %0, #MP2.A // CHECK: store %2 to [trivial] %1 // CHECK: load [trivial] %1 // CHECK: } // end sil function 'trivial_case_of_nontrivial_enum' sil [ossa] @trivial_case_of_nontrivial_enum : $@convention(thin) (@owned MP2) -> T1 { bb0(%0 : @owned $MP2): %1 = alloc_stack $MP2 store %0 to [init] %1 %3 = unchecked_take_enum_data_addr %1, #MP2.A!enumelt %4 = load [trivial] %3 dealloc_stack %1 return %4 } // CHECK-LABEL: sil [ossa] @store_doesnt_dominate_all_loads : // CHECK: %1 = alloc_stack $Optional // CHECK: unchecked_take_enum_data_addr // CHECK: } // end sil function 'store_doesnt_dominate_all_loads' sil [ossa] @store_doesnt_dominate_all_loads : $@convention(thin) (@owned Optional) -> () { bb0(%0 : @owned $Optional): %1 = alloc_stack $Optional store %0 to [init] %1 %3 = unchecked_take_enum_data_addr %1, #Optional.some!enumelt cond_br undef, bb1, bb2 bb1: %4 = load [take] %3 destroy_value %4 br bb3 bb2: destroy_addr %1 br bb3 bb3: dealloc_stack %1 %r = tuple () return %r } // CHECK-LABEL: sil [ossa] @store_dominates_multiple_case_blocks : // CHECK: %1 = alloc_stack $C // CHECK: bb1: // CHECK-NEXT: [[P:%.*]] = unchecked_enum_data %0, #Optional.some // CHECK-NEXT: store [[P]] to [init] %1 // CHECK: bb2: // CHECK-NEXT: destroy_value %0 // CHECK-NEXT: br bb3 // CHECK: } // end sil function 'store_dominates_multiple_case_blocks' sil [ossa] @store_dominates_multiple_case_blocks : $@convention(thin) (@owned Optional) -> () { bb0(%0 : @owned $Optional): %1 = alloc_stack $Optional store %0 to [init] %1 cond_br undef, bb1, bb2 bb1: %3 = unchecked_take_enum_data_addr %1, #Optional.some!enumelt %4 = load [copy] %3 destroy_value %4 destroy_addr %1 br bb3 bb2: destroy_addr %1 inject_enum_addr %1, #Optional.none!enumelt br bb3 bb3: dealloc_stack %1 %r = tuple () return %r } // CHECK-LABEL: sil [ossa] @store_dominates_multiple_case_blocks_trivial : // CHECK: %1 = alloc_stack $Int // CHECK: bb1: // CHECK-NEXT: [[P:%.*]] = unchecked_enum_data %0, #Optional.some // CHECK-NEXT: store [[P]] to [trivial] %1 // CHECK: bb2: // CHECK-NEXT: br bb3 // CHECK: } // end sil function 'store_dominates_multiple_case_blocks_trivial' sil [ossa] @store_dominates_multiple_case_blocks_trivial : $@convention(thin) (Optional) -> () { bb0(%0 : $Optional): %1 = alloc_stack $Optional store %0 to [trivial] %1 cond_br undef, bb1, bb2 bb1: %3 = unchecked_take_enum_data_addr %1, #Optional.some!enumelt %4 = load [trivial] %3 fix_lifetime %4 br bb3 bb2: inject_enum_addr %1, #Optional.none!enumelt br bb3 bb3: dealloc_stack %1 %r = tuple () return %r } // CHECK-LABEL: sil [ossa] @store_in_loop : // CHECK: %0 = alloc_stack $C // CHECK: bb1: // CHECK-NEXT: %2 = apply // CHECK: bb2: // CHECK-NEXT: destroy_value %2 // CHECK-NEXT: br bb1 // CHECK: bb3: // CHECK-NEXT: [[P:%.*]] = unchecked_enum_data %2 // CHECK-NEXT: store [[P]] to [init] %0 // CHECK: } // end sil function 'store_in_loop' sil [ossa] @store_in_loop : $@convention(thin) () -> () { bb0: %1 = alloc_stack $Optional br bb1 bb1: %3 = apply undef() : $@convention(thin) () -> @owned Optional store %3 to [init] %1 cond_br undef, bb2, bb3 bb2: destroy_addr %1 br bb1 bb3: %8 = unchecked_take_enum_data_addr %1, #Optional.some!enumelt %9 = load [copy] %8 destroy_value %9 destroy_addr %1 dealloc_stack %1 %r = tuple () return %r } // CHECK-LABEL: sil [ossa] @store_not_in_pred_block : // CHECK: %1 = alloc_stack $Optional // CHECK: } // end sil function 'store_not_in_pred_block' sil [ossa] @store_not_in_pred_block : $@convention(thin) (@owned Optional) -> () { bb0(%0 : @owned $Optional): %1 = alloc_stack $Optional store %0 to [init] %1 cond_br undef, bb1, bb4 bb1: cond_br undef, bb2, bb3 bb2: %3 = unchecked_take_enum_data_addr %1, #Optional.some!enumelt %4 = load [copy] %3 destroy_value %4 destroy_addr %1 br bb5 bb3: destroy_addr %1 br bb5 bb4: destroy_addr %1 br bb5 bb5: dealloc_stack %1 %r = tuple () return %r } // CHECK-LABEL: sil [ossa] @not_a_single_store : // CHECK: %2 = alloc_stack $Optional // CHECK: unchecked_take_enum_data_addr // CHECK: } // end sil function 'not_a_single_store' sil [ossa] @not_a_single_store : $@convention(thin) (@owned Optional, @owned Optional) -> @owned C { bb0(%0 : @owned $Optional, %1 : @owned $Optional): %2 = alloc_stack $Optional store %0 to [init] %2 destroy_addr %2 store %1 to [init] %2 %3 = unchecked_take_enum_data_addr %2, #Optional.some!enumelt %4 = load [take] %3 dealloc_stack %2 return %4 } // CHECK-LABEL: sil [ossa] @store_and_init : // CHECK: %2 = alloc_stack $Optional // CHECK: unchecked_take_enum_data_addr // CHECK: } // end sil function 'store_and_init' sil [ossa] @store_and_init : $@convention(thin) (@owned Optional, @owned C) -> @owned C { bb0(%0 : @owned $Optional, %1 : @owned $C): %2 = alloc_stack $Optional store %0 to [init] %2 destroy_addr %2 %5 = init_enum_data_addr %2, #Optional.some!enumelt store %1 to [init] %5 inject_enum_addr %2, #Optional.some!enumelt %8 = unchecked_take_enum_data_addr %2, #Optional.some!enumelt %9 = load [take] %8 dealloc_stack %2 return %9 } // CHECK-LABEL: sil [ossa] @mismatching_case : // CHECK: %1 = alloc_stack $MP // CHECK: unchecked_take_enum_data_addr // CHECK: unchecked_take_enum_data_addr // CHECK: } // end sil function 'mismatching_case' sil [ossa] @mismatching_case : $@convention(thin) (MP) -> () { bb0(%0 : $MP): %1 = alloc_stack $MP store %0 to [trivial] %1 cond_br undef, bb1, bb2 bb1: %3 = unchecked_take_enum_data_addr %1, #MP.A!enumelt %4 = load [trivial] %3 fix_lifetime %4 br bb3 bb2: %7 = unchecked_take_enum_data_addr %1, #MP.B!enumelt %8 = load [trivial] %7 fix_lifetime %8 br bb3 bb3: dealloc_stack %1 %r = tuple () return %r } // CHECK-LABEL: sil [ossa] @replace_archetype : // CHECK: [[S:%.*]] = alloc_stack [lexical] $T // CHECK: debug_value [[S]] // CHECK: unchecked_addr_cast [[S]] // CHECK: destroy_addr [[S]] // CHECK: } // end sil function 'replace_archetype' sil [ossa] @replace_archetype : $@convention(thin) (@owned T) -> () { bb0(%0 : @owned $T): %1 = metatype $@thick T.Type %2 = init_existential_metatype %1, $@thick P.Type %3 = open_existential_metatype %2 to $@thick (@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", P) Self).Type %4 = alloc_stack [lexical] $@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", P) Self debug_value %4, var, name "x" %5 = unchecked_addr_cast %4 to $*T store %0 to [init] %5 destroy_addr %4 dealloc_stack %4 %r = tuple () return %r } // TODO: we don't support dependent existential archetypes, yet. Once we do, change this test case. // CHECK-LABEL: sil [ossa] @dont_replace_dependent_archetype : // CHECK: alloc_stack {{.*}}@opened // CHECK: } // end sil function 'dont_replace_dependent_archetype' sil [ossa] @dont_replace_dependent_archetype : $@convention(thin) (@owned U.A) -> () { bb0(%0 : @owned $U.A): %1 = metatype $@thick U.Type %2 = init_existential_metatype %1, $@thick Q.Type %3 = open_existential_metatype %2 to $@thick (@opened("82105EE0-DCB0-11E5-865D-C8E0EB309914", Q) Self).Type %4 = alloc_stack $(@opened("82105EE0-DCB0-11E5-865D-C8E0EB309914", Q) Self).A %5 = unchecked_addr_cast %4 to $*U.A store %0 to [init] %5 destroy_addr %4 dealloc_stack %4 %r = tuple () return %r } // CHECK-LABEL: sil [ossa] @replace_existential_with_concrete_type1 : // CHECK: [[S:%.*]] = alloc_stack $T // CHECK-NOT: init_existential_addr // CHECK-NOT: open_existential_addr // CHECK: destroy_addr [[S]] // CHECK: } // end sil function 'replace_existential_with_concrete_type1' sil [ossa] @replace_existential_with_concrete_type1 : $@convention(thin) (@owned T) -> () { bb0(%0 : @owned $T): %5 = alloc_stack $any P %6 = init_existential_addr %5, $T store %0 to [init] %6 %8 = open_existential_addr mutable_access %5 to $*@opened("83DE9694-7315-11E8-955C-ACDE48001122", P) Self destroy_addr %8 dealloc_stack %5 %r = tuple () return %r } // CHECK-LABEL: sil [ossa] @replace_existential_with_concrete_type2 : // CHECK: [[S:%.*]] = alloc_stack $T // CHECK-NOT: init_existential_addr // CHECK-NOT: open_existential_addr // CHECK: store // CHECK: unconditional_checked_cast_addr T in [[S]] to T in %0 // CHECK: destroy_addr [[S]] // CHECK: } // end sil function 'replace_existential_with_concrete_type2' sil [ossa] @replace_existential_with_concrete_type2 : $@convention(thin) (@owned T) -> @out T { bb0(%0 : $*T, %1 : @owned $T): %2 = metatype $@thick T.Type %3 = init_existential_metatype %2, $@thick P.Type %4 = open_existential_metatype %3 to $@thick (@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", P) Self).Type %5 = alloc_stack $any P %6 = init_existential_addr %5, $(@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", P) Self) %7 = unchecked_addr_cast %6 to $*T store %1 to [init] %7 unconditional_checked_cast_addr any P in %5 to T in %0 %8 = open_existential_addr mutable_access %5 to $*@opened("83DE9694-7315-11E8-955C-ACDE48001122", P) Self destroy_addr %8 dealloc_stack %5 %r = tuple () return %r } // CHECK-LABEL: sil [ossa] @replace_existential_with_concrete_type3 : // CHECK: [[S:%.*]] = alloc_stack $T // CHECK-NOT: init_existential_addr // CHECK-NOT: open_existential_addr // CHECK: debug_value undef : $*any P, let, name "value1" // CHECK: destroy_addr [[S]] // CHECK: } // end sil function 'replace_existential_with_concrete_type3' sil_scope 1 { loc "a.swift":1:1 parent @replace_existential_with_concrete_type3 : $@convention(thin) (@owned T) -> () } sil_scope 2 { loc "inlined.swift":1:1 parent @$inlined : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> () inlined_at 1 } sil [ossa] @replace_existential_with_concrete_type3 : $@convention(thin) (@owned T) -> () { bb0(%0 : @owned $T): %5 = alloc_stack $any P debug_value %5, let, name "value1", loc "inlined.swift":1:1, scope 2 %6 = init_existential_addr %5, $T store %0 to [init] %6 %8 = open_existential_addr mutable_access %5 to $*@opened("83DE9694-7315-11E8-955C-ACDE48001122", P) Self destroy_addr %8 dealloc_stack %5 %r = tuple () return %r } // CHECK-LABEL: sil [ossa] @replace_existential_with_archetype : // CHECK: [[S:%.*]] = alloc_stack $@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", any P) Self // CHECK-NOT: init_existential_addr // CHECK-NOT: open_existential_addr // CHECK: checked_cast_addr_br take_always @opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", any P) Self in [[S]] to T in %0, bb1, bb2 // CHECK: } // end sil function 'replace_existential_with_archetype' sil [ossa] @replace_existential_with_archetype : $@convention(thin) (@owned T, @thick P.Type) -> @out T { bb0(%0 : $*T, %1 : @owned $T, %2 : $@thick P.Type): %3 = open_existential_metatype %2 to $@thick (@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", P) Self).Type %4 = alloc_stack $any P %5 = init_existential_addr %4, $(@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", P) Self) %6 = unchecked_addr_cast %5 to $*T store %1 to [init] %6 checked_cast_addr_br take_always any P in %4 to T in %0, bb1, bb2 bb1: dealloc_stack %4 %r = tuple () return %r bb2: dealloc_stack %4 unreachable } // CHECK-LABEL: sil [ossa] @dont_replace_archetype_not_dominating : // CHECK: alloc_stack $any P // CHECK: init_existential_addr // CHECK: open_existential_addr // CHECK: } // end sil function 'dont_replace_archetype_not_dominating' sil [ossa] @dont_replace_archetype_not_dominating : $@convention(thin) (@owned T, @thick P.Type) -> () { bb0(%0 : @owned $T, %1 : $@thick P.Type): %4 = alloc_stack $any P %3 = open_existential_metatype %1 to $@thick (@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", P) Self).Type %5 = init_existential_addr %4, $(@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", P) Self) %6 = unchecked_addr_cast %5 to $*T store %0 to [init] %6 %8 = open_existential_addr mutable_access %4 to $*@opened("83DE9694-7315-11E8-955C-ACDE48001122", P) Self destroy_addr %8 dealloc_stack %4 %r = tuple () return %r } // CHECK-LABEL: sil [ossa] @dont_replace_multiple_inits : // CHECK: [[S:%.*]] = alloc_stack $any P // CHECK: init_existential_addr [[S]], $T1 // CHECK: init_existential_addr [[S]], $T2 // CHECK: open_existential_addr // CHECK: } // end sil function 'dont_replace_multiple_inits' sil [ossa] @dont_replace_multiple_inits : $@convention(thin) (T1, T2) -> () { bb0(%0 : $T1, %1 : $T2): %5 = alloc_stack $any P cond_br undef, bb1, bb2 bb1: %6 = init_existential_addr %5, $T1 store %0 to [trivial] %6 br bb3 bb2: %9 = init_existential_addr %5, $T2 store %1 to [trivial] %9 br bb3 bb3: %8 = open_existential_addr mutable_access %5 to $*@opened("83DE9694-7315-11E8-955C-ACDE48001122", P) Self destroy_addr %8 dealloc_stack %5 %r = tuple () return %r } // CHECK-LABEL: sil [ossa] @init_existential_with_dynamic_self : // CHECK: [[S:%.*]] = alloc_stack $C2 // CHECK: store %0 to [init] [[S]] // CHECK: apply %{{[0-9]+}}([[S]]) // CHECK: } // end sil function 'init_existential_with_dynamic_self' sil [ossa] @init_existential_with_dynamic_self : $@convention(method) (@owned C2) -> () { bb0(%0 : @owned $C2): %1 = alloc_stack $P %2 = init_existential_addr %1, $@dynamic_self C2 store %0 to [init] %2 %4 = function_ref @use_c2 : $@convention(thin) (@in_guaranteed C2) -> () %5 = apply %4(%2) : $@convention(thin) (@in_guaranteed C2) -> () destroy_addr %1 dealloc_stack %1 return %5 } // CHECK-LABEL: sil [ossa] @dont_replace_existential_with_escaping_addr : // CHECK: alloc_stack $any P // CHECK: } // end sil function 'dont_replace_existential_with_escaping_addr' sil [ossa] @dont_replace_existential_with_escaping_addr : $@convention(thin) (@thick V.Type, @owned C2) -> @out V { bb0(%0 : $*V, %1 : $@thick V.Type, %2 : @owned $C2): %114 = alloc_stack $any P %117 = init_existential_addr %114, $C2 store %2 to [init] %117 %129 = unchecked_addr_cast %114 to $*V copy_addr %129 to [init] %0 destroy_addr %114 dealloc_stack %114 %137 = tuple () return %137 }