mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
322 lines
12 KiB
Plaintext
322 lines
12 KiB
Plaintext
// RUN: %target-sil-opt -update-borrowed-from -test-runner -sil-disable-input-verify %s -o /dev/null 2>&1 | %FileCheck %s
|
|
//
|
|
// REQUIRES: swift_in_compiler
|
|
|
|
sil_stage raw
|
|
|
|
import Builtin
|
|
|
|
struct Trivial {
|
|
var value: Builtin.Int32
|
|
}
|
|
|
|
enum FakeOptional<T> {
|
|
case none
|
|
case some(T)
|
|
}
|
|
|
|
struct PairC {
|
|
var first: C
|
|
var second: C
|
|
}
|
|
|
|
class C {
|
|
var field: C
|
|
}
|
|
|
|
class D : C {}
|
|
|
|
// These introducers have no enclosing def.
|
|
|
|
// CHECK-LABEL: enclosing_def_empty: find_enclosing_defs with: %0
|
|
// CHECK: } // end sil function 'enclosing_def_empty'
|
|
// CHECK: Enclosing Defs:
|
|
// CHECK-NEXT: enclosing_def_empty: find_enclosing_defs with: %0
|
|
|
|
// CHECK-LABEL: enclosing_def_empty: enclosing_values with: %0
|
|
// CHECK: } // end sil function 'enclosing_def_empty'
|
|
// CHECK: Enclosing values for: %0 = argument of bb0 : $C
|
|
// CHECK-NEXT: enclosing_def_empty: enclosing_values with: %0
|
|
|
|
// CHECK-LABEL: enclosing_def_empty: find_enclosing_defs with: %borrow1
|
|
// CHECK: } // end sil function 'enclosing_def_empty'
|
|
// CHECK: Enclosing Defs:
|
|
// CHECK-NEXT: enclosing_def_empty: find_enclosing_defs with: %borrow1
|
|
|
|
// CHECK-LABEL: enclosing_def_empty: enclosing_values with: %borrow1
|
|
// CHECK: } // end sil function 'enclosing_def_empty'
|
|
// CHECK: Enclosing values for: %{{.*}} = load_borrow %1 : $*C
|
|
// CHECK-NEXT: enclosing_def_empty: enclosing_values with: %borrow1
|
|
sil [ossa] @enclosing_def_empty : $@convention(thin) (@guaranteed C, @in C) -> () {
|
|
entry(%0 : @guaranteed $C, %1 : $*C):
|
|
specify_test "find_enclosing_defs %0"
|
|
specify_test "enclosing_values %0"
|
|
%borrow1 = load_borrow %1 : $*C
|
|
specify_test "find_enclosing_defs %borrow1"
|
|
specify_test "enclosing_values %borrow1"
|
|
end_borrow %borrow1 : $C
|
|
destroy_addr %1 : $*C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// There is no introducer if the guaranteed value is produced from a
|
|
// trivial value.
|
|
|
|
// CHECK-LABEL: enclosing_def_trivial: find_enclosing_defs with: %phi
|
|
// CHECK: } // end sil function 'enclosing_def_trivial'
|
|
// CHECK: Enclosing Defs:
|
|
// CHECK-NEXT: enclosing_def_trivial: find_enclosing_defs with: %phi
|
|
|
|
// CHECK-LABEL: enclosing_def_trivial: enclosing_values with: %phi
|
|
// CHECK: } // end sil function 'enclosing_def_trivial'
|
|
// CHECK: Enclosing values for: %{{.*}} = argument of bb1 : $FakeOptional<C>
|
|
// CHECK-NEXT: enclosing_def_trivial: enclosing_values with: %phi
|
|
sil [ossa] @enclosing_def_trivial : $@convention(thin) () -> () {
|
|
entry:
|
|
%trivial = enum $FakeOptional<C>, #FakeOptional.none!enumelt
|
|
br none(%trivial : $FakeOptional<C>)
|
|
|
|
none(%phi : @guaranteed $FakeOptional<C>):
|
|
specify_test "find_enclosing_defs %phi"
|
|
specify_test "enclosing_values %phi"
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// There is an introducer but no enclosing def if the guaranteed value
|
|
// is produced from a an unreachable loop.
|
|
|
|
// CHECK-LABEL: enclosing_def_unreachable: find_enclosing_defs with: %phiCycle
|
|
// CHECK: } // end sil function 'enclosing_def_unreachable'
|
|
// CHECK: Enclosing Defs:
|
|
// CHECK-NEXT: enclosing_def_unreachable: find_enclosing_defs with: %phiCycle
|
|
|
|
// CHECK-LABEL: enclosing_def_unreachable: enclosing_values with: %phiCycle
|
|
// CHECK: } // end sil function 'enclosing_def_unreachable'
|
|
// CHECK: Enclosing values for: %{{.*}} = argument of bb1 : $C
|
|
// CHECK-NEXT: enclosing_def_unreachable: enclosing_values with: %phiCycle
|
|
sil [ossa] @enclosing_def_unreachable : $@convention(thin) () ->() {
|
|
entry:
|
|
br exit
|
|
|
|
unreachable_loop(%phiCycle : @guaranteed $C):
|
|
specify_test "find_enclosing_defs %phiCycle"
|
|
specify_test "enclosing_values %phiCycle"
|
|
br unreachable_loop(%phiCycle : $C)
|
|
|
|
exit:
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// All data flow paths through phis and aggregates originate from the
|
|
// same borrow scope. This is the same as finding the introducer.
|
|
|
|
// CHECK-LABEL: enclosing_def_single_introducer: find_enclosing_defs with: %aggregate2
|
|
// CHECK: sil [ossa] @enclosing_def_single_introducer
|
|
// CHECK: Enclosing Defs:
|
|
// CHECK: begin_borrow %0 : $C
|
|
// CHECK-NEXT: enclosing_def_single_introducer: find_enclosing_defs with: %aggregate2
|
|
|
|
// CHECK-LABEL: enclosing_def_single_introducer: enclosing_values with: %aggregate2
|
|
// CHECK: sil [ossa] @enclosing_def_single_introducer
|
|
// CHECK: Enclosing values for: %{{.*}} = struct $PairC (%11 : $C, %12 : $C)
|
|
// CHECK: begin_borrow %0 : $C
|
|
// CHECK-NEXT: enclosing_def_single_introducer: enclosing_values with: %aggregate2
|
|
sil [ossa] @enclosing_def_single_introducer : $@convention(thin) (@guaranteed C) -> () {
|
|
entry(%0 : @guaranteed $C):
|
|
%borrow = begin_borrow %0 : $C
|
|
%cast = unconditional_checked_cast %borrow : $C to D
|
|
%some = enum $FakeOptional<D>, #FakeOptional.some!enumelt, %cast : $D
|
|
br switch(%some : $FakeOptional<D>)
|
|
|
|
switch(%somePhi : @guaranteed $FakeOptional<D>):
|
|
switch_enum %somePhi : $FakeOptional<D>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2
|
|
|
|
bb1(%payload : @guaranteed $D):
|
|
%upcast = upcast %payload : $D to $C
|
|
%aggregate = struct $PairC(%upcast : $C, %borrow : $C)
|
|
%first = struct_extract %aggregate : $PairC, #PairC.first
|
|
%second = struct_extract %aggregate : $PairC, #PairC.second
|
|
%aggregate2 = struct $PairC(%first : $C, %second : $C)
|
|
specify_test "find_enclosing_defs %aggregate2"
|
|
specify_test "enclosing_values %aggregate2"
|
|
br exit
|
|
|
|
bb2:
|
|
br exit
|
|
|
|
exit:
|
|
end_borrow %borrow : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// All reborrows original from the same dominating borrow scope.
|
|
|
|
// CHECK: enclosing_def_single_outer: find_enclosing_defs with: %reborrow3
|
|
// CHECK: } // end sil function 'enclosing_def_single_outer'
|
|
// CHECK: Enclosing Defs:
|
|
// CHECK-NEXT: %0 = argument of bb0 : $C
|
|
// CHECK-NEXT: enclosing_def_single_outer: find_enclosing_defs with: %reborrow3
|
|
|
|
// CHECK: enclosing_def_single_outer: enclosing_values with: %reborrow3
|
|
// CHECK: } // end sil function 'enclosing_def_single_outer'
|
|
// CHECK: Enclosing values for: %{{.*}} = argument of bb2 : $C
|
|
// CHECK-NEXT: %0 = argument of bb0 : $C
|
|
// CHECK-NEXT: enclosing_def_single_outer: enclosing_values with: %reborrow3
|
|
|
|
sil [ossa] @enclosing_def_single_outer : $@convention(thin) (@guaranteed C) -> () {
|
|
entry(%0 : @guaranteed $C):
|
|
%borrow = begin_borrow %0 : $C
|
|
br bb2(%borrow : $C)
|
|
|
|
bb2(%reborrow2 : @guaranteed $C):
|
|
br bb3(%reborrow2 : $C)
|
|
|
|
bb3(%reborrow3 : @guaranteed $C):
|
|
specify_test "find_enclosing_defs %reborrow3"
|
|
specify_test "enclosing_values %reborrow3"
|
|
end_borrow %reborrow3 : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Find the outer enclosingreborrow.
|
|
|
|
// CHECK-LABEL: enclosing_def_reborrow: find_enclosing_defs with: %reborrow_inner3
|
|
// CHECK: sil [ossa] @enclosing_def_reborrow : $@convention(thin) (@guaranteed C) -> () {
|
|
// CHECK: bb1([[REBORROW:%.*]] : @reborrow $C, %{{.*}} : @reborrow $C):
|
|
// CHECK: } // end sil function 'enclosing_def_reborrow'
|
|
// CHECK: Enclosing Defs:
|
|
// CHECK-NEXT: [[REBORROW]] = argument of bb1 : $C
|
|
// CHECK-NEXT: enclosing_def_reborrow: find_enclosing_defs with: %reborrow_inner3
|
|
|
|
// CHECK-LABEL: enclosing_def_reborrow: enclosing_values with: %reborrow_inner3
|
|
// CHECK: sil [ossa] @enclosing_def_reborrow : $@convention(thin) (@guaranteed C) -> () {
|
|
// CHECK: bb1([[REBORROW:%.*]] : @reborrow $C, %{{.*}} : @reborrow $C):
|
|
// CHECK: } // end sil function 'enclosing_def_reborrow'
|
|
// CHECK: Enclosing values for: %{{.*}} = argument of bb2 : $C
|
|
// CHECK-NEXT: [[REBORROW]] = argument of bb1 : $C
|
|
// CHECK-NEXT: enclosing_def_reborrow: enclosing_values with: %reborrow_inner3
|
|
sil [ossa] @enclosing_def_reborrow : $@convention(thin) (@guaranteed C) -> () {
|
|
entry(%0 : @guaranteed $C):
|
|
%borrow_outer = begin_borrow %0 : $C
|
|
%borrow_inner = begin_borrow %borrow_outer : $C
|
|
br bb2(%borrow_outer : $C, %borrow_inner : $C)
|
|
|
|
bb2(%reborrow_outer : @guaranteed $C, %reborrow_inner : @guaranteed $C):
|
|
br bb3(%reborrow_inner : $C)
|
|
|
|
bb3(%reborrow_inner3 : @guaranteed $C):
|
|
specify_test "find_enclosing_defs %reborrow_inner3"
|
|
specify_test "enclosing_values %reborrow_inner3"
|
|
end_borrow %reborrow_inner3 : $C
|
|
end_borrow %reborrow_outer : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// The enclosing def of a forwarding phi cycle is the reborrow phi cycle.
|
|
|
|
// CHECK-LABEL: enclosing_def_cycle: find_enclosing_defs with: %forward
|
|
// CHECK: sil [ossa] @enclosing_def_cycle : $@convention(thin) (@guaranteed C) -> () {
|
|
// CHECK: bb1([[REBORROW:%.*]] : @guaranteed $C,
|
|
// CHECK: } // end sil function 'enclosing_def_cycle'
|
|
// CHECK: Enclosing Defs:
|
|
// CHECK-NEXT: [[REBORROW]] = argument of bb1 : $C
|
|
// CHECK-NEXT: enclosing_def_cycle: find_enclosing_defs with: %forward
|
|
|
|
// CHECK-LABEL: enclosing_def_cycle: enclosing_values with: %forward
|
|
// CHECK: sil [ossa] @enclosing_def_cycle : $@convention(thin) (@guaranteed C) -> () {
|
|
// CHECK: bb1([[REBORROW:%.*]] : @guaranteed $C,
|
|
// CHECK: } // end sil function 'enclosing_def_cycle'
|
|
// CHECK: Enclosing values for: %{{.*}} = argument of bb1 : $C
|
|
// CHECK-NEXT: %1 = begin_borrow %0
|
|
// CHECK-NEXT: %0 = argument of bb0
|
|
// CHECK-NEXT: enclosing_def_cycle: enclosing_values with: %forward
|
|
sil [ossa] @enclosing_def_cycle : $@convention(thin) (@guaranteed C) -> () {
|
|
entry(%0 : @guaranteed $C):
|
|
%borrow = begin_borrow %0 : $C
|
|
%aggregate1 = struct $PairC(%borrow : $C, %borrow : $C)
|
|
%first1 = struct_extract %aggregate1 : $PairC, #PairC.first
|
|
br bb2(%borrow : $C, %first1 : $C)
|
|
|
|
bb2(%reborrow_outer : @guaranteed $C, %forward : @guaranteed $C):
|
|
specify_test "find_enclosing_defs %forward"
|
|
specify_test "enclosing_values %forward"
|
|
%aggregate2 = struct $PairC(%reborrow_outer : $C, %forward : $C)
|
|
%first2 = struct_extract %aggregate2 : $PairC, #PairC.first
|
|
br bb2(%reborrow_outer : $C, %first2 : $C)
|
|
|
|
exit:
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: enclosing_def_example: enclosing_values with: %0
|
|
// CHECK: Enclosing values for: %0 = argument of bb0 : $C
|
|
// CHECK-NEXT: enclosing_def_example: enclosing_values with: %0
|
|
|
|
// CHECK-LABEL: enclosing_def_example: enclosing_values with: %borrow0
|
|
// CHECK: Enclosing values for: %{{.*}} = begin_borrow %0 : $C
|
|
// CHECK-NEXT: %0 = argument of bb0 : $C
|
|
// CHECK-NEXT: enclosing_def_example: enclosing_values with: %borrow0
|
|
|
|
// CHECK-LABEL: enclosing_def_example: enclosing_values with: %first
|
|
// CHECK: Enclosing values for: %{{.*}} = struct_extract %{{.*}} : $PairC, #PairC.first
|
|
// CHECK-NEXT: %{{.*}} = argument of bb0 : $C
|
|
// CHECK-NEXT: %{{.*}} = begin_borrow %0 : $C
|
|
// CHECK-NEXT: enclosing_def_example: enclosing_values with: %first
|
|
|
|
// CHECK-LABEL: enclosing_def_example: enclosing_values with: %field
|
|
// CHECK: Enclosing values for: %{{.*}} = ref_element_addr %{{.*}} : $C, #C.field
|
|
// CHECK-NEXT: enclosing_def_example: enclosing_values with: %field
|
|
|
|
// CHECK-LABEL: enclosing_def_example: enclosing_values with: %load
|
|
// CHECK: Enclosing values for: %{{.*}} = load_borrow %{{.*}} : $*C
|
|
// CHECK-NEXT: enclosing_def_example: enclosing_values with: %load
|
|
sil [ossa] @enclosing_def_example : $@convention(thin) (@owned C, @guaranteed C) -> () {
|
|
bb0(%0 : @owned $C,
|
|
%1 : @guaranteed $C):
|
|
specify_test "enclosing_values %0"
|
|
%borrow0 = begin_borrow %0 : $C
|
|
specify_test "enclosing_values %borrow0"
|
|
%pair = struct $PairC(%borrow0 : $C, %1 : $C)
|
|
%first = struct_extract %pair : $PairC, #PairC.first
|
|
specify_test "enclosing_values %first"
|
|
%field = ref_element_addr %first : $C, #C.field
|
|
specify_test "enclosing_values %field"
|
|
%load = load_borrow %field : $*C
|
|
specify_test "enclosing_values %load"
|
|
end_borrow %load : $C
|
|
end_borrow %borrow0 : $C
|
|
destroy_value %0 : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: enclosing_def_reborrow_example: enclosing_values with: %outerReborrow
|
|
// CHECK: Enclosing values for: %{{.*}} = argument of bb1 : $C
|
|
// CHECK-NEXT: %0 = argument of bb0 : $C
|
|
// CHECK-NEXT: enclosing_def_reborrow_example: enclosing_values with: %outerReborrow
|
|
|
|
// CHECK-LABEL: enclosing_def_reborrow_example: enclosing_values with: %innerReborrow
|
|
// CHECK: Enclosing values for: %{{.*}} = argument of bb1 : $C
|
|
// CHECK-NEXT: %{{.*}} = argument of bb1 : $C
|
|
// CHECK-NEXT: enclosing_def_reborrow_example: enclosing_values with: %innerReborrow
|
|
sil [ossa] @enclosing_def_reborrow_example : $@convention(thin) (@guaranteed C) -> () {
|
|
bb0(%0 : @guaranteed $C):
|
|
%outerBorrow = begin_borrow %0 : $C
|
|
%innerBorrow = begin_borrow %outerBorrow : $C
|
|
br bb1(%outerBorrow : $C, %innerBorrow : $C)
|
|
bb1(%outerReborrow : @guaranteed $C, %innerReborrow : @guaranteed $C):
|
|
specify_test "enclosing_values %outerReborrow"
|
|
specify_test "enclosing_values %innerReborrow"
|
|
end_borrow %innerReborrow : $C
|
|
end_borrow %outerReborrow : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|