Files
swift-mirror/test/SILOptimizer/simplify_alloc_stack.sil
Erik Eckstein 95d300c062 SimplifyAllocStack: support non-destructive enums and other improvements
Rewrite the enum -> single payload optimization to handle non-destructive `unchecked_take_enum_data_addr` correctly.
Also, we can handle more cases now.
2026-02-11 06:43:46 +01:00

816 lines
24 KiB
Plaintext

// 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<T>
// 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<T>
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<C>) -> @owned C {
bb0(%0 : @owned $Optional<C>):
%1 = alloc_stack $Optional<C>
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<C>
// CHECK: } // end sil function 'store_and_overlapping_inject'
sil [ossa] @store_and_overlapping_inject : $@convention(thin) (@guaranteed Optional<C>) -> () {
bb0(%0 : @guaranteed $Optional<C>):
%1 = alloc_stack $Optional<C>
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<C>
// CHECK: } // end sil function 'inject_diamond'
sil [ossa] @inject_diamond : $@convention(thin) () -> @out C {
bb0(%0 : $*C):
%1 = alloc_stack $Optional<C>
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<C>
// 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<C>) -> () {
bb0(%0 : @owned $Optional<C>):
%1 = alloc_stack $Optional<C>
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<C>) -> () {
bb0(%0 : @owned $Optional<C>):
%1 = alloc_stack $Optional<C>
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<Int>) -> () {
bb0(%0 : $Optional<Int>):
%1 = alloc_stack $Optional<Int>
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<C>
br bb1
bb1:
%3 = apply undef() : $@convention(thin) () -> @owned Optional<C>
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<C>
// CHECK: } // end sil function 'store_not_in_pred_block'
sil [ossa] @store_not_in_pred_block : $@convention(thin) (@owned Optional<C>) -> () {
bb0(%0 : @owned $Optional<C>):
%1 = alloc_stack $Optional<C>
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<C>
// CHECK: unchecked_take_enum_data_addr
// CHECK: } // end sil function 'not_a_single_store'
sil [ossa] @not_a_single_store : $@convention(thin) (@owned Optional<C>, @owned Optional<C>) -> @owned C {
bb0(%0 : @owned $Optional<C>, %1 : @owned $Optional<C>):
%2 = alloc_stack $Optional<C>
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<C>
// CHECK: unchecked_take_enum_data_addr
// CHECK: } // end sil function 'store_and_init'
sil [ossa] @store_and_init : $@convention(thin) (@owned Optional<C>, @owned C) -> @owned C {
bb0(%0 : @owned $Optional<C>, %1 : @owned $C):
%2 = alloc_stack $Optional<C>
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) <V> (@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
}