mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Type annotations for instruction operands are omitted, e.g. ``` %3 = struct $S(%1, %2) ``` Operand types are redundant anyway and were only used for sanity checking in the SIL parser. But: operand types _are_ printed if the definition of the operand value was not printed yet. This happens: * if the block with the definition appears after the block where the operand's instruction is located * if a block or instruction is printed in isolation, e.g. in a debugger The old behavior can be restored with `-Xllvm -sil-print-types`. This option is added to many existing test files which check for operand types in their check-lines.
625 lines
24 KiB
Plaintext
625 lines
24 KiB
Plaintext
// RUN: %target-sil-opt -sil-print-types -update-borrowed-from -compute-side-effects -copy-propagation -enable-sil-verify-all %s | %FileCheck %s
|
|
|
|
// REQUIRES: swift_in_compiler
|
|
|
|
import Builtin
|
|
import Swift
|
|
|
|
// =============================================================================
|
|
// = DECLARATIONS {{
|
|
// =============================================================================
|
|
|
|
class X {}
|
|
class C {
|
|
weak var d: D?
|
|
}
|
|
class D {}
|
|
struct S {}
|
|
class DBox {
|
|
var d: D
|
|
}
|
|
|
|
struct CDCase {
|
|
var c: C
|
|
var d: D
|
|
}
|
|
|
|
class PointedTo {
|
|
}
|
|
class PointerWrapper {
|
|
var pointer: Builtin.RawPointer
|
|
}
|
|
|
|
enum OneOfThree { case one, two, three }
|
|
|
|
sil [ossa] @callee_guaranteed: $@convention(thin) (@guaranteed C) -> ()
|
|
sil [ossa] @get_owned_c : $@convention(thin) () -> (@owned C)
|
|
sil [ossa] @callee_owned : $@convention(thin) (@owned C) -> ()
|
|
sil [ossa] @callee_optional_d_guaranteed: $@convention(thin) (@guaranteed Optional<D>) -> ()
|
|
sil [ossa] @synchronization_point : $@convention(thin) () -> ()
|
|
sil [ossa] @modify_s : $@yield_once @convention(thin) () -> @yields @inout S
|
|
sil [ossa] @barrier : $@convention(thin) () -> ()
|
|
sil @use_C : $@convention(thin) (@guaranteed C) -> ()
|
|
sil @use_CDCase : $@convention(thin) (@guaranteed CDCase) -> ()
|
|
|
|
// This function is not a synchronization point.
|
|
sil [ossa] @empty : $@convention(thin) () -> () {
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
|
|
// =============================================================================
|
|
// = DECLARATIONS }}
|
|
// =============================================================================
|
|
|
|
// =============================================================================
|
|
// branching tests {{
|
|
// =============================================================================
|
|
|
|
// Hoist over br.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @hoist_over_branch_1 : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
|
|
// CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed
|
|
// CHECK: apply [[CALLEE_GUARANTEED]]([[INSTANCE]])
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK: br
|
|
// CHECK-LABEL: } // end sil function 'hoist_over_branch_1'
|
|
sil [ossa] @hoist_over_branch_1 : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance: @owned $C):
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
%_ = apply %callee_guaranteed(%instance) : $@convention(thin) (@guaranteed C) -> ()
|
|
br bl1
|
|
bl1:
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Hoist over cond_br.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @hoist_over_branch_2 : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
|
|
// CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed
|
|
// CHECK: apply [[CALLEE_GUARANTEED]]([[INSTANCE]])
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK: cond_br
|
|
// CHECK-LABEL: } // end sil function 'hoist_over_branch_2'
|
|
sil [ossa] @hoist_over_branch_2 : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance: @owned $C):
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
%_ = apply %callee_guaranteed(%instance) : $@convention(thin) (@guaranteed C) -> ()
|
|
cond_br undef, bl1, bl2
|
|
bl1:
|
|
br exit
|
|
bl2:
|
|
br exit
|
|
exit:
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Hoist over two brs.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @hoist_over_branch_3 : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
|
|
// CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed
|
|
// CHECK: {{%[^,]+}} = apply [[CALLEE_GUARANTEED]]([[INSTANCE]])
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK: cond_br undef
|
|
// CHECK-LABEL: } // end sil function 'hoist_over_branch_3'
|
|
sil [ossa] @hoist_over_branch_3 : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance: @owned $C):
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
%_ = apply %callee_guaranteed(%instance) : $@convention(thin) (@guaranteed C) -> ()
|
|
cond_br undef, bl1, bl2
|
|
bl1:
|
|
br exit
|
|
bl2:
|
|
br exit
|
|
exit:
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Don't hoist over 1 / 2 brs.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @hoist_over_branch_4 : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
|
|
// CHECK: cond_br undef, [[BL1:bb[0-9]+]], [[BL2:bb[0-9]+]]
|
|
// CHECK: [[BL1]]:
|
|
// CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed
|
|
// CHECK: {{%[^,]+}} = apply [[CALLEE_GUARANTEED]]([[INSTANCE]])
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[BL2]]:
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK-LABEL: } // end sil function 'hoist_over_branch_4'
|
|
sil [ossa] @hoist_over_branch_4 : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance: @owned $C):
|
|
cond_br undef, bl1, bl2
|
|
bl1:
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
%_ = apply %callee_guaranteed(%instance) : $@convention(thin) (@guaranteed C) -> ()
|
|
br exit
|
|
bl2:
|
|
br exit
|
|
exit:
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Hoist over switch_enum.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @hoist_over_branch_5 : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C, [[CASE:%[^,]+]] : $OneOfThree):
|
|
// CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed
|
|
// CHECK: apply [[CALLEE_GUARANTEED]]([[INSTANCE]])
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK: switch_enum [[CASE]]
|
|
// CHECK-LABEL: } // end sil function 'hoist_over_branch_5'
|
|
sil [ossa] @hoist_over_branch_5 : $(@owned C, OneOfThree) -> () {
|
|
entry(%instance: @owned $C, %case : $OneOfThree):
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
%_ = apply %callee_guaranteed(%instance) : $@convention(thin) (@guaranteed C) -> ()
|
|
switch_enum %case : $OneOfThree, case #OneOfThree.one!enumelt: one_dest, case #OneOfThree.two!enumelt: two_dest, case #OneOfThree.three!enumelt: three_dest
|
|
one_dest:
|
|
br exit
|
|
two_dest:
|
|
br exit
|
|
three_dest:
|
|
br exit
|
|
exit:
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Don't hoist when there are reborrows.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @hoist_over_terminator_4 : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
|
|
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]]
|
|
// CHECK: br [[WORK:bb[0-9]+]]([[LIFETIME]] : $C)
|
|
// CHECK: [[WORK]]([[LIFETIME_2:%[^,]+]] : @reborrow $C):
|
|
// CHECK: [[R:%.*]] = borrowed [[LIFETIME_2]] : $C from (%0 : $C)
|
|
// CHECK: end_borrow [[R]]
|
|
// CHECK: tuple ()
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK: br
|
|
// CHECK-LABEL: } // end sil function 'hoist_over_terminator_4'
|
|
sil [ossa] @hoist_over_terminator_4 : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance_c : @owned $C):
|
|
%lifetime_c_0 = begin_borrow %instance_c : $C
|
|
br work(%lifetime_c_0 : $C)
|
|
|
|
work(%lifetime_c : @guaranteed $C):
|
|
end_borrow %lifetime_c : $C
|
|
%foo = tuple ()
|
|
destroy_value %instance_c : $C
|
|
br exit
|
|
|
|
exit:
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Don't hoist over phi-use of value.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @dont_hoist_over_some_barred_blocks : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
|
|
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK: br [[EXIT:bb[0-9]+]](undef : $C)
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: br [[EXIT]]([[INSTANCE]] : $C)
|
|
// CHECK: [[EXIT]]([[THING:%[^,]+]] :
|
|
// CHECK: destroy_value [[THING]]
|
|
// CHECK-LABEL: } // end sil function 'dont_hoist_over_some_barred_blocks'
|
|
sil [ossa] @dont_hoist_over_some_barred_blocks : $(@owned C) -> () {
|
|
entry(%instance : @owned $C):
|
|
cond_br undef, left, right
|
|
|
|
left:
|
|
destroy_value %instance : $C
|
|
br exit(undef : $C)
|
|
|
|
right:
|
|
br exit(%instance : $C)
|
|
|
|
exit(%thing : @owned $C):
|
|
destroy_value %thing : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// =============================================================================
|
|
// branching tests }}
|
|
// =============================================================================
|
|
|
|
// =============================================================================
|
|
// loop tests {{
|
|
// =============================================================================
|
|
|
|
// Don't hoist over loop without uses.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @hoist_over_loop_1 : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
|
|
// CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed
|
|
// CHECK: apply [[CALLEE_GUARANTEED]]([[INSTANCE]])
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK: br [[LOOP_HEADER:bb[0-9]+]]
|
|
// CHECK: [[LOOP_HEADER]]:
|
|
// CHECK: br [[LOOP_BODY:bb[0-9]+]]
|
|
// CHECK: [[LOOP_BODY]]:
|
|
// CHECK: br [[LOOP_LATCH:bb[0-9]+]]
|
|
// CHECK: [[LOOP_LATCH]]:
|
|
// CHECK: cond_br undef, [[EXIT:bb[0-9]+]], [[LOOP_BACKEDGE:bb[0-9]+]]
|
|
// CHECK: [[LOOP_BACKEDGE]]:
|
|
// CHECK: br [[LOOP_HEADER]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK-LABEL: } // end sil function 'hoist_over_loop_1'
|
|
sil [ossa] @hoist_over_loop_1 : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance: @owned $C):
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
%_ = apply %callee_guaranteed(%instance) : $@convention(thin) (@guaranteed C) -> ()
|
|
br loop_header
|
|
loop_header:
|
|
br loop_body
|
|
loop_body:
|
|
br loop_latch
|
|
loop_latch:
|
|
cond_br undef, exit, loop_backedge
|
|
loop_backedge:
|
|
br loop_header
|
|
exit:
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Don't hoist over loop with uses.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @hoist_over_loop_2 : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
|
|
// CHECK: br [[LOOP_HEADER:bb[0-9]+]]
|
|
// CHECK: [[LOOP_HEADER]]:
|
|
// CHECK: br [[LOOP_BODY:bb[0-9]+]]
|
|
// CHECK: [[LOOP_BODY]]:
|
|
// CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed
|
|
// CHECK: {{%[^,]+}} = apply [[CALLEE_GUARANTEED]]([[INSTANCE]])
|
|
// CHECK: br [[LOOP_LATCH:bb[0-9]+]]
|
|
// CHECK: [[LOOP_LATCH]]:
|
|
// CHECK: cond_br undef, [[EXIT:bb[0-9]+]], [[LOOP_BACKEDGE:bb[0-9]+]]
|
|
// CHECK: [[LOOP_BACKEDGE]]:
|
|
// CHECK: br [[LOOP_HEADER]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK-LABEL: } // end sil function 'hoist_over_loop_2'
|
|
sil [ossa] @hoist_over_loop_2 : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance: @owned $C):
|
|
br loop_header
|
|
loop_header:
|
|
br loop_body
|
|
loop_body:
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
%_ = apply %callee_guaranteed(%instance) : $@convention(thin) (@guaranteed C) -> ()
|
|
br loop_latch
|
|
loop_latch:
|
|
cond_br undef, exit, loop_backedge
|
|
loop_backedge:
|
|
br loop_header
|
|
exit:
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// =============================================================================
|
|
// loop tests }}
|
|
// =============================================================================
|
|
|
|
// =============================================================================
|
|
// instruction tests {{
|
|
// =============================================================================
|
|
|
|
// Don't hoist over an apply that uses a copy of the value.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @dont_hoist_over_apply_at_copy : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[REGISTER_0:%[^,]+]] :
|
|
// CHECK: apply
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK-LABEL: } // end sil function 'dont_hoist_over_apply_at_copy'
|
|
sil [ossa] @dont_hoist_over_apply_at_copy : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance : @owned $C):
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
%copy = copy_value %instance : $C
|
|
apply %callee_guaranteed(%copy) : $@convention(thin) (@guaranteed C) -> ()
|
|
destroy_value %instance : $C
|
|
destroy_value %copy : $C
|
|
|
|
%result = tuple ()
|
|
return %result : $()
|
|
}
|
|
|
|
// Don't hoist over an apply that uses the value.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @hoist_over_apply_at_value : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
|
|
// CHECK: apply {{%[^,]+}}([[INSTANCE]])
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK-LABEL: } // end sil function 'hoist_over_apply_at_value'
|
|
sil [ossa] @hoist_over_apply_at_value : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance : @owned $C):
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
apply %callee_guaranteed(%instance) : $@convention(thin) (@guaranteed C) -> ()
|
|
destroy_value %instance : $C
|
|
%result = tuple ()
|
|
return %result : $()
|
|
}
|
|
|
|
// Don't hoist over a try apply that uses the value.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @dont_hoist_over_try_apply_at_value : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
|
|
// CHECK: try_apply undef([[INSTANCE]]) : {{.*}}, normal [[GOOD:bb[0-9]+]], error [[BAD:bb[0-9]+]]
|
|
// CHECK: [[GOOD]]
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK: [[BAD]]
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK-LABEL: } // end sil function 'dont_hoist_over_try_apply_at_value'
|
|
sil [ossa] @dont_hoist_over_try_apply_at_value : $@convention(thin) (@owned C) -> @error Error {
|
|
bb0(%instance : @owned $C):
|
|
try_apply undef(%instance) : $@convention(thin) (@guaranteed C) -> @error Error, normal good, error bad
|
|
|
|
good(%8 : $()):
|
|
destroy_value %instance : $C
|
|
%13 = tuple ()
|
|
return %13 : $()
|
|
|
|
bad(%15 : @owned $Error):
|
|
destroy_value %instance : $C
|
|
throw %15 : $Error
|
|
}
|
|
|
|
// Don't hoist over barrier try_apply.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @dont_hoist_over_try_apply_barrier : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
|
|
// CHECK: try_apply undef() : {{.*}}, normal [[GOOD:bb[0-9]+]], error [[BAD:bb[0-9]+]]
|
|
// CHECK: [[GOOD]]({{%[^,]+}} : $()):
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK: [[BAD]]([[ERROR:%[^,]+]] : @owned $any Error):
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK: throw [[ERROR]]
|
|
// CHECK-LABEL: } // end sil function 'dont_hoist_over_try_apply_barrier'
|
|
sil [ossa] @dont_hoist_over_try_apply_barrier : $@convention(thin) (@owned C) -> @error Error {
|
|
bb0(%instance : @owned $C):
|
|
apply undef(%instance) : $@convention(thin) (@guaranteed C) -> ()
|
|
try_apply undef() : $@convention(thin) () -> @error Error, normal good, error bad
|
|
|
|
good(%8 : $()):
|
|
destroy_value %instance : $C
|
|
%13 = tuple ()
|
|
return %13 : $()
|
|
|
|
bad(%15 : @owned $Error):
|
|
destroy_value %instance : $C
|
|
throw %15 : $Error
|
|
}
|
|
|
|
// Hoist up to two parallel barrier applies from a block with two predecessors.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @hoist_up_to_two_barrier_applies : $@convention(thin) (@owned C) -> () {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
|
|
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: apply undef()
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: apply undef()
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK-LABEL: } // end sil function 'hoist_up_to_two_barrier_applies'
|
|
sil [ossa] @hoist_up_to_two_barrier_applies : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance : @owned $C):
|
|
cond_br undef, left, right
|
|
|
|
left:
|
|
%result_left = apply undef() : $@convention(thin) () -> ()
|
|
br exit
|
|
|
|
right:
|
|
%result_right = apply undef() : $@convention(thin) () -> ()
|
|
br exit
|
|
|
|
exit:
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Don't hoist over end_apply. These are lowered to calls to continuations
|
|
// which can have the same sorts of side-effects as function calls.
|
|
|
|
// CHECK-LABEL: sil [ossa] @dont_hoist_over_end_apply : {{.*}} {
|
|
// CHECK: end_apply
|
|
// CHECK: destroy_value
|
|
// CHECK-LABEL: } // end sil function 'dont_hoist_over_end_apply'
|
|
sil [ossa] @dont_hoist_over_end_apply : $@convention(thin) (@owned C, S) -> () {
|
|
entry(%instance : @owned $C, %input : $S):
|
|
%modify_s = function_ref @modify_s : $@yield_once @convention(thin) () -> @yields @inout S
|
|
(%addr, %continuation) = begin_apply %modify_s() : $@yield_once @convention(thin) () -> @yields @inout S
|
|
store %input to [trivial] %addr : $*S
|
|
end_apply %continuation as $()
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Lexical destroy hoisting cannot handle a PointerEscape.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @dont_hoist_over_escape : $@convention(thin) (@owned Optional<@Sendable @callee_guaranteed () -> ()>) -> @owned Optional<@callee_guaranteed () -> ()> {
|
|
// CHECK: bb0(%0 : @owned $Optional<@Sendable @callee_guaranteed () -> ()>):
|
|
// CHECK: [[CAST:%.*]] = unchecked_bitwise_cast %0 : $Optional<@Sendable @callee_guaranteed () -> ()> to $Optional<@callee_guaranteed () -> ()>
|
|
// CHECK: [[COPY:%.*]] = copy_value [[CAST]] : $Optional<@callee_guaranteed () -> ()>
|
|
// CHECK: destroy_value %0 : $Optional<@Sendable @callee_guaranteed () -> ()>
|
|
// CHECK-LABEL: } // end sil function 'dont_hoist_over_escape'
|
|
sil [ossa] @dont_hoist_over_escape : $@convention(thin) (@owned Optional<@Sendable @callee_guaranteed () -> ()>) -> @owned Optional<@callee_guaranteed () -> ()> {
|
|
bb0(%0 : @owned $Optional<@Sendable @callee_guaranteed () -> ()>):
|
|
%cast = unchecked_bitwise_cast %0 : $Optional<@Sendable @callee_guaranteed () -> ()> to $Optional<@callee_guaranteed () -> ()>
|
|
%copy = copy_value %cast : $Optional<@callee_guaranteed () -> ()>
|
|
destroy_value %0 : $Optional<@Sendable @callee_guaranteed () -> ()>
|
|
return %copy : $Optional<@callee_guaranteed () -> ()>
|
|
}
|
|
|
|
// Hoist over applies of non-barrier fns.
|
|
// CHECK-LABEL: sil [ossa] @hoist_over_apply_of_non_barrier_fn : {{.*}} {
|
|
// CHECK: destroy_value
|
|
// CHECK: apply
|
|
// CHECK-LABEL: } // end sil function 'hoist_over_apply_of_non_barrier_fn'
|
|
sil [ossa] @hoist_over_apply_of_non_barrier_fn : $@convention(thin) (@owned X) -> () {
|
|
entry(%instance : @owned $X):
|
|
%empty = function_ref @empty : $@convention(thin) () -> ()
|
|
apply %empty() : $@convention(thin) () -> ()
|
|
destroy_value %instance : $X
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// =============================================================================
|
|
// instruction tests }}
|
|
// =============================================================================
|
|
|
|
// =============================================================================
|
|
// access scope tests {{
|
|
// =============================================================================
|
|
|
|
// Don't hoist into an access scope that contains a barrier.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @nofold_scoped_load_barrier : {{.*}} {
|
|
// CHECK: end_access
|
|
// CHECK: end_access
|
|
// CHECK: destroy_value
|
|
// CHECK-LABEL: // end sil function 'nofold_scoped_load_barrier'
|
|
sil [ossa] @nofold_scoped_load_barrier : $@convention(thin) (@owned C, @owned C) -> (@owned C) {
|
|
entry(%instance : @owned $C, %other : @owned $C):
|
|
%addr = alloc_stack $C
|
|
%store_scope = begin_access [modify] [static] %addr : $*C
|
|
store %other to [init] %store_scope : $*C
|
|
end_access %store_scope : $*C
|
|
%load_scope = begin_access [read] [static] %addr : $*C
|
|
%value = load [copy] %load_scope : $*C
|
|
%barrier = function_ref @barrier : $@convention(thin) () -> ()
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
end_access %load_scope : $*C
|
|
destroy_addr %addr : $*C
|
|
dealloc_stack %addr : $*C
|
|
destroy_value %instance : $C
|
|
return %value : $C
|
|
}
|
|
|
|
// Access scopes that are open at barrier blocks are barriers. Otherwise, we
|
|
// would hoist destroy_values into the scopes when the destroy_values are
|
|
// hoisted up to the begin of blocks whose predecessor is the barrier block.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @nohoist_into_access_scope_barred_by_barrier_block : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C, [[INOUT:%[^,]+]] : $*C):
|
|
// CHECK: [[SCOPE:%[^,]+]] = begin_access [modify] [static] [[INOUT]] : $*C
|
|
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]],
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: end_access [[SCOPE]] : $*C
|
|
// CHECK-NEXT: destroy_value [[INSTANCE]] : $C
|
|
// CHECK-LABEL: } // end sil function 'nohoist_into_access_scope_barred_by_barrier_block'
|
|
sil [ossa] @nohoist_into_access_scope_barred_by_barrier_block : $@convention(thin) (@owned C, @inout C) -> () {
|
|
entry(%instance : @owned $C, %second : $*C):
|
|
%scope = begin_access [modify] [static] %second : $*C
|
|
cond_br undef, left, right
|
|
|
|
left:
|
|
end_access %scope : $*C
|
|
%ignore = tuple ()
|
|
destroy_value %instance : $C
|
|
br exit
|
|
|
|
right:
|
|
end_access %scope : $*C
|
|
apply undef(%instance) : $@convention(thin) (@owned C) -> ()
|
|
br exit
|
|
|
|
exit:
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @hoist_guaranteedforwardingphi1 :
|
|
// bb1:
|
|
// end_borrow
|
|
// destroy_value
|
|
// br bb2
|
|
// CHECK-LABEL: } // end sil function 'hoist_guaranteedforwardingphi1'
|
|
sil [ossa] @hoist_guaranteedforwardingphi1 : $@convention(thin) (@owned CDCase) -> () {
|
|
bb0(%instance_c : @owned $CDCase):
|
|
%lifetime_c_0 = begin_borrow %instance_c : $CDCase
|
|
%ex = struct_extract %lifetime_c_0 : $CDCase, #CDCase.c
|
|
br bb1(%ex : $C)
|
|
|
|
bb1(%phi1 : @guaranteed $C):
|
|
%f1 = function_ref @use_C : $@convention(thin) (@guaranteed C) -> ()
|
|
apply %f1(%phi1) : $@convention(thin) (@guaranteed C) -> ()
|
|
br bb2
|
|
|
|
bb2:
|
|
end_borrow %lifetime_c_0 : $CDCase
|
|
destroy_value %instance_c : $CDCase
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @nohoist_guaranteedforwardingphi2 :
|
|
// CHECK: bb3({{.*}}):
|
|
// CHECK: end_borrow
|
|
// CHECK: destroy_value
|
|
// CHECK-LABEL: } // end sil function 'nohoist_guaranteedforwardingphi2'
|
|
sil [ossa] @nohoist_guaranteedforwardingphi2 : $@convention(thin) (@owned CDCase, @owned CDCase) -> () {
|
|
bb0(%instance_c1 : @owned $CDCase, %instance_c2 : @owned $CDCase):
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
destroy_value %instance_c2 : $CDCase
|
|
%lifetime_c_1 = begin_borrow %instance_c1 : $CDCase
|
|
%ex1 = struct_extract %lifetime_c_1 : $CDCase, #CDCase.c
|
|
br bb3(%ex1 : $C, %lifetime_c_1 : $CDCase, %instance_c1 : $CDCase)
|
|
|
|
bb2:
|
|
destroy_value %instance_c1 : $CDCase
|
|
%lifetime_c_2 = begin_borrow %instance_c2 : $CDCase
|
|
%ex2 = struct_extract %lifetime_c_2 : $CDCase, #CDCase.c
|
|
br bb3(%ex2 : $C, %lifetime_c_2 : $CDCase, %instance_c2 : $CDCase)
|
|
|
|
bb3(%phi1 : @guaranteed $C, %phi2 : @guaranteed $CDCase, %phi3 : @owned $CDCase):
|
|
%f1 = function_ref @use_C : $@convention(thin) (@guaranteed C) -> ()
|
|
apply %f1(%phi1) : $@convention(thin) (@guaranteed C) -> ()
|
|
%f2 = function_ref @empty : $@convention(thin) () -> ()
|
|
apply %f2() : $@convention(thin) () -> ()
|
|
br bb4
|
|
|
|
bb4:
|
|
end_borrow %phi2 : $CDCase
|
|
destroy_value %phi3 : $CDCase
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// =============================================================================
|
|
// access scope tests }}
|
|
// =============================================================================
|