blob: a39232916560be1a8dce046929dd809a1e8c27e2 [file] [log] [blame]
// Verifies that we can correctly handle self cycles in control flow.
// RUN: %target-sil-opt -enable-sil-verify-all %s -redundant-load-elim
// Make sure we can move load of end out of loop even though we have store of start inside loop.
// RUN: %target-sil-opt -enable-sil-verify-all %s -licm
import Builtin
import Swift
sil_global @total : $Int32
class NewRangeGenerator1 {
final var current: Int32
final let end: Int32
init(start: Int32, end: Int32)
}
final class NewHalfOpenRangeGenerator : NewRangeGenerator1 {
override init(start: Int32, end: Int32)
}
// CHECK-LABEL: sil @test
// LICM-LABEL: sil @test
sil @test : $@convention(thin) () -> () {
bb0:
// CHECK: [[ID1:%[0-9]+]] = integer_literal $Builtin.Int32, 0
// CHECK: [[ID2:%[0-9]+]] = struct $Int32 ([[ID1]]
// CHECK: [[ID3:%[0-9]+]] = integer_literal $Builtin.Int32, 10
// CHECK: [[ID4:%[0-9]+]] = struct $Int32 ([[ID3]]
// CHECK: struct_extract [[ID2]]
// CHECK: struct_extract [[ID4]]
// CHECK: cond_br
// LICM: [[REFStart:%[0-9]+]] = ref_element_addr %{{[0-9]+}} : $NewRangeGenerator1, #NewRangeGenerator1.current
// LICM: [[REFEnd:%[0-9]+]] = ref_element_addr %{{[0-9]+}} : $NewRangeGenerator1, #NewRangeGenerator1.end
// LICM: [[IDStart:%[0-9]+]] = struct_element_addr [[REFStart]]
// LICM: [[IDEnd:%[0-9]+]] = struct_element_addr [[REFEnd]]
%0 = global_addr @total : $*Int32
%1 = integer_literal $Builtin.Int32, 0
%2 = struct $Int32 (%1 : $Builtin.Int32)
store %2 to %0 : $*Int32
%4 = integer_literal $Builtin.Int32, 10
%5 = struct $Int32 (%4 : $Builtin.Int32)
%6 = alloc_ref $NewHalfOpenRangeGenerator
%7 = upcast %6 : $NewHalfOpenRangeGenerator to $NewRangeGenerator1
%8 = ref_element_addr %7 : $NewRangeGenerator1, #NewRangeGenerator1.current
store %2 to %8 : $*Int32
%10 = ref_element_addr %7 : $NewRangeGenerator1, #NewRangeGenerator1.end
store %5 to %10 : $*Int32
%12 = struct_element_addr %8 : $*Int32, #Int32._value
%13 = struct_element_addr %10 : $*Int32, #Int32._value
%15 = load %12 : $*Builtin.Int32
%16 = load %13 : $*Builtin.Int32
%17 = builtin "cmp_eq_Int32"(%15 : $Builtin.Int32, %16 : $Builtin.Int32) : $Builtin.Int1
cond_br %17, bb3, bb1
// CHECK: {{bb[0-9]+}}(%{{[0-9]+}} : $Builtin.Int32, [[Phi1:%[0-9]+]] : $Int32, [[Phi2:%[0-9]+]] : $Int32):
// LICM: [[ID1:bb[0-9]+]](
bb2(%20 : $Builtin.Int32):
// We forward the BBArgument to the load.
// CHECK: struct_extract [[Phi1]]
// LICM: load
%21 = load %12 : $*Builtin.Int32
%22 = integer_literal $Builtin.Int32, 1
%24 = integer_literal $Builtin.Int1, -1
%25 = builtin "sadd_with_overflow_Int32"(%20 : $Builtin.Int32, %22 : $Builtin.Int32, %24 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
%26 = tuple_extract %25 : $(Builtin.Int32, Builtin.Int1), 0
%27 = tuple_extract %25 : $(Builtin.Int32, Builtin.Int1), 1
cond_fail %27 : $Builtin.Int1
// CHECK: [[ID5:%[0-9]+]] = struct $Int32
%29 = struct $Int32 (%26 : $Builtin.Int32)
store %29 to %8 : $*Int32
%31 = struct_element_addr %0 : $*Int32, #Int32._value
// CHECK: struct_extract [[Phi2]]
// LICM: load
%32 = load %31 : $*Builtin.Int32
%33 = builtin "sadd_with_overflow_Int32"(%32 : $Builtin.Int32, %21 : $Builtin.Int32, %24 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
%34 = tuple_extract %33 : $(Builtin.Int32, Builtin.Int1), 0
%35 = tuple_extract %33 : $(Builtin.Int32, Builtin.Int1), 1
cond_fail %35 : $Builtin.Int1
%37 = struct $Int32 (%34 : $Builtin.Int32)
store %37 to %0 : $*Int32
// CHECK: struct_extract [[ID5]]
// LICM: load [[IDStart]]
%39 = load %12 : $*Builtin.Int32
// CHECK: load
%40 = load %13 : $*Builtin.Int32
// LICM-NEXT: builtin
%41 = builtin "cmp_eq_Int32"(%39 : $Builtin.Int32, %40 : $Builtin.Int32) : $Builtin.Int1
cond_br %41, bb3, bb2(%39 : $Builtin.Int32)
// LICM: bb{{[0-9]+}}:
// Load of end is moved out of loop.
// LICM: load [[IDEnd]]
// bb1 is after bb2 to make sure the first predecessor of bb2 is not bb2 to
// expose the bug.
bb1:
br bb2(%15 : $Builtin.Int32)
bb3:
strong_release %7 : $NewRangeGenerator1
%44 = tuple ()
return %44 : $()
}