mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
tryJoinIfDestroyConsumingUseInSameBlock replaces a copy with its operand when there is no use of the copy's operand between the copy's forwarded consuming use and the copy operand's destroy in the same block. It is illegal to do this transformation when there is a non-consuming use of the copy operand after the forwarded consuming use of the copy. The code checking this illegal case was not considerin the case where the consuming use of the copy was in the same instruction as the non-consuming use of the copy operand. rdar://154712867
1020 lines
36 KiB
Plaintext
1020 lines
36 KiB
Plaintext
// RUN: %target-sil-opt -sil-print-types -module-name Swift -enable-sil-verify-all -semantic-arc-opts -sil-semantic-arc-peepholes-lifetime-joining %s | %FileCheck %s
|
|
//
|
|
// Enabling specific ARC opts requires an asserts build.
|
|
// REQUIRES: asserts
|
|
|
|
// NOTE: Some of our tests here depend on borrow elimination /not/ running!
|
|
// Please do not add it to clean up the IR like we did in
|
|
// semanticarcopts-loadcopy-to-loadborrow!
|
|
|
|
sil_stage canonical
|
|
|
|
import Builtin
|
|
|
|
//////////////////
|
|
// Declarations //
|
|
//////////////////
|
|
|
|
typealias AnyObject = Builtin.AnyObject
|
|
|
|
struct Bool {
|
|
var value : Builtin.Int1
|
|
}
|
|
|
|
sil @closureCapturesBool : $@convention(thin) (@guaranteed { var Bool }) -> ()
|
|
sil @closureArgumentEscapes : $@convention(thin) (@owned @callee_guaranteed () -> ()) -> ()
|
|
|
|
enum MyNever {}
|
|
enum FakeOptional<T> {
|
|
case none
|
|
case some(T)
|
|
}
|
|
|
|
sil [ossa] @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
|
|
sil [ossa] @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
sil [ossa] @get_owned_obj : $@convention(thin) () -> @owned Builtin.NativeObject
|
|
sil [ossa] @unreachable_guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> MyNever
|
|
sil [ossa] @inout_user : $@convention(thin) (@inout FakeOptional<NativeObjectPair>) -> ()
|
|
sil [ossa] @get_native_object : $@convention(thin) () -> @owned Builtin.NativeObject
|
|
|
|
struct NativeObjectPair {
|
|
var obj1 : Builtin.NativeObject
|
|
var obj2 : Builtin.NativeObject
|
|
}
|
|
|
|
sil [ossa] @get_object_pair : $@convention(thin) () -> @owned NativeObjectPair
|
|
|
|
struct FakeOptionalNativeObjectPairPair {
|
|
var pair1 : FakeOptional<NativeObjectPair>
|
|
var pair2 : FakeOptional<NativeObjectPair>
|
|
}
|
|
sil [ossa] @inout_user2 : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> ()
|
|
|
|
sil [ossa] @get_nativeobject_pair : $@convention(thin) () -> @owned NativeObjectPair
|
|
sil [ossa] @consume_nativeobject_pair : $@convention(thin) (@owned NativeObjectPair) -> ()
|
|
|
|
protocol MyFakeAnyObject : Klass {
|
|
func myFakeMethod()
|
|
}
|
|
|
|
final class Klass {
|
|
var base: Klass
|
|
let baseLet: Klass
|
|
}
|
|
|
|
extension Klass : MyFakeAnyObject {
|
|
func myFakeMethod()
|
|
}
|
|
sil [ossa] @guaranteed_klass_user : $@convention(thin) (@guaranteed Klass) -> ()
|
|
sil [ossa] @guaranteed_fakeoptional_klass_user : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
|
|
sil [ossa] @guaranteed_fakeoptional_classlet_user : $@convention(thin) (@guaranteed FakeOptional<ClassLet>) -> ()
|
|
|
|
struct MyInt {
|
|
var value: Builtin.Int32
|
|
}
|
|
|
|
struct StructWithDataAndOwner {
|
|
var data : Builtin.Int32
|
|
var owner : Klass
|
|
}
|
|
|
|
struct StructMemberTest {
|
|
var c : Klass
|
|
var s : StructWithDataAndOwner
|
|
var t : (Builtin.Int32, StructWithDataAndOwner)
|
|
}
|
|
|
|
class ClassLet {
|
|
@_hasStorage let aLet: Klass
|
|
@_hasStorage var aVar: Klass
|
|
@_hasStorage let aLetTuple: (Klass, Klass)
|
|
@_hasStorage let anOptionalLet: FakeOptional<Klass>
|
|
|
|
@_hasStorage let anotherLet: ClassLet
|
|
}
|
|
|
|
class SubclassLet: ClassLet {}
|
|
|
|
sil_global [let] @a_let_global : $Klass
|
|
sil_global @a_var_global : $Klass
|
|
|
|
enum EnumWithIndirectCase {
|
|
case first
|
|
indirect case second(Builtin.NativeObject)
|
|
}
|
|
|
|
struct StructWithEnumWithIndirectCaseField {
|
|
var i: Builtin.Int23
|
|
var field : EnumWithIndirectCase
|
|
}
|
|
|
|
sil [ossa] @get_fakeoptional_nativeobject : $@convention(thin) () -> @owned FakeOptional<Builtin.NativeObject>
|
|
|
|
struct NativeObjectWrapper {
|
|
var innerWrapper : Builtin.NativeObject
|
|
}
|
|
|
|
sil @owned_user_object_pair : $@convention(thin) (@owned NativeObjectPair) -> ()
|
|
|
|
class X {}
|
|
struct S {}
|
|
|
|
sil @getX : $@convention(thin) () -> @owned X
|
|
sil @getS : $@convention(thin) (@owned X) -> @out S
|
|
sil @loadWeakX_from : $@convention(thin) (@in_guaranteed S) -> @owned FakeOptional<X>
|
|
|
|
///////////
|
|
// Tests //
|
|
///////////
|
|
|
|
// CHECK-LABEL: sil [ossa] @join_liveranges_in_same_block_1 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
|
// CHECK-NOT: copy_value
|
|
// CHECK: } // end sil function 'join_liveranges_in_same_block_1'
|
|
sil [ossa] @join_liveranges_in_same_block_1 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
|
bb0(%0 : @owned $Builtin.NativeObject):
|
|
%1 = copy_value %0 : $Builtin.NativeObject
|
|
destroy_value %0 : $Builtin.NativeObject
|
|
destroy_value %1 : $Builtin.NativeObject
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @join_liveranges_in_same_block_2 : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
|
|
// CHECK-NOT: copy_value
|
|
// CHECK: } // end sil function 'join_liveranges_in_same_block_2'
|
|
sil [ossa] @join_liveranges_in_same_block_2 : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
|
|
bb0(%0 : @owned $Builtin.NativeObject):
|
|
%1 = copy_value %0 : $Builtin.NativeObject
|
|
destroy_value %0 : $Builtin.NativeObject
|
|
return %1 : $Builtin.NativeObject
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @join_liveranges_in_same_block_3 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
|
// CHECK-NOT: copy_value
|
|
// CHECK: } // end sil function 'join_liveranges_in_same_block_3'
|
|
sil [ossa] @join_liveranges_in_same_block_3 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
|
bb0(%0 : @owned $Builtin.NativeObject):
|
|
%1 = copy_value %0 : $Builtin.NativeObject
|
|
br bb1
|
|
|
|
bb1:
|
|
destroy_value %0 : $Builtin.NativeObject
|
|
%f = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
apply %f(%1) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
br bb2
|
|
|
|
bb2:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @join_liveranges_in_same_block_4 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
|
// CHECK-NOT: copy_value
|
|
// CHECK: } // end sil function 'join_liveranges_in_same_block_4'
|
|
sil [ossa] @join_liveranges_in_same_block_4 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
|
bb0(%0 : @owned $Builtin.NativeObject):
|
|
%1 = copy_value %0 : $Builtin.NativeObject
|
|
br bb1
|
|
|
|
bb1:
|
|
destroy_value %0 : $Builtin.NativeObject
|
|
%f = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
|
|
apply %f(%1) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
|
|
%f2 = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
apply %f2(%1) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
br bb2
|
|
|
|
bb2:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @join_liveranges_in_same_block_5 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
|
// CHECK-NOT: copy_value
|
|
// CHECK-LABEL: } // end sil function 'join_liveranges_in_same_block_5'
|
|
sil [ossa] @join_liveranges_in_same_block_5 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
|
bb0(%0 : @owned $Builtin.NativeObject):
|
|
%1 = copy_value %0 : $Builtin.NativeObject
|
|
br bb1
|
|
|
|
bb1:
|
|
%f = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
apply %f(%1) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
destroy_value %0 : $Builtin.NativeObject
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// Forwarding case.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @donot_join_liveranges_in_same_block_2 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
|
// CHECK-NOT: copy_value
|
|
// CHECK: } // end sil function 'donot_join_liveranges_in_same_block_2'
|
|
sil [ossa] @donot_join_liveranges_in_same_block_2 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
|
bb0(%0 : @owned $Builtin.NativeObject):
|
|
%1 = copy_value %0 : $Builtin.NativeObject
|
|
br bb1
|
|
|
|
bb1:
|
|
destroy_value %0 : $Builtin.NativeObject
|
|
%2 = unchecked_ref_cast %1 : $Builtin.NativeObject to $Builtin.NativeObject
|
|
%f = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
apply %f(%2) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// Forwarding case. We need LiveRanges for this.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @donot_join_liveranges_in_same_block_3 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
|
// CHECK: copy_value
|
|
// CHECK: } // end sil function 'donot_join_liveranges_in_same_block_3'
|
|
sil [ossa] @donot_join_liveranges_in_same_block_3 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
|
bb0(%0 : @owned $Builtin.NativeObject):
|
|
%1 = copy_value %0 : $Builtin.NativeObject
|
|
br bb1
|
|
|
|
bb1:
|
|
%2 = unchecked_ref_cast %0 : $Builtin.NativeObject to $Builtin.NativeObject
|
|
destroy_value %2 : $Builtin.NativeObject
|
|
%f = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
apply %f(%1) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// Now test cases where we find our consumer is in the return block or is a
|
|
// return itself.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @join_liveranges_not_same_block_with_consuming_return : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
|
|
// CHECK-NOT: copy_value
|
|
// CHECK: } // end sil function 'join_liveranges_not_same_block_with_consuming_return'
|
|
sil [ossa] @join_liveranges_not_same_block_with_consuming_return : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
|
|
bb0(%0 : @owned $Builtin.NativeObject):
|
|
%1 = copy_value %0 : $Builtin.NativeObject
|
|
br bb1
|
|
|
|
bb1:
|
|
destroy_value %0 : $Builtin.NativeObject
|
|
br bb2
|
|
|
|
bb2:
|
|
return %1 : $Builtin.NativeObject
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @join_liveranges_not_same_block_consumed_in_return_block : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
|
// CHECK-NOT: copy_value
|
|
// CHECK: } // end sil function 'join_liveranges_not_same_block_consumed_in_return_block'
|
|
sil [ossa] @join_liveranges_not_same_block_consumed_in_return_block : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
|
bb0(%0 : @owned $Builtin.NativeObject):
|
|
%1 = copy_value %0 : $Builtin.NativeObject
|
|
br bb1
|
|
|
|
bb1:
|
|
destroy_value %0 : $Builtin.NativeObject
|
|
br bb2
|
|
|
|
bb2:
|
|
%f = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
apply %f(%1) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @donot_join_liveranges_not_same_block_1 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
|
// CHECK: copy_value
|
|
// CHECK: } // end sil function 'donot_join_liveranges_not_same_block_1'
|
|
sil [ossa] @donot_join_liveranges_not_same_block_1 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
|
bb0(%0 : @owned $Builtin.NativeObject):
|
|
%1 = copy_value %0 : $Builtin.NativeObject
|
|
br bb1
|
|
|
|
bb1:
|
|
destroy_value %0 : $Builtin.NativeObject
|
|
br bb2
|
|
|
|
bb2:
|
|
%f = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
apply %f(%1) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
br bb3
|
|
|
|
bb3:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @donot_join_liveranges_not_same_block_2 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
|
// CHECK: copy_value
|
|
// CHECK: } // end sil function 'donot_join_liveranges_not_same_block_2'
|
|
sil [ossa] @donot_join_liveranges_not_same_block_2 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
|
bb0(%0 : @owned $Builtin.NativeObject):
|
|
%1 = copy_value %0 : $Builtin.NativeObject
|
|
br bb1
|
|
|
|
bb1:
|
|
%f = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
apply %f(%1) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
br bb2
|
|
|
|
bb2:
|
|
destroy_value %0 : $Builtin.NativeObject
|
|
br bb3
|
|
|
|
bb3:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @join_liverange_multiple_destroy_value : $@convention(thin) () -> () {
|
|
// CHECK-NOT: copy_value
|
|
// CHECK-NOT: destroy_value
|
|
// CHECK: } // end sil function 'join_liverange_multiple_destroy_value'
|
|
sil [ossa] @join_liverange_multiple_destroy_value : $@convention(thin) () -> () {
|
|
bb0:
|
|
%consumingUse = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
%constructingUse = function_ref @get_owned_obj : $@convention(thin) () -> @owned Builtin.NativeObject
|
|
%obj = apply %constructingUse() : $@convention(thin) () -> @owned Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%obj2 = copy_value %obj : $Builtin.NativeObject
|
|
destroy_value %obj : $Builtin.NativeObject
|
|
cond_br undef, bb1a, bb1b
|
|
|
|
bb1a:
|
|
apply %consumingUse(%obj2) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
br bb3
|
|
|
|
bb1b:
|
|
apply %consumingUse(%obj2) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
br bb3
|
|
|
|
bb2:
|
|
apply %consumingUse(%obj) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
br bb4
|
|
|
|
bb3:
|
|
br bb4
|
|
|
|
bb4:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @join_liverange_forwarding_chain_1 : $@convention(thin) () -> () {
|
|
// CHECK-NOT: copy_value
|
|
// CHECK-NOT: destroy_value
|
|
// CHECK: } // end sil function 'join_liverange_forwarding_chain_1'
|
|
sil [ossa] @join_liverange_forwarding_chain_1 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%consumingUse = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
%constructingUse = function_ref @get_owned_obj : $@convention(thin) () -> @owned Builtin.NativeObject
|
|
%obj = apply %constructingUse() : $@convention(thin) () -> @owned Builtin.NativeObject
|
|
|
|
%obj2 = copy_value %obj : $Builtin.NativeObject
|
|
destroy_value %obj : $Builtin.NativeObject
|
|
%obj3 = unchecked_ref_cast %obj2 : $Builtin.NativeObject to $Builtin.NativeObject
|
|
apply %consumingUse(%obj3) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @join_liverange_multiple_destroy_value_forwarding_chain_1 : $@convention(thin) () -> () {
|
|
// CHECK-NOT: copy_value
|
|
// CHECK-NOT: destroy_value
|
|
// CHECK: } // end sil function 'join_liverange_multiple_destroy_value_forwarding_chain_1'
|
|
sil [ossa] @join_liverange_multiple_destroy_value_forwarding_chain_1 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%consumingUse = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
%constructingUse = function_ref @get_owned_obj : $@convention(thin) () -> @owned Builtin.NativeObject
|
|
%obj = apply %constructingUse() : $@convention(thin) () -> @owned Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%obj2 = copy_value %obj : $Builtin.NativeObject
|
|
destroy_value %obj : $Builtin.NativeObject
|
|
%obj3 = unchecked_ref_cast %obj2 : $Builtin.NativeObject to $Builtin.NativeObject
|
|
cond_br undef, bb1a, bb1b
|
|
|
|
bb1a:
|
|
apply %consumingUse(%obj3) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
br bb3
|
|
|
|
bb1b:
|
|
apply %consumingUse(%obj3) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
br bb3
|
|
|
|
bb2:
|
|
apply %consumingUse(%obj) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
br bb4
|
|
|
|
bb3:
|
|
br bb4
|
|
|
|
bb4:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @join_liverange_multiple_destroy_value_forwarding_chain_2 : $@convention(thin) () -> () {
|
|
// CHECK-NOT: copy_value
|
|
// CHECK-NOT: destroy_value
|
|
// CHECK: } // end sil function 'join_liverange_multiple_destroy_value_forwarding_chain_2'
|
|
sil [ossa] @join_liverange_multiple_destroy_value_forwarding_chain_2 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%consumingUse = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
%constructingUse = function_ref @get_owned_obj : $@convention(thin) () -> @owned Builtin.NativeObject
|
|
%obj = apply %constructingUse() : $@convention(thin) () -> @owned Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%obj2 = copy_value %obj : $Builtin.NativeObject
|
|
%obj3 = unchecked_ref_cast %obj2 : $Builtin.NativeObject to $Builtin.NativeObject
|
|
destroy_value %obj : $Builtin.NativeObject
|
|
cond_br undef, bb1a, bb1b
|
|
|
|
bb1a:
|
|
apply %consumingUse(%obj3) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
br bb3
|
|
|
|
bb1b:
|
|
apply %consumingUse(%obj3) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
br bb3
|
|
|
|
bb2:
|
|
apply %consumingUse(%obj) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
br bb4
|
|
|
|
bb3:
|
|
br bb4
|
|
|
|
bb4:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// We do not support destructures and other multiple value instructions yet...
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @join_liverange_multiple_destroy_value_forwarding_chain_3 : $@convention(thin) () -> () {
|
|
// CHECK: copy_value
|
|
// CHECK: destroy_value
|
|
// CHECK: } // end sil function 'join_liverange_multiple_destroy_value_forwarding_chain_3'
|
|
sil [ossa] @join_liverange_multiple_destroy_value_forwarding_chain_3 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%consumingUse = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
%constructingUse = function_ref @get_owned_obj : $@convention(thin) () -> @owned Builtin.NativeObject
|
|
%obj = apply %constructingUse() : $@convention(thin) () -> @owned Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%obj2 = copy_value %obj : $Builtin.NativeObject
|
|
%obj2a = struct $NativeObjectWrapper(%obj2 : $Builtin.NativeObject)
|
|
(%obj3) = destructure_struct %obj2a : $NativeObjectWrapper
|
|
destroy_value %obj : $Builtin.NativeObject
|
|
cond_br undef, bb1a, bb1b
|
|
|
|
bb1a:
|
|
apply %consumingUse(%obj3) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
br bb3
|
|
|
|
bb1b:
|
|
apply %consumingUse(%obj3) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
br bb3
|
|
|
|
bb2:
|
|
apply %consumingUse(%obj) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
br bb4
|
|
|
|
bb3:
|
|
br bb4
|
|
|
|
bb4:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// This case succeeds since our borrow scope does not overlap with our
|
|
// forwarding region.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @join_live_range_with_borrowscopes_succeed_1 : $@convention(thin) () -> () {
|
|
// CHECK-NOT: copy_value
|
|
// CHECK-NOT: destroy_value
|
|
// CHECK: } // end sil function 'join_live_range_with_borrowscopes_succeed_1'
|
|
sil [ossa] @join_live_range_with_borrowscopes_succeed_1 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%consumingUse = function_ref @owned_user_object_pair : $@convention(thin) (@owned NativeObjectPair) -> ()
|
|
%constructingUse = function_ref @get_object_pair : $@convention(thin) () -> @owned NativeObjectPair
|
|
%obj = apply %constructingUse() : $@convention(thin) () -> @owned NativeObjectPair
|
|
%borrowedObj = begin_borrow %obj : $NativeObjectPair
|
|
%obj1 = struct_extract %borrowedObj : $NativeObjectPair, #NativeObjectPair.obj1
|
|
%guaranteedUse = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
|
|
apply %guaranteedUse(%obj1) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
|
|
end_borrow %borrowedObj : $NativeObjectPair
|
|
%2 = copy_value %obj : $NativeObjectPair
|
|
br bb1
|
|
|
|
bb1:
|
|
destroy_value %obj : $NativeObjectPair
|
|
apply %consumingUse(%2) : $@convention(thin) (@owned NativeObjectPair) -> ()
|
|
br bb2
|
|
|
|
bb2:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// In this case, we validate that we can perform the optimization with
|
|
// forwarding insts.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @join_live_range_with_borrowscopes_succeed_2 : $@convention(thin) () -> () {
|
|
// CHECK-NOT: copy_value
|
|
// CHECK: } // end sil function 'join_live_range_with_borrowscopes_succeed_2'
|
|
sil [ossa] @join_live_range_with_borrowscopes_succeed_2 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%obj = alloc_ref $Klass
|
|
%borrowedObj = begin_borrow %obj : $Klass
|
|
end_borrow %borrowedObj : $Klass
|
|
%2 = copy_value %obj : $Klass
|
|
br bb1
|
|
|
|
bb1:
|
|
destroy_value %obj : $Klass
|
|
%3 = unchecked_ref_cast %2 : $Klass to $Builtin.NativeObject
|
|
%consumingUse = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
apply %consumingUse(%3) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
br bb2
|
|
|
|
bb2:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// Here we succeed even though %2's lifetime ends at the unchecked_ref_cast, we
|
|
// are able to know that
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @join_live_range_with_borrowscopes_succeed_3 : $@convention(thin) () -> () {
|
|
// CHECK-NOT: copy_value
|
|
// CHECK: } // end sil function 'join_live_range_with_borrowscopes_succeed_3'
|
|
sil [ossa] @join_live_range_with_borrowscopes_succeed_3 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%obj = alloc_ref $Klass
|
|
%borrowedObj = begin_borrow %obj : $Klass
|
|
end_borrow %borrowedObj : $Klass
|
|
%2 = copy_value %obj : $Klass
|
|
br bb1
|
|
|
|
bb1:
|
|
%3 = unchecked_ref_cast %2 : $Klass to $Builtin.NativeObject
|
|
destroy_value %obj : $Klass
|
|
%consumingUse = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
apply %consumingUse(%3) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
br bb2
|
|
|
|
bb2:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// In this case we fail since we don't want to have to deal with splitting the
|
|
// scope of %borrowedObj at %3.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @join_live_range_with_borrowscopes_fail_1 : $@convention(thin) () -> () {
|
|
// CHECK: copy_value
|
|
// CHECK: } // end sil function 'join_live_range_with_borrowscopes_fail_1'
|
|
sil [ossa] @join_live_range_with_borrowscopes_fail_1 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%obj = alloc_ref $Klass
|
|
%borrowedObj = begin_borrow %obj : $Klass
|
|
%2 = copy_value %obj : $Klass
|
|
br bb1
|
|
|
|
bb1:
|
|
%3 = unchecked_ref_cast %2 : $Klass to $Builtin.NativeObject
|
|
end_borrow %borrowedObj : $Klass
|
|
destroy_value %obj : $Klass
|
|
%consumingUse = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
apply %consumingUse(%3) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
br bb2
|
|
|
|
bb2:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// This case succeeds since our borrow scope does not overlap with our
|
|
// forwarding region.
|
|
sil [ossa] @join_live_range_with_borrowscopes_multipledestroys_succeed_1 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%consumingUse = function_ref @owned_user_object_pair : $@convention(thin) (@owned NativeObjectPair) -> ()
|
|
%constructingUse = function_ref @get_object_pair : $@convention(thin) () -> @owned NativeObjectPair
|
|
%obj = apply %constructingUse() : $@convention(thin) () -> @owned NativeObjectPair
|
|
%borrowedObj = begin_borrow %obj : $NativeObjectPair
|
|
%obj1 = struct_extract %borrowedObj : $NativeObjectPair, #NativeObjectPair.obj1
|
|
%guaranteedUse = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
|
|
apply %guaranteedUse(%obj1) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
|
|
end_borrow %borrowedObj : $NativeObjectPair
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%2 = copy_value %obj : $NativeObjectPair
|
|
destroy_value %obj : $NativeObjectPair
|
|
apply %consumingUse(%2) : $@convention(thin) (@owned NativeObjectPair) -> ()
|
|
br bb3
|
|
|
|
bb2:
|
|
destroy_value %obj : $NativeObjectPair
|
|
br bb3
|
|
|
|
bb3:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// In this case, we validate that we can perform the optimization with
|
|
// forwarding insts.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @join_live_range_with_borrowscopes_multipledestroys_succeed_2 : $@convention(thin) () -> () {
|
|
// CHECK-NOT: copy_value
|
|
// CHECK: } // end sil function 'join_live_range_with_borrowscopes_multipledestroys_succeed_2'
|
|
sil [ossa] @join_live_range_with_borrowscopes_multipledestroys_succeed_2 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%obj = alloc_ref $Klass
|
|
%borrowedObj = begin_borrow %obj : $Klass
|
|
// We cheat and use end_borrow so we don't optimize this borrow.
|
|
end_borrow %borrowedObj : $Klass
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%2 = copy_value %obj : $Klass
|
|
destroy_value %obj : $Klass
|
|
%3 = unchecked_ref_cast %2 : $Klass to $Builtin.NativeObject
|
|
%consumingUse = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
apply %consumingUse(%3) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
br bb3
|
|
|
|
bb2:
|
|
destroy_value %obj : $Klass
|
|
br bb3
|
|
|
|
bb3:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @join_live_range_with_borrowscopes_multipledestroys_succeed_3 : $@convention(thin) () -> () {
|
|
// CHECK-NOT: copy_value
|
|
// CHECK: } // end sil function 'join_live_range_with_borrowscopes_multipledestroys_succeed_3'
|
|
sil [ossa] @join_live_range_with_borrowscopes_multipledestroys_succeed_3 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%obj = alloc_ref $Klass
|
|
%borrowedObj = begin_borrow %obj : $Klass
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
end_borrow %borrowedObj : $Klass
|
|
%2 = copy_value %obj : $Klass
|
|
%3 = unchecked_ref_cast %2 : $Klass to $Builtin.NativeObject
|
|
destroy_value %obj : $Klass
|
|
%consumingUse = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
apply %consumingUse(%3) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
br bb3
|
|
|
|
bb2:
|
|
end_borrow %borrowedObj : $Klass
|
|
destroy_value %obj : $Klass
|
|
br bb3
|
|
|
|
bb3:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @join_live_range_with_borrowscopes_multipledestroys_succeed_4 : $@convention(thin) () -> () {
|
|
// CHECK-NOT: copy_value
|
|
// CHECK: } // end sil function 'join_live_range_with_borrowscopes_multipledestroys_succeed_4'
|
|
sil [ossa] @join_live_range_with_borrowscopes_multipledestroys_succeed_4 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%obj = alloc_ref $Klass
|
|
%borrowedObj = begin_borrow %obj : $Klass
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%2 = copy_value %obj : $Klass
|
|
end_borrow %borrowedObj : $Klass
|
|
%3 = unchecked_ref_cast %2 : $Klass to $Builtin.NativeObject
|
|
destroy_value %obj : $Klass
|
|
%consumingUse = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
apply %consumingUse(%3) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
br bb3
|
|
|
|
bb2:
|
|
end_borrow %borrowedObj : $Klass
|
|
destroy_value %obj : $Klass
|
|
br bb3
|
|
|
|
bb3:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @join_live_range_with_borrowscopes_multipledestroys_succeed_5 : $@convention(thin) () -> () {
|
|
// CHECK-NOT: copy_value
|
|
// CHECK: } // end sil function 'join_live_range_with_borrowscopes_multipledestroys_succeed_5'
|
|
sil [ossa] @join_live_range_with_borrowscopes_multipledestroys_succeed_5 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%obj = alloc_ref $Klass
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%2 = copy_value %obj : $Klass
|
|
%3 = unchecked_ref_cast %2 : $Klass to $Builtin.NativeObject
|
|
destroy_value %obj : $Klass
|
|
%4 = unchecked_ref_cast %3 : $Builtin.NativeObject to $Klass
|
|
%5 = unchecked_ref_cast %4 : $Klass to $Builtin.NativeObject
|
|
%consumingUse = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
apply %consumingUse(%5) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
br bb3
|
|
|
|
bb2:
|
|
destroy_value %obj : $Klass
|
|
br bb3
|
|
|
|
bb3:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @join_live_range_with_borrowscopes_multipledestroys_succeed_6 : $@convention(thin) () -> () {
|
|
// CHECK-NOT: copy_value
|
|
// CHECK: } // end sil function 'join_live_range_with_borrowscopes_multipledestroys_succeed_6'
|
|
sil [ossa] @join_live_range_with_borrowscopes_multipledestroys_succeed_6 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%obj = alloc_ref $Klass
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%2 = copy_value %obj : $Klass
|
|
%3 = unchecked_ref_cast %2 : $Klass to $Builtin.NativeObject
|
|
destroy_value %obj : $Klass
|
|
br bb1a
|
|
|
|
bb1a:
|
|
%consumingUse = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
apply %consumingUse(%3) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
br bb3
|
|
|
|
bb2:
|
|
destroy_value %obj : $Klass
|
|
br bb3
|
|
|
|
bb3:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @join_live_range_with_borrowscopes_multipledestroys_succeed_7 : $@convention(thin) () -> () {
|
|
// CHECK-NOT: copy_value
|
|
// CHECK: } // end sil function 'join_live_range_with_borrowscopes_multipledestroys_succeed_7'
|
|
sil [ossa] @join_live_range_with_borrowscopes_multipledestroys_succeed_7 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%obj = alloc_ref $Klass
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%2 = copy_value %obj : $Klass
|
|
%3 = unchecked_ref_cast %2 : $Klass to $Builtin.NativeObject
|
|
destroy_value %obj : $Klass
|
|
cond_br undef, bb1a, bb1b
|
|
|
|
bb1a:
|
|
%consumingUse = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
apply %consumingUse(%3) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
br bb1c
|
|
|
|
bb1b:
|
|
destroy_value %3 : $Builtin.NativeObject
|
|
br bb1c
|
|
|
|
bb1c:
|
|
br bb3
|
|
|
|
bb2:
|
|
destroy_value %obj : $Klass
|
|
br bb3
|
|
|
|
bb3:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @join_live_range_with_borrowscopes_multipledestroys_succeed_8 : $@convention(thin) () -> () {
|
|
// CHECK-NOT: copy_value
|
|
// CHECK: } // end sil function 'join_live_range_with_borrowscopes_multipledestroys_succeed_8'
|
|
sil [ossa] @join_live_range_with_borrowscopes_multipledestroys_succeed_8 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%obj = alloc_ref $Klass
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%2 = copy_value %obj : $Klass
|
|
%3 = unchecked_ref_cast %2 : $Klass to $Builtin.NativeObject
|
|
%consumingUse = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
apply %consumingUse(%3) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
destroy_value %obj : $Klass
|
|
br bb3
|
|
|
|
bb2:
|
|
destroy_value %obj : $Klass
|
|
br bb3
|
|
|
|
bb3:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// In this case we fail since we don't want to have to deal with splitting the
|
|
// scope of %borrowedObj at %3.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @join_live_range_with_borrowscopes_multipledestroys_fail_1 : $@convention(thin) () -> () {
|
|
// CHECK: copy_value
|
|
// CHECK: } // end sil function 'join_live_range_with_borrowscopes_multipledestroys_fail_1'
|
|
sil [ossa] @join_live_range_with_borrowscopes_multipledestroys_fail_1 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%obj = alloc_ref $Klass
|
|
%borrowedObj = begin_borrow %obj : $Klass
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%2 = copy_value %obj : $Klass
|
|
%3 = unchecked_ref_cast %2 : $Klass to $Builtin.NativeObject
|
|
end_borrow %borrowedObj : $Klass
|
|
destroy_value %obj : $Klass
|
|
%consumingUse = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
apply %consumingUse(%3) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
|
br bb3
|
|
|
|
bb2:
|
|
end_borrow %borrowedObj : $Klass
|
|
destroy_value %obj : $Klass
|
|
br bb3
|
|
|
|
bb3:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// Make sure we leave only one copy in bb2 and no destroys
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @join_test_with_forwarding_inst : $@convention(thin) () -> @owned FakeOptional<Builtin.NativeObject> {
|
|
// CHECK: bb2:
|
|
// CHECK: copy_value
|
|
// CHECK-NOT: destroy_value
|
|
// CHECK-NOT: copy_value
|
|
// CHECK: br bb3(
|
|
// CHECK: } // end sil function 'join_test_with_forwarding_inst'
|
|
sil [ossa] @join_test_with_forwarding_inst : $@convention(thin) () -> @owned FakeOptional<Builtin.NativeObject> {
|
|
bb0:
|
|
%allocStack = alloc_stack $Builtin.NativeObject
|
|
%0 = function_ref @get_fakeoptional_nativeobject : $@convention(thin) () -> @owned FakeOptional<Builtin.NativeObject>
|
|
%1 = apply %0() : $@convention(thin) () -> @owned FakeOptional<Builtin.NativeObject>
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
destroy_value %1 : $FakeOptional<Builtin.NativeObject>
|
|
%2 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.none!enumelt
|
|
br bb3(%2 : $FakeOptional<Builtin.NativeObject>)
|
|
|
|
bb2:
|
|
%3 = unchecked_enum_data %1 : $FakeOptional<Builtin.NativeObject>, #FakeOptional.some!enumelt
|
|
%4 = copy_value %3 : $Builtin.NativeObject
|
|
store %3 to [init] %allocStack : $*Builtin.NativeObject
|
|
%4c = copy_value %4 : $Builtin.NativeObject
|
|
destroy_value %4 : $Builtin.NativeObject
|
|
%5 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.some!enumelt, %4c : $Builtin.NativeObject
|
|
destroy_addr %allocStack : $*Builtin.NativeObject
|
|
br bb3(%5 : $FakeOptional<Builtin.NativeObject>)
|
|
|
|
bb3(%result : @owned $FakeOptional<Builtin.NativeObject>):
|
|
dealloc_stack %allocStack : $*Builtin.NativeObject
|
|
return %result : $FakeOptional<Builtin.NativeObject>
|
|
}
|
|
|
|
// Don't do this optimization:
|
|
// Eliminate borrowed copy with useless lifetime:
|
|
// %5 = copy_value %0 : ${ var Bool }
|
|
//
|
|
// CHECK: sil hidden [ossa] @testCapturedSingleDestroyCopy : $@convention(thin) () -> Bool {
|
|
// CHECK: load [trivial] %{{.*}} : $*Bool
|
|
// CHECK: destroy_value %0 : ${ var Bool }
|
|
sil hidden [ossa] @testCapturedSingleDestroyCopy : $@convention(thin) () -> Bool {
|
|
bb0:
|
|
// var test = false
|
|
%0 = alloc_box ${ var Bool }, var, name "test"
|
|
%1 = project_box %0 : ${ var Bool }, 0
|
|
%2 = integer_literal $Builtin.Int1, 0
|
|
%3 = struct $Bool (%2 : $Builtin.Int1)
|
|
store %3 to [trivial] %1 : $*Bool
|
|
|
|
// capture test in an escaping closure
|
|
%5 = copy_value %0 : ${ var Bool }
|
|
%6 = function_ref @closureCapturesBool : $@convention(thin) (@guaranteed { var Bool }) -> ()
|
|
%7 = partial_apply [callee_guaranteed] %6(%5) : $@convention(thin) (@guaranteed { var Bool }) -> ()
|
|
%8 = function_ref @closureArgumentEscapes : $@convention(thin) (@owned @callee_guaranteed () -> ()) -> ()
|
|
%9 = apply %8(%7) : $@convention(thin) (@owned @callee_guaranteed () -> ()) -> ()
|
|
|
|
// return test
|
|
%10 = begin_access [read] [dynamic] %1 : $*Bool
|
|
%11 = load [trivial] %10 : $*Bool
|
|
end_access %10 : $*Bool
|
|
destroy_value %0 : ${ var Bool }
|
|
return %11 : $Bool
|
|
}
|
|
|
|
// Don't do this optimization:
|
|
// Eliminate copy of lexical value which ends after lifetime of copy IF there
|
|
// may be deinit barriers between the final consume and the copy.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @testDestroyedLexicalValue : {{.*}} {
|
|
// CHECK: [[GET:%[^,]+]] = function_ref @getX
|
|
// CHECK: [[X:%[^,]+]] = apply [[GET]]()
|
|
// CHECK: [[MX:%[^,]+]] = move_value [lexical] [[X]]
|
|
// CHECK: destroy_value [[MX]] : $X
|
|
// CHECK-LABEL: } // end sil function 'testDestroyedLexicalValue'
|
|
sil [ossa] @testDestroyedLexicalValue : $@convention(thin) () -> @owned FakeOptional<X> {
|
|
bb0:
|
|
%getX = function_ref @getX : $@convention(thin) () -> @owned X
|
|
%x = apply %getX() : $@convention(thin) () -> @owned X
|
|
%mx = move_value [lexical] %x : $X
|
|
%a = alloc_stack [lexical] $S, let, name "s"
|
|
%c = copy_value %mx : $X
|
|
%getS = function_ref @getS : $@convention(thin) (@owned X) -> @out S
|
|
%s = apply %getS(%a, %c) : $@convention(thin) (@owned X) -> @out S
|
|
%loadWeakX_from = function_ref @loadWeakX_from : $@convention(thin) (@in_guaranteed S) -> @owned FakeOptional<X>
|
|
%o = apply %loadWeakX_from(%a) : $@convention(thin) (@in_guaranteed S) -> @owned FakeOptional<X>
|
|
// ^^^^^ Deinit barrier
|
|
destroy_addr %a : $*S
|
|
dealloc_stack %a : $*S
|
|
destroy_value %mx : $X
|
|
return %o : $FakeOptional<X>
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @testDestroyedLexicalValueNoBarriers : {{.*}} {
|
|
// CHECK-NOT: destroy_value
|
|
// CHECK-LABEL: } // end sil function 'testDestroyedLexicalValueNoBarriers'
|
|
sil [ossa] @testDestroyedLexicalValueNoBarriers : $@convention(thin) () -> () {
|
|
bb0:
|
|
%getX = function_ref @getX : $@convention(thin) () -> @owned X
|
|
%x = apply %getX() : $@convention(thin) () -> @owned X
|
|
%mx = move_value [lexical] %x : $X
|
|
%a = alloc_stack [lexical] $S, let, name "s"
|
|
%c = copy_value %mx : $X
|
|
%getS = function_ref @getS : $@convention(thin) (@owned X) -> @out S
|
|
%s = apply %getS(%a, %c) : $@convention(thin) (@owned X) -> @out S
|
|
destroy_addr %a : $*S
|
|
dealloc_stack %a : $*S
|
|
destroy_value %mx : $X
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
sil @consume_and_borrow : $@convention(thin) (@owned Klass, @guaranteed Klass) -> ()
|
|
sil @borrow : $@convention(thin) (@guaranteed Klass) -> ()
|
|
sil @consume : $@convention(thin) (@owned Klass) -> ()
|
|
sil @get_klass : $@convention(thin) () -> @owned Klass
|
|
|
|
// CHECK-LABEL: sil hidden [ossa] @borrow_and_consume_copyable_test1 :
|
|
// CHECK-NOT: copy_value
|
|
// CHECK-LABEL: } // end sil function 'borrow_and_consume_copyable_test1'
|
|
sil hidden [ossa] @borrow_and_consume_copyable_test1 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%0 = function_ref @get_klass : $@convention(thin) () -> @owned Klass
|
|
%1 = apply %0() : $@convention(thin) () -> @owned Klass
|
|
%2 = move_value [var_decl] %1
|
|
%3 = copy_value %2
|
|
%4 = function_ref @borrow : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%5 = apply %4(%2) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%6 = function_ref @consume : $@convention(thin) (@owned Klass) -> ()
|
|
%7 = apply %6(%3) : $@convention(thin) (@owned Klass) -> ()
|
|
destroy_value %2
|
|
%9 = tuple ()
|
|
return %9
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden [ossa] @borrow_and_consume_copyable_test2 :
|
|
// CHECK: copy_value
|
|
// CHECK-LABEL: } // end sil function 'borrow_and_consume_copyable_test2'
|
|
sil hidden [ossa] @borrow_and_consume_copyable_test2 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%0 = function_ref @get_klass : $@convention(thin) () -> @owned Klass
|
|
%1 = apply %0() : $@convention(thin) () -> @owned Klass
|
|
%2 = move_value [var_decl] %1
|
|
%3 = copy_value %2
|
|
%4 = function_ref @consume_and_borrow : $@convention(thin) (@owned Klass, @guaranteed Klass) -> ()
|
|
%5 = apply %4(%3, %2) : $@convention(thin) (@owned Klass, @guaranteed Klass) -> ()
|
|
destroy_value %2
|
|
%7 = tuple ()
|
|
return %7
|
|
}
|
|
|