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.
1250 lines
52 KiB
Plaintext
1250 lines
52 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 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 }
|
|
|
|
final class Object {
|
|
init()
|
|
}
|
|
|
|
public struct ClassStorage {
|
|
var ref: C
|
|
}
|
|
public struct ClassWrapper {
|
|
var storage: ClassStorage
|
|
}
|
|
|
|
sil @returnUnmanagedC : $@convention(method) (@guaranteed C) -> @sil_unmanaged C
|
|
|
|
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 [ossa] @failable : $@convention(thin) () -> @error Error
|
|
// 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: [[LIFETIME:%[^,]]] = begin_borrow [[INSTANCE]]
|
|
// CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed
|
|
// CHECK: {{%[^,]+}} = apply [[CALLEE_GUARANTEED]]([[LIFETIME]])
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK: return [[INSTANCE]]
|
|
// CHECK-LABEL: } // end sil function 'hoist_over_branch_1'
|
|
sil [ossa] @hoist_over_branch_1 : $@convention(thin) (@owned C) -> @owned C {
|
|
entry(%instance: @owned $C):
|
|
%lifetime = begin_borrow %instance : $C
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
%_ = apply %callee_guaranteed(%lifetime) : $@convention(thin) (@guaranteed C) -> ()
|
|
br bl1
|
|
bl1:
|
|
end_borrow %lifetime : $C
|
|
return %instance : $C
|
|
}
|
|
|
|
// Hoist over cond_br.
|
|
// CHECK-LABEL: sil [ossa] @hoist_over_branch_2 : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
|
|
// CHECK: [[LIFETIME:%[^,]]] = begin_borrow [[INSTANCE]]
|
|
// CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed
|
|
// CHECK: {{%[^,]+}} = apply [[CALLEE_GUARANTEED]]([[LIFETIME]])
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK: cond_br undef, [[BL1:bb[0-9]+]], [[BL2:bb[0-9]+]]
|
|
// CHECK: [[BL1]]:
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[BL2]]:
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK: return [[INSTANCE]]
|
|
// CHECK-LABEL: } // end sil function 'hoist_over_branch_2'
|
|
sil [ossa] @hoist_over_branch_2 : $@convention(thin) (@owned C) -> @owned C {
|
|
entry(%instance: @owned $C):
|
|
%lifetime = begin_borrow %instance : $C
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
%_ = apply %callee_guaranteed(%lifetime) : $@convention(thin) (@guaranteed C) -> ()
|
|
cond_br undef, bl1, bl2
|
|
bl1:
|
|
end_borrow %lifetime : $C
|
|
br exit
|
|
bl2:
|
|
end_borrow %lifetime : $C
|
|
br exit
|
|
exit:
|
|
return %instance : $C
|
|
}
|
|
|
|
// Hoist over two brs.
|
|
// CHECK-LABEL: sil [ossa] @hoist_over_branch_3 : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
|
|
// CHECK: [[LIFETIME:%[^,]]] = begin_borrow [[INSTANCE]]
|
|
// CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed
|
|
// CHECK: {{%[^,]+}} = apply [[CALLEE_GUARANTEED]]([[LIFETIME]])
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK: cond_br undef, [[BL1:bb[0-9]+]], [[BL2:bb[0-9]+]]
|
|
// CHECK: [[BL1]]:
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[BL2]]:
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK: return [[INSTANCE]]
|
|
// CHECK-LABEL: } // end sil function 'hoist_over_branch_3'
|
|
sil [ossa] @hoist_over_branch_3 : $@convention(thin) (@owned C) -> @owned C {
|
|
entry(%instance: @owned $C):
|
|
%lifetime = begin_borrow %instance : $C
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
%_ = apply %callee_guaranteed(%lifetime) : $@convention(thin) (@guaranteed C) -> ()
|
|
cond_br undef, bl1, bl2
|
|
bl1:
|
|
br exit
|
|
bl2:
|
|
br exit
|
|
exit:
|
|
end_borrow %lifetime : $C
|
|
return %instance : $C
|
|
}
|
|
|
|
// Don't hoist over 1 / 2 brs.
|
|
// CHECK-LABEL: sil [ossa] @hoist_over_branch_4 : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
|
|
// CHECK: [[LIFETIME:%[^,]]] = begin_borrow [[INSTANCE]]
|
|
// 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]]([[LIFETIME]])
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[BL2]]:
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK: return [[INSTANCE]]
|
|
// CHECK-LABEL: } // end sil function 'hoist_over_branch_4'
|
|
sil [ossa] @hoist_over_branch_4 : $@convention(thin) (@owned C) -> @owned C {
|
|
entry(%instance: @owned $C):
|
|
%lifetime = begin_borrow %instance : $C
|
|
cond_br undef, bl1, bl2
|
|
bl1:
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
%_ = apply %callee_guaranteed(%lifetime) : $@convention(thin) (@guaranteed C) -> ()
|
|
br exit
|
|
bl2:
|
|
br exit
|
|
exit:
|
|
end_borrow %lifetime : $C
|
|
return %instance : $C
|
|
}
|
|
|
|
// Hoist over switch_enum destinations.
|
|
// CHECK-LABEL: sil [ossa] @hoist_over_branch_5 : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C, [[CASE:%[^,]+]] : $OneOfThree):
|
|
// CHECK: [[LIFETIME:%[^,]]] = begin_borrow [[INSTANCE]]
|
|
// CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed
|
|
// CHECK: {{%[0-9]+}} = apply [[CALLEE_GUARANTEED]]([[LIFETIME]])
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK: switch_enum [[CASE]] : $OneOfThree, case #OneOfThree.one!enumelt: [[ONE_DEST:bb[0-9]+]], case #OneOfThree.two!enumelt: [[TWO_DEST:bb[0-9]+]], case #OneOfThree.three!enumelt: [[THREE_DEST:bb[0-9]+]]
|
|
// CHECK: [[ONE_DEST]]:
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[TWO_DEST]]:
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[THREE_DEST]]:
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK: return [[INSTANCE]]
|
|
// CHECK-LABEL: } // end sil function 'hoist_over_branch_5'
|
|
sil [ossa] @hoist_over_branch_5 : $(@owned C, OneOfThree) -> @owned C {
|
|
entry(%instance: @owned $C, %case : $OneOfThree):
|
|
%lifetime = begin_borrow %instance : $C
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
%_ = apply %callee_guaranteed(%lifetime) : $@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:
|
|
end_borrow %lifetime : $C
|
|
return %instance : $C
|
|
}
|
|
|
|
// Don't hoist over transformation terminator which forwards ownership of
|
|
// borrowed value.
|
|
// CHECK-LABEL: sil [ossa] @hoist_over_terminator_1 : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $Optional<C>):
|
|
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]]
|
|
// CHECK: switch_enum [[LIFETIME]] : $Optional<C>, case #Optional.some!enumelt: [[SOME_DEST:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_DEST:bb[0-9]+]]
|
|
// CHECK: [[SOME_DEST]]([[LIFETIME_2:%[^,]+]] : @guaranteed $C):
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[NONE_DEST]]:
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK: return [[INSTANCE]]
|
|
// CHECK-LABEL: } // end sil function 'hoist_over_terminator_1'
|
|
sil [ossa] @hoist_over_terminator_1 : $@convention(thin) (@owned Optional<C>) -> @owned Optional<C> {
|
|
entry(%instance_c : @owned $Optional<C>):
|
|
%lifetime_c = begin_borrow %instance_c : $Optional<C>
|
|
switch_enum %lifetime_c : $Optional<C>, case #Optional.some!enumelt: some_dest, case #Optional.none!enumelt: none_dest
|
|
|
|
some_dest(%lifetime_c_2 : @guaranteed $C):
|
|
br exit
|
|
|
|
none_dest:
|
|
br exit
|
|
|
|
exit:
|
|
end_borrow %lifetime_c : $Optional<C>
|
|
return %instance_c : $Optional<C>
|
|
}
|
|
|
|
// Hoist over brs but don't hoist over transformation terminator which forwards
|
|
// ownership of guaranteed value which itself had forwarding ownership of the
|
|
// original borrow.
|
|
// CHECK-LABEL: sil [ossa] @hoist_over_terminator_2 : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
|
|
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]]
|
|
// CHECK: [[MAYBE:%[^,]+]] = enum $Optional<C>, #Optional.some!enumelt, [[LIFETIME]]
|
|
// CHECK: switch_enum [[MAYBE]] : $Optional<C>, case #Optional.some!enumelt: [[SOME_DEST:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_DEST:bb[0-9]+]]
|
|
// CHECK: [[SOME_DEST]]([[LIFETIME_2:%[^,]+]] : @guaranteed $C):
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[NONE_DEST]]:
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK: return [[INSTANCE]]
|
|
// CHECK-LABEL: } // end sil function 'hoist_over_terminator_2'
|
|
sil [ossa] @hoist_over_terminator_2 : $@convention(thin) (@owned C) -> @owned C {
|
|
entry(%instance_c : @owned $C):
|
|
%lifetime_c = begin_borrow %instance_c : $C
|
|
%maybe_c = enum $Optional<C>, #Optional.some!enumelt, %lifetime_c : $C
|
|
switch_enum %maybe_c : $Optional<C>, case #Optional.some!enumelt: some_dest, case #Optional.none!enumelt: none_dest
|
|
|
|
some_dest(%lifetime_c_2 : @guaranteed $C):
|
|
br exit
|
|
|
|
none_dest:
|
|
br exit
|
|
|
|
exit:
|
|
end_borrow %lifetime_c : $C
|
|
return %instance_c : $C
|
|
}
|
|
|
|
// Don't hoist over transformation terminator which forwards ownership of
|
|
// guaranteed value which itself had forwarding ownership of the original
|
|
// borrow.
|
|
// CHECK-LABEL: sil [ossa] @dont_hoist_over_terminator_3 : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
|
|
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]]
|
|
// CHECK: [[MAYBE:%[^,]+]] = enum $Optional<C>, #Optional.some!enumelt, [[LIFETIME]]
|
|
// CHECK: switch_enum [[MAYBE]] : $Optional<C>, case #Optional.some!enumelt: [[SOME_DEST:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_DEST:bb[0-9]+]]
|
|
// CHECK: [[SOME_DEST]]([[LIFETIME_2:%[^,]+]] : @guaranteed $C):
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[NONE_DEST]]:
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK: return [[INSTANCE]]
|
|
// CHECK-LABEL: } // end sil function 'dont_hoist_over_terminator_3'
|
|
sil [ossa] @dont_hoist_over_terminator_3 : $@convention(thin) (@owned C) -> @owned C {
|
|
entry(%instance_c : @owned $C):
|
|
%lifetime_c = begin_borrow %instance_c : $C
|
|
%maybe_c = enum $Optional<C>, #Optional.some!enumelt, %lifetime_c : $C
|
|
switch_enum %maybe_c : $Optional<C>, case #Optional.some!enumelt: some_dest, case #Optional.none!enumelt: none_dest
|
|
|
|
some_dest(%lifetime_c_2 : @guaranteed $C):
|
|
end_borrow %lifetime_c : $C
|
|
br exit
|
|
|
|
none_dest:
|
|
end_borrow %lifetime_c : $C
|
|
br exit
|
|
|
|
exit:
|
|
return %instance_c : $C
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dont_hoist_over_terminator_3__barrier : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] :
|
|
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]]
|
|
// CHECK: [[MAYBE_C:%[^,]+]] = enum $Optional<C>, #Optional.some!enumelt, [[LIFETIME]]
|
|
// CHECK: switch_enum [[MAYBE_C]] : $Optional<C>, case #Optional.some!enumelt: [[SOME_DEST:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_DEST:bb[0-9]+]]
|
|
// CHECK: [[SOME_DEST]]({{%[^,]+}} :
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK: tuple ()
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[NONE_DEST]]:
|
|
// CHECK: [[BARRIER:%[^,]+]] = function_ref @barrier
|
|
// CHECK: apply [[BARRIER]]()
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK: tuple ()
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK-LABEL: } // end sil function 'dont_hoist_over_terminator_3__barrier'
|
|
sil [ossa] @dont_hoist_over_terminator_3__barrier : $@convention(thin) (@owned C) -> @owned C {
|
|
entry(%instance_c : @owned $C):
|
|
%lifetime_c = begin_borrow %instance_c : $C
|
|
%maybe_c = enum $Optional<C>, #Optional.some!enumelt, %lifetime_c : $C
|
|
switch_enum %maybe_c : $Optional<C>, case #Optional.some!enumelt: some_dest, case #Optional.none!enumelt: none_dest
|
|
|
|
some_dest(%lifetime_c_2 : @guaranteed $C):
|
|
%tuple = tuple ()
|
|
end_borrow %lifetime_c : $C
|
|
br exit
|
|
|
|
none_dest:
|
|
%barrier = function_ref @barrier : $@convention(thin) () -> ()
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
%tuple_2 = tuple ()
|
|
end_borrow %lifetime_c : $C
|
|
br exit
|
|
|
|
exit:
|
|
return %instance_c : $C
|
|
}
|
|
|
|
// Don't hoist over terminator that 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: [[BF:%.*]] = borrowed [[LIFETIME_2]]
|
|
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: end_borrow [[BF]]
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: end_borrow [[BF]]
|
|
// CHECK: br [[EXIT]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK: return [[INSTANCE]]
|
|
// CHECK-LABEL: } // end sil function 'hoist_over_terminator_4'
|
|
sil [ossa] @hoist_over_terminator_4 : $@convention(thin) (@owned C) -> @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):
|
|
cond_br undef, left, right
|
|
|
|
left:
|
|
end_borrow %lifetime_c : $C
|
|
br exit
|
|
|
|
right:
|
|
end_borrow %lifetime_c : $C
|
|
br exit
|
|
|
|
exit:
|
|
return %instance_c : $C
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dont_hoist_over_some_barred_blocks : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
|
|
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]] : $C
|
|
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: br [[EXIT:bb[0-9]+]](undef : $C)
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: [[COPY:%[^,]+]] = copy_value [[LIFETIME]] : $C
|
|
// CHECK: br [[EXIT]]([[COPY]] : $C)
|
|
// CHECK: [[EXIT]]
|
|
// CHECK: end_borrow [[LIFETIME]] : $C
|
|
// 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):
|
|
%borrow = begin_borrow %instance : $C
|
|
cond_br undef, left, right
|
|
|
|
left:
|
|
br exit(undef : $C)
|
|
|
|
right:
|
|
%copy = copy_value %borrow : $C
|
|
br exit(%copy : $C)
|
|
|
|
exit(%thing : @owned $C):
|
|
end_borrow %borrow : $C
|
|
destroy_value %thing : $C
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dont_hoist_over_some_barred_blocks__2 : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
|
|
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [lexical] [[INSTANCE]] : $C
|
|
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: br [[TRAMPOLINE:bb[0-9]+]](undef : $C)
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: [[COPY:%[^,]+]] = copy_value [[LIFETIME]] : $C
|
|
// CHECK: br [[TRAMPOLINE]]([[COPY]] : $C)
|
|
// CHECK: [[TRAMPOLINE]]
|
|
// CHECK-LABEL: } // end sil function 'dont_hoist_over_some_barred_blocks__2'
|
|
sil [ossa] @dont_hoist_over_some_barred_blocks__2 : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance: @owned $C):
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
cond_br undef, left, right
|
|
|
|
left:
|
|
br trampoline(undef : $C)
|
|
|
|
right:
|
|
%copy = copy_value %lifetime : $C
|
|
br trampoline(%copy : $C)
|
|
|
|
trampoline(%copy_1 : @owned $C):
|
|
br exit
|
|
|
|
exit:
|
|
end_borrow %lifetime : $C
|
|
%retval = tuple ()
|
|
destroy_value %copy_1 : $C
|
|
destroy_value %instance : $C
|
|
return %retval : $()
|
|
}
|
|
|
|
// =============================================================================
|
|
// branching tests }}
|
|
// =============================================================================
|
|
|
|
// =============================================================================
|
|
// loop tests {{
|
|
// =============================================================================
|
|
|
|
// Hoist over loop without uses.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @hoist_over_loop_1 : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
|
|
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]]
|
|
// CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed
|
|
// CHECK: {{%[^,]+}} = apply [[CALLEE_GUARANTEED]]([[LIFETIME]])
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// 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: return [[INSTANCE]]
|
|
// CHECK-LABEL: } // end sil function 'hoist_over_loop_1'
|
|
sil [ossa] @hoist_over_loop_1 : $@convention(thin) (@owned C) -> @owned C {
|
|
entry(%instance: @owned $C):
|
|
%lifetime = begin_borrow %instance : $C
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
%_ = apply %callee_guaranteed(%lifetime) : $@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:
|
|
end_borrow %lifetime : $C
|
|
return %instance : $C
|
|
}
|
|
|
|
// Don't hoist over loop with uses.
|
|
// CHECK-LABEL: sil [ossa] @hoist_over_loop_2 : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
|
|
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]]
|
|
// 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]]([[LIFETIME]])
|
|
// 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: end_borrow [[LIFETIME]]
|
|
// CHECK: return [[INSTANCE]]
|
|
// CHECK-LABEL: } // end sil function 'hoist_over_loop_2'
|
|
sil [ossa] @hoist_over_loop_2 : $@convention(thin) (@owned C) -> @owned C {
|
|
entry(%instance: @owned $C):
|
|
%lifetime = begin_borrow %instance : $C
|
|
br loop_header
|
|
loop_header:
|
|
br loop_body
|
|
loop_body:
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
%_ = apply %callee_guaranteed(%lifetime) : $@convention(thin) (@guaranteed C) -> ()
|
|
br loop_latch
|
|
loop_latch:
|
|
cond_br undef, exit, loop_backedge
|
|
loop_backedge:
|
|
br loop_header
|
|
exit:
|
|
end_borrow %lifetime : $C
|
|
return %instance : $C
|
|
}
|
|
|
|
// =============================================================================
|
|
// loop tests }}
|
|
// =============================================================================
|
|
|
|
// =============================================================================
|
|
// instruction tests {{
|
|
// =============================================================================
|
|
|
|
// Don't hoist over struct of begin_borrow'd value.
|
|
// CHECK-LABEL: sil [ossa] @hoist_over_struct : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE_C:%[^,]+]] : @owned $C, [[INSTANCE_D:%[^,]+]] : @owned $D):
|
|
// CHECK: [[LIFETIME_C:%[^,]+]] = begin_borrow [[INSTANCE_C]]
|
|
// CHECK: [[COPY_C:%[^,]+]] = copy_value [[LIFETIME_C]]
|
|
// CHECK: [[LIFETIME_D:%[^,]+]] = begin_borrow [[INSTANCE_D]]
|
|
// CHECK: struct $CDCase ([[LIFETIME_C]] : $C, [[LIFETIME_D]] : $D)
|
|
// CHECK: end_borrow [[LIFETIME_D]]
|
|
// CHECK: end_borrow [[LIFETIME_C]]
|
|
// CHECK: destroy_value [[INSTANCE_D]]
|
|
// CHECK: return [[COPY_C]]
|
|
// CHECK-LABEL: } // end sil function 'hoist_over_struct'
|
|
sil [ossa] @hoist_over_struct : $@convention(thin) (@owned C, @owned D) -> @owned C {
|
|
entry(%instance_c: @owned $C, %instance_d: @owned $D):
|
|
%lifetime_c = begin_borrow %instance_c : $C
|
|
%copy_c = copy_value %lifetime_c : $C
|
|
%lifetime_d = begin_borrow %instance_d : $D
|
|
%copy_d = copy_value %lifetime_d : $D
|
|
|
|
%struct = struct $CDCase (%lifetime_c : $C, %lifetime_d : $D)
|
|
end_borrow %lifetime_d : $D
|
|
|
|
destroy_value %copy_d : $D
|
|
destroy_value %instance_d : $D
|
|
end_borrow %lifetime_c : $C
|
|
destroy_value %instance_c : $C
|
|
return %copy_c : $C
|
|
}
|
|
|
|
// Don't hoist over store_weak into a field of the object being borrowed.
|
|
// CHECK-LABEL: sil [ossa] @hoist_over_store_weak_1 : {{.*}} {
|
|
// CHECK: store_weak
|
|
// CHECK: end_borrow
|
|
// CHECK-LABEL: } // end sil function 'hoist_over_store_weak_1'
|
|
sil [ossa] @hoist_over_store_weak_1 : $@convention(thin) (@owned C, @owned D) -> @owned C {
|
|
entry(%instance_c: @owned $C, %instance_d: @owned $D):
|
|
%lifetime_c = begin_borrow %instance_c : $C
|
|
%lifetime_d = begin_borrow %instance_d : $D
|
|
%copy_d = copy_value %lifetime_d : $D
|
|
%optional_d = enum $Optional<D>, #Optional.some!enumelt, %copy_d : $D
|
|
%c_d_addr = ref_element_addr %lifetime_c : $C, #C.d
|
|
%c_d_access = begin_access [modify] [dynamic] %c_d_addr : $*@sil_weak Optional<D>
|
|
|
|
store_weak %optional_d to %c_d_access : $*@sil_weak Optional<D>
|
|
end_borrow %lifetime_d : $D
|
|
|
|
end_access %c_d_access : $*@sil_weak Optional<D>
|
|
destroy_value %optional_d : $Optional<D>
|
|
destroy_value %instance_d : $D
|
|
end_borrow %lifetime_c : $C
|
|
return %instance_c : $C
|
|
}
|
|
|
|
// Hoist over store to unrelated stack address. Do not hoist over store to
|
|
// field of lifetime.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @hoist_over_store : $@convention(thin) () -> () {
|
|
// CHECK: [[D:%[^,]+]] = alloc_ref $PointerWrapper
|
|
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[D]] : $PointerWrapper
|
|
// CHECK: [[ADDR:%[^,]+]] = alloc_stack $PointedTo
|
|
// CHECK: [[PTR:%[^,]+]] = address_to_pointer [[ADDR]]
|
|
// CHECK: [[FIELD:%[^,]+]] = ref_element_addr [[LIFETIME]]
|
|
// CHECK: store [[PTR]] to [trivial] [[FIELD]]
|
|
// CHECK: end_borrow [[LIFETIME]] : $PointerWrapper
|
|
// CHECK: [[C:%[^,]+]] = alloc_ref $PointedTo
|
|
// CHECK: store [[C]] to [init] [[ADDR]] : $*PointedTo
|
|
// CHECK-LABEL: } // end sil function 'hoist_over_store'
|
|
sil [ossa] @hoist_over_store : $@convention(thin) () -> () {
|
|
bb0:
|
|
%d = alloc_ref $PointerWrapper
|
|
%lifetime = begin_borrow %d : $PointerWrapper
|
|
%addr = alloc_stack $PointedTo
|
|
%ptr = address_to_pointer %addr : $*PointedTo to $Builtin.RawPointer
|
|
%field = ref_element_addr %lifetime : $PointerWrapper, #PointerWrapper.pointer
|
|
|
|
store %ptr to [trivial] %field : $*Builtin.RawPointer
|
|
|
|
%c = alloc_ref $PointedTo
|
|
|
|
store %c to [init] %addr : $*PointedTo
|
|
end_borrow %lifetime : $PointerWrapper
|
|
|
|
destroy_value %d : $PointerWrapper
|
|
|
|
destroy_addr %addr : $*PointedTo
|
|
dealloc_stack %addr : $*PointedTo
|
|
|
|
%33 = tuple ()
|
|
return %33 : $()
|
|
}
|
|
|
|
// Don't hoist over load_weak.
|
|
// There is an ordering guarantee between a load_weak of an weak reference that
|
|
// subsequently is zeroed by a deinit; if the load_weak originally happens
|
|
// before the deinit that would deinit the weakly referenced object, it must
|
|
// always remain first.
|
|
// CHECK-LABEL: sil [ossa] @dont_hoist_over_load_weak : {{.*}} {
|
|
// CHECK: load_weak
|
|
// CHECK: end_borrow
|
|
// CHECK-LABEL: } // end sil function 'dont_hoist_over_load_weak'
|
|
sil [ossa] @dont_hoist_over_load_weak : $@convention(thin) (@owned DBox) -> () {
|
|
entry(%instance : @owned $DBox):
|
|
%lifetime = begin_borrow [lexical] %instance : $DBox
|
|
debug_value %lifetime : $DBox, let, name "dbox"
|
|
%addr = alloc_stack [lexical] $@sil_weak Optional<D>
|
|
%d_addr = ref_element_addr %lifetime : $DBox, #DBox.d
|
|
%d = load [copy] %d_addr : $*D
|
|
%some_d = enum $Optional<D>, #Optional.some!enumelt, %d : $D
|
|
store_weak %some_d to [init] %addr : $*@sil_weak Optional<D>
|
|
destroy_value %some_d : $Optional<D>
|
|
|
|
%loaded = load_weak %addr : $*@sil_weak Optional<D>
|
|
end_borrow %lifetime : $DBox
|
|
|
|
destroy_value %instance : $DBox
|
|
|
|
destroy_value %loaded : $Optional<D>
|
|
destroy_addr %addr : $*@sil_weak Optional<D>
|
|
dealloc_stack %addr : $*@sil_weak Optional<D>
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Don't hoist over load.
|
|
// There is an ordering guarantee between a load of an address the storage of
|
|
// which is subsequently deallocated by a deinit; if the load originally happens
|
|
// before the deinit that would dealocated the pointed-to object, it must always
|
|
// remain first.
|
|
|
|
// Hoist over and rewrite copy of borrow.
|
|
//
|
|
// Everything in this test case except the copy_value and end_borrow is here in
|
|
// order to obstruct other optimizations from kicking in that obfuscate that the
|
|
// fact that the end_borrow was hoisted over the copy_value.
|
|
// CHECK-LABEL: sil [ossa] @hoist_over_copy_of_borrow : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @guaranteed $C):
|
|
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [lexical] [[INSTANCE]]
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK: {{%[^,]+}} = copy_value [[INSTANCE]]
|
|
// CHECK-LABEL: } // end sil function 'hoist_over_copy_of_borrow'
|
|
sil [ossa] @hoist_over_copy_of_borrow : $@convention(thin) (@guaranteed C) -> () {
|
|
entry(%instance : @guaranteed $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) -> ()
|
|
%synchronization_point = function_ref @synchronization_point : $@convention(thin) () -> ()
|
|
%synchronized = apply %synchronization_point() : $@convention(thin) () -> ()
|
|
%copy = copy_value %instance : $C
|
|
end_borrow %lifetime : $C
|
|
%callee_owned = function_ref @callee_owned : $@convention(thin) (@owned C) -> ()
|
|
%2 = apply %callee_owned(%copy) : $@convention(thin) (@owned C) -> ()
|
|
%result = tuple ()
|
|
return %result : $()
|
|
}
|
|
|
|
// Don't hoist over an apply that uses a copy of the borrow.
|
|
// CHECK-LABEL: sil [ossa] @dont_hoist_over_apply_at_copy : {{.*}} {
|
|
// CHECK: begin_borrow
|
|
// CHECK: copy_value
|
|
// CHECK: apply
|
|
// CHECK: end_borrow
|
|
// CHECK: destroy_value
|
|
// 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):
|
|
%synchronization_point = function_ref @synchronization_point : $@convention(thin) () -> ()
|
|
%callee_owned = function_ref @callee_owned : $@convention(thin) (@owned C) -> ()
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
%lifetime = begin_borrow %instance : $C
|
|
%copy = copy_value %lifetime : $C
|
|
%1 = apply %callee_guaranteed(%copy) : $@convention(thin) (@guaranteed C) -> ()
|
|
%synchronized = apply %synchronization_point() : $@convention(thin) () -> ()
|
|
%2 = apply %callee_guaranteed(%copy) : $@convention(thin) (@guaranteed C) -> ()
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
destroy_value %copy : $C
|
|
|
|
%result = tuple ()
|
|
return %result : $()
|
|
}
|
|
|
|
// Don't hoist over an apply that uses the borrow.
|
|
// CHECK-LABEL: sil [ossa] @hoist_over_apply_at_borrow : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
|
|
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]]
|
|
// CHECK: apply {{%[^,]+}}([[LIFETIME]])
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK-LABEL: } // end sil function 'hoist_over_apply_at_borrow'
|
|
sil [ossa] @hoist_over_apply_at_borrow : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance : @owned $C):
|
|
%lifetime = begin_borrow %instance : $C
|
|
%copy = copy_value %lifetime : $C
|
|
%callee_owned = function_ref @callee_owned : $@convention(thin) (@owned C) -> ()
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
%1 = apply %callee_owned(%copy) : $@convention(thin) (@owned C) -> ()
|
|
%synchronization_point = function_ref @synchronization_point : $@convention(thin) () -> ()
|
|
%synchronized = apply %synchronization_point() : $@convention(thin) () -> ()
|
|
%2 = apply %callee_guaranteed(%lifetime) : $@convention(thin) (@guaranteed C) -> ()
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
|
|
%result = tuple ()
|
|
return %result : $()
|
|
}
|
|
|
|
// Hoist over a begin_borrow of a copy_value of the original begin_borrow.
|
|
//
|
|
// Most of the test's contents are just to obstruct optimization.
|
|
// CHECK-LABEL: sil [ossa] @hoist_over_borrow_of_copy : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
|
|
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]]
|
|
// CHECK: [[COPY:%[^,]+]] = copy_value [[LIFETIME]]
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK: begin_borrow [[COPY]]
|
|
// CHECK-LABEL: } // end sil function 'hoist_over_borrow_of_copy'
|
|
sil [ossa] @hoist_over_borrow_of_copy : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance : @owned $C):
|
|
%lifetime_1 = begin_borrow %instance : $C
|
|
%copy_1 = copy_value %lifetime_1 : $C
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
%1 = apply %callee_guaranteed(%copy_1) : $@convention(thin) (@guaranteed C) -> ()
|
|
%synchronization_point = function_ref @synchronization_point : $@convention(thin) () -> ()
|
|
%synchronized = apply %synchronization_point() : $@convention(thin) () -> ()
|
|
%lifetime_2 = begin_borrow %copy_1 : $C
|
|
end_borrow %lifetime_1 : $C
|
|
%copy_2 = copy_value %lifetime_2 : $C
|
|
%2 = apply %callee_guaranteed(%copy_2) : $@convention(thin) (@guaranteed C) -> ()
|
|
%synchronized2 = apply %synchronization_point() : $@convention(thin) () -> ()
|
|
end_borrow %lifetime_2 : $C
|
|
destroy_value %copy_1 : $C
|
|
destroy_value %copy_2 : $C
|
|
destroy_value %instance : $C
|
|
|
|
%result = tuple ()
|
|
return %result : $()
|
|
}
|
|
|
|
// Hoist over copy_value of %copy, a copy_value of %borrow.
|
|
// CHECK-LABEL: sil [ossa] @hoist_over_copy_of_copy : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
|
|
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]] : $C
|
|
// CHECK: [[COPY_1:%[^,]+]] = copy_value [[LIFETIME]] : $C
|
|
// CHECK: end_borrow [[LIFETIME]] : $C
|
|
// CHECK: copy_value [[INSTANCE]] : $C
|
|
// CHECK-LABEL: } // end sil function 'hoist_over_copy_of_copy'
|
|
sil [ossa] @hoist_over_copy_of_copy : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance : @owned $C):
|
|
%synchronization_point = function_ref @synchronization_point : $@convention(thin) () -> ()
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
%callee_owned = function_ref @callee_owned : $@convention(thin) (@owned C) -> ()
|
|
%lifetime_1 = begin_borrow %instance : $C
|
|
%copy_1 = copy_value %lifetime_1 : $C
|
|
%_ = apply %callee_guaranteed(%lifetime_1) : $@convention(thin) (@guaranteed C) -> ()
|
|
%synchronized = apply %synchronization_point() : $@convention(thin) () -> ()
|
|
%copy_2 = copy_value %copy_1 : $C
|
|
%result = tuple ()
|
|
end_borrow %lifetime_1 : $C
|
|
%0 = apply %callee_owned(%instance) : $@convention(thin) (@owned C) -> ()
|
|
%1 = apply %callee_owned(%copy_1) : $@convention(thin) (@owned C) -> ()
|
|
%2 = apply %callee_owned(%copy_2) : $@convention(thin) (@owned C) -> ()
|
|
|
|
return %result : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dont_hoist_over_try_apply_at_borrow : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
|
|
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]]
|
|
// CHECK: try_apply undef([[LIFETIME]]) : {{.*}}, normal [[GOOD:bb[0-9]+]], error [[BAD:bb[0-9]+]]
|
|
// CHECK: [[GOOD]]
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK: [[BAD]]
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK-LABEL: } // end sil function 'dont_hoist_over_try_apply_at_borrow'
|
|
sil [ossa] @dont_hoist_over_try_apply_at_borrow : $@convention(thin) (@owned C) -> @error Error {
|
|
bb0(%instance : @owned $C):
|
|
%lifetime = begin_borrow %instance : $C
|
|
try_apply undef(%lifetime) : $@convention(thin) (@guaranteed C) -> @error Error, normal good, error bad
|
|
|
|
good(%8 : $()):
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
%13 = tuple ()
|
|
return %13 : $()
|
|
|
|
bad(%15 : @owned $Error):
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
throw %15 : $Error
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dont_hoist_over_try_apply_barrier : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
|
|
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]]
|
|
// CHECK: try_apply undef() : {{.*}}, normal [[GOOD:bb[0-9]+]], error [[BAD:bb[0-9]+]]
|
|
// CHECK: [[GOOD]]({{%[^,]+}} : $()):
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK: [[BAD]]([[ERROR:%[^,]+]] : @owned $any Error):
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// 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):
|
|
%lifetime = begin_borrow %instance : $C
|
|
%_ = apply undef(%lifetime) : $@convention(thin) (@guaranteed C) -> ()
|
|
try_apply undef() : $@convention(thin) () -> @error Error, normal good, error bad
|
|
|
|
good(%8 : $()):
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
%13 = tuple ()
|
|
return %13 : $()
|
|
|
|
bad(%15 : @owned $Error):
|
|
end_borrow %lifetime : $C
|
|
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: [[LIFETIME:%[^,]+]] = begin_borrow [lexical] [[INSTANCE]]
|
|
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: apply undef()
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: apply undef()
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// 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):
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
%_ = apply undef(%lifetime) : $@convention(thin) (@guaranteed 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:
|
|
end_borrow %lifetime : $C
|
|
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: end_borrow
|
|
// 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):
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
%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 $()
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Don't hoist over abort_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_abort_apply : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[REGISTER_1:%[^,]+]] : $any Error):
|
|
// CHECK: abort_apply
|
|
// CHECK: end_borrow
|
|
// CHECK: destroy_value
|
|
// CHECK: tuple
|
|
// CHECK: throw
|
|
// CHECK-LABEL: } // end sil function 'dont_hoist_over_abort_apply'
|
|
sil [ossa] @dont_hoist_over_abort_apply : $@convention(thin) (@owned C, S) -> @error Error {
|
|
entry(%instance : @owned $C, %input : $S):
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
apply %callee_guaranteed(%lifetime) : $@convention(thin) (@guaranteed C) -> ()
|
|
%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
|
|
%failable = function_ref @failable : $@convention(thin) () -> @error Error
|
|
try_apply %failable() : $@convention(thin) () -> @error Error, normal success, error failure
|
|
success(%retval : $()):
|
|
store %input to [trivial] %addr : $*S
|
|
end_apply %continuation as $()
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
return %retval : $()
|
|
failure(%error : $Error):
|
|
abort_apply %continuation
|
|
%blah = tuple ()
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
throw %error : $Error
|
|
}
|
|
|
|
// Don't hoist out of a block when one of its predecessors has a terminator that
|
|
// is a use of the end_borrow.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @dont_hoist_over_user_br__other_br_multiple_preds : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] :
|
|
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [lexical] [[INSTANCE]]
|
|
// CHECK: cond_br undef, {{bb[0-9]+}}, [[RIGHT:bb[0-9]+]]
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: [[COPY:%[^,]+]] = copy_value [[LIFETIME]]
|
|
// CHECK: br [[EXIT:bb[0-9]+]]([[COPY]] :
|
|
// CHECK: [[EXIT]]({{%[^,]+}} :
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK-LABEL: } // end sil function 'dont_hoist_over_user_br__other_br_multiple_preds'
|
|
sil [ossa] @dont_hoist_over_user_br__other_br_multiple_preds : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance : @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) -> ()
|
|
cond_br undef, left1, right
|
|
|
|
left1:
|
|
cond_br undef, left2, left3
|
|
|
|
left2:
|
|
br left4
|
|
|
|
left3:
|
|
br left4
|
|
|
|
left4:
|
|
%get_owned_c = function_ref @get_owned_c : $@convention(thin) () -> (@owned C)
|
|
%owned_c = apply %get_owned_c() : $@convention(thin) () -> (@owned C)
|
|
br exit(%owned_c : $C)
|
|
|
|
right:
|
|
%barrier = function_ref @barrier : $@convention(thin) () -> ()
|
|
apply %barrier() : $@convention(thin) () -> ()
|
|
%copy = copy_value %lifetime : $C
|
|
br exit(%copy : $C)
|
|
|
|
exit(%value : @owned $C):
|
|
destroy_value %value : $C
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Don't hoist over begin_borrows of copies.
|
|
// CHECK-LABEL: sil [ossa] @dont_hoist_over_begin_borrow_copy : {{.*}} {
|
|
// CHECK: begin_borrow
|
|
// CHECK: copy_value
|
|
// CHECK: begin_borrow
|
|
// CHECK: end_borrow
|
|
// CHECK-LABEL: } // end sil function 'dont_hoist_over_begin_borrow_copy'
|
|
sil [ossa] @dont_hoist_over_begin_borrow_copy : $@convention(thin) (@owned C) -> (@owned C) {
|
|
entry(%owned_in : @owned $C):
|
|
%borrow_1 = begin_borrow [lexical] %owned_in : $C
|
|
apply undef(%borrow_1) : $@convention(thin) (@guaranteed C) -> ()
|
|
%copy_1_1 = copy_value %borrow_1 : $C
|
|
%borrow_out = begin_borrow [lexical] %copy_1_1 : $C
|
|
%copy_2 = copy_value %borrow_out : $C
|
|
end_borrow %borrow_1 : $C
|
|
destroy_value %owned_in : $C
|
|
apply undef(%borrow_out) : $@convention(thin) (@guaranteed C) -> ()
|
|
br exit(%copy_1_1 : $C, %borrow_out : $C, %copy_2 : $C)
|
|
exit(%copy_1_2 : @owned $C, %borrow_in : @guaranteed $C, %copy_2_2 : @owned $C):
|
|
end_borrow %borrow_in : $C
|
|
destroy_value %copy_1_2 : $C
|
|
return %copy_2_2 : $C
|
|
}
|
|
|
|
// Do not hoist the end_borrow (or destroy_value) of Storage above the
|
|
// string_copy_unmanaged_value of the BridgeObject. Here, the initial
|
|
// ref_to_unmanaged is hidden by a call.
|
|
//
|
|
// rdar://90909833 (Extend deinit barriers to handle conversion to strong reference)
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @testCopyUnmanagedCall : $@convention(method) (@inout ClassWrapper) -> () {
|
|
// CHECK: [[STORAGE:%.*]] = load [take] %1 : $*ClassStorage
|
|
// CHECK: [[BORROW:%.*]] = begin_borrow [[STORAGE]] : $ClassStorage
|
|
// CHECK: [[CALL:%.*]] = apply %{{.*}} : $@convention(method) (@guaranteed C) -> @sil_unmanaged C
|
|
// CHECK: strong_copy_unmanaged_value [[CALL]] : $@sil_unmanaged C
|
|
// CHECK: end_borrow [[BORROW]] : $ClassStorage
|
|
// CHECK: destroy_value [[STORAGE]] : $ClassStorage
|
|
// CHECK-LABEL: } // end sil function
|
|
sil [ossa] @testCopyUnmanagedCall : $@convention(method) (@inout ClassWrapper) -> () {
|
|
bb0(%0 : $*ClassWrapper):
|
|
%1 = struct_element_addr %0 : $*ClassWrapper, #ClassWrapper.storage
|
|
%2 = load [take] %1 : $*ClassStorage
|
|
%4 = begin_borrow %2 : $ClassStorage
|
|
%5 = struct_extract %4 : $ClassStorage, #ClassStorage.ref
|
|
%f = function_ref @returnUnmanagedC : $@convention(method) (@guaranteed C) -> @sil_unmanaged C
|
|
%call = apply %f(%5) : $@convention(method) (@guaranteed C) -> @sil_unmanaged C
|
|
%7 = strong_copy_unmanaged_value %call : $@sil_unmanaged C
|
|
end_borrow %4 : $ClassStorage
|
|
destroy_value %2 : $ClassStorage
|
|
%10 = struct $ClassStorage (%7 : $C)
|
|
%11 = struct $ClassWrapper (%10 : $ClassStorage)
|
|
store %11 to [init] %0 : $*ClassWrapper
|
|
%23 = tuple ()
|
|
return %23 : $()
|
|
}
|
|
|
|
// Do not hoist the end_borrow (or destroy_value) of Storage above the
|
|
// string_copy_unmanaged_value of the BridgeObject. Here, the initial
|
|
// ref_to_unmanaged is hidden by a call.
|
|
//
|
|
// rdar://90909833 (Extend deinit barriers to handle conversion to strong reference)
|
|
//
|
|
// The inlined case was already handled because the ref_to_unmanaged
|
|
// was considered a pointer escape. But in the future, this might not be considered a pointer escape.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @testCopyUnmanagedInlined : $@convention(method) (@inout ClassWrapper) -> () {
|
|
// CHECK: [[STORAGE:%.*]] = load [take] %1 : $*ClassStorage
|
|
// CHECK: [[BORROW:%.*]] = begin_borrow [[STORAGE]] : $ClassStorage
|
|
// CHECK: strong_copy_unmanaged_value
|
|
// CHECK: end_borrow [[BORROW]] : $ClassStorage
|
|
// CHECK: destroy_value [[STORAGE]] : $ClassStorage
|
|
// CHECK-LABEL: } // end sil function
|
|
sil [ossa] @testCopyUnmanagedInlined : $@convention(method) (@inout ClassWrapper) -> () {
|
|
bb0(%0 : $*ClassWrapper):
|
|
%1 = struct_element_addr %0 : $*ClassWrapper, #ClassWrapper.storage
|
|
%2 = load [take] %1 : $*ClassStorage
|
|
%4 = begin_borrow %2 : $ClassStorage
|
|
%5 = struct_extract %4 : $ClassStorage, #ClassStorage.ref
|
|
%6 = ref_to_unmanaged %5 : $C to $@sil_unmanaged C
|
|
%7 = strong_copy_unmanaged_value %6 : $@sil_unmanaged C
|
|
end_borrow %4 : $ClassStorage
|
|
destroy_value %2 : $ClassStorage
|
|
%10 = struct $ClassStorage (%7 : $C)
|
|
%11 = struct $ClassWrapper (%10 : $ClassStorage)
|
|
store %11 to [init] %0 : $*ClassWrapper
|
|
%23 = tuple ()
|
|
return %23 : $()
|
|
}
|
|
|
|
// Hoist over applies of non-barrier fns.
|
|
// CHECK-LABEL: sil [ossa] @hoist_over_apply_of_non_barrier_fn : {{.*}} {
|
|
// CHECK: apply
|
|
// CHECK: end_borrow
|
|
// 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) () -> () {
|
|
entry:
|
|
%get_owned_c = function_ref @get_owned_c : $@convention(thin) () -> (@owned C)
|
|
%c = apply %get_owned_c() : $@convention(thin) () -> (@owned C)
|
|
%borrow = begin_borrow [lexical] %c : $C
|
|
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
|
|
apply %callee_guaranteed(%borrow) : $@convention(thin) (@guaranteed C) -> ()
|
|
%empty = function_ref @empty : $@convention(thin) () -> ()
|
|
apply %empty() : $@convention(thin) () -> ()
|
|
end_borrow %borrow : $C
|
|
destroy_value %c : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Don't hoist over a copy_value that is rewritten.
|
|
//
|
|
// The borrowee's lifetime will be canonicalized again regardless.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @nohoist_over_rewritten_copy : {{.*}} {
|
|
// CHECK: [[INSTANCE:%[^,]+]] = apply
|
|
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [lexical] [[INSTANCE]]
|
|
// CHECK: [[COPY:%[^,]+]] = copy_value [[INSTANCE]]
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK: tuple ([[COPY]] : $C, [[INSTANCE]] : $C)
|
|
// CHECK-LABEL: } // end sil function 'nohoist_over_rewritten_copy'
|
|
sil [ossa] @nohoist_over_rewritten_copy : $@convention(thin) () -> (@owned C, @owned C) {
|
|
%get_owned_c = function_ref @get_owned_c : $@convention(thin) () -> (@owned C)
|
|
%instance = apply %get_owned_c() : $@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 = copy_value %lifetime : $C
|
|
end_borrow %lifetime : $C
|
|
%retval = tuple (%copy : $C, %instance : $C)
|
|
return %retval : $(C, C)
|
|
}
|
|
|
|
// Don't hoist over multiple copy_values that are rewritten.
|
|
//
|
|
// The borrowee's lifetime will be canonicalized again regardless.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @nohoist_over_rewritten_copy_multiple : {{.*}} {
|
|
// CHECK: [[INSTANCE:%[^,]+]] = apply
|
|
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [lexical] [[INSTANCE]]
|
|
// CHECK: [[COPY1:%[^,]+]] = copy_value [[INSTANCE]]
|
|
// CHECK: [[COPY2:%[^,]+]] = copy_value [[INSTANCE]]
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK: tuple ([[COPY2]] : $C, [[COPY1]] : $C, [[INSTANCE]] : $C)
|
|
// CHECK-LABEL: } // end sil function 'nohoist_over_rewritten_copy_multiple'
|
|
sil [ossa] @nohoist_over_rewritten_copy_multiple : $@convention(thin) () -> (@owned C, @owned C, @owned C) {
|
|
%get_owned_c = function_ref @get_owned_c : $@convention(thin) () -> (@owned C)
|
|
%instance = apply %get_owned_c() : $@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) -> ()
|
|
%copy1 = copy_value %lifetime : $C
|
|
%copy2 = copy_value %lifetime : $C
|
|
end_borrow %lifetime : $C
|
|
%retval = tuple (%copy2 : $C, %copy1 : $C, %instance : $C)
|
|
return %retval : $(C, C, C)
|
|
}
|
|
|
|
// =============================================================================
|
|
// 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: end_borrow
|
|
// 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):
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
apply undef(%lifetime) : $@convention(thin) (@guaranteed 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
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
return %value : $C
|
|
}
|
|
|
|
// Access scopes that are open at barrier blocks are barriers. Otherwise, we
|
|
// would hoist end_borrows into the scopes when the end_borrows 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: [[LIFETIME:%[^,]+]] = begin_borrow [lexical] [[INSTANCE]]
|
|
// 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: end_borrow [[LIFETIME]] : $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):
|
|
%lifetime = begin_borrow [lexical] %instance : $C
|
|
%scope = begin_access [modify] [static] %second : $*C
|
|
cond_br undef, left, right
|
|
|
|
left:
|
|
end_access %scope : $*C
|
|
%ignore = tuple ()
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
br exit
|
|
|
|
right:
|
|
end_access %scope : $*C
|
|
apply undef(%lifetime) : $@convention(thin) (@guaranteed C) -> ()
|
|
end_borrow %lifetime : $C
|
|
destroy_value %instance : $C
|
|
br exit
|
|
|
|
exit:
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// =============================================================================
|
|
// access scope tests }}
|
|
// =============================================================================
|