// RUN: %target-sil-opt -array-element-propagation %s | %FileCheck %s sil_stage canonical import Builtin import Swift struct MyInt { @_hasStorage var _value: Builtin.Int64 } struct MyBool {} struct _MyDependenceToken {} struct _MyBridgeStorage { @_hasStorage var rawValue : Builtin.BridgeObject } struct _MyArrayBuffer { @_hasStorage var _storage : _MyBridgeStorage } struct MyArray { @_hasStorage var _buffer : _MyArrayBuffer } sil @swift_bufferAllocate : $@convention(thin)() -> @owned AnyObject sil [_semantics "array.uninitialized"] @adoptStorage : $@convention(thin) (@owned AnyObject, MyInt, @thin MyArray.Type) -> @owned (MyArray, UnsafeMutablePointer) sil [_semantics "array.props.isNativeTypeChecked"] @hoistableIsNativeTypeChecked : $@convention(method) (@guaranteed MyArray) -> MyBool sil [_semantics "array.check_subscript"] @checkSubscript : $@convention(method) (MyInt, MyBool, @guaranteed MyArray) -> _MyDependenceToken sil [_semantics "array.get_element"] @getElement : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray) -> MyInt sil @unknown_array_use : $@convention(method) (@guaranteed MyArray) -> MyBool sil [_semantics "array.uninitialized"] @arrayAdoptStorage : $@convention(thin) (@owned AnyObject, MyInt, @thin Array.Type) -> @owned (Array, UnsafeMutablePointer) sil @arrayInit : $@convention(method) (@thin Array.Type) -> @owned Array sil [_semantics "array.finalize_intrinsic"] @finalize : $@convention(thin) (@owned MyArray) -> @owned MyArray sil [_semantics "array.append_contentsOf"] @arrayAppendContentsOf : $@convention(method) (@owned Array, @inout Array) -> () // CHECK-LABEL: sil [ossa] @propagate_with_get_element_returning_direct_result : // CHECK: struct $MyInt // CHECK: [[V0:%.*]] = integer_literal $Builtin.Int64, 0 // CHECK: [[I0:%.*]] = struct $MyInt ([[V0]] : $Builtin.Int64) // CHECK: [[V1:%.*]] = integer_literal $Builtin.Int64, 1 // CHECK: [[I1:%.*]] = struct $MyInt ([[V1]] : $Builtin.Int64) // CHECK: [[V2:%.*]] = integer_literal $Builtin.Int64, 2 // CHECK: [[I2:%.*]] = struct $MyInt ([[V2]] : $Builtin.Int64) // CHECK: [[S0:%.*]] = alloc_stack $MyInt // CHECK: [[HFUN:%.*]] = function_ref @hoistableIsNativeTypeChecked // CHECK-NOT: apply [[HFUN]] // CHECK: [[CFUN:%.*]] = function_ref @checkSubscript // CHECK-NOT: apply [[CFUN]] // CHECK: [[GFUN:%.*]] = function_ref @getElement // CHECK-NOT: apply [[GFUN]] // CHECK-NOT: apply [[HFUN]] // CHECK-NOT: apply [[CFUN]] // CHECK-NOT: apply [[GFUN]] // CHECK: store [[I0]] to [trivial] [[S0]] // CHECK: [[S1:%.*]] = alloc_stack $MyInt // CHECK: store [[I1]] to [trivial] [[S1]] // CHECK: [[S2:%.*]] = alloc_stack $MyInt // CHECK: store [[I2]] to [trivial] [[S2]] // CHECK-LABEL: } // end sil function 'propagate_with_get_element_returning_direct_result' sil [ossa] @propagate_with_get_element_returning_direct_result : $@convention(thin) () -> () { %0 = function_ref @swift_bufferAllocate : $@convention(thin) () -> @owned AnyObject %1 = integer_literal $Builtin.Int64, 3 %2 = struct $MyInt (%1 : $Builtin.Int64) %3 = apply %0() : $@convention(thin) () -> @owned AnyObject %4 = metatype $@thin MyArray.Type %5 = function_ref @adoptStorage : $@convention(thin) (@owned AnyObject, MyInt, @thin MyArray.Type) -> @owned (MyArray, UnsafeMutablePointer) %6 = apply %5(%3, %2, %4) : $@convention(thin) (@owned AnyObject, MyInt, @thin MyArray.Type) -> @owned (MyArray, UnsafeMutablePointer) (%7, %8) = destructure_tuple %6 : $(MyArray, UnsafeMutablePointer) debug_value %7 : $MyArray debug_value %8 : $UnsafeMutablePointer %9 = struct_extract %8 : $UnsafeMutablePointer, #UnsafeMutablePointer._rawValue %10 = pointer_to_address %9 : $Builtin.RawPointer to [strict] $*MyInt %11 = integer_literal $Builtin.Int64, 0 %12 = struct $MyInt (%11 : $Builtin.Int64) store %12 to [trivial] %10 : $*MyInt %13 = integer_literal $Builtin.Word, 1 %14 = index_addr %10 : $*MyInt, %13 : $Builtin.Word %15 = integer_literal $Builtin.Int64, 1 %16 = struct $MyInt (%15 : $Builtin.Int64) store %16 to [trivial] %14 : $*MyInt %17 = integer_literal $Builtin.Word, 2 %18 = index_addr %10 : $*MyInt, %17 : $Builtin.Word %19 = integer_literal $Builtin.Int64, 2 %20 = struct $MyInt (%19 : $Builtin.Int64) store %20 to [trivial] %18 : $*MyInt %borrow7 = begin_borrow %7 : $MyArray %23 = struct_extract %borrow7 : $MyArray, #MyArray._buffer %24 = struct_extract %23 : $_MyArrayBuffer, #_MyArrayBuffer._storage %25 = struct_extract %24 : $_MyBridgeStorage, #_MyBridgeStorage.rawValue end_borrow %borrow7 : $MyArray %26 = alloc_stack $MyInt debug_value %7 : $MyArray %27 = function_ref @hoistableIsNativeTypeChecked : $@convention(method) (@guaranteed MyArray) -> MyBool %28 = apply %27(%7) : $@convention(method) (@guaranteed MyArray) -> MyBool debug_value %28 : $MyBool %29 = function_ref @checkSubscript : $@convention(method) (MyInt, MyBool, @guaranteed MyArray) -> _MyDependenceToken %30 = apply %29(%12, %28, %7) : $@convention(method) (MyInt, MyBool, @guaranteed MyArray) -> _MyDependenceToken debug_value %30 : $_MyDependenceToken %31 = function_ref @getElement : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray) -> MyInt %32 = apply %31(%12, %28, %30, %7) : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray) -> MyInt store %32 to [trivial] %26 : $*MyInt %35 = alloc_stack $MyInt debug_value %16 : $MyInt debug_value %7 : $MyArray debug_value %28 : $MyBool %36 = apply %29(%16, %28, %7) : $@convention(method) (MyInt, MyBool, @guaranteed MyArray) -> _MyDependenceToken debug_value %36 : $_MyDependenceToken %37 = apply %31(%16, %28, %36, %7) : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray) -> MyInt store %37 to [trivial] %35 : $*MyInt %44 = alloc_stack $MyInt debug_value %7 : $MyArray debug_value %28 : $MyBool %45 = apply %29(%20, %28, %7) : $@convention(method) (MyInt, MyBool, @guaranteed MyArray) -> _MyDependenceToken debug_value %45 : $_MyDependenceToken %46 = apply %31(%20, %28, %45, %7) : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray) -> MyInt store %46 to [trivial] %44 : $*MyInt %52 = tuple () dealloc_stack %44 : $*MyInt dealloc_stack %35 : $*MyInt dealloc_stack %26 : $*MyInt destroy_value %7 : $MyArray return %52 : $() } // CHECK-LABEL: sil [ossa] @repeated_initialization : // CHECK: [[GFUN:%.*]] = function_ref @getElement // CHECK: apply [[GFUN]] // CHECK: apply [[GFUN]] // CHECK-LABEL: } // end sil function 'repeated_initialization' sil [ossa] @repeated_initialization : $@convention(thin) () -> () { %0 = function_ref @swift_bufferAllocate : $@convention(thin) () -> @owned AnyObject %1 = integer_literal $Builtin.Int64, 2 %2 = struct $MyInt (%1 : $Builtin.Int64) %3 = apply %0() : $@convention(thin) () -> @owned AnyObject %4 = metatype $@thin MyArray.Type %5 = function_ref @adoptStorage : $@convention(thin) (@owned AnyObject, MyInt, @thin MyArray.Type) -> @owned (MyArray, UnsafeMutablePointer) %6 = apply %5(%3, %2, %4) : $@convention(thin) (@owned AnyObject, MyInt, @thin MyArray.Type) -> @owned (MyArray, UnsafeMutablePointer) (%7, %8) = destructure_tuple %6 : $(MyArray, UnsafeMutablePointer) %9 = struct_extract %8 : $UnsafeMutablePointer, #UnsafeMutablePointer._rawValue %10 = pointer_to_address %9 : $Builtin.RawPointer to [strict] $*MyInt %11 = integer_literal $Builtin.Int64, 0 %12 = struct $MyInt (%11 : $Builtin.Int64) store %12 to [trivial] %10 : $*MyInt %13 = integer_literal $Builtin.Word, 0 %14 = index_addr %10 : $*MyInt, %13 : $Builtin.Word %15 = integer_literal $Builtin.Int64, 1 %16 = struct $MyInt (%15 : $Builtin.Int64) store %16 to [trivial] %14 : $*MyInt %borrow7 = begin_borrow %7 : $MyArray %23 = struct_extract %borrow7 : $MyArray, #MyArray._buffer %24 = struct_extract %23 : $_MyArrayBuffer, #_MyArrayBuffer._storage %25 = struct_extract %24 : $_MyBridgeStorage, #_MyBridgeStorage.rawValue end_borrow %borrow7 : $MyArray %26 = alloc_stack $MyInt %27 = function_ref @hoistableIsNativeTypeChecked : $@convention(method) (@guaranteed MyArray) -> MyBool %28 = apply %27(%7) : $@convention(method) (@guaranteed MyArray) -> MyBool %29 = function_ref @checkSubscript : $@convention(method) (MyInt, MyBool, @guaranteed MyArray) -> _MyDependenceToken %30 = apply %29(%12, %28, %7) : $@convention(method) (MyInt, MyBool, @guaranteed MyArray) -> _MyDependenceToken %31 = function_ref @getElement : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray) -> MyInt %32 = apply %31(%12, %28, %30, %7) : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray) -> MyInt store %32 to [trivial] %26 : $*MyInt %35 = alloc_stack $MyInt %36 = apply %29(%16, %28, %7) : $@convention(method) (MyInt, MyBool, @guaranteed MyArray) -> _MyDependenceToken %37 = apply %31(%16, %28, %36, %7) : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray) -> MyInt store %37 to [trivial] %35 : $*MyInt %52 = tuple () dealloc_stack %35 : $*MyInt dealloc_stack %26 : $*MyInt destroy_value %7 : $MyArray return %52 : $() } // CHECK-LABEL: sil [ossa] @unknown_use : // CHECK: [[GFUN:%.*]] = function_ref @getElement // CHECK: apply [[GFUN]] // CHECK-LABEL: } // end sil function 'unknown_use' sil [ossa] @unknown_use : $@convention(thin) () -> () { %0 = function_ref @swift_bufferAllocate : $@convention(thin) () -> @owned AnyObject %1 = integer_literal $Builtin.Int64, 2 %2 = struct $MyInt (%1 : $Builtin.Int64) %3 = apply %0() : $@convention(thin) () -> @owned AnyObject %4 = metatype $@thin MyArray.Type %5 = function_ref @adoptStorage : $@convention(thin) (@owned AnyObject, MyInt, @thin MyArray.Type) -> @owned (MyArray, UnsafeMutablePointer) %6 = apply %5(%3, %2, %4) : $@convention(thin) (@owned AnyObject, MyInt, @thin MyArray.Type) -> @owned (MyArray, UnsafeMutablePointer) (%7, %8) = destructure_tuple %6 : $(MyArray, UnsafeMutablePointer) %9 = struct_extract %8 : $UnsafeMutablePointer, #UnsafeMutablePointer._rawValue %10 = pointer_to_address %9 : $Builtin.RawPointer to [strict] $*MyInt %11 = integer_literal $Builtin.Int64, 0 %12 = struct $MyInt (%11 : $Builtin.Int64) store %12 to [trivial] %10 : $*MyInt %borrow7 = begin_borrow %7 : $MyArray %23 = struct_extract %borrow7 : $MyArray, #MyArray._buffer %24 = struct_extract %23 : $_MyArrayBuffer, #_MyArrayBuffer._storage %25 = struct_extract %24 : $_MyBridgeStorage, #_MyBridgeStorage.rawValue end_borrow %borrow7 : $MyArray %26 = alloc_stack $MyInt %27 = function_ref @hoistableIsNativeTypeChecked : $@convention(method) (@guaranteed MyArray) -> MyBool %28 = apply %27(%7) : $@convention(method) (@guaranteed MyArray) -> MyBool %29 = function_ref @checkSubscript : $@convention(method) (MyInt, MyBool, @guaranteed MyArray) -> _MyDependenceToken %30 = apply %29(%12, %28, %7) : $@convention(method) (MyInt, MyBool, @guaranteed MyArray) -> _MyDependenceToken %31 = function_ref @getElement : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray) -> MyInt %32 = apply %31( %12, %28, %30, %7) : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray) -> MyInt store %32 to [trivial] %26 : $*MyInt %33 = function_ref @unknown_array_use : $@convention(method) (@guaranteed MyArray) -> MyBool %34 = apply %33(%7) : $@convention(method) (@guaranteed MyArray) -> MyBool %52 = tuple () dealloc_stack %26 : $*MyInt destroy_value %7 : $MyArray return %52 : $() } // CHECK-LABEL: sil [ossa] @append_contentsOf_int : // CHECK: [[ASFUN:%.*]] = function_ref @arrayAdoptStorage // CHECK-NEXT: [[ARR:%.*]] = apply [[ASFUN]] // CHECK-NEXT: ([[OWNER:%[0-9]+]], [[PTR:%[0-9]+]]) = destructure_tuple [[ARR]]{{.*}} // CHECK: [[ACFUN:%.*]] = function_ref @arrayAppendContentsOf // CHECK-NOT: apply [[ACFUN]] // CHECK: [[AEFUN:%.*]] = function_ref @$sSa6appendyyxnF // CHECK-NEXT: [[STACK:%.*]] = alloc_stack $MyInt // CHECK-NEXT: store %{{[0-9]+}} to [trivial] [[STACK]] // CHECK-NEXT: apply [[AEFUN]]([[STACK]] // CHECK-NEXT: dealloc_stack [[STACK]] // CHECK-NEXT: destroy_value [[OWNER]] // CHECK-LABEL: } // end sil function 'append_contentsOf_int' sil [ossa] @append_contentsOf_int : $@convention(thin) () -> () { %0 = function_ref @swift_bufferAllocate : $@convention(thin) () -> @owned AnyObject %1 = integer_literal $Builtin.Int64, 1 %2 = struct $MyInt (%1 : $Builtin.Int64) %3 = apply %0() : $@convention(thin) () -> @owned AnyObject %4 = metatype $@thin Array.Type %5 = function_ref @arrayAdoptStorage : $@convention(thin) (@owned AnyObject, MyInt, @thin Array.Type) -> @owned (Array, UnsafeMutablePointer) %6 = apply %5(%3, %2, %4) : $@convention(thin) (@owned AnyObject, MyInt, @thin Array.Type) -> @owned (Array, UnsafeMutablePointer) (%7, %8) = destructure_tuple %6 : $(Array, UnsafeMutablePointer) %9 = struct_extract %8 : $UnsafeMutablePointer, #UnsafeMutablePointer._rawValue %10 = pointer_to_address %9 : $Builtin.RawPointer to [strict] $*MyInt %11 = integer_literal $Builtin.Int64, 27 %12 = struct $MyInt (%11 : $Builtin.Int64) store %12 to [trivial] %10 : $*MyInt %13 = alloc_stack $Array %14 = metatype $@thin Array.Type %15 = function_ref @arrayInit : $@convention(method) (@thin Array.Type) -> @owned Array %16 = apply %15(%14) : $@convention(method) (@thin Array.Type) -> @owned Array store %16 to [init] %13 : $*Array %17 = function_ref @arrayAppendContentsOf : $@convention(method) (@owned Array, @inout Array) -> () %18 = apply %17(%7, %13) : $@convention(method) (@owned Array, @inout Array) -> () destroy_addr %13 : $*Array dealloc_stack %13 : $*Array %19 = tuple () return %19 : $() } // Ignore an invalid negative index without crashing. // // CHECK-LABEL: sil [ossa] @negative_index // CHECK: store %{{[0-9]+}} to [trivial] // CHECK: [[GETF:%.*]] = function_ref @getElement : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray) -> MyInt // CHECK: apply [[GETF]](%15, %17, %19, %7) : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray) -> MyInt // CHECK-LABEL: // end sil function 'negative_index' sil [ossa] @negative_index : $@convention(thin) () -> () { bb0: %0 = function_ref @swift_bufferAllocate : $@convention(thin) () -> @owned AnyObject // user: %3 %1 = integer_literal $Builtin.Int64, 1 %2 = struct $MyInt (%1 : $Builtin.Int64) %3 = apply %0() : $@convention(thin) () -> @owned AnyObject %4 = metatype $@thin MyArray.Type %5 = function_ref @adoptStorage : $@convention(thin) (@owned AnyObject, MyInt, @thin MyArray.Type) -> @owned (MyArray, UnsafeMutablePointer) %6 = apply %5(%3, %2, %4) : $@convention(thin) (@owned AnyObject, MyInt, @thin MyArray.Type) -> @owned (MyArray, UnsafeMutablePointer) (%7, %8) = destructure_tuple %6 : $(MyArray, UnsafeMutablePointer) %9 = struct_extract %8 : $UnsafeMutablePointer, #UnsafeMutablePointer._rawValue %10 = pointer_to_address %9 : $Builtin.RawPointer to [strict] $*MyInt %11 = integer_literal $Builtin.Int64, 0 %12 = struct $MyInt (%11 : $Builtin.Int64) store %12 to [trivial] %10 : $*MyInt %14 = integer_literal $Builtin.Int64, -1 %15 = struct $MyInt (%14 : $Builtin.Int64) %16 = function_ref @hoistableIsNativeTypeChecked : $@convention(method) (@guaranteed MyArray) -> MyBool %17 = apply %16(%7) : $@convention(method) (@guaranteed MyArray) -> MyBool %18 = function_ref @checkSubscript : $@convention(method) (MyInt, MyBool, @guaranteed MyArray) -> _MyDependenceToken %19 = apply %18(%12, %17, %7) : $@convention(method) (MyInt, MyBool, @guaranteed MyArray) -> _MyDependenceToken %20 = function_ref @getElement : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray) -> MyInt %21 = apply %20(%15, %17, %19, %7) : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray) -> MyInt destroy_value %7 : $MyArray %23 = tuple () return %23 : $() }