mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
342 lines
10 KiB
Plaintext
342 lines
10 KiB
Plaintext
// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all -deadobject-elim %s | %FileCheck %s
|
|
|
|
import Swift
|
|
import Builtin
|
|
|
|
//////////
|
|
// Data //
|
|
//////////
|
|
|
|
class TrivialDestructor {
|
|
var int : Builtin.Int32
|
|
var ptr : Builtin.NativeObject
|
|
init()
|
|
deinit { }
|
|
}
|
|
|
|
sil @_T04main17TrivialDestructorCfD : $@convention(method) (@owned TrivialDestructor) -> () {
|
|
bb0(%0 : $TrivialDestructor):
|
|
// Alloc/Dealloc stack should not disrupt elimination of the
|
|
// alloc_ref.
|
|
%1 = alloc_stack $Builtin.Int64
|
|
dealloc_stack %1 : $*Builtin.Int64
|
|
|
|
// Storing into the struct should not disrupt elimination of the
|
|
// alloc_ref.
|
|
%2 = ref_element_addr %0 : $TrivialDestructor, #TrivialDestructor.int
|
|
%3 = integer_literal $Builtin.Int32, 1
|
|
store %3 to %2 : $*Builtin.Int32
|
|
|
|
// Calling a builtin without side effects should not disrupt
|
|
// elimination of the alloc_ref.
|
|
%4 = integer_literal $Builtin.Int32, 0
|
|
%6 = builtin "xor_Int32" (%4 : $Builtin.Int32, %3 : $Builtin.Int32) : $Builtin.Int32
|
|
|
|
// Calling dealloc ref on self should not disrupt elimination of the
|
|
// alloc_ref.
|
|
dealloc_ref %0 : $TrivialDestructor
|
|
|
|
%7 = tuple()
|
|
return %7 : $()
|
|
}
|
|
|
|
sil @ptr_user : $@convention(thin) (Builtin.NativeObject) -> ()
|
|
sil @int_user : $@convention(thin) (Builtin.Int32) -> ()
|
|
|
|
///////////
|
|
// Tests //
|
|
///////////
|
|
|
|
// Trivial case. Remove the alloc_ref.
|
|
//
|
|
// CHECK-LABEL: sil @trivial_destructor_trivial : $@convention(thin) () -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
sil @trivial_destructor_trivial : $@convention(thin) () -> () {
|
|
%0 = alloc_ref $TrivialDestructor
|
|
strong_release %0 : $TrivialDestructor
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
// We load/use a pointer from the alloc_ref, do nothing.
|
|
//
|
|
// CHECK-LABEL: sil @trivial_destructor_load : $@convention(thin) () -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: alloc_ref
|
|
// CHECK-NEXT: ref_element_addr
|
|
// CHECK-NEXT: load
|
|
// CHECK-NEXT: function_ref
|
|
// CHECK-NEXT: function_ref
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
sil @trivial_destructor_load : $@convention(thin) () -> () {
|
|
%0 = alloc_ref $TrivialDestructor
|
|
%1 = ref_element_addr %0 : $TrivialDestructor, #TrivialDestructor.int
|
|
%2 = load %1 : $*Builtin.Int32
|
|
%3 = function_ref @int_user : $@convention(thin) (Builtin.Int32) -> ()
|
|
apply %3 (%2) : $@convention(thin) (Builtin.Int32) -> ()
|
|
strong_release %0 : $TrivialDestructor
|
|
%4 = tuple()
|
|
return %4 : $()
|
|
}
|
|
|
|
// We store into the alloc_ref, eliminate it!
|
|
//
|
|
// CHECK-LABEL: sil @trivial_destructor_store_into : $@convention(thin) () -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: integer_literal
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
sil @trivial_destructor_store_into : $@convention(thin) () -> () {
|
|
%0 = alloc_ref $TrivialDestructor
|
|
%1 = ref_element_addr %0 : $TrivialDestructor, #TrivialDestructor.int
|
|
%2 = integer_literal $Builtin.Int32, 5
|
|
store %2 to %1 : $*Builtin.Int32
|
|
strong_release %0 : $TrivialDestructor
|
|
%4 = tuple()
|
|
return %4 : $()
|
|
}
|
|
|
|
// We store a pointer from the alloc_ref, don't do anything!
|
|
//
|
|
// CHECK-LABEL: sil @trivial_destructor_store_ptr
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: alloc_ref
|
|
// CHECK-NEXT: ref_element_addr
|
|
// CHECK-NEXT: address_to_pointer
|
|
// CHECK-NEXT: store
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
sil @trivial_destructor_store_ptr : $@convention(thin) (@inout Builtin.RawPointer) -> () {
|
|
bb0(%0 : $*Builtin.RawPointer):
|
|
%1 = alloc_ref $TrivialDestructor
|
|
%2 = ref_element_addr %1 : $TrivialDestructor, #TrivialDestructor.int
|
|
%3 = address_to_pointer %2 : $*Builtin.Int32 to $Builtin.RawPointer
|
|
store %3 to %0 : $*Builtin.RawPointer
|
|
strong_release %1 : $TrivialDestructor
|
|
%4 = tuple()
|
|
return %4 : $()
|
|
}
|
|
|
|
// We are returning the alloc_ref, do nothing.
|
|
//
|
|
// CHECK-LABEL: sil @trivial_destructor_return_value_use : $@convention(thin) () -> TrivialDestructor {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: alloc_ref
|
|
// CHECK-NEXT: return
|
|
sil @trivial_destructor_return_value_use : $@convention(thin) () -> TrivialDestructor {
|
|
%0 = alloc_ref $TrivialDestructor
|
|
return %0 : $TrivialDestructor
|
|
}
|
|
|
|
// Retains/releases on the alloc_ref can be ignored.
|
|
//
|
|
// CHECK-LABEL: sil @trivial_destructor_refcount_inst_on_value : $@convention(thin) () -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
sil @trivial_destructor_refcount_inst_on_value : $@convention(thin) () -> () {
|
|
%0 = alloc_ref $TrivialDestructor
|
|
strong_retain %0 : $TrivialDestructor
|
|
strong_release %0 : $TrivialDestructor
|
|
strong_release %0 : $TrivialDestructor
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
// Retains/Releases on a different value in the use list implies abort.
|
|
//
|
|
// CHECK-LABEL: sil @trivial_destructor_refcount_inst_on_diff_value : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: alloc_ref
|
|
// CHECK-NEXT: ref_element_addr
|
|
// CHECK-NEXT: store
|
|
// CHECK-NEXT: load
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
sil @trivial_destructor_refcount_inst_on_diff_value : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
%1 = alloc_ref $TrivialDestructor
|
|
%2 = ref_element_addr %1 : $TrivialDestructor, #TrivialDestructor.ptr
|
|
store %0 to %2 : $*Builtin.NativeObject
|
|
%3 = load %2 : $*Builtin.NativeObject
|
|
strong_release %3 : $Builtin.NativeObject
|
|
strong_release %1 : $TrivialDestructor
|
|
%4 = tuple()
|
|
return %4 : $()
|
|
}
|
|
|
|
/*
|
|
sil @trivial_destructor_apply_use
|
|
|
|
sil @trivial_destructor_side_effect_use
|
|
*/
|
|
|
|
//sil @non_trivial_destructor
|
|
|
|
class NonTrivialDestructor {
|
|
var ptr : Builtin.NativeObject
|
|
|
|
init()
|
|
deinit { }
|
|
}
|
|
|
|
sil @_TFC4main17NonTrivialDestructorD : $@convention(method) (@owned NonTrivialDestructor) -> () {
|
|
bb0(%0 : $NonTrivialDestructor):
|
|
%1 = ref_element_addr %0 : $NonTrivialDestructor, #NonTrivialDestructor.ptr
|
|
%2 = load %1 : $*Builtin.NativeObject
|
|
strong_retain %2 : $Builtin.NativeObject
|
|
dealloc_ref %0 : $NonTrivialDestructor
|
|
%3 = tuple()
|
|
return %3 : $()
|
|
}
|
|
|
|
// Make sure that a ref count operation on a different value in the
|
|
// destructor disrupts the algorithm.
|
|
//
|
|
// CHECK-LABEL: sil @non_trivial_destructor_refcount_on_different_value : $@convention(thin) () -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: alloc_ref
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
sil @non_trivial_destructor_refcount_on_different_value : $@convention(thin) () -> () {
|
|
%0 = alloc_ref $NonTrivialDestructor
|
|
strong_release %0 : $NonTrivialDestructor
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
class NonTrivialDestructor2 {
|
|
var ptr : NonTrivialDestructor
|
|
|
|
init()
|
|
deinit { }
|
|
}
|
|
|
|
// Test if dealloc_ref on a different value disrupts the algorithm.
|
|
sil @_TFC4main17NonTrivialDestructor2D : $@convention(method) (@owned NonTrivialDestructor2) -> () {
|
|
bb0(%0 : $NonTrivialDestructor2):
|
|
%1 = ref_element_addr %0 : $NonTrivialDestructor2, #NonTrivialDestructor2.ptr
|
|
%2 = load %1 : $*NonTrivialDestructor
|
|
dealloc_ref %2 : $NonTrivialDestructor
|
|
dealloc_ref %0 : $NonTrivialDestructor2
|
|
%3 = tuple()
|
|
return %3 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @non_trivial_destructor_deallocref_on_different_value : $@convention(thin) () -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: alloc_ref
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
sil @non_trivial_destructor_deallocref_on_different_value : $@convention(thin) () -> () {
|
|
%0 = alloc_ref $NonTrivialDestructor
|
|
strong_release %0 : $NonTrivialDestructor
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
class NonTrivialDestructor3 {
|
|
var ptr : Builtin.NativeObject
|
|
|
|
init()
|
|
deinit { }
|
|
}
|
|
|
|
// Make sure a non-builtin apply disrupts the algorithm.
|
|
sil @_TFC4main17NonTrivialDestructor3D : $@convention(method) (@owned NonTrivialDestructor3) -> () {
|
|
bb0(%0 : $NonTrivialDestructor3):
|
|
%1 = ref_element_addr %0 : $NonTrivialDestructor3, #NonTrivialDestructor3.ptr
|
|
%2 = load %1 : $*Builtin.NativeObject
|
|
%3 = function_ref @ptr_user : $@convention(thin) (Builtin.NativeObject) -> ()
|
|
apply %3 (%2) : $@convention(thin) (Builtin.NativeObject) -> ()
|
|
dealloc_ref %0 : $NonTrivialDestructor3
|
|
%4 = tuple()
|
|
return %4 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @non_trivial_destructor_unknown_apply : $@convention(thin) () -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: alloc_ref
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
sil @non_trivial_destructor_unknown_apply : $@convention(thin) () -> () {
|
|
%0 = alloc_ref $NonTrivialDestructor
|
|
strong_release %0 : $NonTrivialDestructor
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
class NonTrivialObjCDestructor {
|
|
var ptr : Builtin.NativeObject
|
|
|
|
init() { }
|
|
deinit { }
|
|
}
|
|
|
|
// Make sure we do not handle objc_methods
|
|
sil @_TFC4main17NonTrivialObjCDestructorD : $@convention(objc_method) (@owned NonTrivialObjCDestructor) -> () {
|
|
bb0(%0 : $NonTrivialObjCDestructor):
|
|
dealloc_ref %0 : $NonTrivialObjCDestructor
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @non_trivial_destructor_objc_destructor : $@convention(thin) () -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: alloc_ref
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
sil @non_trivial_destructor_objc_destructor : $@convention(thin) () -> () {
|
|
%0 = alloc_ref $NonTrivialObjCDestructor
|
|
strong_release %0 : $NonTrivialObjCDestructor
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @non_trivial_destructor_on_stack : $@convention(thin) () -> () {
|
|
// CHECK: alloc_stack
|
|
// CHECK: return
|
|
sil @non_trivial_destructor_on_stack : $@convention(thin) () -> () {
|
|
%0 = alloc_stack $NonTrivialDestructor
|
|
dealloc_stack %0 : $*NonTrivialDestructor
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @trivial_destructor_on_stack : $@convention(thin) () -> () {
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK-NOT: dealloc_stack
|
|
// CHECK: return
|
|
sil @trivial_destructor_on_stack : $@convention(thin) () -> () {
|
|
%0 = alloc_stack $Int
|
|
destroy_addr %0 : $*Int
|
|
dealloc_stack %0 : $*Int
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
// If we have an instruction that mayTrap that uses the alloc_ref, we can't
|
|
// eliminate it.
|
|
//
|
|
// CHECK-LABEL: sil @trivial_destructor_may_trap : $@convention(thin) () -> () {
|
|
// CHECK: alloc_ref
|
|
sil @trivial_destructor_may_trap : $@convention(thin) () -> () {
|
|
%0 = alloc_ref $TrivialDestructor
|
|
%1 = unconditional_checked_cast %0 : $TrivialDestructor to $AnyObject
|
|
strong_release %0 : $TrivialDestructor
|
|
%4 = tuple()
|
|
return %4 : $()
|
|
}
|