| // 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 : $() |
| } |