mirror of
https://github.com/apple/swift.git
synced 2026-02-27 18:26:24 +01:00
Rewrite the enum -> single payload optimization to handle non-destructive `unchecked_take_enum_data_addr` correctly. Also, we can handle more cases now.
816 lines
24 KiB
Plaintext
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
|
|
}
|