mirror of
https://github.com/apple/swift.git
synced 2026-10-14 15:51:20 +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
849 lines
36 KiB
Plaintext
849 lines
36 KiB
Plaintext
// RUN: %target-sil-opt -sil-print-types -copy-propagation -enable-sil-verify-all %s | %FileCheck %s
|
|
|
|
// =============================================================================
|
|
// = DECLARATIONS {{
|
|
// =============================================================================
|
|
|
|
class C {}
|
|
class D {}
|
|
|
|
sil [ossa] @barrier : $@convention(thin) () -> ()
|
|
sil [ossa] @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
sil [ossa] @callee_owned : $@convention(thin) (@owned C) -> ()
|
|
sil [ossa] @callee_owned_owned : $@convention(thin) (@owned C, @owned C) -> ()
|
|
sil [ossa] @callee_owned_guaranteed : $@convention(thin) (@owned C, @guaranteed C) -> ()
|
|
sil [ossa] @get_owned : $@convention(thin) () -> @owned C
|
|
|
|
// =============================================================================
|
|
// = DECLARATIONS }}
|
|
// =============================================================================
|
|
|
|
// =============================================================================
|
|
// TESTS {{
|
|
// =============================================================================
|
|
|
|
// The simplest test for LexicalDestroyFolding. Check that an outer lexical
|
|
// owned lexical lifetime is added around the existing inner guaranteed lexical
|
|
// lifetime. The new lifetime should begin with a move_value [lexical] and end
|
|
// with an apply.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @fold_simplest : {{.*}} {
|
|
// CHECK: [[GET_OWNED:%[^,]+]] = function_ref @get_owned
|
|
// CHECK: [[INSTANCE:%[^,]+]] = apply [[GET_OWNED]]
|
|
// CHECK: [[CALEE_OWNED:%[^,]+]] = function_ref @callee_owned
|
|
// CHECK: [[MOVE:%[^,]+]] = move_value [lexical] [[INSTANCE]]
|
|
// CHECK: apply [[CALEE_OWNED]]([[MOVE]])
|
|
// CHECK-LABEL: } // end sil function 'fold_simplest'
|
|
sil [ossa] @fold_simplest : $@convention(thin) () -> () {
|
|
%get_owned = function_ref @get_owned : $@convention(thin) () -> (@owned C)
|
|
%instance = apply %get_owned() : $@convention(thin) () -> (@owned C)
|
|
%callee_owned = function_ref @callee_owned : $@convention(thin) (@owned C) -> ()
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
%copy = copy_value %lifetime : $C
|
|
apply %callee_owned(%copy) : $@convention(thin) (@owned C) -> ()
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Fold when there is a use of %original_borrowee prior to the lexical lifetime.
|
|
sil [ossa] @fold_prior_use : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance : @owned $C):
|
|
%callee_owned = function_ref @callee_owned : $@convention(thin) (@owned C) -> ()
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
%copy = copy_value %lifetime : $C
|
|
apply %callee_owned(%copy) : $@convention(thin) (@owned C) -> ()
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Don't fold an apply where an owned value is passed to a guaranteed parameter.
|
|
// The callee can't end ownership.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @nofold_owned_arg_to_guaranteed_param : {{.*}} {
|
|
// CHECK-NOT: move_value [lexical]
|
|
// CHECK-LABEL: } // end sil function 'nofold_owned_arg_to_guaranteed_param'
|
|
sil [ossa] @nofold_owned_arg_to_guaranteed_param : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance : @owned $C):
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
%copy = copy_value %lifetime : $C
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
apply %callee_guaranteed(%copy) : $@convention(thin) (@guaranteed C) -> ()
|
|
end_borrow %lifetime : $C
|
|
destroy_value %copy : $C
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Enclose a single block guaranteed lexical scope ending in a consuming use
|
|
// and destroy within a single block owned lexical scope, leaving the original
|
|
// borrowee intact on other paths.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @fold_left_only : {{.*}} {
|
|
// CHECK: [[GET_OWNED:%[^,]+]] = function_ref @get_owned
|
|
// CHECK: [[INSTANCE:%[^,]+]] = apply [[GET_OWNED]]
|
|
// CHECK: [[CALLEE_OWNED:%[^,]+]] = function_ref @callee_owned
|
|
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: [[MOVE:%[^,]+]] = move_value [lexical] [[INSTANCE]]
|
|
// CHECK: apply [[CALLEE_OWNED]]([[MOVE]])
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: apply [[CALLEE_OWNED]]([[INSTANCE]])
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK-LABEL: } // end sil function 'fold_left_only'
|
|
sil [ossa] @fold_left_only : $@convention(thin) () -> () {
|
|
entry:
|
|
%get_owned = function_ref @get_owned : $@convention(thin) () -> (@owned C)
|
|
%instance = apply %get_owned() : $@convention(thin) () -> (@owned C)
|
|
%callee_owned = function_ref @callee_owned : $@convention(thin) (@owned C) -> ()
|
|
cond_br undef, left, right
|
|
|
|
left:
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
%copy = copy_value %lifetime : $C
|
|
apply %callee_owned(%copy) : $@convention(thin) (@owned C) -> ()
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
br exit
|
|
|
|
right:
|
|
apply %callee_owned(%instance) : $@convention(thin) (@owned C) -> ()
|
|
br exit
|
|
|
|
exit:
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
|
|
}
|
|
|
|
// Enclose two independent parallel guaranteed lexical scopes within two
|
|
// independents owned lexical scopes.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @fold_two_independent_scopes : {{.*}} {
|
|
// CHECK: [[GET_OWNED:%[^,]+]] = function_ref @get_owned
|
|
// CHECK: [[INSTANCE:%[^,]+]] = apply [[GET_OWNED]]
|
|
// CHECK: [[CALLEE_OWNED:%[^,]+]] = function_ref @callee_owned
|
|
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: [[MOVE_LEFT:%[^,]+]] = move_value [lexical] [[INSTANCE]]
|
|
// CHECK: apply [[CALLEE_OWNED]]([[MOVE_LEFT]])
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: [[MOVE_RIGHT:%[^,]+]] = move_value [lexical] [[INSTANCE]]
|
|
// CHECK: apply [[CALLEE_OWNED]]([[MOVE_RIGHT]])
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK-LABEL: } // end sil function 'fold_two_independent_scopes'
|
|
sil [ossa] @fold_two_independent_scopes : $@convention(thin) () -> () {
|
|
entry:
|
|
%get_owned = function_ref @get_owned : $@convention(thin) () -> (@owned C)
|
|
%instance = apply %get_owned() : $@convention(thin) () -> (@owned C)
|
|
%callee_owned = function_ref @callee_owned : $@convention(thin) (@owned C) -> ()
|
|
cond_br undef, left, right
|
|
|
|
left:
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
%copy = copy_value %lifetime : $C
|
|
apply %callee_owned(%copy) : $@convention(thin) (@owned C) -> ()
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
br exit
|
|
|
|
right:
|
|
%lifetime_1 = begin_borrow [lexical] %instance : $C
|
|
%copy_1 = copy_value %lifetime_1 : $C
|
|
apply %callee_owned(%copy_1) : $@convention(thin) (@owned C) -> ()
|
|
end_borrow %lifetime_1 : $C
|
|
destroy_value %instance : $C
|
|
br exit
|
|
|
|
exit:
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
|
|
}
|
|
|
|
// Enclose a single guaranteed lexical scope that contains two parallel
|
|
// applies of owned arguments with the destroy at a NONcanonical position
|
|
// within a single owned lexical scope.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @fold_two_parallel_applies___noncanonical_destroys : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}:
|
|
// CHECK: [[GET_OWNED:%[^,]+]] = function_ref @get_owned
|
|
// CHECK: [[INSTANCE:%[^,]+]] = apply [[GET_OWNED]]
|
|
// CHECK: [[CALLEE_OWNED:%[^,]+]] = function_ref @callee_owned
|
|
// CHECK: [[MOVE:%[^,]+]] = move_value [lexical] [[INSTANCE]]
|
|
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: apply [[CALLEE_OWNED]]([[MOVE]])
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: apply [[CALLEE_OWNED]]([[MOVE]])
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK-LABEL: } // end sil function 'fold_two_parallel_applies___noncanonical_destroys'
|
|
sil [ossa] @fold_two_parallel_applies___noncanonical_destroys : $@convention(thin) () -> () {
|
|
entry:
|
|
%get_owned = function_ref @get_owned : $@convention(thin) () -> (@owned C)
|
|
%instance = apply %get_owned() : $@convention(thin) () -> (@owned C)
|
|
%callee_owned = function_ref @callee_owned : $@convention(thin) (@owned C) -> ()
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
cond_br undef, left, right
|
|
|
|
left:
|
|
%copy = copy_value %lifetime : $C
|
|
apply %callee_owned(%copy) : $@convention(thin) (@owned C) -> ()
|
|
br exit
|
|
|
|
right:
|
|
%copy_2 = copy_value %lifetime : $C
|
|
apply %callee_owned(%copy_2) : $@convention(thin) (@owned C) -> ()
|
|
br exit
|
|
|
|
exit:
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Enclose a single guaranteed lexical scope that contains two parallel
|
|
// applies of owned arguments with the destroy at a noncanonical position
|
|
// within a single owned lexical scope.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @fold_two_parallel_applies___canonical_destroys : {{.*}} {
|
|
// CHECK: [[GET_OWNED:%[^,]+]] = function_ref @get_owned
|
|
// CHECK: [[INSTANCE:%[^,]+]] = apply [[GET_OWNED]]
|
|
// CHECK: [[CALLEE_OWNED:%[^,]+]] = function_ref @callee_owned
|
|
// CHECK: [[MOVE:%[^,]+]] = move_value [lexical] [[INSTANCE]] : $C
|
|
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
|
|
// CHECK: [[LEFT:bb[0-9]+]]:
|
|
// CHECK: apply [[CALLEE_OWNED]]([[MOVE]])
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: apply [[CALLEE_OWNED]]([[MOVE]])
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK-LABEL: } // end sil function 'fold_two_parallel_applies___canonical_destroys'
|
|
sil [ossa] @fold_two_parallel_applies___canonical_destroys : $@convention(thin) () -> () {
|
|
entry:
|
|
%get_owned = function_ref @get_owned : $@convention(thin) () -> (@owned C)
|
|
%instance = apply %get_owned() : $@convention(thin) () -> (@owned C)
|
|
%callee_owned = function_ref @callee_owned : $@convention(thin) (@owned C) -> ()
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
cond_br undef, left, right
|
|
|
|
left:
|
|
%copy = copy_value %lifetime : $C
|
|
apply %callee_owned(%copy) : $@convention(thin) (@owned C) -> ()
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
br exit
|
|
|
|
right:
|
|
%copy_2 = copy_value %lifetime : $C
|
|
apply %callee_owned(%copy_2) : $@convention(thin) (@owned C) -> ()
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
br exit
|
|
|
|
exit:
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Enclose a guaranteed lexical scope within an owned lexical scope when it
|
|
// appears in a multiblock subgraph that is parallel to another apply use of the
|
|
// borrowee that is not within the scope.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @fold_multiblock_borrow_single_apply_with_parallel_use : {{.*}} {
|
|
// CHECK: [[GET_OWNED:%[^,]+]] = function_ref @get_owned
|
|
// CHECK: [[INSTANCE:%[^,]+]] = apply [[GET_OWNED]]
|
|
// CHECK: [[CALLEE_OWNED:%[^,]+]] = function_ref @callee_owned
|
|
// CHECK: cond_br undef, [[LEFT1:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
|
|
// CHECK: [[LEFT1]]:
|
|
// CHECK: [[MOVE:%[^,]+]] = move_value [lexical] [[INSTANCE]]
|
|
// CHECK: cond_br undef, [[LEFT2:bb[0-9]+]], [[LEFT3:bb[0-9]+]]
|
|
// CHECK: [[LEFT2]]:
|
|
// CHECK: apply [[CALLEE_OWNED]]([[MOVE]])
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[LEFT3]]:
|
|
// CHECK: destroy_value [[MOVE]]
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: apply [[CALLEE_OWNED]]([[INSTANCE]])
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK-LABEL: } // end sil function 'fold_multiblock_borrow_single_apply_with_parallel_use'
|
|
sil [ossa] @fold_multiblock_borrow_single_apply_with_parallel_use : $@convention(thin) () -> () {
|
|
entry:
|
|
%get_owned = function_ref @get_owned : $@convention(thin) () -> (@owned C)
|
|
%instance = apply %get_owned() : $@convention(thin) () -> (@owned C)
|
|
%callee_owned = function_ref @callee_owned : $@convention(thin) (@owned C) -> ()
|
|
cond_br undef, left1, right
|
|
|
|
left1:
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
%copy = copy_value %lifetime : $C
|
|
cond_br undef, left2, left3
|
|
|
|
left2:
|
|
apply %callee_owned(%copy) : $@convention(thin) (@owned C) -> ()
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
br exit
|
|
|
|
left3:
|
|
destroy_value %copy : $C
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
br exit
|
|
|
|
right:
|
|
apply %callee_owned(%instance) : $@convention(thin) (@owned C) -> ()
|
|
br exit
|
|
|
|
exit:
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Enclose a guaranteed lexical scope within an owned lexical scope when it
|
|
// appears in a multiblock subgraph that is parallel to another apply use of the
|
|
// borrowee that is not within the scope.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @fold_multiblock_borrow_single_apply_and_parallel_singleblock_borrow : {{.*}} {
|
|
// CHECK: [[GET_OWNED:%[^,]+]] = function_ref @get_owned
|
|
// CHECK: [[INSTANCE:%[^,]+]] = apply [[GET_OWNED]]
|
|
// CHECK: [[CALLEE_OWNED:%[^,]+]] = function_ref @callee_owned
|
|
// CHECK: cond_br undef, [[LEFT1:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
|
|
// CHECK: [[LEFT1]]:
|
|
// CHECK: [[MOVE:%[^,]+]] = move_value [lexical] [[INSTANCE]]
|
|
// CHECK: cond_br undef, [[LEFT2:bb[0-9]+]], [[LEFT3:bb[0-9]+]]
|
|
// CHECK: [[LEFT2]]:
|
|
// CHECK: apply [[CALLEE_OWNED]]([[MOVE]])
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[LEFT3]]:
|
|
// CHECK: destroy_value [[MOVE]]
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: [[MOVE_2:%[^,]+]] = move_value [lexical] [[INSTANCE]]
|
|
// CHECK: apply [[CALLEE_OWNED]]([[MOVE_2]])
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK-LABEL: } // end sil function 'fold_multiblock_borrow_single_apply_and_parallel_singleblock_borrow'
|
|
sil [ossa] @fold_multiblock_borrow_single_apply_and_parallel_singleblock_borrow : $@convention(thin) () -> () {
|
|
entry:
|
|
%get_owned = function_ref @get_owned : $@convention(thin) () -> (@owned C)
|
|
%instance = apply %get_owned() : $@convention(thin) () -> (@owned C)
|
|
%callee_owned = function_ref @callee_owned : $@convention(thin) (@owned C) -> ()
|
|
cond_br undef, left1, right
|
|
|
|
left1:
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
%copy = copy_value %lifetime : $C
|
|
cond_br undef, left2, left3
|
|
|
|
left2:
|
|
apply %callee_owned(%copy) : $@convention(thin) (@owned C) -> ()
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
br exit
|
|
|
|
left3:
|
|
destroy_value %copy : $C
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
br exit
|
|
|
|
right:
|
|
%lifetime_1 = begin_borrow [lexical] %instance : $C
|
|
%copy_1 = copy_value %lifetime_1 : $C
|
|
apply %callee_owned(%copy_1) : $@convention(thin) (@owned C) -> ()
|
|
end_borrow %lifetime_1 : $C
|
|
destroy_value %instance : $C
|
|
br exit
|
|
|
|
exit:
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
|
|
}
|
|
|
|
// Fold with an apply that takes the borrowee @owned twice and no use of the
|
|
// guaranteed lifetime remains.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @fold_single_block_one_apply_double_use_all_owned : {{.*}} {
|
|
// CHECK: [[GET_OWNED:%[^,]+]] = function_ref @get_owned
|
|
// CHECK: [[INSTANCE:%[^,]+]] = apply [[GET_OWNED]]
|
|
// CHECK: [[LIFETIME:%[^,]+]] = move_value [lexical] [[INSTANCE]]
|
|
// CHECK: [[LIFETIME_GUARANTEED:%[^,]+]] = begin_borrow [lexical] [[LIFETIME]]
|
|
// CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed
|
|
// CHECK: apply [[CALLEE_GUARANTEED]]([[LIFETIME_GUARANTEED]])
|
|
// CHECK: end_borrow [[LIFETIME_GUARANTEED]]
|
|
// CHECK: [[COPY:%[^,]+]] = copy_value [[LIFETIME]]
|
|
// CHECK: [[CALLEE_OWNED_OWNED:%[^,]+]] = function_ref @callee_owned_owned
|
|
// CHECK: apply [[CALLEE_OWNED_OWNED]]([[LIFETIME]], [[COPY]])
|
|
// CHECK-LABEL: } // end sil function 'fold_single_block_one_apply_double_use_all_owned'
|
|
sil [ossa] @fold_single_block_one_apply_double_use_all_owned : $@convention(thin) () -> () {
|
|
entry:
|
|
%get_owned = function_ref @get_owned : $@convention(thin) () -> (@owned C)
|
|
%instance = apply %get_owned() : $@convention(thin) () -> (@owned C)
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
apply %callee_guaranteed(%lifetime) : $@convention(thin) (@guaranteed C) -> ()
|
|
%copy_1 = copy_value %lifetime : $C
|
|
%copy_2 = copy_value %lifetime : $C
|
|
%callee_owned_owned = function_ref @callee_owned_owned : $@convention(thin) (@owned C, @owned C) -> ()
|
|
apply %callee_owned_owned(%copy_1, %copy_2) : $@convention(thin) (@owned C, @owned C) -> ()
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Fold with an apply that takes the borrowee @owned twice and a use of the
|
|
// guaranteed lifetime remains.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @fold_single_block_one_apply_double_use_all_owned__no_remaining_uses : {{.*}} {
|
|
// CHECK: [[GET_OWNED:%[^,]+]] = function_ref @get_owned
|
|
// CHECK: [[INSTANCE:%[^,]+]] = apply [[GET_OWNED]]
|
|
// CHECK: [[MOVE:%[^,]+]] = move_value [lexical] [[INSTANCE]]
|
|
// CHECK: [[COPY:%[^,]+]] = copy_value [[MOVE]]
|
|
// CHECK: [[CALLEE_OWNED_OWNED:%[^,]+]] = function_ref @callee_owned_owned
|
|
// CHECK: apply [[CALLEE_OWNED_OWNED]]([[MOVE]], [[COPY]])
|
|
// CHECK-LABEL: } // end sil function 'fold_single_block_one_apply_double_use_all_owned__no_remaining_uses'
|
|
sil [ossa] @fold_single_block_one_apply_double_use_all_owned__no_remaining_uses : $@convention(thin) () -> () {
|
|
entry:
|
|
%get_owned = function_ref @get_owned : $@convention(thin) () -> (@owned C)
|
|
%instance = apply %get_owned() : $@convention(thin) () -> (@owned C)
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
%copy_1 = copy_value %lifetime : $C
|
|
%copy_2 = copy_value %lifetime : $C
|
|
%callee_owned_owned = function_ref @callee_owned_owned : $@convention(thin) (@owned C, @owned C) -> ()
|
|
apply %callee_owned_owned(%copy_1, %copy_2) : $@convention(thin) (@owned C, @owned C) -> ()
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
} // end sil function 'test'
|
|
|
|
// Do NOT fold with an apply that takes both a copy of the borrow @owned and
|
|
// also the borrow itself @guaranteed.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @nofold_single_block_one_apply_double_use_one_guaranteed : {{.*}} {
|
|
// CHECK-NOT: move_value [lexical]
|
|
// CHECK-LABEL: } // end sil function 'nofold_single_block_one_apply_double_use_one_guaranteed'
|
|
sil [ossa] @nofold_single_block_one_apply_double_use_one_guaranteed : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance : @owned $C):
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
%copy = copy_value %lifetime : $C
|
|
%callee_owned_guaranteed = function_ref @callee_owned_guaranteed : $@convention(thin) (@owned C, @guaranteed C) -> ()
|
|
apply %callee_owned_guaranteed(%copy, %lifetime) : $@convention(thin) (@owned C, @guaranteed C) -> ()
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Do NOT fold an apply of an owned value when the borrowee is guaranteed.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @nofold_guaranteed_borrowee : {{.*}} {
|
|
// CHECK-NOT: move_value [lexical]
|
|
// CHECK-LABEL: } // end sil function 'nofold_guaranteed_borrowee'
|
|
sil [ossa] @nofold_guaranteed_borrowee : $@convention(thin) (@guaranteed C) -> () {
|
|
entry(%instance : @guaranteed $C):
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
%callee_owned = function_ref @callee_owned : $@convention(thin) (@owned C) -> ()
|
|
%copy = copy_value %lifetime : $C
|
|
apply %callee_owned(%copy) : $@convention(thin) (@owned C) -> ()
|
|
end_borrow %lifetime : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @nofold_nonlexical : {{.*}} {
|
|
// CHECK-NOT: move_value [lexical]
|
|
// CHECK-LABEL: } // end sil function 'nofold_nonlexical'
|
|
sil [ossa] @nofold_nonlexical : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance : @owned $C):
|
|
%callee_owned = function_ref @callee_owned : $@convention(thin) (@owned C) -> ()
|
|
%lifetime = begin_borrow %instance : $C
|
|
%copy = copy_value %lifetime : $C
|
|
apply %callee_owned(%copy) : $@convention(thin) (@owned C) -> ()
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Fold with the last consuming use but not with a previous consuming use.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @fold_single_block_two_applies_first_only : {{.*}} {
|
|
// CHECK: [[GET_OWNED:%[^,]+]] = function_ref @get_owned
|
|
// CHECK: [[INSTANCE:%[^,]+]] = apply [[GET_OWNED]]
|
|
// CHECK: [[MOVE:%[^,]+]] = move_value [lexical] [[INSTANCE]]
|
|
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [lexical] [[MOVE]]
|
|
// CHECK: [[CALLEE_OWNED:%[^,]+]] = function_ref @callee_owned
|
|
// CHECK: [[COPY:%[^,]+]] = copy_value [[LIFETIME]]
|
|
// CHECK: apply [[CALLEE_OWNED]]([[COPY]])
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK: tuple ()
|
|
// CHECK: apply [[CALLEE_OWNED]]([[MOVE]])
|
|
// CHECK-LABEL: } // end sil function 'fold_single_block_two_applies_first_only'
|
|
sil [ossa] @fold_single_block_two_applies_first_only : $@convention(thin) () -> () {
|
|
%get_owned = function_ref @get_owned : $@convention(thin) () -> (@owned C)
|
|
%instance = apply %get_owned() : $@convention(thin) () -> (@owned C)
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
%callee_owned = function_ref @callee_owned : $@convention(thin) (@owned C) -> ()
|
|
%copy_1 = copy_value %lifetime : $C
|
|
apply %callee_owned(%copy_1) : $@convention(thin) (@owned C) -> ()
|
|
%retval = tuple ()
|
|
%copy_2 = copy_value %lifetime : $C
|
|
apply %callee_owned(%copy_2) : $@convention(thin) (@owned C) -> ()
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
return %retval : $()
|
|
}
|
|
|
|
// Don't fold with apply when guaranteed lexical value used in one but not two
|
|
// branches and the lexical scope ends after the use on the non-lexical branch.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @nofold_two_parallel_owned_uses_one_lexical : {{.*}} {
|
|
// CHECK-NOT: move_value [lexical]
|
|
// CHECK-LABEL: } // end sil function 'nofold_two_parallel_owned_uses_one_lexical'
|
|
sil [ossa] @nofold_two_parallel_owned_uses_one_lexical : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance : @owned $C):
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
%callee_owned = function_ref @callee_owned : $@convention(thin) (@owned C) -> ()
|
|
cond_br undef, left, right
|
|
|
|
left:
|
|
%copy_1 = copy_value %lifetime : $C
|
|
apply %callee_owned(%copy_1) : $@convention(thin) (@owned C) -> ()
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
br exit
|
|
|
|
right:
|
|
%copy_2 = copy_value %instance : $C
|
|
apply %callee_owned(%copy_2) : $@convention(thin) (@owned C) -> ()
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
br exit
|
|
|
|
exit:
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Fold even if there is a noncanonicalized copy which is otherwise used.
|
|
// CHECK-LABEL: sil [ossa] @fold_noncanonical_copy_with_other_use : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}:
|
|
// CHECK: [[GET_OWNED:%[^,]+]] = function_ref @get_owned
|
|
// CHECK: [[INSTANCE:%[^,]+]] = apply [[GET_OWNED]]()
|
|
// CHECK: [[MOVE:%[^,]+]] = move_value [lexical] [[INSTANCE]]
|
|
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [lexical] [[MOVE]]
|
|
// CHECK: [[COPY:%[^,]+]] = copy_value [[LIFETIME]]
|
|
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: [[CALLEE_OWNED:%[^,]+]] = function_ref @callee_owned
|
|
// CHECK: destroy_value [[COPY]]
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK: apply [[CALLEE_OWNED]]([[MOVE]])
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed
|
|
// CHECK: apply [[CALLEE_GUARANTEED]]([[COPY]])
|
|
// CHECK: destroy_value [[COPY]]
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK: destroy_value [[MOVE]]
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK-LABEL: } // end sil function 'fold_noncanonical_copy_with_other_use'
|
|
sil [ossa] @fold_noncanonical_copy_with_other_use : $@convention(thin) () -> () {
|
|
entry:
|
|
%get_owned = function_ref @get_owned : $@convention(thin) () -> (@owned C)
|
|
%instance = apply %get_owned() : $@convention(thin) () -> (@owned C)
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
%copy = copy_value %lifetime : $C
|
|
cond_br undef, left, right
|
|
|
|
left:
|
|
%callee_owned = function_ref @callee_owned : $@convention(thin) (@owned C) -> ()
|
|
apply %callee_owned(%copy) : $@convention(thin) (@owned C) -> ()
|
|
br exit
|
|
|
|
right:
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
apply %callee_guaranteed(%copy) : $@convention(thin) (@guaranteed C) -> ()
|
|
destroy_value %copy : $C
|
|
br exit
|
|
|
|
exit:
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Fold in the face of an unreachable block on one path so long as there is no
|
|
// use of %original_borrowee in that unreachable-terminated branch.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @fold_unreachable : {{.*}} {
|
|
// CHECK: [[GET_OWNED:%[^,]+]] = function_ref @get_owned
|
|
// CHECK: [[INSTANCE:%[^,]+]] = apply [[GET_OWNED]]
|
|
// CHECK: [[MOVE:%[^,]+]] = move_value [lexical] [[INSTANCE]]
|
|
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: unreachable
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: [[CALLEE_OWNED:%[^,]+]] = function_ref @callee_owned
|
|
// CHECK: apply [[CALLEE_OWNED]]([[MOVE]])
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK-LABEL: } // end sil function 'fold_unreachable'
|
|
sil [ossa] @fold_unreachable : $@convention(thin) () -> () {
|
|
entry:
|
|
%get_owned = function_ref @get_owned : $@convention(thin) () -> (@owned C)
|
|
%instance = apply %get_owned() : $@convention(thin) () -> (@owned C)
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
cond_br undef, left, right
|
|
|
|
left:
|
|
end_borrow %lifetime
|
|
destroy_value [dead_end] %instance
|
|
unreachable
|
|
|
|
right:
|
|
%callee_owned = function_ref @callee_owned : $@convention(thin) (@owned C) -> ()
|
|
%copy = copy_value %lifetime : $C
|
|
apply %callee_owned(%copy) : $@convention(thin) (@owned C) -> ()
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
br exit
|
|
|
|
exit:
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Don't fold in the face of an unreachable block on one path so long as there
|
|
// is no use of %original_borrowee in that "unterminated" branch.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @nofold_unreachable : {{.*}} {
|
|
// CHECK-NOT: move_value [lexical]
|
|
// CHECK-LABEL: } // end sil function 'nofold_unreachable'
|
|
sil [ossa] @nofold_unreachable : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance : @owned $C):
|
|
%callee_owned = function_ref @callee_owned : $@convention(thin) (@owned C) -> ()
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
cond_br undef, left, right
|
|
|
|
left:
|
|
end_borrow %lifetime
|
|
apply %callee_owned(%instance) : $@convention(thin) (@owned C) -> ()
|
|
unreachable
|
|
|
|
right:
|
|
%copy = copy_value %lifetime : $C
|
|
apply %callee_owned(%copy) : $@convention(thin) (@owned C) -> ()
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
br exit
|
|
|
|
exit:
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Don't fold if there's an outer borrow scope enclosing the guaranteed lexical
|
|
// scope and it has a use within the lexical scope.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @nofold_outer_borrow : {{.*}} {
|
|
// CHECK-NOT: move_value [lexical]
|
|
// CHECK-LABEL: } // end sil function 'nofold_outer_borrow'
|
|
sil [ossa] @nofold_outer_borrow : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance : @owned $C):
|
|
%outer = begin_borrow %instance : $C
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
%callee_owned = function_ref @callee_owned : $@convention(thin) (@owned C) -> ()
|
|
%barrier = function_ref @barrier : $@convention(thin) () -> ()
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
%copy = copy_value %lifetime : $C
|
|
apply %callee_guaranteed(%outer) : $@convention(thin) (@guaranteed C) -> ()
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
apply %callee_owned(%copy) : $@convention(thin) (@owned C) -> ()
|
|
end_borrow %lifetime : $C
|
|
end_borrow %outer : $C
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Don't fold if there's an outer borrow scope started in one block enclosing
|
|
// the guaranteed lexical scope started in another block and it has a use
|
|
// within the lexical scope.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @nofold_outer_borrow__twoblock : {{.*}} {
|
|
// CHECK-NOT: move_value [lexical]
|
|
// CHECK-LABEL: } // end sil function 'nofold_outer_borrow__twoblock'
|
|
sil [ossa] @nofold_outer_borrow__twoblock : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance : @owned $C):
|
|
%outer = begin_borrow %instance : $C
|
|
br exit
|
|
exit:
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
%callee_owned = function_ref @callee_owned : $@convention(thin) (@owned C) -> ()
|
|
%barrier = function_ref @barrier : $@convention(thin) () -> ()
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
%copy = copy_value %lifetime : $C
|
|
apply %callee_guaranteed(%outer) : $@convention(thin) (@guaranteed C) -> ()
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
apply %callee_owned(%copy) : $@convention(thin) (@owned C) -> ()
|
|
end_borrow %lifetime : $C
|
|
end_borrow %outer : $C
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Don't fold if there are TWO layers of outer borrows, both started in one
|
|
// block enclosing the guaranteed lexical scope started--all together in the
|
|
// same block--and both have a use within the lexical scope.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @nofold_outer_borrow_2x : {{.*}} {
|
|
// CHECK-NOT: move_value [lexical]
|
|
// CHECK-LABEL: } // end sil function 'nofold_outer_borrow_2x'
|
|
sil [ossa] @nofold_outer_borrow_2x : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance : @owned $C):
|
|
%outer = begin_borrow %instance : $C
|
|
%middle = begin_borrow %outer : $C
|
|
br exit
|
|
exit:
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
%callee_owned = function_ref @callee_owned : $@convention(thin) (@owned C) -> ()
|
|
%barrier = function_ref @barrier : $@convention(thin) () -> ()
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
%copy = copy_value %lifetime : $C
|
|
apply %callee_guaranteed(%outer) : $@convention(thin) (@guaranteed C) -> ()
|
|
apply %callee_guaranteed(%middle) : $@convention(thin) (@guaranteed C) -> ()
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
apply %callee_owned(%copy) : $@convention(thin) (@owned C) -> ()
|
|
end_borrow %lifetime : $C
|
|
end_borrow %middle : $C
|
|
end_borrow %outer : $C
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Don't fold if there are TWO layers of outer borrows, both started in one
|
|
// block, enclosing the guaranteed lexical scope started in another block and
|
|
// both have a use within the lexical scope.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @nofold_outer_borrow_2x__twoblock : {{.*}} {
|
|
// CHECK-NOT: move_value [lexical]
|
|
// CHECK-LABEL: } // end sil function 'nofold_outer_borrow_2x__twoblock'
|
|
sil [ossa] @nofold_outer_borrow_2x__twoblock : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance : @owned $C):
|
|
%outer = begin_borrow %instance : $C
|
|
%middle = begin_borrow %outer : $C
|
|
br exit
|
|
exit:
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
%callee_owned = function_ref @callee_owned : $@convention(thin) (@owned C) -> ()
|
|
%barrier = function_ref @barrier : $@convention(thin) () -> ()
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
%copy = copy_value %lifetime : $C
|
|
apply %callee_guaranteed(%outer) : $@convention(thin) (@guaranteed C) -> ()
|
|
apply %callee_guaranteed(%middle) : $@convention(thin) (@guaranteed C) -> ()
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
apply %callee_owned(%copy) : $@convention(thin) (@owned C) -> ()
|
|
end_borrow %lifetime : $C
|
|
end_borrow %middle : $C
|
|
end_borrow %outer : $C
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Don't fold when a different borrow of the enclosing %original_borrowee end
|
|
// in the middle of the lexical scope.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @nofold_outer_borrow_2x_end_inside__twoblock : {{.*}} {
|
|
// CHECK-NOT: move_value [lexical]
|
|
// CHECK-LABEL: } // end sil function 'nofold_outer_borrow_2x_end_inside__twoblock'
|
|
sil [ossa] @nofold_outer_borrow_2x_end_inside__twoblock : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance : @owned $C):
|
|
%outer = begin_borrow %instance : $C
|
|
%middle = begin_borrow %outer : $C
|
|
br exit
|
|
exit:
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
%callee_owned = function_ref @callee_owned : $@convention(thin) (@owned C) -> ()
|
|
%barrier = function_ref @barrier : $@convention(thin) () -> ()
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
%copy = copy_value %lifetime : $C
|
|
apply %callee_guaranteed(%outer) : $@convention(thin) (@guaranteed C) -> ()
|
|
apply %callee_guaranteed(%middle) : $@convention(thin) (@guaranteed C) -> ()
|
|
end_borrow %middle : $C
|
|
end_borrow %outer : $C
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
apply %callee_owned(%copy) : $@convention(thin) (@owned C) -> ()
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Don't fold applies of the borrowed value.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @nofold_closure : $@convention(thin) (@owned () -> ()) -> () {
|
|
// CHECK-NOT: move_value [lexical]
|
|
// CHECK-LABEL: } // end sil function 'nofold_closure'
|
|
sil [ossa] @nofold_closure : $@convention(thin) (@owned @convention(thick) () -> ()) -> () {
|
|
entry(%instance : @owned $@convention(thick) () -> ()):
|
|
%lifetime = begin_borrow [lexical] %instance : $@convention(thick) () -> ()
|
|
apply %lifetime() : $@convention(thick) () -> ()
|
|
end_borrow %lifetime : $@convention(thick) () -> ()
|
|
destroy_value %instance : $@convention(thick) () -> ()
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Lexical destroy folding cannot handle a PointerEscape.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @dont_fold_over_escape : $@convention(thin) (@owned C) -> @owned D {
|
|
// CHECK: bb0(%0 : @owned $C):
|
|
// CHECK: [[CAST:%.*]] = unchecked_bitwise_cast %0 : $C to $D
|
|
// CHECK: [[BORROW:%.*]] = begin_borrow [lexical] %0 : $C
|
|
// CHECK: [[COPY0:%.*]] = copy_value [[BORROW]] : $C
|
|
// CHECK: apply %{{.*}}([[COPY0]]) : $@convention(thin) (@owned C) -> ()
|
|
// CHECK: [[COPY1:%.*]] = copy_value [[CAST]] : $D
|
|
// CHECK: destroy_value %0 : $C
|
|
// CHECK-LABEL: } // end sil function 'dont_fold_over_escape'
|
|
sil [ossa] @dont_fold_over_escape : $@convention(thin) (@owned C) -> @owned D {
|
|
bb0(%0 : @owned $C):
|
|
%callee_owned = function_ref @callee_owned : $@convention(thin) (@owned C) -> ()
|
|
%cast = unchecked_bitwise_cast %0 : $C to $D
|
|
%lifetime = begin_borrow [lexical] %0 : $C
|
|
%copy0 = copy_value %lifetime : $C
|
|
apply %callee_owned(%copy0) : $@convention(thin) (@owned C) -> ()
|
|
end_borrow %lifetime : $C
|
|
%copy = copy_value %cast : $D
|
|
destroy_value %0 : $C
|
|
return %copy : $D
|
|
}
|
|
|
|
// =============================================================================
|
|
// TESTS }}
|
|
// =============================================================================
|