mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
1158 lines
44 KiB
Plaintext
1158 lines
44 KiB
Plaintext
// RUN: %target-sil-opt -address-lowering -enable-sil-opaque-values -emit-sorted-sil -module-name Swift -sil-verify-all %s | %FileCheck %s
|
|
//
|
|
// Test the PhiStorageOptimizer within the AddressLowering pass.
|
|
|
|
import Builtin
|
|
|
|
sil_stage raw
|
|
|
|
protocol Error {}
|
|
|
|
typealias AnyObject = Builtin.AnyObject
|
|
typealias Int = Builtin.Int64
|
|
typealias Bool = Builtin.Int1
|
|
|
|
enum Optional<T> {
|
|
case none
|
|
case some(T)
|
|
}
|
|
|
|
struct S {}
|
|
|
|
struct SRef<T> {
|
|
@_hasStorage var object: AnyObject { get set }
|
|
@_hasStorage var element: T { get set }
|
|
init(object: AnyObject, element: T)
|
|
}
|
|
|
|
enum InnerEnum<T> {
|
|
case payload(T, AnyObject)
|
|
}
|
|
enum OuterEnum<T> {
|
|
case inner(InnerEnum<T>, AnyObject)
|
|
}
|
|
|
|
struct Box<T> {
|
|
var t: T
|
|
}
|
|
|
|
struct InnerStruct<T> {
|
|
var t: T
|
|
var object: AnyObject
|
|
}
|
|
struct OuterStruct<T> {
|
|
var inner: InnerStruct<T>
|
|
var object: AnyObject
|
|
}
|
|
|
|
struct Pair<T> {
|
|
var x: T
|
|
var y: T
|
|
}
|
|
|
|
sil [ossa] @getOut : $@convention(thin) <T> () -> @out T
|
|
|
|
// Test BBArgs allocation.
|
|
|
|
// No projection from incoming values. No interference.
|
|
// CHECK-LABEL: sil [ossa] @f010_testBBArgSelect : $@convention(thin) <T> () -> @out T {
|
|
// CHECK: bb0(%0 : $*T):
|
|
// CHECK: [[F:%.*]] = function_ref @getOut : $@convention(thin) <τ_0_0> () -> @out τ_0_0
|
|
// CHECK: cond_br undef, bb2, bb1
|
|
// CHECK: bb1:
|
|
// CHECK: [[GET0:%.*]] = apply [[F]]<T>(%0) : $@convention(thin) <τ_0_0> () -> @out τ_0_0
|
|
// CHECK: br bb3
|
|
// CHECK: bb2:
|
|
// CHECK: [[GET1:%.*]] = apply [[F]]<T>(%0) : $@convention(thin) <τ_0_0> () -> @out τ_0_0
|
|
// CHECK: br bb3
|
|
// CHECK: bb3:
|
|
// CHECK: %{{.*}} = tuple ()
|
|
// CHECK: return %{{.*}} : $()
|
|
// CHECK-LABEL: } // end sil function 'f010_testBBArgSelect'
|
|
sil [ossa] @f010_testBBArgSelect : $@convention(thin) <T> () -> @out T {
|
|
bb0:
|
|
%get = function_ref @getOut : $@convention(thin) <τ_0_0>() -> @out τ_0_0
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%get0 = apply %get<T>() : $@convention(thin) <τ_0_0>() -> @out τ_0_0
|
|
br bb3(%get0 : $T)
|
|
|
|
bb2:
|
|
%get1 = apply %get<T>() : $@convention(thin) <τ_0_0>() -> @out τ_0_0
|
|
br bb3(%get1 : $T)
|
|
|
|
// %15
|
|
bb3(%15 : @owned $T):
|
|
return %15 : $T
|
|
}
|
|
|
|
// Double use projection without interference.
|
|
// CHECK-LABEL: sil [ossa] @f011_testBBArgSelect_useProjection : $@convention(thin) <T> () -> () {
|
|
// CHECK: [[STACK:%[^,]+]] = alloc_stack $Optional<T>
|
|
// CHECK: cond_br undef, [[RIGHT:bb[0-9]+]], [[LEFT:bb[0-9]+]]
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: [[LEFT_ADDR:%[^,]+]] = init_enum_data_addr [[STACK]]
|
|
// CHECK: apply {{%[^,]+}}<T>([[LEFT_ADDR]])
|
|
// CHECK: inject_enum_addr [[STACK]]
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: [[RIGHT_ADDR:%[^,]+]] = init_enum_data_addr [[STACK]]
|
|
// CHECK: apply {{%[^,]+}}<T>([[RIGHT_ADDR]])
|
|
// CHECK: inject_enum_addr [[STACK]]
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK: destroy_addr [[STACK]]
|
|
// CHECK: dealloc_stack [[STACK]]
|
|
// CHECK-LABEL: } // end sil function 'f011_testBBArgSelect_useProjection'
|
|
sil [ossa] @f011_testBBArgSelect_useProjection : $@convention(thin) <T> () -> () {
|
|
entry:
|
|
%get = function_ref @getOut : $@convention(thin) <τ_0_0>() -> @out τ_0_0
|
|
cond_br undef, left, right
|
|
left:
|
|
%left = apply %get<T>() : $@convention(thin) <T> () -> (@out T)
|
|
%forward = enum $Optional<T>, #Optional.some, %left : $T
|
|
br exit(%forward : $Optional<T>)
|
|
right:
|
|
%right = apply %get<T>() : $@convention(thin) <T> () -> (@out T)
|
|
%backward = enum $Optional<T>, #Optional.some, %right : $T
|
|
br exit(%backward : $Optional<T>)
|
|
exit(%box : @owned $Optional<T>):
|
|
destroy_value %box : $Optional<T>
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Double use projection + interference.
|
|
// CHECK-LABEL: sil [ossa] @f012_testBBArgSelect_useProjection_oneInterference : $@convention(thin) <T> () -> () {
|
|
// CHECK: [[LEFT_OUTER:%[^,]+]] = alloc_stack $Optional<T>
|
|
// CHECK: [[LEFT_ADDR:%[^,]+]] = init_enum_data_addr [[LEFT_OUTER]]
|
|
// CHECK: apply {{%[^,]+}}<T>([[LEFT_ADDR]])
|
|
// CHECK: [[PHI_ADDR:%[^,]+]] = alloc_stack $Optional<T>
|
|
// CHECK: [[RIGHT_ADDR:%[^,]+]] = init_enum_data_addr [[PHI_ADDR]]
|
|
// CHECK: apply {{%[^,]+}}<T>([[RIGHT_ADDR]])
|
|
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: destroy_addr [[LEFT_ADDR]]
|
|
// CHECK: inject_enum_addr [[PHI_ADDR]]
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: destroy_addr [[RIGHT_ADDR]]
|
|
// CHECK: inject_enum_addr [[LEFT_OUTER]]
|
|
// CHECK: copy_addr [take] [[LEFT_OUTER]] to [init] [[PHI_ADDR]]
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK: destroy_addr [[PHI_ADDR]]
|
|
// CHECK: dealloc_stack [[PHI_ADDR]]
|
|
// CHECK: dealloc_stack [[LEFT_OUTER]]
|
|
// CHECK-LABEL: } // end sil function 'f012_testBBArgSelect_useProjection_oneInterference'
|
|
sil [ossa] @f012_testBBArgSelect_useProjection_oneInterference : $@convention(thin) <T> () -> () {
|
|
entry:
|
|
%get = function_ref @getOut : $@convention(thin) <τ_0_0>() -> @out τ_0_0
|
|
%left = apply %get<T>() : $@convention(thin) <T> () -> (@out T)
|
|
%right = apply %get<T>() : $@convention(thin) <T> () -> (@out T)
|
|
cond_br undef, left, right
|
|
left:
|
|
destroy_value %right : $T
|
|
%forward = enum $Optional<T>, #Optional.some, %left : $T
|
|
br exit(%forward : $Optional<T>)
|
|
right:
|
|
destroy_value %left : $T
|
|
%backward = enum $Optional<T>, #Optional.some, %right : $T
|
|
br exit(%backward : $Optional<T>)
|
|
exit(%box : @owned $Optional<T>):
|
|
destroy_value %box : $Optional<T>
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @f013_testBBArgSelect_useProjections_interference : {{.*}} {
|
|
// CHECK: [[S2_ADDR:%[^,]+]] = alloc_stack $Box<T>
|
|
// CHECK: [[PHI_ADDR:%[^,]+]] = alloc_stack $Box<T>
|
|
// CHECK: [[T_ADDR:%[^,]+]] = struct_element_addr [[PHI_ADDR]] : $*Box<T>, #Box.t
|
|
// CHECK: apply undef<T>([[T_ADDR]])
|
|
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: br [[MERGE:bb[0-9]+]]
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: [[S2_FIELD_ADDR:%[^,]+]] = struct_element_addr [[S2_ADDR]] : $*Box<T>, #Box.t
|
|
// CHECK: copy_addr [take] [[T_ADDR]] to [init] [[S2_FIELD_ADDR]]
|
|
// CHECK: copy_addr [take] [[S2_ADDR]] to [init] [[PHI_ADDR]]
|
|
// CHECK: br [[MERGE]]
|
|
// CHECK: [[MERGE]]:
|
|
// CHECK: apply undef<Box<T>>([[PHI_ADDR]])
|
|
// CHECK: destroy_addr [[PHI_ADDR]]
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK: dealloc_stack [[PHI_ADDR]]
|
|
// CHECK: dealloc_stack [[S2_ADDR]]
|
|
// CHECK-LABEL: } // end sil function 'f013_testBBArgSelect_useProjections_interference'
|
|
sil [ossa] @f013_testBBArgSelect_useProjections_interference : $@convention(thin) <T> () -> () {
|
|
entry:
|
|
%t = apply undef<T>() : $@convention(thin) <T> () -> (@out T)
|
|
cond_br undef, left, right
|
|
|
|
left:
|
|
%s2 = struct $Box<T>(%t : $T)
|
|
br merge(%s2 : $Box<T>)
|
|
|
|
right:
|
|
%s = struct $Box<T>(%t : $T)
|
|
br merge(%s : $Box<T>)
|
|
|
|
merge(%tb : @owned $Box<T>):
|
|
apply undef<Box<T>>(%tb) : $@convention(thin) <T> (@in_guaranteed T) -> ()
|
|
destroy_value %tb : $Box<T>
|
|
br exit
|
|
|
|
exit:
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// One projection from incoming values. One interference.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @f020_testBBArgProjectOne : $@convention(thin) <T> () -> @out T {
|
|
// CHECK: bb0(%0 : $*T):
|
|
// CHECK: [[ALLOC:%.*]] = alloc_stack $T
|
|
// CHECK: apply %{{.*}}<T>(%0) : $@convention(thin) <τ_0_0> () -> @out τ_0_0
|
|
// CHECK: apply %{{.*}}<T>([[ALLOC]]) : $@convention(thin) <τ_0_0> () -> @out τ_0_0
|
|
// CHECK: cond_br undef, bb2, bb1
|
|
// CHECK: bb1:
|
|
// CHECK: destroy_addr %0 : $*T
|
|
// CHECK: copy_addr [take] %1 to [init] %0 : $*T
|
|
// CHECK: br bb3
|
|
// CHECK: bb2:
|
|
// CHECK: destroy_addr %1 : $*T
|
|
// CHECK: br bb3
|
|
// CHECK: bb3:
|
|
// CHECK: dealloc_stack [[ALLOC]] : $*T
|
|
// CHECK: return %{{.*}} : $()
|
|
// CHECK-LABEL: } // end sil function 'f020_testBBArgProjectOne'
|
|
sil [ossa] @f020_testBBArgProjectOne : $@convention(thin) <T> () -> @out T {
|
|
bb0:
|
|
%get = function_ref @getOut : $@convention(thin) <τ_0_0>() -> @out τ_0_0
|
|
%get0 = apply %get<T>() : $@convention(thin) <τ_0_0>() -> @out τ_0_0
|
|
%get1 = apply %get<T>() : $@convention(thin) <τ_0_0>() -> @out τ_0_0
|
|
cond_br undef, bb2, bb1
|
|
|
|
bb1:
|
|
destroy_value %get0 : $T
|
|
br bb3(%get1 : $T)
|
|
|
|
bb2:
|
|
destroy_value %get1 : $T
|
|
br bb3(%get0 : $T)
|
|
|
|
bb3(%arg : @owned $T):
|
|
return %arg : $T
|
|
}
|
|
|
|
// Projection from incoming values. No interference.
|
|
// CHECK-LABEL: sil [ossa] @f030_testBBArgProjectIn : $@convention(thin) <T> (@in T, @in T) -> @out T {
|
|
// CHECK: bb0(%0 : $*T, %1 : $*T, %2 : $*T):
|
|
// CHECK: cond_br undef, bb2, bb1
|
|
// CHECK: bb1:
|
|
// CHECK: destroy_addr %2 : $*T
|
|
// CHECK: copy_addr [take] %1 to [init] %0 : $*T
|
|
// CHECK: br bb3
|
|
// CHECK: bb2:
|
|
// CHECK: destroy_addr %1 : $*T
|
|
// CHECK: copy_addr [take] %2 to [init] %0 : $*T
|
|
// CHECK: br bb3
|
|
// CHECK: bb3:
|
|
// CHECK-LABEL: } // end sil function 'f030_testBBArgProjectIn'
|
|
sil [ossa] @f030_testBBArgProjectIn : $@convention(thin) <T> (@in T, @in T) -> @out T {
|
|
bb0(%0 : @owned $T, %1 : @owned $T):
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
destroy_value %0 : $T
|
|
br bb3(%1 : $T)
|
|
|
|
bb2:
|
|
destroy_value %1 : $T
|
|
br bb3(%0 : $T)
|
|
|
|
bb3(%arg : @owned $T):
|
|
return %arg : $T
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @f040_testInSwapOut : $@convention(thin) <T> (@in T, @in T) -> (@out T, @out T) {
|
|
// CHECK: bb0(%0 : $*T, %1 : $*T, %2 : $*T, %3 : $*T):
|
|
// CHECK: cond_br undef, bb2, bb1
|
|
// CHECK: bb1:
|
|
// CHECK: copy_addr [take] %2 to [init] %1 : $*T
|
|
// CHECK: copy_addr [take] %3 to [init] %0 : $*T
|
|
// CHECK: br bb3
|
|
// CHECK: bb2:
|
|
// CHECK: copy_addr [take] %2 to [init] %0 : $*T
|
|
// CHECK: copy_addr [take] %3 to [init] %1 : $*T
|
|
// CHECK: br bb3
|
|
// CHECK-LABEL: } // end sil function 'f040_testInSwapOut'
|
|
sil [ossa] @f040_testInSwapOut : $@convention(thin) <T> (@in T, @in T) -> (@out T, @out T) {
|
|
bb0(%0 : @owned $T, %1 : @owned $T):
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
br bb3(%0 : $T, %1 : $T)
|
|
|
|
bb2:
|
|
br bb3(%1 : $T, %0 : $T)
|
|
|
|
bb3(%arg0 : @owned $T, %arg1 : @owned $T):
|
|
%result = tuple (%arg0 : $T, %arg1 : $T)
|
|
return %result : $(T, T)
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @f050_testCombine : $@convention(thin) <T> (@in T, @in T) -> (@out T, @out T) {
|
|
// CHECK: bb0(%0 : $*T, %1 : $*T, %2 : $*T, %3 : $*T):
|
|
// CHECK: cond_br undef, bb2, bb1
|
|
// CHECK: bb1:
|
|
// CHECK: copy_addr [take] %2 to [init] %0 : $*T
|
|
// CHECK: copy_addr [take] %3 to [init] %1 : $*T
|
|
// CHECK: br bb3
|
|
// CHECK: bb2:
|
|
// CHECK: copy_addr %2 to [init] %1 : $*T
|
|
// CHECK: destroy_addr %3 : $*T
|
|
// CHECK: copy_addr [take] %2 to [init] %0 : $*T
|
|
// CHECK: br bb3
|
|
// CHECK: bb3:
|
|
// CHECK-LABEL: } // end sil function 'f050_testCombine'
|
|
sil [ossa] @f050_testCombine : $@convention(thin) <T> (@in T, @in T) -> (@out T, @out T) {
|
|
bb0(%0 : @owned $T, %1 : @owned $T):
|
|
cond_br undef, bb2, bb1
|
|
|
|
bb1:
|
|
br bb3(%0 : $T, %1 : $T)
|
|
|
|
bb2:
|
|
%copy = copy_value %0 : $T
|
|
destroy_value %1 : $T
|
|
br bb3(%0 : $T, %copy : $T)
|
|
|
|
bb3(%arg0 : @owned $T, %arg1 : @owned $T):
|
|
%result = tuple (%arg0 : $T, %arg1 : $T)
|
|
return %result : $(T, T)
|
|
}
|
|
|
|
// Test cyclic anti-dependence on phi copies.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @f060_testInoutSwap : $@convention(thin) <T> (@inout T, @inout T) -> () {
|
|
// CHECK: bb0(%0 : $*T, %1 : $*T):
|
|
// CHECK: [[ALLOC1:%.*]] = alloc_stack $T
|
|
// CHECK: copy_addr [take] %0 to [init] [[ALLOC1]] : $*T
|
|
// CHECK: [[ALLOC0:%.*]] = alloc_stack $T
|
|
// CHECK: copy_addr [take] %1 to [init] [[ALLOC0]] : $*T
|
|
// CHECK: cond_br undef, bb2, bb1
|
|
// CHECK: bb1:
|
|
// CHECK: [[TMP:%.*]] = alloc_stack $T
|
|
// CHECK: copy_addr [take] [[ALLOC0]] to [init] [[TMP]] : $*T
|
|
// CHECK: copy_addr [take] [[ALLOC1]] to [init] [[ALLOC0]] : $*T
|
|
// CHECK: copy_addr [take] [[TMP]] to [init] [[ALLOC1]] : $*T
|
|
// CHECK: dealloc_stack [[TMP]] : $*T
|
|
// CHECK: br bb3
|
|
// CHECK: bb2:
|
|
// CHECK: br bb3
|
|
// CHECK: bb3:
|
|
// CHECK: copy_addr [take] [[ALLOC0]] to [init] %0 : $*T
|
|
// CHECK: copy_addr [take] [[ALLOC1]] to [init] %1 : $*T
|
|
// CHECK: dealloc_stack [[ALLOC0]] : $*T
|
|
// CHECK: dealloc_stack [[ALLOC1]] : $*T
|
|
// CHECK-LABEL: } // end sil function 'f060_testInoutSwap'
|
|
sil [ossa] @f060_testInoutSwap : $@convention(thin) <T> (@inout T, @inout T) -> () {
|
|
bb0(%0 : $*T, %1 : $*T):
|
|
%2 = load [take] %0 : $*T
|
|
%3 = load [take] %1 : $*T
|
|
cond_br undef, bb2, bb1
|
|
|
|
bb1:
|
|
br bb3(%2 : $T, %3 : $T)
|
|
|
|
bb2:
|
|
br bb3(%3 : $T, %2 : $T)
|
|
|
|
bb3(%phi0 : @owned $T, %phi1 : @owned $T):
|
|
store %phi0 to [init] %0 : $*T
|
|
store %phi1 to [init] %1 : $*T
|
|
%99 = tuple ()
|
|
return %99 : $()
|
|
}
|
|
|
|
// Test phi copies that project into their use.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @f070_testInoutFieldSwap : $@convention(thin) <T> (@inout SRef<T>, @inout SRef<T>) -> () {
|
|
// CHECK: bb0(%0 : $*SRef<T>, %1 : $*SRef<T>):
|
|
// CHECK: [[ALLOCA:%.*]] = alloc_stack $SRef<T>
|
|
// CHECK: [[ALLOCB:%.*]] = alloc_stack $SRef<T>
|
|
// CHECK: [[ALLOCSA:%.*]] = alloc_stack $SRef<T>
|
|
// CHECK: [[ALLOCSB:%.*]] = alloc_stack $SRef<T>
|
|
// CHECK: copy_addr [take] %0 to [init] [[ALLOCA]] : $*SRef<T>
|
|
// CHECK: copy_addr [take] %1 to [init] [[ALLOCB]] : $*SRef<T>
|
|
// CHECK: cond_br undef, bb2, bb1
|
|
// CHECK: bb1:
|
|
// CHECK: [[A1OADR:%.*]] = struct_element_addr [[ALLOCA]] : $*SRef<T>, #SRef.object
|
|
// CHECK: [[A1O:%.*]] = load [take] [[A1OADR]] : $*AnyObject
|
|
// CHECK: [[B1OADR:%.*]] = struct_element_addr [[ALLOCB]] : $*SRef<T>, #SRef.object
|
|
// CHECK: [[B1O:%.*]] = load [take] [[B1OADR]] : $*AnyObject
|
|
// CHECK: destroy_value [[B1O]] : $AnyObject
|
|
// CHECK: [[CP1:%.*]] = copy_value [[A1O]] : $AnyObject
|
|
// CHECK: [[SA1EADR:%.*]] = struct_element_addr [[ALLOCSA]] : $*SRef<T>, #SRef.element
|
|
// CHECK: [[A1EADR:%.*]] = struct_element_addr [[ALLOCA]] : $*SRef<T>, #SRef.element
|
|
// CHECK: copy_addr [take] [[A1EADR]] to [init] [[SA1EADR]] : $*T
|
|
// CHECK: [[SB1EADR:%.*]] = struct_element_addr [[ALLOCSB]] : $*SRef<T>, #SRef.element
|
|
// CHECK: [[B1EADR:%.*]] = struct_element_addr [[ALLOCB]] : $*SRef<T>, #SRef.element
|
|
// CHECK: copy_addr [take] [[B1EADR]] to [init] [[SB1EADR]] : $*T
|
|
// CHECK: br bb3([[A1O]] : $AnyObject, [[CP1]] : $AnyObject)
|
|
// CHECK: bb2:
|
|
// CHECK: [[A2OADR:%.*]] = struct_element_addr [[ALLOCA]] : $*SRef<T>, #SRef.object
|
|
// CHECK: [[A2O:%.*]] = load [take] [[A2OADR]] : $*AnyObject
|
|
// CHECK: [[B2OADR:%.*]] = struct_element_addr [[ALLOCB]] : $*SRef<T>, #SRef.object
|
|
// CHECK: [[B2O:%.*]] = load [take] [[B2OADR]] : $*AnyObject
|
|
// CHECK: destroy_value [[B2O]] : $AnyObject
|
|
// CHECK: [[CP2:%.*]] = copy_value [[A2O]] : $AnyObject
|
|
// CHECK: [[SB2EADR:%.*]] = struct_element_addr [[ALLOCSB]] : $*SRef<T>, #SRef.element
|
|
// CHECK: [[A2EADR:%.*]] = struct_element_addr [[ALLOCA]] : $*SRef<T>, #SRef.element
|
|
// CHECK: copy_addr [take] [[A2EADR]] to [init] [[SB2EADR]] : $*T
|
|
// CHECK: [[SA2EADR:%.*]] = struct_element_addr [[ALLOCSA]] : $*SRef<T>, #SRef.element
|
|
// CHECK: [[B2EADR:%.*]] = struct_element_addr [[ALLOCB]] : $*SRef<T>, #SRef.element
|
|
// CHECK: copy_addr [take] [[B2EADR]] to [init] [[SA2EADR]] : $*T
|
|
// CHECK: br bb3([[A2O]] : $AnyObject, [[CP2]] : $AnyObject)
|
|
// CHECK: bb3([[PHI0:%.*]] : @owned $AnyObject, [[PHI1:%.*]] : @owned $AnyObject):
|
|
// CHECK: [[SA3EADR:%.*]] = struct_element_addr [[ALLOCSA]] : $*SRef<T>, #SRef.object
|
|
// CHECK: store [[PHI0]] to [init] [[SA3EADR]] : $*AnyObject
|
|
// CHECK: [[SB3EADR:%.*]] = struct_element_addr [[ALLOCSB]] : $*SRef<T>, #SRef.object
|
|
// CHECK: store [[PHI1]] to [init] [[SB3EADR]] : $*AnyObject
|
|
// CHECK: copy_addr [take] [[ALLOCSA]] to [init] %0 : $*SRef<T>
|
|
// CHECK: copy_addr [take] [[ALLOCSB]] to [init] %1 : $*SRef<T>
|
|
// CHECK-LABEL: } // end sil function 'f070_testInoutFieldSwap'
|
|
sil [ossa] @f070_testInoutFieldSwap : $@convention(thin) <T> (@inout SRef<T>, @inout SRef<T>) -> () {
|
|
bb0(%0 : $*SRef<T>, %1 : $*SRef<T>):
|
|
%la = load [take] %0 : $*SRef<T>
|
|
%lb = load [take] %1 : $*SRef<T>
|
|
cond_br undef, bb2, bb1
|
|
|
|
bb1:
|
|
(%da1o, %da1e) = destructure_struct %la : $SRef<T>
|
|
(%db1o, %db1e) = destructure_struct %lb : $SRef<T>
|
|
destroy_value %db1o : $AnyObject
|
|
%ca1o = copy_value %da1o : $AnyObject
|
|
br bb3(%da1o : $AnyObject, %ca1o : $AnyObject, %da1e : $T, %db1e : $T)
|
|
|
|
bb2:
|
|
(%da2o, %da2e) = destructure_struct %la : $SRef<T>
|
|
(%db2o, %db2e) = destructure_struct %lb : $SRef<T>
|
|
destroy_value %db2o : $AnyObject
|
|
%ca2o = copy_value %da2o : $AnyObject
|
|
br bb3(%da2o : $AnyObject, %ca2o : $AnyObject, %db2e : $T, %da2e : $T)
|
|
|
|
bb3(%phio0 : @owned $AnyObject, %phio1 : @owned $AnyObject, %phie0 : @owned $T, %phie1 : @owned $T):
|
|
%sa = struct $SRef<T> (%phio0 : $AnyObject, %phie0 : $T)
|
|
%sb = struct $SRef<T> (%phio1 : $AnyObject, %phie1 : $T)
|
|
store %sa to [init] %0 : $*SRef<T>
|
|
store %sb to [init] %1 : $*SRef<T>
|
|
%99 = tuple ()
|
|
return %99 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @f080_testNestedComposeEnumPhi : $@convention(thin) <T> (@in T, @in T, @owned AnyObject, @owned AnyObject) -> @out OuterEnum<T> {
|
|
// CHECK: bb0(%0 : $*OuterEnum<T>, %1 : $*T, %2 : $*T, %3 : @owned $AnyObject, %4 : @owned $AnyObject):
|
|
// CHECK: cond_br undef, bb2, bb1
|
|
// CHECK: bb1:
|
|
// CHECK: destroy_addr %2 : $*T
|
|
// CHECK: [[TUPLE1:%.*]] = init_enum_data_addr [[INNER1:%.*]] : $*InnerEnum<T>, #InnerEnum.payload!enumelt
|
|
// CHECK: [[TUPLE1_0:%.*]] = tuple_element_addr [[TUPLE1]] : $*(T, AnyObject), 0
|
|
// CHECK: copy_addr [take] %1 to [init] [[TUPLE1_0]] : $*T
|
|
// CHECK: [[TUPLE1_1:%.*]] = tuple_element_addr [[TUPLE1]] : $*(T, AnyObject), 1
|
|
// CHECK: store %3 to [init] [[TUPLE1_1]] : $*AnyObject
|
|
// CHECK: inject_enum_addr [[INNER1]] : $*InnerEnum<T>, #InnerEnum.payload!enumelt
|
|
// CHECK: br bb6
|
|
// CHECK: bb2:
|
|
// CHECK: cond_br undef, bb4, bb3
|
|
// CHECK: bb3:
|
|
// CHECK: destroy_addr %1 : $*T
|
|
// CHECK: copy_addr [take] %2 to [init] [[PHI5:%.*]] : $*T
|
|
// CHECK: br bb5
|
|
// CHECK: bb4:
|
|
// CHECK: destroy_addr %2 : $*T
|
|
// CHECK: copy_addr [take] %1 to [init] [[PHI5]] : $*T
|
|
// CHECK: br bb5
|
|
// CHECK: bb5:
|
|
// CHECK: [[TUPLE5:%.*]] = init_enum_data_addr [[INNER5:%.*]] : $*InnerEnum<T>, #InnerEnum.payload!enumelt
|
|
// CHECK: [[TUPLE5_0:%.*]] = tuple_element_addr [[TUPLE5]] : $*(T, AnyObject), 0
|
|
// CHECK: copy_addr [take] [[PHI5]] to [init] [[TUPLE5_0]] : $*T
|
|
// CHECK: [[TUPLE5_1:%.*]] = tuple_element_addr [[TUPLE5]] : $*(T, AnyObject), 1
|
|
// CHECK: store %3 to [init] [[TUPLE5_1]] : $*AnyObject
|
|
// CHECK: inject_enum_addr [[INNER5]] : $*InnerEnum<T>, #InnerEnum.payload!enumelt
|
|
// CHECK: br bb6
|
|
// CHECK: bb6:
|
|
// CHECK: [[TUPLE6:%.*]] = init_enum_data_addr %0 : $*OuterEnum<T>, #OuterEnum.inner!enumelt
|
|
// CHECK: [[TUPLE6_0:%.*]] = tuple_element_addr [[TUPLE6]] : $*(InnerEnum<T>, AnyObject), 0
|
|
// CHECK: copy_addr [take] [[INNER1]] to [init] [[TUPLE6_0]] : $*InnerEnum<T>
|
|
// CHECK: [[TUPLE6_1:%.*]] = tuple_element_addr [[TUPLE6]] : $*(InnerEnum<T>, AnyObject), 1
|
|
// CHECK: store %4 to [init] [[TUPLE6_1]] : $*AnyObject
|
|
// CHECK: inject_enum_addr %0 : $*OuterEnum<T>, #OuterEnum.inner!enumelt
|
|
// CHECK-LABEL: } // end sil function 'f080_testNestedComposeEnumPhi'
|
|
sil [ossa] @f080_testNestedComposeEnumPhi : $@convention(thin) <T> (@in T, @in T, @owned AnyObject, @owned AnyObject) -> @out OuterEnum<T> {
|
|
bb0(%0 : @owned $T, %1 : @owned $T, %2 : @owned $AnyObject, %3 : @owned $AnyObject):
|
|
cond_br undef, bb2, bb1
|
|
bb1:
|
|
destroy_value %1 : $T
|
|
%tuple1 = tuple (%0 : $T, %2 : $AnyObject)
|
|
%inner1 = enum $InnerEnum<T>, #InnerEnum.payload, %tuple1 : $(T, AnyObject)
|
|
br bb6(%inner1 : $InnerEnum<T>)
|
|
bb2:
|
|
cond_br undef, bb4, bb3
|
|
bb3:
|
|
destroy_value %0 : $T
|
|
br bb5(%1 : $T)
|
|
bb4:
|
|
destroy_value %1 : $T
|
|
br bb5(%0 : $T)
|
|
bb5(%phi5 : @owned $T):
|
|
%tuple5 = tuple (%phi5 : $T, %2 : $AnyObject)
|
|
%inner5 = enum $InnerEnum<T>, #InnerEnum.payload, %tuple5 : $(T, AnyObject)
|
|
br bb6(%inner5 : $InnerEnum<T>)
|
|
bb6(%phi6 : @owned $InnerEnum<T>):
|
|
%tuple6 = tuple (%phi6 : $InnerEnum<T>, %3 : $AnyObject)
|
|
%outer = enum $OuterEnum<T>, #OuterEnum.inner, %tuple6 : $(InnerEnum<T>, AnyObject)
|
|
return %outer : $OuterEnum<T>
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @f080_testNestedComposeStructWithPhi : $@convention(thin) <T> (@in T, @in T, @owned AnyObject, @owned AnyObject) -> @out OuterStruct<T> {
|
|
// CHECK: bb0(%0 : $*OuterStruct<T>, %1 : $*T, %2 : $*T, %3 : @owned $AnyObject, %4 : @owned $AnyObject):
|
|
// CHECK-NOT: alloc
|
|
// CHECK: cond_br undef, bb2, bb1
|
|
// CHECK: bb1:
|
|
// CHECK: destroy_addr %2 : $*T
|
|
// CHECK: [[INNER1:%.*]] = struct_element_addr %0 : $*OuterStruct<T>, #OuterStruct.inner
|
|
// CHECK: [[T2:%.*]] = struct_element_addr [[INNER1]] : $*InnerStruct<T>, #InnerStruct.t
|
|
// CHECK: copy_addr [take] %1 to [init] [[T2]] : $*T
|
|
// CHECK: [[O2:%.*]] = struct_element_addr [[INNER1]] : $*InnerStruct<T>, #InnerStruct.object
|
|
// CHECK: store %3 to [init] [[O2]] : $*AnyObject
|
|
// CHECK: br bb6
|
|
// CHECK: bb2:
|
|
// CHECK: cond_br undef, bb4, bb3
|
|
// CHECK: bb3:
|
|
// CHECK: destroy_addr %1 : $*T
|
|
// CHECK: [[INNER3:%.*]] = struct_element_addr %0 : $*OuterStruct<T>, #OuterStruct.inner
|
|
// CHECK: [[T3:%.*]] = struct_element_addr [[INNER3]] : $*InnerStruct<T>, #InnerStruct.t
|
|
// CHECK: copy_addr [take] %2 to [init] [[T3]] : $*T
|
|
// CHECK: br bb5
|
|
// CHECK: bb4:
|
|
// CHECK: destroy_addr %2 : $*T
|
|
// CHECK: [[INNER4:%.*]] = struct_element_addr %0 : $*OuterStruct<T>, #OuterStruct.inner
|
|
// CHECK: [[T4:%.*]] = struct_element_addr [[INNER4]] : $*InnerStruct<T>, #InnerStruct.t
|
|
// CHECK: copy_addr [take] %1 to [init] [[T4]] : $*T
|
|
// CHECK: br bb5
|
|
// CHECK: bb5:
|
|
// CHECK: [[INNER5:%.*]] = struct_element_addr %0 : $*OuterStruct<T>, #OuterStruct.inner
|
|
// CHECK: [[O5:%.*]] = struct_element_addr [[INNER5]] : $*InnerStruct<T>, #InnerStruct.object
|
|
// CHECK: store %3 to [init] [[O5]] : $*AnyObject
|
|
// CHECK: br bb6
|
|
// CHECK: bb6:
|
|
// CHECK: [[O6:%.*]] = struct_element_addr %0 : $*OuterStruct<T>, #OuterStruct.object
|
|
// CHECK: store %4 to [init] [[O6]] : $*AnyObject
|
|
// CHECK-NOT: dealloc
|
|
// CHECK-LABEL: } // end sil function 'f080_testNestedComposeStructWithPhi'
|
|
sil [ossa] @f080_testNestedComposeStructWithPhi : $@convention(thin) <T> (@in T, @in T, @owned AnyObject, @owned AnyObject) -> @out OuterStruct<T> {
|
|
bb0(%0 : @owned $T, %1 : @owned $T, %2 : @owned $AnyObject, %3 : @owned $AnyObject):
|
|
cond_br undef, bb2, bb1
|
|
bb1:
|
|
destroy_value %1 : $T
|
|
%inner2 = struct $InnerStruct<T> (%0 : $T, %2 : $AnyObject)
|
|
br bb6(%inner2 : $InnerStruct<T>)
|
|
bb2:
|
|
cond_br undef, bb4, bb3
|
|
bb3:
|
|
destroy_value %0 : $T
|
|
br bb5(%1 : $T)
|
|
bb4:
|
|
destroy_value %1 : $T
|
|
br bb5(%0 : $T)
|
|
bb5(%phi5 : @owned $T):
|
|
%inner5 = struct $InnerStruct<T> (%phi5 : $T, %2 : $AnyObject)
|
|
br bb6(%inner5 : $InnerStruct<T>)
|
|
bb6(%phi6 : @owned $InnerStruct<T>):
|
|
%outer = struct $OuterStruct<T> (%phi6 : $InnerStruct<T>, %3 : $AnyObject)
|
|
return %outer : $OuterStruct<T>
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @f090_payloadPhiOperand : $@convention(thin) <T> (@in Optional<T>, @in T) -> @out T {
|
|
// CHECK: bb0(%0 : $*T, %1 : $*Optional<T>, %2 : $*T):
|
|
// CHECK: cond_br undef, bb2, bb1
|
|
// CHECK: bb1:
|
|
// CHECK: destroy_addr %2 : $*T
|
|
// CHECK: [[P:%.*]] = unchecked_take_enum_data_addr %1 : $*Optional<T>, #Optional.some!enumelt
|
|
// CHECK: copy_addr [take] [[P]] to [init] %0 : $*T
|
|
// CHECK: br bb3
|
|
// CHECK: bb2:
|
|
// CHECK: destroy_addr %1 : $*Optional<T>
|
|
// CHECK: copy_addr [take] %2 to [init] %0 : $*T
|
|
// CHECK: br bb3
|
|
// CHECK-LABEL: } // end sil function 'f090_payloadPhiOperand'
|
|
sil [ossa] @f090_payloadPhiOperand : $@convention(thin) <T> (@in Optional<T>, @in T) -> @out T {
|
|
bb0(%0 : @owned $Optional<T>, %1 : @owned $T):
|
|
cond_br undef, bb2, bb1
|
|
bb1:
|
|
destroy_value %1 : $T
|
|
%payload = unchecked_enum_data %0 : $Optional<T>, #Optional.some!enumelt
|
|
br bb3(%payload : $T)
|
|
bb2:
|
|
destroy_value %0 : $Optional<T>
|
|
br bb3(%1 : $T)
|
|
bb3(%phi : @owned $T):
|
|
return %phi : $T
|
|
}
|
|
|
|
// Check that the debug_value instruction that is created when deleting a load
|
|
// gets rewritten and doesn't obstruct the deletion of the phi.
|
|
// CHECK-LABEL: sil [ossa] @f100_store_phi : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}({{%[^,]+}} : $*Value):
|
|
// CHECK: [[TEMP:%[^,]+]] = alloc_stack $Value
|
|
// CHECK: [[VAR:%[^,]+]] = alloc_stack [lexical] $Value, var, name "value"
|
|
// CHECK: cond_br undef, bb2, bb1
|
|
// CHECK: bb3:
|
|
// CHECK: debug_value [[TEMP]] : $*Value, var, name "value"
|
|
// CHECK: copy_addr [take] [[TEMP]] to [init] [[VAR]]
|
|
// CHECK-LABEL: } // end sil function 'f100_store_phi'
|
|
sil [ossa] @f100_store_phi : $@convention(thin) <Value> (@in Value) -> () {
|
|
entry(%instance : @owned $Value):
|
|
%14 = alloc_stack [lexical] $Value, var, name "value"
|
|
cond_br undef, left, right
|
|
|
|
left:
|
|
br merge(%instance : $Value)
|
|
|
|
right:
|
|
br merge(%instance : $Value)
|
|
|
|
merge(%34 : @owned $Value):
|
|
store %34 to [init] %14 : $*Value
|
|
destroy_addr %14 : $*Value
|
|
dealloc_stack %14 : $*Value
|
|
%43 = tuple ()
|
|
return %43 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @f105_phi_into_tuple : {{.*}} {
|
|
// CHECK: [[STORAGE:%[^,]+]] = alloc_stack $(Self, Builtin.Int1)
|
|
// CHECK: [[SELF_ADDR:%[^,]+]] = tuple_element_addr [[STORAGE]] : {{.*}}, 0
|
|
// CHECK: apply {{%[^,]+}}<Self>([[SELF_ADDR]])
|
|
// CHECK-LABEL: } // end sil function 'f105_phi_into_tuple'
|
|
sil [ossa] @f105_phi_into_tuple : $@convention(thin) <Self> () -> () {
|
|
%getOut = function_ref @getOut : $@convention(thin) <T> () -> @out T
|
|
%self = apply %getOut<Self>() : $@convention(thin) <τ_0_0> () -> @out τ_0_0
|
|
br exit(%self : $Self)
|
|
|
|
exit(%self_2 : @owned $Self):
|
|
%tuple = tuple (%self_2 : $Self, undef : $Bool)
|
|
destroy_value %tuple : $(Self, Bool)
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Check deleting the first of multiple block arguments.
|
|
// CHECK-LABEL: sil [ossa] @f110_nonfinal_argument : {{.*}} {
|
|
// CHECK: bb3({{%[^,]+}} : $S):
|
|
// CHECK-LABEL: } // end sil function 'f110_nonfinal_argument'
|
|
sil [ossa] @f110_nonfinal_argument : $@convention(thin) <T> (@in T, S) -> () {
|
|
entry(%instance : @owned $T, %s : $S):
|
|
cond_br undef, left, right
|
|
left:
|
|
br exit(%instance : $T, %s : $S)
|
|
right:
|
|
br exit(%instance : $T, %s : $S)
|
|
exit(%instance_2 : @owned $T, %s_2 : $S):
|
|
destroy_value %instance_2 : $T
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Check behavior of non-coalesceable single incoming phi.
|
|
// CHECK-LABEL: sil [ossa] @f120_single_phi_argument_forwarded_function_argument : {{.*}} {
|
|
// CHECK: bb0([[T:%[^,]+]] :
|
|
// CHECK: [[STORAGE:%[^,]+]] = alloc_stack
|
|
// CHECK: copy_addr [take] [[T]] to [init] [[STORAGE]]
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK: destroy_addr [[STORAGE]]
|
|
// CHECK: dealloc_stack [[STORAGE]]
|
|
// CHECK-LABEL: } // end sil function 'f120_single_phi_argument_forwarded_function_argument'
|
|
sil [ossa]@f120_single_phi_argument_forwarded_function_argument : $@convention(thin) <T> (@in T) -> () {
|
|
entry(%t : @owned $T):
|
|
br exit(%t : $T)
|
|
|
|
exit(%t2 : @owned $T):
|
|
destroy_value %t2 : $T
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @f121_single_phi_argument_forwarded_function_argument_returned : {{.*}} {
|
|
// CHECK: bb0([[OUT:%[^,]+]] :
|
|
// CHECK-SAME: [[IN:%[^,]+]] :
|
|
// CHECK: copy_addr [take] [[IN]] to [init] [[OUT]]
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK-LABEL: } // end sil function 'f121_single_phi_argument_forwarded_function_argument_returned'
|
|
sil [ossa]@f121_single_phi_argument_forwarded_function_argument_returned : $@convention(thin) <T> (@in T) -> @out T {
|
|
entry(%t : @owned $T):
|
|
br exit(%t : $T)
|
|
|
|
exit(%t2 : @owned $T):
|
|
return %t2 : $T
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @f122_single_phi_argument_destructure : $@convention(thin) <T> () -> () {
|
|
// CHECK: [[PHI_ADDR:%[^,]+]] = alloc_stack $T
|
|
// CHECK: [[BOX_ADDR:%[^,]+]] = alloc_stack $Box<T>
|
|
// CHECK: apply undef<T>([[BOX_ADDR]])
|
|
// CHECK: [[T_ADDR:%[^,]+]] = struct_element_addr [[BOX_ADDR]] : $*Box<T>, #Box.t
|
|
// CHECK: copy_addr [take] [[T_ADDR]] to [init] [[PHI_ADDR]]
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK: destroy_addr [[PHI_ADDR]]
|
|
// CHECK: dealloc_stack [[BOX_ADDR]]
|
|
// CHECK: dealloc_stack [[PHI_ADDR]]
|
|
// CHECK-LABEL: } // end sil function 'f122_single_phi_argument_destructure'
|
|
sil [ossa]@f122_single_phi_argument_destructure : $@convention(thin) <T> () -> () {
|
|
entry:
|
|
%box = apply undef<T>() : $@convention(thin) <T> () -> (@out Box<T>)
|
|
%t = destructure_struct %box : $Box<T>
|
|
br exit(%t : $T)
|
|
|
|
exit(%t2 : @owned $T):
|
|
destroy_value %t2 : $T
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @f130_single_phi_use_of_phi {{.*}} {
|
|
// CHECK: [[ADDR:%[^,]+]] = alloc_stack $Box<T>
|
|
// CHECK: [[T_ADDR:%[^,]+]] = struct_element_addr [[ADDR]] : $*Box<T>, #Box.t
|
|
// CHECK: apply undef<T>([[T_ADDR]])
|
|
// CHECK: br [[FAKE_MERGE1:bb[0-9]+]]
|
|
// CHECK: [[FAKE_MERGE1]]:
|
|
// CHECK: [[T_ADDR_2:%[^,]+]] = struct_element_addr [[ADDR]] : $*Box<T>, #Box.t
|
|
// CHECK: apply undef<T>([[T_ADDR_2]])
|
|
// CHECK: br [[FAKE_MERGE2:bb[0-9]+]]
|
|
// CHECK: [[FAKE_MERGE2]]:
|
|
// CHECK: apply undef<Box<T>>([[ADDR]])
|
|
// CHECK: destroy_addr [[ADDR]]
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK: dealloc_stack [[ADDR]]
|
|
// CHECK-LABEL: } // end sil function 'f130_single_phi_use_of_phi'
|
|
sil [ossa] @f130_single_phi_use_of_phi : $@convention(thin) <T> () -> () {
|
|
entry:
|
|
%t = apply undef<T>() : $@convention(thin) <T> () -> (@out T)
|
|
br fakeMerge1(%t : $T)
|
|
|
|
fakeMerge1(%tp : @owned $T):
|
|
apply undef<T>(%tp) : $@convention(thin) <T> (@in_guaranteed T) -> ()
|
|
%box = struct $Box<T>(%tp : $T)
|
|
br fakeMerge2(%box : $Box<T>)
|
|
|
|
fakeMerge2(%boxp : @owned $Box<T>):
|
|
apply undef<Box<T>>(%boxp) : $@convention(thin) <T> (@in_guaranteed T) -> ()
|
|
destroy_value %boxp : $Box<T>
|
|
br exit
|
|
|
|
exit:
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @f131_single_phi_use_of_phi_interference : {{.*}} {
|
|
// CHECK: [[BOXP_ADDR:%[^,]+]] = alloc_stack $Box<T>
|
|
// CHECK: [[T_ADDR:%[^,]+]] = struct_element_addr [[BOXP_ADDR]] : $*Box<T>, #Box.t
|
|
// CHECK: apply undef<T>([[T_ADDR]])
|
|
// CHECK: br [[FAKE_MERGE:bb[0-9]+]]
|
|
// CHECK: [[FAKE_MERGE]]:
|
|
// CHECK: [[T_ADDR_2:%[^,]+]] = struct_element_addr [[BOXP_ADDR]] : $*Box<T>, #Box.t
|
|
// CHECK: apply undef<T>([[T_ADDR_2]])
|
|
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: [[BOX_2_ADDR:%[^,]+]] = alloc_stack $Box<T>
|
|
// CHECK: apply undef<Box<T>>([[BOX_2_ADDR]])
|
|
// CHECK: destroy_addr [[BOXP_ADDR]]
|
|
// CHECK: copy_addr [take] [[BOX_2_ADDR]] to [init] [[BOXP_ADDR]]
|
|
// CHECK: dealloc_stack [[BOX_2_ADDR]]
|
|
// CHECK: br [[MERGE:bb[0-9]+]]
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: br [[MERGE]]
|
|
// CHECK: [[MERGE]]:
|
|
// CHECK: apply undef<Box<T>>([[BOXP_ADDR]])
|
|
// CHECK: destroy_addr [[BOXP_ADDR]]
|
|
// CHECK: dealloc_stack [[BOXP_ADDR]]
|
|
// CHECK-LABEL: } // end sil function 'f131_single_phi_use_of_phi_interference'
|
|
sil [ossa] @f131_single_phi_use_of_phi_interference : $@convention(thin) <T> () -> () {
|
|
entry:
|
|
%t = apply undef<T>() : $@convention(thin) <T> () -> (@out T)
|
|
br fakeMerge1(%t : $T)
|
|
|
|
fakeMerge1(%tp : @owned $T):
|
|
apply undef<T>(%tp) : $@convention(thin) <T> (@in_guaranteed T) -> ()
|
|
%box = struct $Box<T>(%tp : $T)
|
|
cond_br undef, left, right
|
|
|
|
right:
|
|
%box2 = apply undef<Box<T>>() : $@convention(thin) <T> () -> (@out T)
|
|
destroy_value %box : $Box<T>
|
|
br merge2(%box2 : $Box<T>)
|
|
|
|
left:
|
|
br merge2(%box : $Box<T>)
|
|
|
|
merge2(%boxp : @owned $Box<T>):
|
|
apply undef<Box<T>>(%boxp) : $@convention(thin) <T> (@in_guaranteed T) -> ()
|
|
destroy_value %boxp : $Box<T>
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @f140_interfering_use_projection : {{.*}} {
|
|
// CHECK: [[S2_ADDR:%[^,]+]] = alloc_stack $Pair<T>
|
|
// CHECK: [[T2_ADDR:%[^,]+]] = struct_element_addr [[S2_ADDR]] : $*Pair<T>, #Pair.y
|
|
// CHECK: apply undef<T>([[T2_ADDR]])
|
|
// CHECK: [[PHI_ADDR:%[^,]+]] = alloc_stack $Pair<T>
|
|
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: apply undef<Pair<T>>([[PHI_ADDR]])
|
|
// CHECK: destroy_addr [[T2_ADDR]]
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: [[T1_ADDR:%[^,]+]] = struct_element_addr [[S2_ADDR]] : $*Pair<T>, #Pair.x
|
|
// CHECK: apply undef<T>([[T1_ADDR]])
|
|
// CHECK: copy_addr [take] [[S2_ADDR]] to [init] [[PHI_ADDR]]
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK: destroy_addr [[PHI_ADDR]]
|
|
// CHECK: dealloc_stack [[PHI_ADDR]]
|
|
// CHECK: dealloc_stack [[S2_ADDR]]
|
|
// CHECK-LABEL: } // end sil function 'f140_interfering_use_projection'
|
|
sil [ossa] @f140_interfering_use_projection : $@convention(thin) <T> () -> () {
|
|
entry:
|
|
%t2 = apply undef<T>() : $@convention(thin) <T> () -> (@out T)
|
|
cond_br undef, left, right
|
|
|
|
left:
|
|
%t1 = apply undef<T>() : $@convention(thin) <T> () -> (@out T)
|
|
%s2 = struct $Pair<T>(%t1 : $T, %t2 : $T)
|
|
br merge(%s2 : $Pair<T>)
|
|
|
|
right:
|
|
%s1 = apply undef<Pair<T>>() : $@convention(thin) <T> () -> (@out T)
|
|
destroy_value %t2 : $T
|
|
br merge(%s1 : $Pair<T>)
|
|
|
|
merge(%sp : @owned $Pair<T>):
|
|
destroy_value %sp : $Pair<T>
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Incoming value is the root of a chain of projections:
|
|
// storage <- use <- use <- def
|
|
// ^^^ ^^^ ^^^
|
|
// %s projects out of %s2's storage
|
|
// ^^^ ^^^
|
|
// %box projects out of %s's storage
|
|
// ^^^
|
|
// %t projects out of %box's storage
|
|
// There is no interference (and only one incoming phi.)
|
|
// CHECK-LABEL: sil [ossa] @f150_incoming_use_use_def_no_interference : {{.*}} {
|
|
// CHECK: [[PHI_ADDR:%[^,]+]] = alloc_stack $Box<Box<Box<T>>>
|
|
// CHECK: [[S_ADDR:%[^,]+]] = struct_element_addr [[PHI_ADDR]] : $*Box<Box<Box<T>>>, #Box.t
|
|
// CHECK: [[BOX_ADDR:%[^,]+]] = struct_element_addr [[S_ADDR]] : $*Box<Box<T>>, #Box.t
|
|
// CHECK: apply undef<Box<T>>([[BOX_ADDR]])
|
|
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: br [[FAKE_MERGE:bb[0-9]+]]
|
|
// CHECK: [[FAKE_MERGE]]:
|
|
// CHECK: apply undef<Box<Box<Box<T>>>>([[PHI_ADDR]])
|
|
// CHECK: destroy_addr [[PHI_ADDR]]
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: [[T_ADDR:%[^,]+]] = struct_element_addr [[BOX_ADDR]] : $*Box<T>, #Box.t
|
|
// CHECK: destroy_addr [[T_ADDR]]
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK: dealloc_stack [[PHI_ADDR]]
|
|
// CHECK-LABEL: } // end sil function 'f150_incoming_use_use_def_no_interference'
|
|
sil [ossa] @f150_incoming_use_use_def_no_interference : $@convention(thin) <T> () -> () {
|
|
entry:
|
|
%box = apply undef<Box<T>>() : $@convention(thin) <T> () -> (@out T)
|
|
cond_br undef, left, right
|
|
|
|
left:
|
|
%t = destructure_struct %box : $Box<T>
|
|
destroy_value %t : $T
|
|
br exit
|
|
|
|
right:
|
|
%s = struct $Box<Box<T>>(%box : $Box<T>)
|
|
%s2 = struct $Box<Box<Box<T>>>(%s : $Box<Box<T>>)
|
|
br fakeMerge(%s2 : $Box<Box<Box<T>>>)
|
|
|
|
fakeMerge(%tb : @owned $Box<Box<Box<T>>>):
|
|
apply undef<Box<Box<Box<T>>>>(%tb) : $@convention(thin) <T> (@in_guaranteed T) -> ()
|
|
destroy_value %tb : $Box<Box<Box<T>>>
|
|
br exit
|
|
|
|
exit:
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Incoming value is the root of a chain of projections:
|
|
// storage <- use <- use <- def
|
|
// ^^^ ^^^ ^^^
|
|
// %s projects out of %s2's storage
|
|
// ^^^ ^^^
|
|
// %box projects out of %s's storage
|
|
// ^^^
|
|
// %t projects out of %box's storage
|
|
// There is interference of the _def_ projection (which can only be detected by
|
|
// adding its uses to liveness:
|
|
// %t is destroyed in ^left2
|
|
// %s3 is defined in ^left2
|
|
// TODO: When doing per-instruction rather than per-block liveness, this test
|
|
// will no longer have interference. At that point, move the
|
|
// destroy_value %t below the subsequent apply to reintroduce interference
|
|
// and duplicate this test.
|
|
// CHECK-LABEL: sil [ossa] @f160_incoming_use_use_def_interference : {{.*}} {
|
|
// CHECK: [[PHI_ADDR:%[^,]+]] = alloc_stack $Box<Box<Box<T>>>
|
|
// CHECK: [[S_ADDR:%[^,]+]] = struct_element_addr [[PHI_ADDR]] : $*Box<Box<Box<T>>>, #Box.t
|
|
// CHECK: [[BOX_ADDR:%[^,]+]] = struct_element_addr [[S_ADDR]] : $*Box<Box<T>>, #Box.t
|
|
// CHECK: apply undef<Box<T>>([[BOX_ADDR]])
|
|
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: br [[MERGE:bb[0-9]+]]
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: br [[LEFT2:bb[0-9]+]]
|
|
// CHECK: [[LEFT2]]:
|
|
// CHECK: [[S3_ADDR:%[^,]+]] = alloc_stack $Box<Box<Box<T>>>
|
|
// CHECK: [[T_ADDR:%[^,]+]] = struct_element_addr [[BOX_ADDR]] : $*Box<T>, #Box.t
|
|
// CHECK: destroy_addr [[T_ADDR]]
|
|
// CHECK: apply undef<Box<Box<Box<T>>>>([[S3_ADDR]])
|
|
// CHECK: copy_addr [take] [[S3_ADDR]] to [init] [[PHI_ADDR]] : $*Box<Box<Box<T>>>
|
|
// CHECK: dealloc_stack [[S3_ADDR]]
|
|
// CHECK: br [[MERGE:bb[0-9]+]]
|
|
// CHECK: [[MERGE]]:
|
|
// CHECK: apply undef<Box<Box<Box<T>>>>([[PHI_ADDR]])
|
|
// CHECK: destroy_addr [[PHI_ADDR]]
|
|
// CHECK: dealloc_stack [[PHI_ADDR]]
|
|
// CHECK-LABEL: } // end sil function 'f160_incoming_use_use_def_interference'
|
|
sil [ossa] @f160_incoming_use_use_def_interference : $@convention(thin) <T> () -> () {
|
|
entry:
|
|
%box = apply undef<Box<T>>() : $@convention(thin) <T> () -> (@out T)
|
|
cond_br undef, left, right
|
|
|
|
left:
|
|
%t = destructure_struct %box : $Box<T>
|
|
br left2
|
|
|
|
left2:
|
|
destroy_value %t : $T
|
|
%s3 = apply undef<Box<Box<Box<T>>>>() : $@convention(thin) <T> () -> (@out T)
|
|
br merge(%s3 : $Box<Box<Box<T>>>)
|
|
|
|
right:
|
|
%s = struct $Box<Box<T>>(%box : $Box<T>)
|
|
%s2 = struct $Box<Box<Box<T>>>(%s : $Box<Box<T>>)
|
|
br merge(%s2 : $Box<Box<Box<T>>>)
|
|
|
|
merge(%tb : @owned $Box<Box<Box<T>>>):
|
|
apply undef<Box<Box<Box<T>>>>(%tb) : $@convention(thin) <T> (@in_guaranteed T) -> ()
|
|
destroy_value %tb : $Box<Box<Box<T>>>
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Incoming phi.
|
|
// TODO: Coalesce in this case.
|
|
// CHECK-LABEL: sil [ossa] @f170_incoming_phi_no_interference : {{.*}} {
|
|
// CHECK: [[T_ADDR:%[^,]+]] = alloc_stack $T
|
|
// CHECK: apply undef<T>([[T_ADDR]])
|
|
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: br [[FAKE_MERGE_1:bb[0-9]+]]
|
|
// CHECK: [[FAKE_MERGE_1]]:
|
|
// CHECK: [[TP_ADDR:%[^,]+]] = alloc_stack $T
|
|
// CHECK: apply undef<T>([[T_ADDR]])
|
|
// CHECK: copy_addr [take] [[T_ADDR]] to [init] [[TP_ADDR]]
|
|
// CHECK: br [[FAKE_MERGE_2:bb[0-9]+]]
|
|
// CHECK: [[FAKE_MERGE_2]]:
|
|
// CHECK: apply undef<T>([[TP_ADDR]])
|
|
// CHECK: destroy_addr [[TP_ADDR]]
|
|
// CHECK: dealloc_stack [[TP_ADDR]]
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: destroy_addr [[T_ADDR]]
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK: dealloc_stack [[T_ADDR]]
|
|
// CHECK-LABEL: } // end sil function 'f170_incoming_phi_no_interference'
|
|
sil [ossa] @f170_incoming_phi_no_interference : $@convention(thin) <T> () -> () {
|
|
entry:
|
|
%t = apply undef<T>() : $@convention(thin) <T> () -> (@out T)
|
|
cond_br undef, left, right
|
|
|
|
left:
|
|
destroy_value %t : $T
|
|
br exit
|
|
|
|
right:
|
|
br fakeMerge1(%t : $T)
|
|
|
|
fakeMerge1(%tp : @owned $T):
|
|
apply undef<T>(%tp) : $@convention(thin) <T> (@in_guaranteed T) -> ()
|
|
br fakeMerge2(%tp : $T)
|
|
|
|
fakeMerge2(%tpp : @owned $T):
|
|
apply undef<T>(%tpp) : $@convention(thin) <T> (@in_guaranteed T) -> ()
|
|
destroy_value %tpp : $T
|
|
br exit
|
|
|
|
exit:
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @f180_incoming_terminator_results : {{.*}} {
|
|
// CHECK: bb0(%0 :
|
|
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: try_apply undef<T>(%0)
|
|
// CHECK-SAME: normal [[RIGHT_SUCCESS:bb[0-9]+]], error [[RIGHT_FAILURE:bb[0-9]+]]
|
|
// CHECK: [[RIGHT_FAILURE]]({{%[^,]+}} : @owned $any Error):
|
|
// CHECK: unreachable
|
|
// CHECK: [[RIGHT_SUCCESS]]
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: try_apply undef<T>(%0)
|
|
// CHECK-SAME: normal [[LEFT_SUCCESS:bb[0-9]+]], error [[LEFT_FAILURE:bb[0-9]+]]
|
|
// CHECK: [[LEFT_FAILURE]]({{%[^,]+}} : @owned $any Error):
|
|
// CHECK: unreachable
|
|
// CHECK: [[LEFT_SUCCESS]]
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK-LABEL: } // end sil function 'f180_incoming_terminator_results'
|
|
sil [ossa] @f180_incoming_terminator_results : $@convention(thin) <T> () -> (@out T) {
|
|
entry:
|
|
cond_br undef, left, right
|
|
|
|
left:
|
|
try_apply undef<T>() : $@convention(thin) <T> () -> (@out T, @error any Error), normal left_success, error left_failure
|
|
|
|
left_success(%lt : @owned $T):
|
|
br exit(%lt : $T)
|
|
|
|
left_failure(%lerror : @owned $any Error):
|
|
unreachable
|
|
|
|
right:
|
|
try_apply undef<T>() : $@convention(thin) <T> () -> (@out T, @error any Error), normal right_success, error right_failure
|
|
|
|
right_success(%rt : @owned $T):
|
|
br exit(%rt : $T)
|
|
|
|
exit(%tp : @owned $T):
|
|
return %tp : $T
|
|
|
|
right_failure(%rerror : @owned $any Error):
|
|
unreachable
|
|
}
|
|
|
|
// Verify that LCA for `%agg` is correctly determined to be `parent` so that the
|
|
// backwards walk when determining the liveness contribution from `%v` stops at
|
|
// `%trouble2`, that there is only a single `alloc_stack`.
|
|
// CHECK-LABEL: sil [ossa] @f190_vexing_incoming_def_projection : {{.*}} {
|
|
// CHECK: [[P_ADDR:%[^,]+]] = alloc_stack $Box<Box<T>>
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK: apply undef<Box<Box<T>>>([[P_ADDR]])
|
|
// CHECK: cond_br undef, [[OKAY:bb[0-9]+]], [[TROUBLE:bb[0-9]+]]
|
|
// CHECK: [[TROUBLE]]:
|
|
// CHECK: destroy_addr [[P_ADDR]]
|
|
// CHECK: br [[TROUBLE2:bb[0-9]+]]
|
|
// CHECK: [[TROUBLE2]]:
|
|
// CHECK: [[V_ADDR:%[^,]+]] = struct_element_addr [[P_ADDR]]
|
|
// CHECK: apply undef<Box<T>>([[V_ADDR]])
|
|
// CHECK: cond_br undef, [[PARENT:bb[0-9]+]], [[OTHER:bb[0-9]+]]
|
|
// CHECK: [[OTHER]]:
|
|
// CHECK: destroy_addr [[V_ADDR]]
|
|
// CHECK: br [[OTHER2:bb[0-9]+]]
|
|
// CHECK: [[OTHER2]]:
|
|
// CHECK: apply undef<Box<Box<T>>>([[P_ADDR]])
|
|
// CHECK: br [[MERGE:bb[0-9]+]]
|
|
// CHECK: [[PARENT]]:
|
|
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: br [[MERGE]]
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: [[T_ADDR:%[^,]+]] = struct_element_addr [[V_ADDR]]
|
|
// CHECK: destroy_addr [[T_ADDR]]
|
|
// CHECK: br [[LEFT2:bb[0-9]+]]
|
|
// CHECK: [[LEFT2]]:
|
|
// CHECK: apply undef<Box<Box<T>>>([[P_ADDR]])
|
|
// CHECK: br [[MERGE]]
|
|
// CHECK: [[OKAY]]:
|
|
// CHECK: br [[MERGE]]
|
|
// CHECK: [[MERGE]]:
|
|
// CHECK: destroy_addr [[P_ADDR]]
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK: dealloc_stack [[P_ADDR]]
|
|
// CHECK-LABEL: } // end sil function 'f190_vexing_incoming_def_projection'
|
|
sil [ossa] @f190_vexing_incoming_def_projection : $@convention(thin) <T> () -> () {
|
|
entry:
|
|
%agg4 = apply undef<Box<Box<T>>>() : $@convention(thin) <T> () -> (@out T)
|
|
cond_br undef, okay, trouble
|
|
|
|
okay:
|
|
br merge(%agg4 : $Box<Box<T>>)
|
|
|
|
|
|
trouble:
|
|
destroy_value %agg4 : $Box<Box<T>>
|
|
br trouble2
|
|
|
|
trouble2:
|
|
%v = apply undef<Box<T>>() : $@convention(thin) <T> () -> (@out T)
|
|
cond_br undef, parent, other
|
|
|
|
parent:
|
|
cond_br undef, left, right
|
|
|
|
left:
|
|
%t = destructure_struct %v : $Box<T>
|
|
destroy_value %t : $T
|
|
br left2
|
|
|
|
left2:
|
|
%agg2 = apply undef<Box<Box<T>>>() : $@convention(thin) <T> () -> (@out T)
|
|
br merge(%agg2 : $Box<Box<T>>)
|
|
|
|
right:
|
|
%agg = struct $Box<Box<T>>(%v : $Box<T>)
|
|
br merge(%agg : $Box<Box<T>>)
|
|
|
|
other:
|
|
destroy_value %v : $Box<T>
|
|
br other2
|
|
|
|
other2:
|
|
%agg3 = apply undef<Box<Box<T>>>() : $@convention(thin) <T> () -> (@out T)
|
|
br merge(%agg3 : $Box<Box<T>>)
|
|
|
|
merge(%p : @owned $Box<Box<T>>):
|
|
destroy_value %p : $Box<Box<T>>
|
|
br exit
|
|
|
|
exit:
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|