mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
KeyPath's getter/setter/hash/equals functions have their own calling convention, which receives generic arguments and embedded indices from a given KeyPath argument buffer. The convention was previously implemented by: 1. Accepting an argument buffer as an UnsafeRawPointer and casting it to indices tuple pointer in SIL. 2. Bind generic arguments info from the given argument buffer while emitting prologue in IRGen by creating a new forwarding thunk. This 2-phase lowering approach was not ideal, as it blocked KeyPath projection optimization [^1], and also required having a target arch specific signature lowering logic in SIL-level [^2]. This patch centralizes the KeyPath accessor calling convention logic to IRGen, by introducing `@convention(keypath_accessor_XXX)` convention in SIL and lowering it in IRGen. This change unblocks the KeyPath projection optimization while capturing subscript indices, and also makes it easier to support WebAssembly target. [^1]: https://github.com/apple/swift/pull/28799 [^2]: https://forums.swift.org/t/wasm-support/16087/21
544 lines
20 KiB
Plaintext
544 lines
20 KiB
Plaintext
// RUN: %target-sil-opt -enable-sil-verify-all -deadobject-elim %s | %FileCheck %s
|
|
|
|
import Swift
|
|
import Builtin
|
|
import SwiftShims
|
|
|
|
//////////
|
|
// Data //
|
|
//////////
|
|
|
|
class TrivialDestructor {
|
|
var int : Builtin.Int32
|
|
var ptr : Builtin.NativeObject
|
|
init()
|
|
deinit { }
|
|
}
|
|
|
|
class Kl {}
|
|
|
|
class NontrivialDestructor {
|
|
@_hasStorage var p : Kl
|
|
@_hasStorage var i : Int
|
|
init()
|
|
}
|
|
|
|
class ArrayStorage {
|
|
@_hasStorage var bodyField : Kl
|
|
init()
|
|
}
|
|
|
|
protocol P { }
|
|
struct X : P { }
|
|
|
|
sil @$s4main17TrivialDestructorCfD : $@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 : $()
|
|
}
|
|
|
|
// Fake destructor for NontrivialDestructor
|
|
sil [ossa] @$s4main20NontrivialDestructorCfD : $@convention(method) (@owned NontrivialDestructor) -> () {
|
|
bb0(%0 : @owned $NontrivialDestructor):
|
|
dealloc_ref %0 : $NontrivialDestructor
|
|
%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 [ossa] @trivial_destructor_trivial : $@convention(thin) () -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
sil [ossa] @trivial_destructor_trivial : $@convention(thin) () -> () {
|
|
%0 = alloc_ref $TrivialDestructor
|
|
destroy_value %0 : $TrivialDestructor
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
// If the destructor is not called, we don't care about it.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @devirtualized_destructor : $@convention(thin) () -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
sil [ossa] @devirtualized_destructor : $@convention(thin) () -> () {
|
|
%0 = alloc_ref $NontrivialDestructor
|
|
%1 = begin_dealloc_ref %0 : $NontrivialDestructor of %0 : $NontrivialDestructor
|
|
fix_lifetime %1 : $NontrivialDestructor
|
|
dealloc_ref %1 : $NontrivialDestructor
|
|
%4 = tuple()
|
|
return %4 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @store_to_non_trivial_property1
|
|
// CHECK-NOT: alloc_ref [stack] $NontrivialDestructor
|
|
// CHECK: } // end sil function 'store_to_non_trivial_property1'
|
|
sil [ossa] @store_to_non_trivial_property1 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%0 = apply undef () : $@convention(thin) () -> @owned Kl
|
|
%1 = alloc_ref [stack] $NontrivialDestructor
|
|
%2 = begin_borrow %1 : $NontrivialDestructor
|
|
%3 = ref_element_addr %2 : $NontrivialDestructor, #NontrivialDestructor.p
|
|
store %0 to [init] %3 : $*Kl
|
|
end_borrow %2 : $NontrivialDestructor
|
|
%6 = begin_dealloc_ref %1 : $NontrivialDestructor of %1 : $NontrivialDestructor
|
|
destroy_value %6 : $NontrivialDestructor
|
|
dealloc_stack_ref %1 : $NontrivialDestructor
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @store_to_trivial_property
|
|
// CHECK-NOT: alloc_ref
|
|
// CHECK: } // end sil function 'store_to_trivial_property'
|
|
sil [ossa] @store_to_trivial_property : $@convention(thin) (Int) -> () {
|
|
bb0(%0 : $Int):
|
|
%1 = alloc_ref [stack] $NontrivialDestructor
|
|
%2 = begin_borrow %1 : $NontrivialDestructor
|
|
%3 = ref_element_addr %2 : $NontrivialDestructor, #NontrivialDestructor.i
|
|
%4 = begin_access [modify] [dynamic] %3 : $*Int
|
|
store %0 to [trivial] %4 : $*Int
|
|
end_access %4 : $*Int
|
|
end_borrow %2 : $NontrivialDestructor
|
|
%6 = begin_dealloc_ref %1 : $NontrivialDestructor of %1 : $NontrivialDestructor
|
|
dealloc_ref %6 : $NontrivialDestructor
|
|
dealloc_stack_ref %1 : $NontrivialDestructor
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
|
|
// We load/use a pointer from the alloc_ref, do nothing.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @trivial_destructor_load : $@convention(thin) () -> () {
|
|
// CHECK: alloc_ref
|
|
sil [ossa] @trivial_destructor_load : $@convention(thin) () -> () {
|
|
%0 = alloc_ref $TrivialDestructor
|
|
%1 = begin_borrow %0 : $TrivialDestructor
|
|
%2 = ref_element_addr %1 : $TrivialDestructor, #TrivialDestructor.int
|
|
%3 = load [trivial] %2 : $*Builtin.Int32
|
|
%4 = function_ref @int_user : $@convention(thin) (Builtin.Int32) -> ()
|
|
apply %4 (%3) : $@convention(thin) (Builtin.Int32) -> ()
|
|
end_borrow %1 : $TrivialDestructor
|
|
destroy_value %0 : $TrivialDestructor
|
|
%r = tuple()
|
|
return %r : $()
|
|
}
|
|
|
|
// We store into the alloc_ref, eliminate it!
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @trivial_destructor_store_into : $@convention(thin) () -> () {
|
|
// CHECK-NOT: alloc_ref
|
|
// CHECK-LABEL: } // end sil function 'trivial_destructor_store_into'
|
|
sil [ossa] @trivial_destructor_store_into : $@convention(thin) () -> () {
|
|
%0 = alloc_ref $TrivialDestructor
|
|
%b = begin_borrow %0 : $TrivialDestructor
|
|
%1 = ref_element_addr %b : $TrivialDestructor, #TrivialDestructor.int
|
|
%2 = integer_literal $Builtin.Int32, 5
|
|
store %2 to [trivial] %1 : $*Builtin.Int32
|
|
end_borrow %b : $TrivialDestructor
|
|
destroy_value %0 : $TrivialDestructor
|
|
%4 = tuple()
|
|
return %4 : $()
|
|
}
|
|
|
|
// We store a pointer from the alloc_ref, don't do anything!
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @trivial_destructor_store_ptr
|
|
// CHECK: alloc_ref
|
|
// CHECK-LABEL: } // end sil function 'trivial_destructor_store_ptr'
|
|
sil [ossa] @trivial_destructor_store_ptr : $@convention(thin) (@inout Builtin.RawPointer) -> () {
|
|
bb0(%0 : $*Builtin.RawPointer):
|
|
%1 = alloc_ref $TrivialDestructor
|
|
%b = begin_borrow %1 : $TrivialDestructor
|
|
%2 = ref_element_addr %b : $TrivialDestructor, #TrivialDestructor.int
|
|
%3 = address_to_pointer %2 : $*Builtin.Int32 to $Builtin.RawPointer
|
|
store %3 to [trivial] %0 : $*Builtin.RawPointer
|
|
end_borrow %b : $TrivialDestructor
|
|
destroy_value %1 : $TrivialDestructor
|
|
%4 = tuple()
|
|
return %4 : $()
|
|
}
|
|
|
|
// We are returning the alloc_ref, do nothing.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @trivial_destructor_return_value_use :
|
|
// CHECK: alloc_ref
|
|
// CHECK-LABEL: } // end sil function 'trivial_destructor_return_value_use'
|
|
sil [ossa] @trivial_destructor_return_value_use : $@convention(thin) () -> @owned TrivialDestructor {
|
|
%0 = alloc_ref $TrivialDestructor
|
|
return %0 : $TrivialDestructor
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @trivial_destructor_refcount_inst_on_value : $@convention(thin) () -> () {
|
|
// CHECK-NOT: alloc_ref
|
|
// CHECK-LABEL: } // end sil function 'trivial_destructor_refcount_inst_on_value'
|
|
sil [ossa] @trivial_destructor_refcount_inst_on_value : $@convention(thin) () -> () {
|
|
%0 = alloc_ref $TrivialDestructor
|
|
%copy = copy_value %0 : $TrivialDestructor
|
|
destroy_value %copy : $TrivialDestructor
|
|
destroy_value %0 : $TrivialDestructor
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
class NonTrivialDestructor {
|
|
var ptr : Builtin.NativeObject
|
|
|
|
init()
|
|
deinit { }
|
|
}
|
|
|
|
sil [ossa] @_TFC4main17NonTrivialDestructorD : $@convention(method) (@owned NonTrivialDestructor) -> () {
|
|
bb0(%0 : @owned $NonTrivialDestructor):
|
|
%b = begin_borrow %0 : $NonTrivialDestructor
|
|
%1 = ref_element_addr %b : $NonTrivialDestructor, #NonTrivialDestructor.ptr
|
|
%2 = load [copy] %1 : $*Builtin.NativeObject
|
|
end_borrow %b : $NonTrivialDestructor
|
|
destroy_value %2 : $Builtin.NativeObject
|
|
dealloc_ref %0 : $NonTrivialDestructor
|
|
%3 = tuple()
|
|
return %3 : $()
|
|
}
|
|
|
|
class NonTrivialDestructor2 {
|
|
var ptr : NonTrivialDestructor
|
|
|
|
init()
|
|
deinit { }
|
|
}
|
|
|
|
// Test if dealloc_ref on a different value disrupts the algorithm.
|
|
sil [ossa] @_TFC4main17NonTrivialDestructor2D : $@convention(method) (@owned NonTrivialDestructor2) -> () {
|
|
bb0(%0 : @owned $NonTrivialDestructor2):
|
|
%b = begin_borrow %0 : $NonTrivialDestructor2
|
|
%1 = ref_element_addr %b : $NonTrivialDestructor2, #NonTrivialDestructor2.ptr
|
|
%2 = load [copy] %1 : $*NonTrivialDestructor
|
|
end_borrow %b : $NonTrivialDestructor2
|
|
dealloc_ref %2 : $NonTrivialDestructor
|
|
dealloc_ref %0 : $NonTrivialDestructor2
|
|
%3 = tuple()
|
|
return %3 : $()
|
|
}
|
|
|
|
class NonTrivialDestructor3 {
|
|
var ptr : Builtin.NativeObject
|
|
|
|
init()
|
|
deinit { }
|
|
}
|
|
|
|
// Make sure a non-builtin apply disrupts the algorithm.
|
|
sil [ossa] @_TFC4main17NonTrivialDestructor3D : $@convention(method) (@owned NonTrivialDestructor3) -> () {
|
|
bb0(%0 : @owned $NonTrivialDestructor3):
|
|
%b = begin_borrow %0 : $NonTrivialDestructor3
|
|
%1 = ref_element_addr %b : $NonTrivialDestructor3, #NonTrivialDestructor3.ptr
|
|
%2 = load [take] %1 : $*Builtin.NativeObject
|
|
%3 = function_ref @ptr_user : $@convention(thin) (Builtin.NativeObject) -> ()
|
|
apply %3 (%2) : $@convention(thin) (Builtin.NativeObject) -> ()
|
|
destroy_value %2 : $Builtin.NativeObject
|
|
end_borrow %b : $NonTrivialDestructor3
|
|
dealloc_ref %0 : $NonTrivialDestructor3
|
|
%4 = tuple()
|
|
return %4 : $()
|
|
}
|
|
|
|
class NonTrivialObjCDestructor {
|
|
var ptr : Builtin.NativeObject
|
|
|
|
init() { }
|
|
deinit { }
|
|
}
|
|
|
|
// Make sure we do not handle objc_methods
|
|
sil [ossa] @_TFC4main17NonTrivialObjCDestructorD : $@convention(objc_method) (@owned NonTrivialObjCDestructor) -> () {
|
|
bb0(%0 : @owned $NonTrivialObjCDestructor):
|
|
dealloc_ref %0 : $NonTrivialObjCDestructor
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @non_trivial_destructor_objc_destructor : $@convention(thin) () -> () {
|
|
// CHECK: alloc_ref
|
|
// CHECK-LABEL: } // end sil function 'non_trivial_destructor_objc_destructor'
|
|
sil [ossa] @non_trivial_destructor_objc_destructor : $@convention(thin) () -> () {
|
|
%0 = alloc_ref $NonTrivialObjCDestructor
|
|
destroy_value %0 : $NonTrivialObjCDestructor
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @non_trivial_destructor_on_stack : $@convention(thin) () -> () {
|
|
// CHECK: bb0:
|
|
// CHECK-NEXT: %0 = tuple ()
|
|
// CHECK-NEXT: return %0
|
|
sil [ossa] @non_trivial_destructor_on_stack : $@convention(thin) () -> () {
|
|
%0 = alloc_stack $NonTrivialDestructor
|
|
dealloc_stack %0 : $*NonTrivialDestructor
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
sil [ossa] @non_trivial_destructor_on_stack_with_stores1 : $@convention(thin) (@owned NonTrivialDestructor) -> () {
|
|
bb0(%0 : @owned $NonTrivialDestructor):
|
|
%copy = copy_value %0 : $NonTrivialDestructor
|
|
%1 = alloc_stack $NonTrivialDestructor
|
|
store %0 to [init] %1 : $*NonTrivialDestructor
|
|
store %copy to [assign] %1 : $*NonTrivialDestructor
|
|
destroy_addr %1 : $*NonTrivialDestructor
|
|
dealloc_stack %1 : $*NonTrivialDestructor
|
|
%2 = tuple()
|
|
return %2 : $()
|
|
}
|
|
|
|
sil [ossa] @non_trivial_destructor_on_stack_with_stores2 : $@convention(thin) (@owned NonTrivialDestructor, @owned NonTrivialDestructor) -> () {
|
|
bb0(%0 : @owned $NonTrivialDestructor, %1 : @owned $NonTrivialDestructor):
|
|
%2 = alloc_stack $NonTrivialDestructor
|
|
store %0 to [init] %2 : $*NonTrivialDestructor
|
|
store %1 to [assign] %2 : $*NonTrivialDestructor
|
|
destroy_addr %2 : $*NonTrivialDestructor
|
|
dealloc_stack %2 : $*NonTrivialDestructor
|
|
%3 = tuple()
|
|
return %3 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @trivial_destructor_on_stack : $@convention(thin) () -> () {
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK-NOT: dealloc_stack
|
|
// CHECK: return
|
|
sil [ossa] @trivial_destructor_on_stack : $@convention(thin) () -> () {
|
|
%0 = alloc_stack $Int
|
|
destroy_addr %0 : $*Int
|
|
dealloc_stack %0 : $*Int
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @remove_dead_enum_stackloc :
|
|
// CHECK: bb0:
|
|
// CHECK-NEXT: %0 = tuple ()
|
|
// CHECK-NEXT: return %0
|
|
sil [ossa] @remove_dead_enum_stackloc : $@convention(thin) () -> () {
|
|
bb0:
|
|
%0 = alloc_stack $FloatingPointRoundingRule
|
|
inject_enum_addr %0 : $*FloatingPointRoundingRule, #FloatingPointRoundingRule.toNearestOrEven!enumelt
|
|
destroy_addr %0 : $*FloatingPointRoundingRule
|
|
dealloc_stack %0 : $*FloatingPointRoundingRule
|
|
%1 = tuple ()
|
|
return %1 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @remove_dead_optional_existential :
|
|
// CHECK: bb0(%0 : $X):
|
|
// CHECK-NEXT: %1 = tuple ()
|
|
// CHECK-NEXT: return %1
|
|
sil [ossa] @remove_dead_optional_existential : $@convention(thin) (X) -> () {
|
|
bb0(%0 : $X):
|
|
%3 = alloc_stack $Optional<P>
|
|
%4 = init_enum_data_addr %3 : $*Optional<P>, #Optional.some!enumelt
|
|
%5 = init_existential_addr %4 : $*P, $X
|
|
store %0 to [trivial] %5 : $*X
|
|
inject_enum_addr %3 : $*Optional<P>, #Optional.some!enumelt
|
|
destroy_addr %3 : $*Optional<P>
|
|
dealloc_stack %3 : $*Optional<P>
|
|
%10 = tuple ()
|
|
return %10 : $()
|
|
}
|
|
|
|
// If we have an instruction that mayTrap that uses the alloc_ref, we can't
|
|
// eliminate it.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @trivial_destructor_may_trap : $@convention(thin) () -> () {
|
|
// CHECK: alloc_ref
|
|
sil [ossa] @trivial_destructor_may_trap : $@convention(thin) () -> () {
|
|
%0 = alloc_ref $TrivialDestructor
|
|
%1 = unconditional_checked_cast %0 : $TrivialDestructor to AnyObject
|
|
destroy_value %1 : $AnyObject
|
|
%4 = tuple()
|
|
return %4 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @remove_dead_array_with_destroy_simple
|
|
// CHECK-NOT: alloc_ref
|
|
// CHECK: } // end sil function 'remove_dead_array_with_destroy_simple'
|
|
sil [ossa] @remove_dead_array_with_destroy_simple : $@convention(thin) () -> () {
|
|
bb0:
|
|
%0 = apply undef () : $@convention(thin) () -> @owned Kl
|
|
%copy = copy_value %0 : $Kl
|
|
%3 = integer_literal $Builtin.Word, 2
|
|
%4 = alloc_ref [tail_elems $Kl * %3 : $Builtin.Word] $ArrayStorage
|
|
%5 = begin_borrow %4 : $ArrayStorage
|
|
%11 = ref_tail_addr %5 : $ArrayStorage, $Kl
|
|
store %0 to [init] %11 : $*Kl
|
|
%27 = integer_literal $Builtin.Word, 1
|
|
%28 = index_addr %11 : $*Kl, %27 : $Builtin.Word
|
|
store %copy to [init] %28 : $*Kl
|
|
end_borrow %5 : $ArrayStorage
|
|
%6 = begin_dealloc_ref %4 : $ArrayStorage of %4 : $ArrayStorage
|
|
%7 = begin_borrow %6 : $ArrayStorage
|
|
%8 = ref_tail_addr %7 : $ArrayStorage, $Kl
|
|
%65 = address_to_pointer %8 : $*Kl to $Builtin.RawPointer
|
|
%66 = metatype $@thick Kl.Type
|
|
%67 = builtin "destroyArray"<Kl>(%66 : $@thick Kl.Type, %65 : $Builtin.RawPointer, %3 : $Builtin.Word) : $()
|
|
end_borrow %7 : $ArrayStorage
|
|
dealloc_ref %6 : $ArrayStorage
|
|
%10 = tuple ()
|
|
return %10 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @remove_dead_array_with_destroy_complex
|
|
// CHECK-NOT: alloc_ref
|
|
// CHECK: } // end sil function 'remove_dead_array_with_destroy_complex'
|
|
sil [ossa] @remove_dead_array_with_destroy_complex : $@convention(thin) (@guaranteed String, Int, UInt) -> () {
|
|
bb0(%0 : @guaranteed $String, %1 : $Int, %2 : $UInt):
|
|
%copy0 = copy_value %0 : $String
|
|
%copy1 = copy_value %0 : $String
|
|
%3 = integer_literal $Builtin.Word, 2
|
|
%4 = alloc_ref [stack] [tail_elems $(Int, String) * %3 : $Builtin.Word] $_ContiguousArrayStorage<(Int, String)>
|
|
%5 = upcast %4 : $_ContiguousArrayStorage<(Int, String)> to $__ContiguousArrayStorageBase
|
|
%6 = struct $_SwiftArrayBodyStorage (%1 : $Int, %2 : $UInt)
|
|
%7 = struct $_ArrayBody (%6 : $_SwiftArrayBodyStorage)
|
|
%b = begin_borrow %5 : $__ContiguousArrayStorageBase
|
|
%9 = ref_element_addr %b : $__ContiguousArrayStorageBase, #__ContiguousArrayStorageBase.countAndCapacity
|
|
store %7 to [trivial] %9 : $*_ArrayBody
|
|
%11 = ref_tail_addr %b : $__ContiguousArrayStorageBase, $(Int, String)
|
|
%12 = tuple_element_addr %11 : $*(Int, String), 0
|
|
%13 = tuple_element_addr %11 : $*(Int, String), 1
|
|
store %1 to [trivial] %12 : $*Int
|
|
store %copy0 to [init] %13 : $*String
|
|
%27 = integer_literal $Builtin.Word, 1
|
|
%28 = index_addr %11 : $*(Int, String), %27 : $Builtin.Word
|
|
%29 = tuple_element_addr %28 : $*(Int, String), 0
|
|
%30 = tuple_element_addr %28 : $*(Int, String), 1
|
|
store %1 to [trivial] %29 : $*Int
|
|
store %copy1 to [init] %30 : $*String
|
|
end_borrow %b : $__ContiguousArrayStorageBase
|
|
%31 = begin_dealloc_ref %5 : $__ContiguousArrayStorageBase of %4 : $_ContiguousArrayStorage<(Int, String)>
|
|
%b2 = begin_borrow %31 : $__ContiguousArrayStorageBase
|
|
%64 = ref_tail_addr %b2 : $__ContiguousArrayStorageBase, $(Int, String)
|
|
%65 = address_to_pointer %64 : $*(Int, String) to $Builtin.RawPointer
|
|
%66 = metatype $@thick (Int, String).Type
|
|
%67 = builtin "destroyArray"<(Int, String)>(%66 : $@thick (Int, String).Type, %65 : $Builtin.RawPointer, %3 : $Builtin.Word) : $()
|
|
end_borrow %b2 : $__ContiguousArrayStorageBase
|
|
dealloc_ref %31 : $__ContiguousArrayStorageBase
|
|
dealloc_stack_ref %4 : $_ContiguousArrayStorage<(Int, String)>
|
|
%10 = tuple ()
|
|
return %10 : $()
|
|
}
|
|
|
|
struct II { }
|
|
|
|
struct I {
|
|
@_hasStorage public let x: II { get }
|
|
}
|
|
|
|
struct S2 { }
|
|
|
|
sil @getter1 : $@convention(method) (@guaranteed KeyPath<I, II>, S2) -> @out II
|
|
sil @kpgetter1 : $@convention(keypath_accessor_getter) (@in_guaranteed S2, @in_guaranteed KeyPath<I, II>) -> @out II
|
|
sil @getter2 : $@convention(keypath_accessor_getter) (@guaranteed String, Foo) -> @owned String
|
|
sil @kpgetter2 : $@convention(keypath_accessor_getter) (@in_guaranteed Foo, @in_guaranteed KeyPath<I, II>) -> @out String
|
|
sil @equ : $@convention(keypath_accessor_equals) (@in_guaranteed KeyPath<I, II>, @in_guaranteed KeyPath<I, II>) -> Bool
|
|
sil @hsh : $@convention(keypath_accessor_hash) (@in_guaranteed KeyPath<I, II>) -> Int
|
|
|
|
|
|
// CHECK-LABEL: sil [ossa] @remove_dead_keypath
|
|
// CHECK-NOT: keypath
|
|
// CHECK: } // end sil function 'remove_dead_keypath'
|
|
sil [ossa] @remove_dead_keypath: $@convention(thin) () -> () {
|
|
bb0:
|
|
%0 = keypath $KeyPath<I, II>, (root $I; stored_property #I.x : $II)
|
|
%1 = keypath $KeyPath<S2, II>, (root $S2; gettable_property $II, id @getter1 : $@convention(method) (@guaranteed KeyPath<I, II>, S2) -> @out II, getter @kpgetter1: $@convention(keypath_accessor_getter) (@in_guaranteed S2, @in_guaranteed KeyPath<I, II>) -> @out II, indices [%$0 : $KeyPath<I, II> : $KeyPath<I, II>], indices_equals @equ : $@convention(keypath_accessor_equals) (@in_guaranteed KeyPath<I, II>, @in_guaranteed KeyPath<I, II>) -> Bool, indices_hash @hsh : $@convention(keypath_accessor_hash) (@in_guaranteed KeyPath<I, II>) -> Int) (%0)
|
|
destroy_value %1 : $KeyPath<S2, II>
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
struct Foo {
|
|
subscript(x: String) -> String { get }
|
|
init()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @remove_nontrivial_dead_keypath
|
|
// CHECK-NOT: keypath
|
|
// CHECK: } // end sil function 'remove_nontrivial_dead_keypath'
|
|
sil [ossa] @remove_nontrivial_dead_keypath : $@convention(thin) (@owned String) -> () {
|
|
bb0(%0 : @owned $String):
|
|
%3 = keypath $KeyPath<Foo, String>, (root $Foo; gettable_property $String, id @getter2 : $@convention(keypath_accessor_getter) (@guaranteed String, Foo) -> @owned String, getter @kpgetter2 : $@convention(keypath_accessor_getter) (@in_guaranteed Foo, @in_guaranteed KeyPath<I, II>) -> @out String, indices [%$0 : $String : $String], indices_equals @equ : $@convention(keypath_accessor_equals) (@in_guaranteed KeyPath<I, II>, @in_guaranteed KeyPath<I, II>) -> Bool, indices_hash @hsh : $@convention(keypath_accessor_hash) (@in_guaranteed KeyPath<I, II>) -> Int) (%0) // user: %4
|
|
destroy_value %3 : $KeyPath<Foo, String>
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
sil @createit : $@convention(thin) () -> @owned Kl
|
|
|
|
// Check that we don't crash here.
|
|
sil [ossa] @not_dominating_stores : $@convention(thin) () -> () {
|
|
bb0:
|
|
%7 = integer_literal $Builtin.Word, 1
|
|
%10 = alloc_ref [stack] [tail_elems $Kl * %7 : $Builtin.Word] $_ContiguousArrayStorage<Kl>
|
|
%b = begin_borrow %10 : $_ContiguousArrayStorage<Kl>
|
|
%11 = upcast %b : $_ContiguousArrayStorage<Kl> to $__ContiguousArrayStorageBase
|
|
%18 = ref_tail_addr %11 : $__ContiguousArrayStorageBase, $Kl
|
|
%35 = function_ref @createit : $@convention(thin) () -> @owned Kl
|
|
cond_br undef, bb1, bb2
|
|
bb1:
|
|
%36 = apply %35() : $@convention(thin) () -> @owned Kl
|
|
store %36 to [init] %18 : $*Kl
|
|
br bb3
|
|
bb2:
|
|
%46 = apply %35() : $@convention(thin) () -> @owned Kl
|
|
store %46 to [init] %18 : $*Kl
|
|
br bb3
|
|
bb3:
|
|
end_borrow %b : $_ContiguousArrayStorage<Kl>
|
|
destroy_value %10 : $_ContiguousArrayStorage<Kl>
|
|
dealloc_stack_ref %10 : $_ContiguousArrayStorage<Kl>
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
sil [ossa] @$ss23_ContiguousArrayStorageCfD : $@convention(method) <Element> (@owned _ContiguousArrayStorage<Element>) -> () {
|
|
bb0(%0 : @owned $_ContiguousArrayStorage<Element>):
|
|
%b = begin_borrow %0 : $_ContiguousArrayStorage<Element>
|
|
%1 = ref_tail_addr %b : $_ContiguousArrayStorage<Element>, $Element
|
|
%2 = address_to_pointer %1 : $*Element to $Builtin.RawPointer
|
|
%10 = metatype $@thick Element.Type
|
|
%12 = builtin "destroyArray"<Element>(%10 : $@thick Element.Type, %2 : $Builtin.RawPointer, undef : $Builtin.Word) : $()
|
|
end_borrow %b : $_ContiguousArrayStorage<Element>
|
|
dealloc_ref %0 : $_ContiguousArrayStorage<Element>
|
|
%15 = tuple ()
|
|
return %15 : $()
|
|
}
|
|
|