mirror of
https://github.com/apple/swift.git
synced 2026-10-04 11:58:22 +02:00
This new OSSA invariant simplifies many optimizations because they don't have to take care of the corner case of incomplete lifetimes in dead-end blocks. The implementation basically consists of these changes: * add the lifetime completion utility * add a flag in SILFunction which tells optimization that they need to run the lifetime completion utility * let all optimizations complete lifetimes if necessary * enable the ownership verifier to check complete lifetimes
1015 lines
42 KiB
Plaintext
1015 lines
42 KiB
Plaintext
// RUN: %target-sil-opt -sil-print-types -test-runner %s -o /dev/null 2>&1 | %FileCheck %s
|
|
|
|
import Builtin
|
|
import Swift
|
|
|
|
class C {}
|
|
|
|
enum Never {}
|
|
|
|
struct Pointer {
|
|
var rawValue: Builtin.RawPointer
|
|
}
|
|
|
|
struct Int32 {
|
|
var int: Builtin.Int32
|
|
}
|
|
sil @run : $@convention(thin) () -> Never
|
|
sil @getOwned : $@convention(thin) () -> @owned C
|
|
sil @barrier : $@convention(thin) () -> ()
|
|
sil [ossa] @getC : $@convention(thin) () -> @owned C
|
|
sil [ossa] @borrowC : $@convention(thin) (@guaranteed C) -> ()
|
|
sil [ossa] @takeC : $@convention(thin) (@owned C) -> ()
|
|
sil @getPointer : $@convention(thin) () -> (@owned Pointer)
|
|
|
|
struct S {}
|
|
|
|
struct MoS: ~Copyable {}
|
|
struct MoE: ~Copyable {}
|
|
|
|
// CHECK-LABEL: begin running test 1 of 1 on fn: ossa_canonicalize_lifetime with: true, true, true, @trace
|
|
// CHECK-LABEL: end running test 1 of 1 on fn: ossa_canonicalize_lifetime with: true, true, true, @trace
|
|
sil [ossa] @fn : $@convention(thin) () -> () {
|
|
entry:
|
|
specify_test "ossa_canonicalize_lifetime true true true @trace"
|
|
%getC = function_ref @getC : $@convention(thin) () -> @owned C
|
|
%c = apply %getC() : $@convention(thin) () -> @owned C
|
|
debug_value [trace] %c : $C
|
|
%borrowC = function_ref @borrowC : $@convention(thin) (@guaranteed C) -> ()
|
|
apply %borrowC(%c) : $@convention(thin) (@guaranteed C) -> ()
|
|
debug_value %c : $C
|
|
destroy_value %c : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// When access scopes are respected, the lifetime which previously extended
|
|
// beyond the access scope still extends beyond it.
|
|
// CHECK-LABEL: begin running test 1 of 2 on retract_value_lifetime_into_access_scope_when_access_scopes_not_respected: ossa_canonicalize_lifetime with: true, false, true, @trace
|
|
// CHECK-LABEL: sil [ossa] @retract_value_lifetime_into_access_scope_when_access_scopes_not_respected {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[ADDR:%[^,]+]] :
|
|
// CHECK: [[INSTANCE:%[^,]+]] = apply
|
|
// CHECK: [[COPY:%[^,]+]] = copy_value [[INSTANCE]]
|
|
// CHECK: [[ACCESS:%[^,]+]] = begin_access [modify] [static] [[ADDR]]
|
|
// CHECK: store [[COPY]] to [init] [[ACCESS]]
|
|
// CHECK: end_access [[ACCESS]]
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK-LABEL: } // end sil function 'retract_value_lifetime_into_access_scope_when_access_scopes_not_respected'
|
|
// CHECK-LABEL: end running test 1 of 2 on retract_value_lifetime_into_access_scope_when_access_scopes_not_respected: ossa_canonicalize_lifetime with: true, false, true, @trace
|
|
|
|
// When access scopes are not respected, the lifetime which previously extended
|
|
// beyond the access scope is retracted into the scope.
|
|
// CHECK-LABEL: begin running test 2 of 2 on retract_value_lifetime_into_access_scope_when_access_scopes_not_respected: ossa_canonicalize_lifetime with: true, false, false, @trace
|
|
// CHECK-LABEL: sil [ossa] @retract_value_lifetime_into_access_scope_when_access_scopes_not_respected {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[ADDR:%[^,]+]] :
|
|
// CHECK: [[INSTANCE:%[^,]+]] = apply
|
|
// CHECK: [[ACCESS:%[^,]+]] = begin_access [modify] [static] [[ADDR]]
|
|
// CHECK: store [[INSTANCE]] to [init] [[ACCESS]]
|
|
// CHECK: end_access [[ACCESS]]
|
|
// CHECK-LABEL: } // end sil function 'retract_value_lifetime_into_access_scope_when_access_scopes_not_respected'
|
|
// CHECK-LABEL: end running test 2 of 2 on retract_value_lifetime_into_access_scope_when_access_scopes_not_respected: ossa_canonicalize_lifetime with: true, false, false, @trace
|
|
sil [ossa] @retract_value_lifetime_into_access_scope_when_access_scopes_not_respected : $@convention(thin) () -> @out C {
|
|
bb0(%addr : $*C):
|
|
%instance = apply undef() : $@convention(thin) () -> @owned C
|
|
debug_value [trace] %instance : $C
|
|
// respect access scopes
|
|
// VVVV
|
|
specify_test "ossa_canonicalize_lifetime true false true @trace"
|
|
specify_test "ossa_canonicalize_lifetime true false false @trace"
|
|
// ^^^^^
|
|
// respect access scopes
|
|
%copy = copy_value %instance : $C
|
|
%access = begin_access [modify] [static] %addr : $*C
|
|
store %copy to [init] %access : $*C
|
|
end_access %access : $*C
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
|
|
// CHECK-LABEL: begin running test 1 of 1 on reuse_destroy_after_barrier_phi: ossa_canonicalize_lifetime with: true, false, true, @trace
|
|
// CHECK-LABEL: sil [ossa] @reuse_destroy_after_barrier_phi : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] :
|
|
// CHECK: {{bb[0-9]+}}({{%[^,]+}}
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK-LABEL: } // end sil function 'reuse_destroy_after_barrier_phi'
|
|
// CHECK-LABEL: end running test 1 of 1 on reuse_destroy_after_barrier_phi: ossa_canonicalize_lifetime with: true, false, true, @trace
|
|
sil [ossa] @reuse_destroy_after_barrier_phi : $@convention(thin) (@owned C) -> @owned C {
|
|
entry(%instance : @owned $C):
|
|
debug_value [trace] %instance : $C
|
|
specify_test "ossa_canonicalize_lifetime true false true @trace"
|
|
%get = function_ref @getOwned : $@convention(thin) () -> @owned C
|
|
cond_br undef, through, loop
|
|
|
|
through:
|
|
%4 = copy_value %instance : $C
|
|
br exit(%4 : $C)
|
|
|
|
loop:
|
|
%other = apply %get() : $@convention(thin) () -> @owned C
|
|
br exit(%other : $C)
|
|
|
|
exit(%out : @owned $C):
|
|
destroy_value %instance : $C
|
|
return %out : $C
|
|
}
|
|
|
|
// CHECK-LABEL: begin running test 1 of 1 on store_arg_to_out_addr: ossa_canonicalize_lifetime with: true, false, true, @trace
|
|
// CHECK-LABEL: sil [ossa] @store_arg_to_out_addr : $@convention(thin) (@owned C) -> @out C {
|
|
// CHECK: {{bb[0-9]+}}([[ADDR:%[^,]+]] : $*C, [[INSTANCE:%[^,]+]] :
|
|
// CHECK: store [[INSTANCE]] to [init] [[ADDR]]
|
|
// CHECK-LABEL: } // end sil function 'store_arg_to_out_addr'
|
|
// CHECK-LABEL: end running test 1 of 1 on store_arg_to_out_addr: ossa_canonicalize_lifetime with: true, false, true, @trace
|
|
sil [ossa] @store_arg_to_out_addr : $@convention(thin) (@owned C) -> @out C {
|
|
bb0(%0 : $*C, %instance : @owned $C):
|
|
debug_value [trace] %instance : $C
|
|
specify_test "ossa_canonicalize_lifetime true false true @trace"
|
|
%copy = copy_value %instance : $C
|
|
store %copy to [init] %0 : $*C
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: begin running test 1 of 1 on store_arg_to_out_addr_with_barrier: ossa_canonicalize_lifetime with: true, false, true, @trace
|
|
// CHECK-LABEL: sil [ossa] @store_arg_to_out_addr_with_barrier : $@convention(thin) (@owned C) -> @out C {
|
|
// CHECK: {{bb[0-9]+}}([[ADDR:%[^,]+]] : $*C, [[INSTANCE:%[^,]+]] :
|
|
// CHECK: [[BARRIER:%[^,]+]] = function_ref @barrier
|
|
// CHECK: [[COPY:%[^,]+]] = copy_value [[INSTANCE]]
|
|
// CHECK: store [[COPY]] to [init] [[ADDR]]
|
|
// CHECK: apply [[BARRIER]]()
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK-LABEL: } // end sil function 'store_arg_to_out_addr_with_barrier'
|
|
// CHECK-LABEL: end running test 1 of 1 on store_arg_to_out_addr_with_barrier: ossa_canonicalize_lifetime with: true, false, true, @trace
|
|
sil [ossa] @store_arg_to_out_addr_with_barrier : $@convention(thin) (@owned C) -> @out C {
|
|
bb0(%0 : $*C, %instance : @owned $C):
|
|
%barrier = function_ref @barrier : $@convention(thin) () -> ()
|
|
debug_value [trace] %instance : $C
|
|
specify_test "ossa_canonicalize_lifetime true false true @trace"
|
|
%copy = copy_value %instance : $C
|
|
store %copy to [init] %0 : $*C
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Don't crash on an adjacent phi with an incoming undef.
|
|
sil [ossa] @adjacent_phi_with_incoming_undef : $@convention(thin) () -> () {
|
|
entry:
|
|
%getC = function_ref @getOwned : $@convention(thin) () -> @owned C
|
|
%c2 = apply %getC() : $@convention(thin) () -> @owned C
|
|
br right2(%c2 : $C)
|
|
|
|
right2(%c2p : @owned $C):
|
|
br exit(%c2p : $C, undef : $S)
|
|
|
|
exit(%phi : @owned $C, %typhi : $S):
|
|
debug_value [trace] %phi : $C
|
|
specify_test "ossa_canonicalize_lifetime true false true @trace"
|
|
destroy_value %phi : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
sil @empty : $@convention(thin) () -> () {
|
|
[global: ]
|
|
bb0:
|
|
%0 = tuple ()
|
|
return %0 : $()
|
|
}
|
|
|
|
// Even though the apply of %empty is not a deinit barrier, verify that the
|
|
// destroy is not hoisted, because MoS is move-only.
|
|
// CHECK-LABEL: begin running test {{.*}} on dont_move_destroy_value_of_moveonly_struct: ossa_canonicalize_lifetime with: true, false, true, @argument
|
|
// CHECK-LABEL: sil [ossa] @dont_move_destroy_value_of_moveonly_struct : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] :
|
|
// CHECK: apply
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK-LABEL: } // end sil function 'dont_move_destroy_value_of_moveonly_struct'
|
|
// CHECK-LABEL: end running test {{.*}} on dont_move_destroy_value_of_moveonly_struct: ossa_canonicalize_lifetime with: true, false, true, @argument
|
|
sil [ossa] @dont_move_destroy_value_of_moveonly_struct : $@convention(thin) (@owned MoS) -> () {
|
|
entry(%instance : @owned $MoS):
|
|
specify_test "ossa_canonicalize_lifetime true false true @argument"
|
|
%empty = function_ref @empty : $@convention(thin) () -> ()
|
|
apply %empty() : $@convention(thin) () -> ()
|
|
destroy_value %instance : $MoS
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: begin running test {{.*}} on dont_move_destroy_value_of_moveonly_enum: ossa_canonicalize_lifetime with: true, false, true, @argument
|
|
// CHECK-LABEL: sil [ossa] @dont_move_destroy_value_of_moveonly_enum : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] :
|
|
// CHECK: apply
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK-LABEL: } // end sil function 'dont_move_destroy_value_of_moveonly_enum'
|
|
// CHECK-LABEL: end running test {{.*}} on dont_move_destroy_value_of_moveonly_enum: ossa_canonicalize_lifetime with: true, false, true, @argument
|
|
sil [ossa] @dont_move_destroy_value_of_moveonly_enum : $@convention(thin) (@owned MoE) -> () {
|
|
entry(%instance : @owned $MoE):
|
|
specify_test "ossa_canonicalize_lifetime true false true @argument"
|
|
%empty = function_ref @empty : $@convention(thin) () -> ()
|
|
apply %empty() : $@convention(thin) () -> ()
|
|
destroy_value %instance : $MoE
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: begin running test 1 of 1 on respect_boundary_edges_when_extending_to_deinit_barriers
|
|
// CHECK-LABEL: sil [ossa] @respect_boundary_edges_when_extending_to_deinit_barriers : {{.*}} {
|
|
// CHECK: bb0([[INSTANCE:%[^,]+]] :
|
|
// CHECK: apply {{%[^,]+}}()
|
|
// CHECK: destroy_value [[INSTANCE]] : $C
|
|
// CHECK: cond_br undef, [[DIE:bb[0-9]+]], [[DESTROY:bb[0-9]+]]
|
|
// CHECK: [[DIE]]:
|
|
// CHECK: unreachable
|
|
// CHECK: [[DESTROY]]:
|
|
// CHECK: return
|
|
// CHECK-LABEL: } // end sil function 'respect_boundary_edges_when_extending_to_deinit_barriers'
|
|
// CHECK-LABEL: end running test 1 of 1 on respect_boundary_edges_when_extending_to_deinit_barriers
|
|
sil [ossa] @respect_boundary_edges_when_extending_to_deinit_barriers : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance : @owned $C):
|
|
specify_test "ossa_canonicalize_lifetime true false true @argument"
|
|
%barrier = function_ref @barrier : $@convention(thin) () -> ()
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
cond_br undef, die, destroy
|
|
|
|
die:
|
|
destroy_value [dead_end] %instance
|
|
unreachable
|
|
|
|
destroy:
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: begin running test {{.*}} on respect_boundary_edges_when_extending_to_deinit_barriers_2
|
|
// CHECK-LABEL: sil [ossa] @respect_boundary_edges_when_extending_to_deinit_barriers_2 : {{.*}} {
|
|
// CHECK: bb0([[INSTANCE:%[^,]+]] :
|
|
// CHECK: apply
|
|
// CHECK: cond_br undef, [[DIE:bb[0-9]+]], [[DESTROY:bb[0-9]+]]
|
|
// CHECK: [[DIE]]:
|
|
// CHECK: apply
|
|
// CHECK: unreachable
|
|
// CHECK: [[DESTROY]]:
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK-LABEL: } // end sil function 'respect_boundary_edges_when_extending_to_deinit_barriers_2'
|
|
// CHECK-LABEL: end running test {{.*}} on respect_boundary_edges_when_extending_to_deinit_barriers_2
|
|
sil [ossa] @respect_boundary_edges_when_extending_to_deinit_barriers_2 : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance : @owned $C):
|
|
specify_test "ossa_canonicalize_lifetime true false true @argument"
|
|
%barrier = function_ref @barrier : $@convention(thin) () -> ()
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
cond_br undef, die, destroy
|
|
|
|
die:
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
br rlydie
|
|
|
|
rlydie:
|
|
destroy_value [dead_end] %instance
|
|
unreachable
|
|
|
|
destroy:
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: begin running test {{.*}} on respect_boundary_edges_when_extending_to_deinit_barriers_3
|
|
// CHECK-LABEL: sil [ossa] @respect_boundary_edges_when_extending_to_deinit_barriers_3 : {{.*}} {
|
|
// CHECK: bb0([[INSTANCE:%[^,]+]] :
|
|
// CHECK: apply
|
|
// CHECK: cond_br undef, [[DIE:bb[0-9]+]], [[DESTROY:bb[0-9]+]]
|
|
// CHECK: [[DIE]]:
|
|
// CHECK: apply
|
|
// CHECK-NOT: destroy_value [[INSTANCE]]
|
|
// CHECK: unreachable
|
|
// CHECK: [[DESTROY]]:
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK-LABEL: } // end sil function 'respect_boundary_edges_when_extending_to_deinit_barriers_3'
|
|
// CHECK-LABEL: end running test {{.*}} on respect_boundary_edges_when_extending_to_deinit_barriers_3
|
|
sil [ossa] @respect_boundary_edges_when_extending_to_deinit_barriers_3 : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance : @owned $C):
|
|
specify_test "ossa_canonicalize_lifetime true false true @argument"
|
|
%barrier = function_ref @barrier : $@convention(thin) () -> ()
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
cond_br undef, die, destroy
|
|
|
|
die:
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
destroy_value [dead_end] %instance
|
|
unreachable
|
|
|
|
destroy:
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Verify that an explicit destroy_value which happens to be just before an
|
|
// unreachable isn't deleted if liveness extends to the previous instruction.
|
|
// CHECK-LABEL: begin running test 1 of 1 on respect_preexisting_destroy_values_when_extending_to_deinit_barriers
|
|
// CHECK-LABEL: sil [ossa] @respect_preexisting_destroy_values_when_extending_to_deinit_barriers : {{.*}} {
|
|
// CHECK: bb0([[INSTANCE:%[^,]+]] :
|
|
// CHECK: cond_br undef, [[DIE:bb[0-9]+]], [[DESTROY:bb[0-9]+]]
|
|
// CHECK: [[DIE]]:
|
|
// CHECK: apply {{%[^,]+}}()
|
|
// CHECK: destroy_value [[INSTANCE]] : $C
|
|
// CHECK: unreachable
|
|
// CHECK: [[DESTROY]]:
|
|
// CHECK: destroy_value [[INSTANCE]] : $C
|
|
// CHECK: return
|
|
// CHECK-LABEL: } // end sil function 'respect_preexisting_destroy_values_when_extending_to_deinit_barriers'
|
|
// CHECK-LABEL: end running test 1 of 1 on respect_preexisting_destroy_values_when_extending_to_deinit_barriers
|
|
sil [ossa] @respect_preexisting_destroy_values_when_extending_to_deinit_barriers : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance : @owned $C):
|
|
specify_test "ossa_canonicalize_lifetime true false true @argument"
|
|
%barrier = function_ref @barrier : $@convention(thin) () -> ()
|
|
cond_br undef, die, destroy
|
|
|
|
die:
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
destroy_value %instance : $C
|
|
unreachable
|
|
|
|
destroy:
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: begin running test {{.*}} on preserve_dead_end_1
|
|
// CHECK-LABEL: sil [ossa] @preserve_dead_end_1 : {{.*}} {
|
|
// CHECK: destroy_value [dead_end]
|
|
// CHECK-LABEL: } // end sil function 'preserve_dead_end_1'
|
|
// CHECK-LABEL: end running test {{.*}} on preserve_dead_end_1
|
|
sil [ossa] @preserve_dead_end_1 : $@convention(thin) () -> () {
|
|
entry:
|
|
specify_test "ossa_canonicalize_lifetime true false true %c"
|
|
|
|
%get = function_ref @getOwned : $@convention(thin) () -> @owned C
|
|
%barrier = function_ref @barrier : $@convention(thin) () -> ()
|
|
|
|
%c = apply %get() : $@convention(thin) () -> @owned C
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
destroy_value [dead_end] %c : $C
|
|
unreachable
|
|
}
|
|
|
|
// CHECK-LABEL: begin running test {{.*}} on preserve_dead_end_2
|
|
// CHECK-LABEL: sil [ossa] @preserve_dead_end_2 : {{.*}} {
|
|
// CHECK: destroy_value [dead_end]
|
|
// CHECK-LABEL: } // end sil function 'preserve_dead_end_2'
|
|
// CHECK-LABEL: end running test {{.*}} on preserve_dead_end_2
|
|
sil [ossa] @preserve_dead_end_2 : $@convention(thin) () -> () {
|
|
entry:
|
|
specify_test "ossa_canonicalize_lifetime true false true %c"
|
|
|
|
%get = function_ref @getOwned : $@convention(thin) () -> @owned C
|
|
%barrier = function_ref @barrier : $@convention(thin) () -> ()
|
|
%borrow = function_ref @borrowC : $@convention(thin) (@guaranteed C) -> ()
|
|
|
|
%c = apply %get() : $@convention(thin) () -> @owned C
|
|
%c2 = copy_value %c : $C
|
|
destroy_value %c : $C
|
|
apply %borrow(%c2) : $@convention(thin) (@guaranteed C) -> ()
|
|
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
destroy_value [dead_end] %c2 : $C
|
|
unreachable
|
|
}
|
|
|
|
// CHECK-LABEL: begin running test {{.*}} on preserve_dead_end_3
|
|
// CHECK-LABEL: sil [ossa] @preserve_dead_end_3 : {{.*}} {
|
|
// CHECK: destroy_value [dead_end]
|
|
// CHECK-LABEL: } // end sil function 'preserve_dead_end_3'
|
|
// CHECK-LABEL: end running test {{.*}} on preserve_dead_end_3
|
|
sil [ossa] @preserve_dead_end_3 : $@convention(thin) () -> () {
|
|
entry:
|
|
specify_test "ossa_canonicalize_lifetime true false true %c"
|
|
|
|
%get = function_ref @getOwned : $@convention(thin) () -> @owned C
|
|
%barrier = function_ref @barrier : $@convention(thin) () -> ()
|
|
%borrow = function_ref @borrowC : $@convention(thin) (@guaranteed C) -> ()
|
|
|
|
%c = apply %get() : $@convention(thin) () -> @owned C
|
|
%c2 = copy_value %c : $C
|
|
destroy_value %c : $C
|
|
apply %borrow(%c2) : $@convention(thin) (@guaranteed C) -> ()
|
|
br die
|
|
|
|
die:
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
destroy_value [dead_end] %c2 : $C
|
|
unreachable
|
|
}
|
|
|
|
// CHECK-LABEL: begin running test {{.*}} on preserve_dead_end_4
|
|
// CHECK-LABEL: sil [ossa] @preserve_dead_end_4 : {{.*}} {
|
|
// CHECK-NOT: destroy_value [dead_end]
|
|
// CHECK-LABEL: } // end sil function 'preserve_dead_end_4'
|
|
// CHECK-LABEL: end running test {{.*}} on preserve_dead_end_4
|
|
sil [ossa] @preserve_dead_end_4 : $@convention(thin) () -> () {
|
|
entry:
|
|
specify_test "ossa_canonicalize_lifetime true false true %c"
|
|
|
|
%get = function_ref @getOwned : $@convention(thin) () -> @owned C
|
|
%barrier = function_ref @barrier : $@convention(thin) () -> ()
|
|
%borrow = function_ref @borrowC : $@convention(thin) (@guaranteed C) -> ()
|
|
|
|
%c = apply %get() : $@convention(thin) () -> @owned C
|
|
%c2 = copy_value %c : $C
|
|
destroy_value %c : $C
|
|
apply %borrow(%c2) : $@convention(thin) (@guaranteed C) -> ()
|
|
cond_br undef, exit, die
|
|
|
|
exit:
|
|
destroy_value %c2 : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
|
|
die:
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
destroy_value [dead_end] %c2 : $C
|
|
unreachable
|
|
}
|
|
|
|
// CHECK-LABEL: begin running test {{.*}} on preserve_dead_end_5
|
|
// CHECK-LABEL: sil [ossa] @preserve_dead_end_5 : {{.*}} {
|
|
// CHECK-NOT: destroy_value [dead_end]
|
|
// CHECK-LABEL: } // end sil function 'preserve_dead_end_5'
|
|
// CHECK-LABEL: end running test {{.*}} on preserve_dead_end_5
|
|
sil [ossa] @preserve_dead_end_5 : $@convention(thin) () -> () {
|
|
entry:
|
|
specify_test "ossa_canonicalize_lifetime true false true %c"
|
|
|
|
%get = function_ref @getOwned : $@convention(thin) () -> @owned C
|
|
%barrier = function_ref @barrier : $@convention(thin) () -> ()
|
|
%borrow = function_ref @borrowC : $@convention(thin) (@guaranteed C) -> ()
|
|
|
|
%c = apply %get() : $@convention(thin) () -> @owned C
|
|
%c5 = copy_value %c : $C
|
|
apply %borrow(%c5) : $@convention(thin) (@guaranteed C) -> ()
|
|
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
destroy_value %c : $C
|
|
destroy_value [dead_end] %c5 : $C
|
|
unreachable
|
|
}
|
|
|
|
// CHECK-LABEL: begin running test {{.*}} on preserve_dead_end_6
|
|
// CHECK-LABEL: sil [ossa] @preserve_dead_end_6 : {{.*}} {
|
|
// CHECK: destroy_value [dead_end]
|
|
// CHECK-LABEL: } // end sil function 'preserve_dead_end_6'
|
|
// CHECK-LABEL: end running test {{.*}} on preserve_dead_end_6
|
|
sil [ossa] @preserve_dead_end_6 : $@convention(thin) () -> () {
|
|
entry:
|
|
specify_test "ossa_canonicalize_lifetime true false true %c"
|
|
|
|
%get = function_ref @getOwned : $@convention(thin) () -> @owned C
|
|
%barrier = function_ref @barrier : $@convention(thin) () -> ()
|
|
%borrow = function_ref @borrowC : $@convention(thin) (@guaranteed C) -> ()
|
|
|
|
%c = apply %get() : $@convention(thin) () -> @owned C
|
|
%c2 = copy_value %c : $C
|
|
destroy_value %c : $C
|
|
apply %borrow(%c2) : $@convention(thin) (@guaranteed C) -> ()
|
|
cond_br undef, die1, die2
|
|
|
|
die1:
|
|
destroy_value [dead_end] %c2 : $C
|
|
unreachable
|
|
|
|
die2:
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
destroy_value [dead_end] %c2 : $C
|
|
unreachable
|
|
}
|
|
|
|
// CHECK-LABEL: begin running test {{.*}} on preserve_dead_end_7
|
|
// CHECK-LABEL: sil [ossa] @preserve_dead_end_7 : {{.*}} {
|
|
// CHECK-NOT: destroy_value [dead_end]
|
|
// CHECK-LABEL: } // end sil function 'preserve_dead_end_7'
|
|
// CHECK-LABEL: end running test {{.*}} on preserve_dead_end_7
|
|
sil [ossa] @preserve_dead_end_7 : $@convention(thin) () -> () {
|
|
entry:
|
|
specify_test "ossa_canonicalize_lifetime true false true %c"
|
|
|
|
%get = function_ref @getOwned : $@convention(thin) () -> @owned C
|
|
%barrier = function_ref @barrier : $@convention(thin) () -> ()
|
|
%borrow = function_ref @borrowC : $@convention(thin) (@guaranteed C) -> ()
|
|
|
|
%c = apply %get() : $@convention(thin) () -> @owned C
|
|
%c2 = copy_value %c : $C
|
|
destroy_value %c : $C
|
|
apply %borrow(%c2) : $@convention(thin) (@guaranteed C) -> ()
|
|
cond_br undef, die1, die2
|
|
|
|
die1:
|
|
destroy_value %c2 : $C
|
|
unreachable
|
|
|
|
die2:
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
destroy_value [dead_end] %c2 : $C
|
|
unreachable
|
|
}
|
|
|
|
// (1) When no end is specified, the lifetime ends after the barrier.
|
|
// CHECK-LABEL: begin running test {{.*}} on lexical_end_at_end_1: ossa_canonicalize_lifetime
|
|
// CHECK-LABEL: sil [ossa] @lexical_end_at_end_1 : {{.*}} {
|
|
// CHECK: bb0([[C1:%[^,]+]] :
|
|
// CHECK: [[TAKE_C:%[^,]+]] = function_ref @takeC
|
|
// CHECK: [[BARRIER:%[^,]+]] = function_ref @barrier
|
|
// CHECK: [[C2:%[^,]+]] = copy_value [[C1]]
|
|
// CHECK: [[M:%[^,]+]] = move_value [[C2]]
|
|
// CHECK: apply [[TAKE_C]]([[M]])
|
|
// CHECK: apply [[BARRIER]]()
|
|
// CHECK: destroy_value [[C1]]
|
|
// CHECK-LABEL: } // end sil function 'lexical_end_at_end_1'
|
|
// CHECK-LABEL: end running test {{.*}} on lexical_end_at_end_1: ossa_canonicalize_lifetime
|
|
// (2) When the move_value is specified as a lexical-lifetime-end, the lifetime doesn't extend to the destroy.
|
|
// CHECK-LABEL: begin running test {{.*}} on lexical_end_at_end_1: ossa_canonicalize_lifetime
|
|
// CHECK-LABEL: sil [ossa] @lexical_end_at_end_1 : {{.*}} {
|
|
// CHECK: bb0([[C1:%[^,]+]] :
|
|
// CHECK: [[TAKE_C:%[^,]+]] = function_ref @takeC
|
|
// CHECK: [[BARRIER:%[^,]+]] = function_ref @barrier
|
|
// CHECK: [[M:%[^,]+]] = move_value [[C1]]
|
|
// CHECK: apply [[TAKE_C]]([[M]])
|
|
// CHECK: apply [[BARRIER]]()
|
|
// CHECK-LABEL: } // end sil function 'lexical_end_at_end_1'
|
|
// CHECK-LABEL: end running test {{.*}} on lexical_end_at_end_1: ossa_canonicalize_lifetime
|
|
sil [ossa] @lexical_end_at_end_1 : $@convention(thin) (@owned C) -> () {
|
|
entry(%c1 : @owned $C):
|
|
specify_test "ossa_canonicalize_lifetime true false true @argument"
|
|
specify_test "ossa_canonicalize_lifetime true false true @argument %m"
|
|
%takeC = function_ref @takeC : $@convention(thin) (@owned C) -> ()
|
|
%barrier = function_ref @barrier : $@convention(thin) () -> ()
|
|
%c2 = copy_value %c1 : $C
|
|
%m = move_value %c2 : $C
|
|
apply %takeC(%m) : $@convention(thin) (@owned C) -> ()
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
destroy_value %c1 : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// (1) When no end is specified, the lifetime ends after the barrier.
|
|
// CHECK-LABEL: begin running test {{.*}} on lexical_end_at_end_2: ossa_canonicalize_lifetime
|
|
// CHECK-LABEL: sil [ossa] @lexical_end_at_end_2 : {{.*}} {
|
|
// CHECK: bb0([[C1:%[^,]+]] :
|
|
// CHECK: [[TAKE_C:%[^,]+]] = function_ref @takeC
|
|
// CHECK: [[BARRIER:%[^,]+]] = function_ref @barrier
|
|
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: [[C2:%[^,]+]] = copy_value [[C1]]
|
|
// CHECK: [[M:%[^,]+]] = move_value [[C2]]
|
|
// CHECK: apply [[TAKE_C]]([[M]])
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: apply [[BARRIER]]()
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK: apply [[BARRIER]]()
|
|
// CHECK: destroy_value [[C1]]
|
|
// CHECK-LABEL: } // end sil function 'lexical_end_at_end_2'
|
|
// CHECK-LABEL: end running test {{.*}} on lexical_end_at_end_2: ossa_canonicalize_lifetime
|
|
// (2) When the move_value is specified as a lexical-lifetime-end, the lifetime
|
|
// doesn't extend to the destroy. But it DOES extend beyond barriers in
|
|
// blocks where unaffected by the move_value.
|
|
// CHECK-LABEL: begin running test {{.*}} on lexical_end_at_end_2: ossa_canonicalize_lifetime
|
|
// CHECK-LABEL: sil [ossa] @lexical_end_at_end_2 : {{.*}} {
|
|
// CHECK: bb0([[C1:%[^,]+]] : @owned $C):
|
|
// CHECK: [[TAKE_C:%[^,]+]] = function_ref @takeC
|
|
// CHECK: [[BARRIER:%[^,]+]] = function_ref @barrier
|
|
// CHECK: cond_br undef, [[LEFT]], [[RIGHT]]
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: [[M:%[^,]+]] = move_value [[C1]]
|
|
// CHECK: apply [[TAKE_C]]([[M]])
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: apply [[BARRIER]]()
|
|
// CHECK: destroy_value [[C1]]
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK: apply [[BARRIER]]()
|
|
// CHECK-LABEL: } // end sil function 'lexical_end_at_end_2'
|
|
// CHECK-LABEL: end running test {{.*}} on lexical_end_at_end_2: ossa_canonicalize_lifetime
|
|
sil [ossa] @lexical_end_at_end_2 : $@convention(thin) (@owned C) -> () {
|
|
entry(%c1 : @owned $C):
|
|
specify_test "ossa_canonicalize_lifetime true false true @argument"
|
|
specify_test "ossa_canonicalize_lifetime true false true @argument %m"
|
|
%takeC = function_ref @takeC : $@convention(thin) (@owned C) -> ()
|
|
%barrier = function_ref @barrier : $@convention(thin) () -> ()
|
|
cond_br undef, left, right
|
|
left:
|
|
%c2 = copy_value %c1 : $C
|
|
%m = move_value %c2 : $C
|
|
apply %takeC(%m) : $@convention(thin) (@owned C) -> ()
|
|
br exit
|
|
right:
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
br exit
|
|
exit:
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
destroy_value %c1 : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Check barriers on branching unconsumed paths are respected.
|
|
// CHECK-LABEL: begin running test {{.*}} on lexical_end_at_end_3: ossa_canonicalize_lifetime
|
|
// CHECK-LABEL: sil [ossa] @lexical_end_at_end_3 : {{.*}} {
|
|
// CHECK: bb0([[C1:%[^,]+]] :
|
|
// CHECK: [[TAKE_C:%[^,]+]] = function_ref @takeC
|
|
// CHECK: [[BARRIER:%[^,]+]] = function_ref @barrier
|
|
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT_TOP:bb[0-9]+]]
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: [[C2:%[^,]+]] = copy_value [[C1]]
|
|
// CHECK: [[M:%[^,]+]] = move_value [[C2]]
|
|
// CHECK: apply [[TAKE_C]]([[M]])
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[RIGHT_TOP]]:
|
|
// CHECK: cond_br undef, [[RIGHT_LEFT:bb[0-9]+]], [[RIGHT_RIGHT:bb[0-9]+]]
|
|
// CHECK: [[RIGHT_LEFT]]:
|
|
// CHECK: [[C2P:%[^,]+]] = copy_value [[C1]]
|
|
// CHECK: apply [[TAKE_C]]([[C2P]])
|
|
// CHECK: br [[RIGHT_BOTTOM:bb[0-9]+]]
|
|
// CHECK: [[RIGHT_RIGHT]]:
|
|
// CHECK: apply [[BARRIER]]()
|
|
// CHECK: br [[RIGHT_BOTTOM]]
|
|
// CHECK: [[RIGHT_BOTTOM]]:
|
|
// CHECK: apply [[BARRIER]]()
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK: apply [[BARRIER]]()
|
|
// CHECK: destroy_value [[C1]]
|
|
// CHECK-LABEL: } // end sil function 'lexical_end_at_end_3'
|
|
// CHECK-LABEL: end running test {{.*}} on lexical_end_at_end_3: ossa_canonicalize_lifetime
|
|
// CHECK-LABEL: begin running test {{.*}} on lexical_end_at_end_3: ossa_canonicalize_lifetime
|
|
// CHECK-LABEL: sil [ossa] @lexical_end_at_end_3 : {{.*}} {
|
|
// CHECK: bb0([[C1:%[^,]+]] :
|
|
// CHECK: [[TAKE_C:%[^,]+]] = function_ref @takeC
|
|
// CHECK: [[BARRIER:%[^,]+]] = function_ref @barrier
|
|
// CHECK: cond_br undef, bb1, bb2
|
|
// CHECK: bb1:
|
|
// CHECK: [[M:%[^,]+]] = move_value [[C1]]
|
|
// CHECK: apply [[TAKE_C]]([[M]])
|
|
// CHECK: br bb6
|
|
// CHECK: bb2:
|
|
// CHECK: cond_br undef, bb3, bb4
|
|
// CHECK: bb3:
|
|
// CHECK: [[C2P:%[^,]+]] = copy_value [[C1]]
|
|
// CHECK: apply [[TAKE_C]]([[C2P]])
|
|
// CHECK: br bb5
|
|
// CHECK: bb4:
|
|
// CHECK: apply [[BARRIER]]()
|
|
// CHECK: br bb5
|
|
// CHECK: bb5:
|
|
// CHECK: apply [[BARRIER]]()
|
|
// CHECK: destroy_value [[C1]]
|
|
// CHECK: br bb6
|
|
// CHECK: bb6:
|
|
// CHECK: apply [[BARRIER]]()
|
|
// CHECK-LABEL: } // end sil function 'lexical_end_at_end_3'
|
|
// CHECK-LABEL: end running test {{.*}} on lexical_end_at_end_3: ossa_canonicalize_lifetime
|
|
sil [ossa] @lexical_end_at_end_3 : $@convention(thin) (@owned C) -> () {
|
|
entry(%c1 : @owned $C):
|
|
specify_test "ossa_canonicalize_lifetime true false true @argument"
|
|
specify_test "ossa_canonicalize_lifetime true false true @argument %m"
|
|
%takeC = function_ref @takeC : $@convention(thin) (@owned C) -> ()
|
|
%barrier = function_ref @barrier : $@convention(thin) () -> ()
|
|
cond_br undef, left, right_top
|
|
left:
|
|
%c2 = copy_value %c1 : $C
|
|
%m = move_value %c2 : $C
|
|
apply %takeC(%m) : $@convention(thin) (@owned C) -> ()
|
|
br exit
|
|
right_top:
|
|
cond_br undef, right_left, right_right
|
|
right_left:
|
|
%c2p = copy_value %c1 : $C
|
|
apply %takeC(%c2p) : $@convention(thin) (@owned C) -> ()
|
|
br right_bottom
|
|
right_right:
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
br right_bottom
|
|
right_bottom:
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
br exit
|
|
exit:
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
destroy_value %c1 : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: begin running test {{.*}} on lexical_end_at_end_4: ossa_canonicalize_lifetime
|
|
// CHECK-LABEL: sil [ossa] @lexical_end_at_end_4 : {{.*}} {
|
|
// CHECK: bb0([[C1:%[^,]+]] :
|
|
// CHECK: [[TAKE_C:%[^,]+]] = function_ref @takeC
|
|
// CHECK: [[BARRIER:%[^,]+]] = function_ref @barrier
|
|
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT_TOP:bb[0-9]+]]
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: [[C2:%[^,]+]] = copy_value [[C1]]
|
|
// CHECK: [[M:%[^,]+]] = move_value [[C2]]
|
|
// CHECK: apply [[TAKE_C]]([[M]])
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[RIGHT_TOP]]:
|
|
// CHECK: cond_br undef, [[RIGHT_LEFT:bb[0-9]+]], [[RIGHT_RIGHT:bb[0-9]+]]
|
|
// CHECK: [[RIGHT_LEFT]]:
|
|
// CHECK: [[C2P:%[^,]+]] = copy_value [[C1]]
|
|
// CHECK: [[M2:%[^,]+]] = move_value [[C2P]]
|
|
// CHECK: apply [[TAKE_C]]([[M2]])
|
|
// CHECK: br [[RIGHT_BOTTOM:bb[0-9]+]]
|
|
// CHECK: [[RIGHT_RIGHT]]:
|
|
// CHECK: apply [[BARRIER]]()
|
|
// CHECK: br [[RIGHT_BOTTOM]]
|
|
// CHECK: [[RIGHT_BOTTOM]]:
|
|
// CHECK: apply [[BARRIER]]()
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK: apply [[BARRIER]]()
|
|
// CHECK: destroy_value [[C1]]
|
|
// CHECK-LABEL: } // end sil function 'lexical_end_at_end_4'
|
|
// CHECK-LABEL: end running test {{.*}} on lexical_end_at_end_4: ossa_canonicalize_lifetime
|
|
// CHECK-LABEL: begin running test {{.*}} on lexical_end_at_end_4: ossa_canonicalize_lifetime
|
|
// CHECK-LABEL: sil [ossa] @lexical_end_at_end_4 : {{.*}} {
|
|
// CHECK: bb0([[C1:%[^,]+]] :
|
|
// CHECK: [[TAKE_C:%[^,]+]] = function_ref @takeC : $@convention(thin) (@owned C) -> ()
|
|
// CHECK: [[BARRIER:%[^,]+]] = function_ref @barrier : $@convention(thin) () -> ()
|
|
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT_TOP:bb[0-9]+]]
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: [[M:%[^,]+]] = move_value [[C1]]
|
|
// CHECK: apply [[TAKE_C]]([[M]])
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[RIGHT_TOP]]:
|
|
// CHECK: cond_br undef, [[RIGHT_LEFT:bb[0-9]+]], [[RIGHT_RIGHT:bb[0-9]+]]
|
|
// CHECK: [[RIGHT_LEFT]]:
|
|
// CHECK: [[M2:%[^,]+]] = move_value [[C1]]
|
|
// CHECK: apply [[TAKE_C]]([[M2]])
|
|
// CHECK: br [[RIGHT_BOTTOM:bb[0-9]+]]
|
|
// CHECK: [[RIGHT_RIGHT]]:
|
|
// CHECK: apply [[BARRIER]]()
|
|
// CHECK: destroy_value [[C1]]
|
|
// CHECK: br [[RIGHT_BOTTOM]]
|
|
// CHECK: [[RIGHT_BOTTOM]]:
|
|
// CHECK: apply [[BARRIER]]()
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK: apply [[BARRIER]]()
|
|
// CHECK-LABEL: } // end sil function 'lexical_end_at_end_4'
|
|
// CHECK-LABEL: end running test {{.*}} on lexical_end_at_end_4: ossa_canonicalize_lifetime
|
|
sil [ossa] @lexical_end_at_end_4 : $@convention(thin) (@owned C) -> () {
|
|
entry(%c1 : @owned $C):
|
|
specify_test "ossa_canonicalize_lifetime true false true @argument"
|
|
specify_test "ossa_canonicalize_lifetime true false true @argument %m %m2"
|
|
%takeC = function_ref @takeC : $@convention(thin) (@owned C) -> ()
|
|
%barrier = function_ref @barrier : $@convention(thin) () -> ()
|
|
cond_br undef, left, right_top
|
|
left:
|
|
%c2 = copy_value %c1 : $C
|
|
%m = move_value %c2 : $C
|
|
apply %takeC(%m) : $@convention(thin) (@owned C) -> ()
|
|
br exit
|
|
right_top:
|
|
cond_br undef, right_left, right_right
|
|
right_left:
|
|
%c2p = copy_value %c1 : $C
|
|
%m2 = move_value %c2p : $C
|
|
apply %takeC(%m2) : $@convention(thin) (@owned C) -> ()
|
|
br right_bottom
|
|
right_right:
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
br right_bottom
|
|
right_bottom:
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
br exit
|
|
exit:
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
destroy_value %c1 : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: begin running test {{.*}} on dead_arg_debug_dead_end
|
|
// CHECK-LABEL: sil [ossa] @dead_arg_debug_dead_end : {{.*}} {
|
|
// CHECK: debug_value
|
|
// CHECK-LABEL: } // end sil function 'dead_arg_debug_dead_end'
|
|
// CHECK-LABEL: end running test {{.*}} on dead_arg_debug_dead_end
|
|
sil [ossa] @dead_arg_debug_dead_end : $@convention(thin) (@owned C) -> () {
|
|
entry(%c : @owned $C):
|
|
debug_value %c : $C
|
|
specify_test "ossa_canonicalize_lifetime false false true %c"
|
|
destroy_value [dead_end] %c
|
|
unreachable
|
|
}
|
|
|
|
// CHECK-LABEL: begin running test {{.*}} on consume_copy_of_borrowed_from
|
|
// CHECK-LABEL: sil [ossa] @consume_copy_of_borrowed_from : {{.*}} {
|
|
// The copy can't be eliminated because it's a copy of a borrowed-from. Such
|
|
// copies are not rewritten.
|
|
// CHECK: copy_value
|
|
// CHECK-LABEL: } // end sil function 'consume_copy_of_borrowed_from'
|
|
// CHECK-LABEL: end running test {{.*}} on consume_copy_of_borrowed_from
|
|
sil [ossa] @consume_copy_of_borrowed_from : $@convention(thin) (@owned C) -> () {
|
|
bb0(%instance : @owned $C):
|
|
%borrow = begin_borrow %instance : $C
|
|
br bb1(%instance : $C, %borrow : $C)
|
|
|
|
bb1(%instance2 : @owned $C, %reborrowed : @reborrow $C):
|
|
specify_test "ossa_canonicalize_lifetime true false true %instance2"
|
|
%reborrow = borrowed %reborrowed : $C from (%instance2 : $C)
|
|
cond_br undef, bb2, bb3
|
|
|
|
bb2:
|
|
end_borrow %reborrow : $C
|
|
destroy_value %instance2 : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
|
|
bb3:
|
|
%copy = copy_value %reborrow : $C
|
|
%takeC = function_ref @takeC : $@convention(thin) (@owned C) -> ()
|
|
apply %takeC(%copy) : $@convention(thin) (@owned C) -> ()
|
|
end_borrow %reborrow
|
|
destroy_value [dead_end] %instance2
|
|
unreachable
|
|
}
|
|
|
|
// CHECK-LABEL: begin running test {{.*}} on consume_copy_of_borrowed_from_2
|
|
// CHECK-LABEL: sil [ossa] @consume_copy_of_borrowed_from_2 : {{.*}} {
|
|
// The copy can't be eliminated because it's a copy of a borrowed-from. Such
|
|
// copies are not rewritten.
|
|
// CHECK: copy_value
|
|
// CHECK-LABEL: } // end sil function 'consume_copy_of_borrowed_from_2'
|
|
// CHECK-LABEL: end running test {{.*}} on consume_copy_of_borrowed_from_2
|
|
sil [ossa] @consume_copy_of_borrowed_from_2 : $@convention(thin) (@owned C) -> () {
|
|
bb0(%instance : @owned $C):
|
|
%borrow = begin_borrow %instance : $C
|
|
br bb1(%instance : $C, %borrow : $C)
|
|
|
|
bb1(%instance2 : @owned $C, %reborrowed : @reborrow $C):
|
|
specify_test "ossa_canonicalize_lifetime true false true %instance2"
|
|
%reborrow = borrowed %reborrowed : $C from (%instance2 : $C)
|
|
cond_br undef, bb2, bb3
|
|
|
|
bb2:
|
|
end_borrow %reborrow : $C
|
|
destroy_value %instance2 : $C
|
|
br exit
|
|
|
|
bb3:
|
|
%copy = copy_value %reborrow : $C
|
|
end_borrow %reborrow : $C
|
|
destroy_value %instance2 : $C
|
|
br bb4
|
|
|
|
bb4:
|
|
%takeC = function_ref @takeC : $@convention(thin) (@owned C) -> ()
|
|
apply %takeC(%copy) : $@convention(thin) (@owned C) -> ()
|
|
br exit
|
|
|
|
exit:
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: begin running test {{.*}} on consume_copy_before_use_in_dead_end
|
|
// CHECK-LABEL: sil [ossa] @consume_copy_before_use_in_dead_end : {{.*}} {
|
|
// CHECK: destroy_value [dead_end]
|
|
// CHECK-LABEL: } // end sil function 'consume_copy_before_use_in_dead_end'
|
|
// CHECK-LABEL: end running test {{.*}} on consume_copy_before_use_in_dead_end
|
|
sil [ossa] @consume_copy_before_use_in_dead_end : $@convention(thin) (@owned C) -> () {
|
|
entry(%c : @owned $C):
|
|
cond_br undef, exit, die
|
|
|
|
exit:
|
|
destroy_value %c
|
|
%retval = tuple ()
|
|
return %retval
|
|
|
|
die:
|
|
%move = move_value [lexical] %c
|
|
%copy = copy_value %move
|
|
specify_test "ossa_canonicalize_lifetime true false true %move"
|
|
apply undef(%move) : $@convention(thin) (@owned C) -> ()
|
|
%addr = alloc_stack $C
|
|
%token = store_borrow %copy to %addr
|
|
apply undef() : $@convention(thin) () -> ()
|
|
%reload = load_borrow %token
|
|
apply undef(%reload) : $@convention(thin) (@guaranteed C) -> ()
|
|
end_borrow %reload
|
|
end_borrow %token
|
|
destroy_value [dead_end] %copy
|
|
unreachable
|
|
}
|
|
|
|
// CHECK-LABEL: begin running test {{.*}} on consume_copy_before_use_in_dead_end_2
|
|
// CHECK-LABEL: sil [ossa] @consume_copy_before_use_in_dead_end_2 : {{.*}} {
|
|
// CHECK: destroy_value [dead_end]
|
|
// CHECK-LABEL: } // end sil function 'consume_copy_before_use_in_dead_end_2'
|
|
// CHECK-LABEL: end running test {{.*}} on consume_copy_before_use_in_dead_end_2
|
|
sil [ossa] @consume_copy_before_use_in_dead_end_2 : $@convention(thin) (@owned C) -> () {
|
|
entry(%c : @owned $C):
|
|
cond_br undef, exit, die
|
|
|
|
exit:
|
|
destroy_value %c
|
|
%retval = tuple ()
|
|
return %retval
|
|
|
|
die:
|
|
%move = move_value %c
|
|
%copy = copy_value %move
|
|
specify_test "ossa_canonicalize_lifetime true false true %move"
|
|
apply undef(%move) : $@convention(thin) (@owned C) -> ()
|
|
%addr = alloc_stack $C
|
|
%token = store_borrow %copy to %addr
|
|
apply undef() : $@convention(thin) () -> ()
|
|
%reload = load_borrow %token
|
|
apply undef(%reload) : $@convention(thin) (@guaranteed C) -> ()
|
|
end_borrow %reload
|
|
end_borrow %token
|
|
destroy_value [dead_end] %copy
|
|
unreachable
|
|
}
|
|
|
|
// The destroy of a value must not be hoisted over a destroy of a copy of a
|
|
// partial_apply [on_stack] which captures the value.
|
|
// CHECK-LABEL: begin running test {{.*}} on destroy_after_pa_copy_destroy
|
|
// CHECK-LABEL: sil [ossa] @destroy_after_pa_copy_destroy : {{.*}} {
|
|
// CHECK: bb0([[A:%[^,]+]] :
|
|
// CHECK: [[C:%[^,]+]] = move_value [[A]]
|
|
// CHECK: [[BORROW_C:%[^,]+]] = function_ref @borrowC
|
|
// CHECK: [[PA:%[^,]+]] = partial_apply [callee_guaranteed] [on_stack] [[BORROW_C]]([[C]])
|
|
// CHECK: [[PA2:%[^,]+]] = copy_value [[PA]]
|
|
// CHECK: destroy_value [[PA]]
|
|
// CHECK: destroy_value [[PA2]]
|
|
// CHECK: destroy_value [[C]]
|
|
// CHECK: apply undef()
|
|
// CHECK-LABEL: } // end sil function 'destroy_after_pa_copy_destroy'
|
|
// CHECK-LABEL: end running test {{.*}} on destroy_after_pa_copy_destroy
|
|
sil [ossa] @destroy_after_pa_copy_destroy : $@convention(thin) (@owned C) -> () {
|
|
entry(%a: @owned $C):
|
|
// To defeat deinit barriers (apply undef).
|
|
%c = move_value %a
|
|
specify_test "ossa_canonicalize_lifetime true false true %c"
|
|
|
|
%callee = function_ref @borrowC : $@convention(thin) (@guaranteed C) -> ()
|
|
%pa = partial_apply [callee_guaranteed] [on_stack] %callee(%c) : $@convention(thin) (@guaranteed C) -> ()
|
|
%pa2 = copy_value %pa
|
|
destroy_value %pa
|
|
|
|
destroy_value %pa2
|
|
// To defeat ignoredByDestroyHoisting.
|
|
apply undef() : $@convention(thin) () -> ()
|
|
destroy_value %c
|
|
%retval = tuple ()
|
|
return %retval
|
|
}
|
|
|
|
// CHECK-LABEL: begin running test {{.*}} on extend_lifetime_to_deadend_despite_copy_consume
|
|
// CHECK-LABEL: sil [ossa] @extend_lifetime_to_deadend_despite_copy_consume : {{.*}} {
|
|
// CHECK-NOT: copy_value
|
|
// CHECK-LABEL: } // end sil function 'extend_lifetime_to_deadend_despite_copy_consume'
|
|
// CHECK-LABEL: end running test {{.*}} on extend_lifetime_to_deadend_despite_copy_consume
|
|
sil [ossa] @extend_lifetime_to_deadend_despite_copy_consume : $@convention(thin) (@owned C) -> () {
|
|
entry(%c : @owned $C):
|
|
specify_test "ossa_canonicalize_lifetime true false true @argument"
|
|
%cc = copy_value %c
|
|
%takeC = function_ref @takeC : $@convention(thin) (@owned C) -> ()
|
|
apply %takeC(%cc) : $@convention(thin) (@owned C) -> ()
|
|
%run = function_ref @run : $@convention(thin) () -> Never
|
|
destroy_value [dead_end] %c
|
|
unreachable
|
|
}
|
|
|
|
/// If there's a pointer escape (here, mark_dependence) of the value, we can't
|
|
/// canonicalize its lifetime.
|
|
// CHECK-LABEL: begin running test {{.*}} on dont_canonicalize_on_pointer_escape
|
|
// CHECK-LABEL: sil [ossa] @dont_canonicalize_on_pointer_escape : {{.*}} {
|
|
// CHECK: load
|
|
// CHECK-NEXT: destroy_value
|
|
// CHECK-LABEL: } // end sil function 'dont_canonicalize_on_pointer_escape'
|
|
// CHECK-LABEL: end running test {{.*}} on dont_canonicalize_on_pointer_escape
|
|
sil [ossa] @dont_canonicalize_on_pointer_escape : $@convention(thin) () -> () {
|
|
entry:
|
|
%getC = function_ref @getC : $@convention(thin) () -> (@owned C)
|
|
%getPointer = function_ref @getPointer : $@convention(thin) () -> (@owned Pointer)
|
|
%c = apply %getC() : $@convention(thin) () -> (@owned C)
|
|
%pointer = apply %getPointer() : $@convention(thin) () -> (@owned Pointer)
|
|
specify_test "ossa_canonicalize_lifetime true false true %c"
|
|
%rawPointer = struct_extract %pointer, #Pointer.rawValue
|
|
%o = pointer_to_address %rawPointer to [strict] $*Int32
|
|
%dependent = mark_dependence [nonescaping] %o on %c
|
|
%int_addr = struct_element_addr %dependent, #Int32.int
|
|
%int = load [trivial] %int_addr
|
|
destroy_value %c
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|