Files
swift-mirror/test/SILOptimizer/licm_multiend.sil
John McCall 90995b82f4 Teach the SIL verifier to enforce stronger rules around
edges into dead-end regions.

- Only treat edges *into* dead-end regions as special; edges internal
  the region must use the normal rules.

- Conservatively merge information along those edges rather than just
  picking one at random. This requires us to not walk into the region
  until we've processed all of the edges to it.

- Make sure we prevent *any* stack allocations from being deallocated
  if the stack is inconsistent entering a block.

Additionally, fix a bug which was incorrectly treating all blocks that
don't themselves exit the function as ultimately leading to unreachable,
which had inadvertently largely turned off the consistency check.
2025-10-11 02:12:19 -04:00

206 lines
8.1 KiB
Plaintext

// RUN: %target-sil-opt -sil-print-types -enable-sil-verify-all %s -loop-invariant-code-motion | %FileCheck %s
// REQUIRES: PTRSIZE=64
// REQUIRES: OS=macosx
sil_stage canonical
import Builtin
import Swift
import SwiftShims
var x: Int
let reversedArray: ReversedCollection<[Int]>
// x
sil_global hidden @$s3tmp1xSivp : $Int
// reversedArray
sil_global hidden [let] @$s3tmp13reversedArrays18ReversedCollectionVySaySiGGvp : $ReversedCollection<Array<Int>>
// _swiftEmptyArrayStorage
sil_global @_swiftEmptyArrayStorage : $_SwiftEmptyArrayStorage
// CHECK-LABEL: sil hidden @multi_end_licm : $@convention(thin) () -> () {
// CHECK: bb0:
// CHECK: %10 = struct_element_addr %9 : $*Int, #Int._value
// CHECK: bb2:
// CHECK: load %10
// CHECK: bb3({{.*}} : $Builtin.Int64):
// CHECK: load
// CHECK-NOT: load
// CHECK-NOT: store
// CHECK: bb5:
// CHECK-NEXT: store
// CHECK-NOT: store
// CHECK: bb7:
// CHECK-NEXT: store
// CHECK-NOT: store
// CHECK: } // end sil function 'multi_end_licm'
sil hidden @multi_end_licm : $@convention(thin) () -> () {
bb0:
%0 = global_addr @$s3tmp13reversedArrays18ReversedCollectionVySaySiGGvp : $*ReversedCollection<Array<Int>>
%1 = struct_element_addr %0 : $*ReversedCollection<Array<Int>>, #ReversedCollection._base
%2 = struct_element_addr %1 : $*Array<Int>, #Array._buffer
%3 = struct_element_addr %2 : $*_ArrayBuffer<Int>, #_ArrayBuffer._storage
%4 = struct_element_addr %3 : $*_BridgeStorage<__ContiguousArrayStorageBase>, #_BridgeStorage.rawValue
%5 = load %4 : $*Builtin.BridgeObject
%6 = unchecked_ref_cast %5 : $Builtin.BridgeObject to $__ContiguousArrayStorageBase
%7 = ref_element_addr %6 : $__ContiguousArrayStorageBase, #__ContiguousArrayStorageBase.countAndCapacity
%8 = struct_element_addr %7 : $*_ArrayBody, #_ArrayBody._storage
%9 = struct_element_addr %8 : $*_SwiftArrayBodyStorage, #_SwiftArrayBodyStorage.count
%10 = struct_element_addr %9 : $*Int, #Int._value
%11 = load %10 : $*Builtin.Int64
%12 = builtin "assumeNonNegative_Int64"(%11 : $Builtin.Int64) : $Builtin.Int64
%13 = integer_literal $Builtin.Int64, 0
%14 = integer_literal $Builtin.Int1, 0
%15 = builtin "cmp_eq_Int64"(%12 : $Builtin.Int64, %13 : $Builtin.Int64) : $Builtin.Int1
%16 = builtin "int_expect_Int1"(%15 : $Builtin.Int1, %14 : $Builtin.Int1) : $Builtin.Int1
cond_br %16, bb1, bb2
bb1:
br bb12
bb2:
%19 = global_addr @$s3tmp1xSivp : $*Int
%20 = integer_literal $Builtin.Int64, 1
%21 = integer_literal $Builtin.Int1, -1
%23 = ref_tail_addr %6 : $__ContiguousArrayStorageBase, $Int
br bb4(%12 : $Builtin.Int64)
bb4(%27 : $Builtin.Int64):
%28 = builtin "ssub_with_overflow_Int64"(%27 : $Builtin.Int64, %20 : $Builtin.Int64, %21 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
%29 = tuple_extract %28 : $(Builtin.Int64, Builtin.Int1), 0
%30 = tuple_extract %28 : $(Builtin.Int64, Builtin.Int1), 1
cond_fail %30 : $Builtin.Int1
%32 = builtin "cmp_slt_Int64"(%29 : $Builtin.Int64, %13 : $Builtin.Int64) : $Builtin.Int1
%33 = load %10 : $*Builtin.Int64
%34 = builtin "assumeNonNegative_Int64"(%33 : $Builtin.Int64) : $Builtin.Int64
%35 = builtin "cmp_slt_Int64"(%29 : $Builtin.Int64, %34 : $Builtin.Int64) : $Builtin.Int1
%36 = builtin "xor_Int1"(%35 : $Builtin.Int1, %21 : $Builtin.Int1) : $Builtin.Int1
%37 = builtin "or_Int1"(%32 : $Builtin.Int1, %36 : $Builtin.Int1) : $Builtin.Int1
cond_fail %37 : $Builtin.Int1
%39 = builtin "truncOrBitCast_Int64_Word"(%29 : $Builtin.Int64) : $Builtin.Word
%40 = index_addr %23 : $*Int, %39 : $Builtin.Word
%41 = struct_element_addr %40 : $*Int, #Int._value
%42 = load %41 : $*Builtin.Int64
%43 = struct $Int (%42 : $Builtin.Int64)
debug_value %43 : $Int, let, name "item"
%global = begin_access [modify] [dynamic] [no_nested_conflict] %19 : $*Int
%46 = builtin "cmp_eq_Int64"(%29 : $Builtin.Int64, %13 : $Builtin.Int64) : $Builtin.Int1
%47 = builtin "int_expect_Int1"(%46 : $Builtin.Int1, %14 : $Builtin.Int1) : $Builtin.Int1
cond_br %47, bb10, bb11
bb10:
store %43 to %global : $*Int
end_access %global : $*Int
cond_br %47, bb6, bb5
bb11:
%otherInt = struct $Int (%27 : $Builtin.Int64)
store %otherInt to %global : $*Int
end_access %global : $*Int
cond_br %47, bb6, bb5
bb5:
br bb4(%29 : $Builtin.Int64)
bb6:
br bb12
bb12:
%25 = tuple ()
return %25 : $()
} // end sil function 'multi_end_licm'
// CHECK-LABEL: sil hidden @multi_end_licm_loop_exit : $@convention(thin) () -> () {
// CHECK: bb2:
// CHECK: begin_access [modify] [dynamic] [no_nested_conflict]
// CHECK: br bb3
// CHECK: bb5:
// CHECK: end_access
// CHECK: bb6:
// CHECK: bb7:
// CHECK: end_access
// CHECK: bb8:
// CHECK: } // end sil function 'multi_end_licm_loop_exit'
sil hidden @multi_end_licm_loop_exit : $@convention(thin) () -> () {
bb0:
%0 = global_addr @$s3tmp13reversedArrays18ReversedCollectionVySaySiGGvp : $*ReversedCollection<Array<Int>>
%1 = struct_element_addr %0 : $*ReversedCollection<Array<Int>>, #ReversedCollection._base
%2 = struct_element_addr %1 : $*Array<Int>, #Array._buffer
%3 = struct_element_addr %2 : $*_ArrayBuffer<Int>, #_ArrayBuffer._storage
%4 = struct_element_addr %3 : $*_BridgeStorage<__ContiguousArrayStorageBase>, #_BridgeStorage.rawValue
%5 = load %4 : $*Builtin.BridgeObject
%6 = unchecked_ref_cast %5 : $Builtin.BridgeObject to $__ContiguousArrayStorageBase
%7 = ref_element_addr %6 : $__ContiguousArrayStorageBase, #__ContiguousArrayStorageBase.countAndCapacity
%8 = struct_element_addr %7 : $*_ArrayBody, #_ArrayBody._storage
%9 = struct_element_addr %8 : $*_SwiftArrayBodyStorage, #_SwiftArrayBodyStorage.count
%10 = struct_element_addr %9 : $*Int, #Int._value
%11 = load %10 : $*Builtin.Int64
%12 = builtin "assumeNonNegative_Int64"(%11 : $Builtin.Int64) : $Builtin.Int64
%13 = integer_literal $Builtin.Int64, 0
%14 = integer_literal $Builtin.Int1, 0
%15 = builtin "cmp_eq_Int64"(%12 : $Builtin.Int64, %13 : $Builtin.Int64) : $Builtin.Int1
%16 = builtin "int_expect_Int1"(%15 : $Builtin.Int1, %14 : $Builtin.Int1) : $Builtin.Int1
cond_br %16, bb1, bb2
bb1:
br bbRet
bb2:
%19 = global_addr @$s3tmp1xSivp : $*Int
%20 = integer_literal $Builtin.Int64, 1
%21 = integer_literal $Builtin.Int1, -1
%23 = ref_tail_addr %6 : $__ContiguousArrayStorageBase, $Int
br bb4(%12 : $Builtin.Int64)
bb4(%27 : $Builtin.Int64):
%28 = builtin "ssub_with_overflow_Int64"(%27 : $Builtin.Int64, %20 : $Builtin.Int64, %21 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
%29 = tuple_extract %28 : $(Builtin.Int64, Builtin.Int1), 0
%30 = tuple_extract %28 : $(Builtin.Int64, Builtin.Int1), 1
cond_fail %30 : $Builtin.Int1
%32 = builtin "cmp_slt_Int64"(%29 : $Builtin.Int64, %13 : $Builtin.Int64) : $Builtin.Int1
%33 = load %10 : $*Builtin.Int64
%34 = builtin "assumeNonNegative_Int64"(%33 : $Builtin.Int64) : $Builtin.Int64
%35 = builtin "cmp_slt_Int64"(%29 : $Builtin.Int64, %34 : $Builtin.Int64) : $Builtin.Int1
%36 = builtin "xor_Int1"(%35 : $Builtin.Int1, %21 : $Builtin.Int1) : $Builtin.Int1
%37 = builtin "or_Int1"(%32 : $Builtin.Int1, %36 : $Builtin.Int1) : $Builtin.Int1
cond_fail %37 : $Builtin.Int1
%39 = builtin "truncOrBitCast_Int64_Word"(%29 : $Builtin.Int64) : $Builtin.Word
%40 = index_addr %23 : $*Int, %39 : $Builtin.Word
%41 = struct_element_addr %40 : $*Int, #Int._value
%42 = load %41 : $*Builtin.Int64
%43 = struct $Int (%42 : $Builtin.Int64)
debug_value %43 : $Int, let, name "item"
%global = begin_access [modify] [dynamic] [no_nested_conflict] %19 : $*Int
%46 = builtin "cmp_eq_Int64"(%29 : $Builtin.Int64, %13 : $Builtin.Int64) : $Builtin.Int1
%47 = builtin "int_expect_Int1"(%46 : $Builtin.Int1, %14 : $Builtin.Int1) : $Builtin.Int1
cond_br %47, bbend1, bbend2
bbend1:
store %43 to %global : $*Int
end_access %global : $*Int
cond_br %47, bb6, bb5
bbend2:
%otherInt = struct $Int (%27 : $Builtin.Int64)
store %otherInt to %global : $*Int
end_access %global : $*Int
cond_br %47, bbOut, bb5
bbOut:
br bb6
bb5:
br bb4(%29 : $Builtin.Int64)
bb6:
br bbRet
bbRet:
%25 = tuple ()
return %25 : $()
} // end sil function 'multi_end_licm_loop_exit'