// RUN: %target-sil-opt -sil-print-types -enable-objc-interop -enforce-exclusivity=none -enable-sil-verify-all -loop-rotate %s | %FileCheck %s // Declare this SIL to be canonical because some tests break raw SIL // conventions. e.g. address-type block args. -enforce-exclusivity=none is also // required to allow address-type block args in canonical SIL. sil_stage canonical import Builtin import Swift protocol P { func boo() -> Int64 } class Bar { func boo() -> Int64 func foo() @objc func foo_objc() } sil [ossa] @getBar : $@convention(thin) () -> @owned Bar sil [ossa] @_TFC4main3Bar3foofS0_FT_T_ : $@convention(method) (@guaranteed Bar) -> () sil [ossa] @_TFC4main3Bar3boofS0_FT_T_ : $@convention(method) (@guaranteed Bar) -> Int64 sil [ossa] @_TFC4main3Bar3foo_objcfS0_FT_T_ : $@convention(objc_method) (Bar) -> () sil_vtable Bar { #Bar.boo: @_TFC4main3Bar3boofS0_FT_T_ #Bar.foo: @_TFC4main3Bar3foofS0_FT_T_ #Bar.foo_objc: @_TFC4main3Bar3foofS0_FT_T_ } // CHECK-LABEL: sil [ossa] @looprotate : // CHECK: bb0(%0 : $Int32, %1 : @owned $Bar): // CHECK: class_method // CHECK: apply // CHECK: cond_br {{.*}}, bb2, bb1 // CHECK: bb1: // CHECK-NEXT: br bb3({{.*}} : $Builtin.Int32, {{.*}} : $Builtin.Int32, {{.*}}: $Int32) // CHECK: bb3({{.*}}: $Builtin.Int32, {{.*}} : $Builtin.Int32, {{.*}} : $Int32): // CHECK: class_method // CHECK: apply // CHECK: cond_br {{%.*}}, bb5, bb4 // CHECK: bb5: // CHECK-NEXT: br bb6({{.*}} : $Builtin.Int32, {{.*}} : $Bar, {{.*}} : $<τ_0_0> { var τ_0_0 } ) // CHECK: bb6({{.*}} : $Builtin.Int32, {{.*}} : @owned $Bar, {{.*}} : @owned $<τ_0_0> { var τ_0_0 } ): // CHECK: [[STRUCT:%.*]] = struct $Int32 ({{%.*}} : $Builtin.Int32) // CHECK: return [[STRUCT]] : $Int32 // CHECK: } // end sil function 'looprotate' sil [ossa] @looprotate : $@convention(thin) (Int32, @owned Bar) -> Int32 { bb0(%0 : $Int32, %25: @owned $Bar): %1 = struct_extract %0 : $Int32, #Int32._value %2 = integer_literal $Builtin.Int32, 0 %30 = alloc_box $<τ_0_0> { var τ_0_0 } %30a = project_box %30 : $<τ_0_0> { var τ_0_0 } , 0 br bb1(%1 : $Builtin.Int32, %2 : $Builtin.Int32, %25: $Bar, %30 : $<τ_0_0> { var τ_0_0 } ) bb1(%4 : $Builtin.Int32, %5 : $Builtin.Int32, %26: @owned $Bar, %31 : @owned $<τ_0_0> { var τ_0_0 } ): %24 = class_method %26 : $Bar, #Bar.foo : (Bar) -> () -> (), $@convention(method) (@guaranteed Bar) -> () // user: %6 %27 = apply %24(%26) : $@convention(method) (@guaranteed Bar) -> () %6 = struct $Int32 (%5 : $Builtin.Int32) %8 = builtin "cmp_eq_Word"(%5 : $Builtin.Int32, %1 : $Builtin.Int32) : $Builtin.Int1 cond_br %8, bb3, bb2 bb2: %10 = integer_literal $Builtin.Int32, 1 %12 = integer_literal $Builtin.Int1, -1 %13 = builtin "sadd_with_overflow_Word"(%5 : $Builtin.Int32, %10 : $Builtin.Int32, %12 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) %14 = tuple_extract %13 : $(Builtin.Int32, Builtin.Int1), 0 %15 = enum $Optional, #Optional.some!enumelt, %6 : $Int32 %16 = unchecked_enum_data %15 : $Optional, #Optional.some!enumelt %17 = struct_extract %16 : $Int32, #Int32._value %19 = integer_literal $Builtin.Int1, -1 %20 = builtin "sadd_with_overflow_Word"(%4 : $Builtin.Int32, %17 : $Builtin.Int32, %19 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) %21 = tuple_extract %20 : $(Builtin.Int32, Builtin.Int1), 0 br bb1(%21 : $Builtin.Int32, %14 : $Builtin.Int32, %26: $Bar, %31 : $<τ_0_0> { var τ_0_0 } ) bb3: destroy_value %26 : $Bar destroy_value %31 : $<τ_0_0> { var τ_0_0 } %23 = struct $Int32 (%4 : $Builtin.Int32) return %23 : $Int32 } // CHECK-LABEL: sil [ossa] @dont_rotate_multi_exit_loop : // CHECK: bb1({{.*}}): // CHECK: cond_br %{{.*}}, bb4, bb2 // CHECK: bb2: // CHECK: cond_br undef, bb3, bb5 // CHECK: bb6: // CHECK: return // CHECK-NOT: bb7 // CHECK: } // end sil function 'dont_rotate_multi_exit_loop' sil [ossa] @dont_rotate_multi_exit_loop : $@convention(thin) (Int32, @owned Bar) -> Int32 { bb0(%0 : $Int32, %25: @owned $Bar): %1 = struct_extract %0 : $Int32, #Int32._value %2 = integer_literal $Builtin.Int32, 0 %30 = alloc_box $<τ_0_0> { var τ_0_0 } %30a = project_box %30 : $<τ_0_0> { var τ_0_0 } , 0 br bb1(%1 : $Builtin.Int32, %2 : $Builtin.Int32, %25: $Bar, %30 : $<τ_0_0> { var τ_0_0 } ) bb1(%4 : $Builtin.Int32, %5 : $Builtin.Int32, %26: @owned $Bar, %31 : @owned $<τ_0_0> { var τ_0_0 } ): %24 = class_method %26 : $Bar, #Bar.foo : (Bar) -> () -> (), $@convention(method) (@guaranteed Bar) -> () // user: %6 %27 = apply %24(%26) : $@convention(method) (@guaranteed Bar) -> () %6 = struct $Int32 (%5 : $Builtin.Int32) %8 = builtin "cmp_eq_Word"(%5 : $Builtin.Int32, %1 : $Builtin.Int32) : $Builtin.Int1 cond_br %8, bb4, bb2 bb2: %10 = integer_literal $Builtin.Int32, 1 %12 = integer_literal $Builtin.Int1, -1 %13 = builtin "sadd_with_overflow_Word"(%5 : $Builtin.Int32, %10 : $Builtin.Int32, %12 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) %14 = tuple_extract %13 : $(Builtin.Int32, Builtin.Int1), 0 %15 = enum $Optional, #Optional.some!enumelt, %6 : $Int32 %16 = unchecked_enum_data %15 : $Optional, #Optional.some!enumelt %17 = struct_extract %16 : $Int32, #Int32._value %19 = integer_literal $Builtin.Int1, -1 %20 = builtin "sadd_with_overflow_Word"(%4 : $Builtin.Int32, %17 : $Builtin.Int32, %19 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) %21 = tuple_extract %20 : $(Builtin.Int32, Builtin.Int1), 0 cond_br undef, bb3, bb5 bb3: br bb1(%21 : $Builtin.Int32, %14 : $Builtin.Int32, %26: $Bar, %31 : $<τ_0_0> { var τ_0_0 } ) bb4: br bb6 bb5: br bb6 bb6: destroy_value %26 : $Bar destroy_value %31 : $<τ_0_0> { var τ_0_0 } %23 = struct $Int32 (%4 : $Builtin.Int32) return %23 : $Int32 } // CHECK-LABEL: sil [ossa] @dont_duplicate_large_block : // CHECK: bb0(%0 : $Int32, %1 : @owned $Bar): // CHECK-NOT: class_method // CHECK-NOT: apply // CHECK: br bb1 // CHECK: bb1({{.*}}): // CHECK: class_method // CHECK: apply // CHECK: cond_br // CHECK: bb2: // CHECK: br bb1 // CHECK: bb3: // CHECK: return // CHECK: } // end sil function 'dont_duplicate_large_block' sil [ossa] @dont_duplicate_large_block : $@convention(thin) (Int32, @owned Bar) -> Int32 { bb0(%0 : $Int32, %25: @owned $Bar): %1 = struct_extract %0 : $Int32, #Int32._value %2 = integer_literal $Builtin.Int32, 0 %30 = alloc_box $<τ_0_0> { var τ_0_0 } %30a = project_box %30 : $<τ_0_0> { var τ_0_0 } , 0 br bb1(%1 : $Builtin.Int32, %2 : $Builtin.Int32, %25: $Bar, %30 : $<τ_0_0> { var τ_0_0 } ) bb1(%4 : $Builtin.Int32, %5 : $Builtin.Int32, %26: @owned $Bar, %31 : @owned $<τ_0_0> { var τ_0_0 } ): %24 = class_method %26 : $Bar, #Bar.foo : (Bar) -> () -> (), $@convention(method) (@guaranteed Bar) -> () // user: %6 %27 = apply %24(%26) : $@convention(method) (@guaranteed Bar) -> () %28 = apply %24(%26) : $@convention(method) (@guaranteed Bar) -> () %29 = apply %24(%26) : $@convention(method) (@guaranteed Bar) -> () %33 = apply %24(%26) : $@convention(method) (@guaranteed Bar) -> () %34 = apply %24(%26) : $@convention(method) (@guaranteed Bar) -> () %35 = apply %24(%26) : $@convention(method) (@guaranteed Bar) -> () %36 = apply %24(%26) : $@convention(method) (@guaranteed Bar) -> () %37 = apply %24(%26) : $@convention(method) (@guaranteed Bar) -> () %38 = apply %24(%26) : $@convention(method) (@guaranteed Bar) -> () %39 = apply %24(%26) : $@convention(method) (@guaranteed Bar) -> () %40 = apply %24(%26) : $@convention(method) (@guaranteed Bar) -> () %41 = apply %24(%26) : $@convention(method) (@guaranteed Bar) -> () %42 = apply %24(%26) : $@convention(method) (@guaranteed Bar) -> () %43 = apply %24(%26) : $@convention(method) (@guaranteed Bar) -> () %44 = apply %24(%26) : $@convention(method) (@guaranteed Bar) -> () %45 = apply %24(%26) : $@convention(method) (@guaranteed Bar) -> () %46 = apply %24(%26) : $@convention(method) (@guaranteed Bar) -> () %47 = apply %24(%26) : $@convention(method) (@guaranteed Bar) -> () %48 = apply %24(%26) : $@convention(method) (@guaranteed Bar) -> () %49 = apply %24(%26) : $@convention(method) (@guaranteed Bar) -> () %50 = apply %24(%26) : $@convention(method) (@guaranteed Bar) -> () %51 = apply %24(%26) : $@convention(method) (@guaranteed Bar) -> () %52 = apply %24(%26) : $@convention(method) (@guaranteed Bar) -> () %53 = apply %24(%26) : $@convention(method) (@guaranteed Bar) -> () %54 = apply %24(%26) : $@convention(method) (@guaranteed Bar) -> () %6 = struct $Int32 (%5 : $Builtin.Int32) %8 = builtin "cmp_eq_Word"(%5 : $Builtin.Int32, %1 : $Builtin.Int32) : $Builtin.Int1 cond_br %8, bb3, bb2 bb2: %10 = integer_literal $Builtin.Int32, 1 %12 = integer_literal $Builtin.Int1, -1 %13 = builtin "sadd_with_overflow_Word"(%5 : $Builtin.Int32, %10 : $Builtin.Int32, %12 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) %14 = tuple_extract %13 : $(Builtin.Int32, Builtin.Int1), 0 %15 = enum $Optional, #Optional.some!enumelt, %6 : $Int32 %16 = unchecked_enum_data %15 : $Optional, #Optional.some!enumelt %17 = struct_extract %16 : $Int32, #Int32._value %19 = integer_literal $Builtin.Int1, -1 %20 = builtin "sadd_with_overflow_Word"(%4 : $Builtin.Int32, %17 : $Builtin.Int32, %19 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) %21 = tuple_extract %20 : $(Builtin.Int32, Builtin.Int1), 0 br bb1(%21 : $Builtin.Int32, %14 : $Builtin.Int32, %26: $Bar, %31 : $<τ_0_0> { var τ_0_0 } ) bb3: destroy_value %26 : $Bar destroy_value %31 : $<τ_0_0> { var τ_0_0 } %23 = struct $Int32 (%4 : $Builtin.Int32) return %23 : $Int32 } // This example illustrates the problem with using ValueUseIterators. // As part of updating SSA form we will introduce a phi node argument to the // branch to bb2. This means we change "cond_br %8, bb3(%4 : $Builtin.Int32), // bb2" invalidating any outstanding use iterator pointing to the use of "%4" in // said branch. // CHECK-LABEL: sil [ossa] @looprotate2 : // CHECK: return // CHECK-LABEL: } // end sil function 'looprotate2' sil [ossa] @looprotate2 : $@convention(thin) (Int32) -> Int32 { bb0(%0 : $Int32): %1 = struct_extract %0 : $Int32, #Int32._value %2 = integer_literal $Builtin.Int32, 0 br bb1(%1 : $Builtin.Int32, %2 : $Builtin.Int32) bb1(%4 : $Builtin.Int32, %5 : $Builtin.Int32): %6 = struct $Int32 (%5 : $Builtin.Int32) %8 = builtin "cmp_eq_Word"(%5 : $Builtin.Int32, %1 : $Builtin.Int32) : $Builtin.Int1 cond_br %8, bb3, bb2 bb2: %10 = integer_literal $Builtin.Int32, 1 %12 = integer_literal $Builtin.Int1, -1 %13 = builtin "sadd_with_overflow_Word"(%5 : $Builtin.Int32, %10 : $Builtin.Int32, %12 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) %14 = tuple_extract %13 : $(Builtin.Int32, Builtin.Int1), 0 %15 = enum $Optional, #Optional.some!enumelt, %6 : $Int32 %16 = unchecked_enum_data %15 : $Optional, #Optional.some!enumelt %17 = struct_extract %16 : $Int32, #Int32._value %19 = integer_literal $Builtin.Int1, -1 %20 = builtin "sadd_with_overflow_Word"(%4 : $Builtin.Int32, %17 : $Builtin.Int32, %19 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) %21 = tuple_extract %20 : $(Builtin.Int32, Builtin.Int1), 0 br bb1(%21 : $Builtin.Int32, %14 : $Builtin.Int32) bb3: %24 = struct $Int32 (%4 : $Builtin.Int32) return %24 : $Int32 } // The following function used to crash the compiler, because loop rotate // could not properly handle the reference from witness_method to the // archetype opened by open_existential_addr // CHECK-LABEL: sil [ossa] @looprotate_with_opened_archetype : // CHECK: return // CHECK-LABEL: } // end sil function 'looprotate_with_opened_archetype' sil [ossa] @looprotate_with_opened_archetype : $@convention(thin) (Int32, @in_guaranteed P) -> Int32 { bb0(%0 : $Int32, %25: $*P): %1 = struct_extract %0 : $Int32, #Int32._value %2 = integer_literal $Builtin.Int32, 0 %30 = alloc_box $<τ_0_0> { var τ_0_0 } %30a = project_box %30 : $<τ_0_0> { var τ_0_0 } , 0 %40 = open_existential_addr immutable_access %25 : $*P to $*@opened("C22498FA-CABF-11E5-B9A9-685B35C48C83", P) Self br bb1(%1 : $Builtin.Int32, %2 : $Builtin.Int32, %30 : $<τ_0_0> { var τ_0_0 } ) bb1(%4 : $Builtin.Int32, %5 : $Builtin.Int32, %31 : @owned $<τ_0_0> { var τ_0_0 } ): %111 = witness_method $@opened("C22498FA-CABF-11E5-B9A9-685B35C48C83", P) Self, #P.boo, %40 : $*@opened("C22498FA-CABF-11E5-B9A9-685B35C48C83", P) Self : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int64 %122 = apply %111<@opened("C22498FA-CABF-11E5-B9A9-685B35C48C83", P) Self>(%40) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int64 %6 = struct $Int32 (%5 : $Builtin.Int32) %8 = builtin "cmp_eq_Word"(%5 : $Builtin.Int32, %1 : $Builtin.Int32) : $Builtin.Int1 cond_br %8, bb3, bb2 bb2: %10 = integer_literal $Builtin.Int32, 1 %12 = integer_literal $Builtin.Int1, -1 %13 = builtin "sadd_with_overflow_Word"(%5 : $Builtin.Int32, %10 : $Builtin.Int32, %12 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) %14 = tuple_extract %13 : $(Builtin.Int32, Builtin.Int1), 0 %15 = enum $Optional, #Optional.some!enumelt, %6 : $Int32 %16 = unchecked_enum_data %15 : $Optional, #Optional.some!enumelt %17 = struct_extract %16 : $Int32, #Int32._value %19 = integer_literal $Builtin.Int1, -1 %20 = builtin "sadd_with_overflow_Word"(%4 : $Builtin.Int32, %17 : $Builtin.Int32, %19 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) %21 = tuple_extract %20 : $(Builtin.Int32, Builtin.Int1), 0 br bb1(%21 : $Builtin.Int32, %14 : $Builtin.Int32, %31 : $<τ_0_0> { var τ_0_0 } ) bb3: destroy_value %31 : $<τ_0_0> { var τ_0_0 } %23 = struct $Int32 (%4 : $Builtin.Int32) return %23 : $Int32 } // Don't assert on this loop. bb2 is bb1 loop's new header after rotation but // also bb2 loop's header. // CHECK-LABEL: sil [ossa] @testnested : // CHECK: return // CHECK-LABEL: } // end sil function 'testnested' sil [ossa] @testnested : $@convention(thin) () -> () { bb0: br bb1(undef : $Builtin.Int32, undef : $Builtin.Int32) bb1(%1 : $Builtin.Int32, %2 : $Builtin.Int32): %3 = integer_literal $Builtin.Int1, 0 cond_br %3, bb1a, bb10 bb1a: br bb2(%1 : $Builtin.Int32, %2 : $Builtin.Int32) bb2(%5 : $Builtin.Int32, %6 : $Builtin.Int32): %7 = integer_literal $Builtin.Int1, -1 cond_br %7, bb3, bb2a bb2a: br bb1(%5 : $Builtin.Int32, %6 : $Builtin.Int32) bb3: %9 = integer_literal $Builtin.Int32, 0 %10 = integer_literal $Builtin.Int32, 1 br bb4(%9 : $Builtin.Int32) bb4(%12 : $Builtin.Int32): %14 = builtin "cmp_eq_Word"(%12 : $Builtin.Int32, %10 : $Builtin.Int32) : $Builtin.Int1 cond_br %14, bb5, bb9 bb5: %16 = enum $Optional, #Optional.none!enumelt br bb6(%12 : $Builtin.Int32, %16 : $Optional) bb6(%18 : $Builtin.Int32, %19 : $Optional): switch_enum %19 : $Optional, case #Optional.some!enumelt: bb7, case #Optional.none!enumelt: bb8 bb7(%arg : $Int32): %21 = unchecked_enum_data %19 : $Optional, #Optional.some!enumelt br bb4(%18 : $Builtin.Int32) bb8: br bb2(%18 : $Builtin.Int32, %10 : $Builtin.Int32) bb9: %24 = struct $Int32 (%12 : $Builtin.Int32) %25 = integer_literal $Builtin.Int32, 1 %27 = integer_literal $Builtin.Int1, -1 %28 = builtin "sadd_with_overflow_Word"(%12 : $Builtin.Int32, %25 : $Builtin.Int32, %27 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) %29 = tuple_extract %28 : $(Builtin.Int32, Builtin.Int1), 0 %30 = tuple_extract %28 : $(Builtin.Int32, Builtin.Int1), 1 cond_fail %30 : $Builtin.Int1 %32 = enum $Optional, #Optional.some!enumelt, %24 : $Int32 br bb6(%29 : $Builtin.Int32, %32 : $Optional) bb10: %34 = tuple () return %34 : $() } // CHECK-LABEL: sil [ossa] @dont_looprotate_objc : // CHECK: bb0{{.*}}: // CHECK: br bb1 // CHECK: bb1{{.*}}: // CHECK: cond_br {{.*}}, bb3, bb2 // CHECK: bb2: // CHECK: br bb1 // CHECK: bb3: // CHECK: return // CHECK-LABEL: } // end sil function 'dont_looprotate_objc' sil [ossa] @dont_looprotate_objc : $@convention(thin) (Int32, @owned Bar) -> Int32 { bb0(%0 : $Int32, %25: @owned $Bar): %100 = alloc_ref $Bar %1 = struct_extract %0 : $Int32, #Int32._value %2 = integer_literal $Builtin.Int32, 0 br bb1(%1 : $Builtin.Int32, %2 : $Builtin.Int32, %25: $Bar) bb1(%4 : $Builtin.Int32, %5 : $Builtin.Int32, %26: @owned $Bar): %101 = objc_method %100 : $Bar, #Bar.foo!foreign : (Bar) -> () -> (), $@convention(objc_method) (Bar) -> () %6 = struct $Int32 (%5 : $Builtin.Int32) %8 = builtin "cmp_eq_Word"(%5 : $Builtin.Int32, %1 : $Builtin.Int32) : $Builtin.Int1 cond_br %8, bb3, bb2 bb2: %102 = apply %101(%100) : $@convention(objc_method) (Bar) -> () %10 = integer_literal $Builtin.Int32, 1 %12 = integer_literal $Builtin.Int1, -1 %13 = builtin "sadd_with_overflow_Word"(%5 : $Builtin.Int32, %10 : $Builtin.Int32, %12 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) %14 = tuple_extract %13 : $(Builtin.Int32, Builtin.Int1), 0 %15 = enum $Optional, #Optional.some!enumelt, %6 : $Int32 %16 = unchecked_enum_data %15 : $Optional, #Optional.some!enumelt %17 = struct_extract %16 : $Int32, #Int32._value %19 = integer_literal $Builtin.Int1, -1 %20 = builtin "sadd_with_overflow_Word"(%4 : $Builtin.Int32, %17 : $Builtin.Int32, %19 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) %21 = tuple_extract %20 : $(Builtin.Int32, Builtin.Int1), 0 br bb1(%21 : $Builtin.Int32, %14 : $Builtin.Int32, %26: $Bar) bb3: destroy_value %100 : $Bar destroy_value %26 : $Bar %23 = struct $Int32 (%4 : $Builtin.Int32) return %23 : $Int32 } sil [ossa] @readInt : $@convention(thin) (Int32) -> () { bb0(%a0 : $Int32): %t1 = tuple () return %t1 : $() } // Test LoopRotate insertBackedgeBlock. // // CHECK-LABEL: sil [ossa] @insert_backedge_block : // PreLoop Check // CHECK: bb0(% // CHECK: cond_br // Loop Header // CHECK: bb1: // CHECK-NEXT: br bb3 // CHECK: bb3: // CHECK: cond_br %{{.*}}, bb4, bb8 // CHECK: bb4: // CHECK: apply // CHECK: br bb5( // CHECK: bb5(%[[ARG:[0-9]*]] // CHECK-NEXT: cond_br %{{.*}}, bb7, bb6 // CHECK: bb8: // CHECK: apply // CHECK: br bb5(% // CHECK: bb9 // CHECK: return // CHECK-LABEL: } // end sil function 'insert_backedge_block' sil [ossa] @insert_backedge_block : $@convention(thin) (@owned @callee_owned () -> Builtin.Int32) -> () { bb0(%0 : @owned $@callee_owned () -> Builtin.Int32): %copy0 = copy_value %0 : $@callee_owned () -> Builtin.Int32 %r0 = apply %copy0() : $@callee_owned () -> Builtin.Int32 br bb1(%r0: $Builtin.Int32) bb1(%a1 : $Builtin.Int32): %z1 = integer_literal $Builtin.Int1, 0 cond_br %z1, bb5, bb2 bb2: %z2 = integer_literal $Builtin.Int1, 0 cond_br %z2, bb3, bb4 bb3: %copy1 = copy_value %0 : $@callee_owned () -> Builtin.Int32 %r1 = apply %copy1() : $@callee_owned () -> Builtin.Int32 br bb1(%r1: $Builtin.Int32) bb4: %copy2 = copy_value %0 : $@callee_owned () -> Builtin.Int32 %r2 = apply %copy2() : $@callee_owned () -> Builtin.Int32 br bb1(%r2: $Builtin.Int32) bb5: destroy_value %0 : $@callee_owned () -> Builtin.Int32 %r3 = tuple () return %r3 : $() } // CHECK-LABEL: sil [ossa] @dont_rotate_single_basic_block_loop : // CHECK: bb0({{.*}}): // CHECK: br bb1 // CHECK: bb1: // CHECK: cond_br {{.*}}, bb2, bb3 // CHECK: bb2: // CHECK: br bb1 // CHECK: bb3: // CHECK: return // CHECK-LABEL: } // end sil function 'dont_rotate_single_basic_block_loop' sil [ossa] @dont_rotate_single_basic_block_loop : $@convention(thin) (Builtin.Int1) -> () { bb0(%0 : $Builtin.Int1): br bb1 bb1: cond_br %0, bb1a, bb2 bb1a: %t = tuple(%0 : $Builtin.Int1, %0 : $Builtin.Int1) br bb1 bb2: %1 = tuple () return %1 : $() } // Make sure that we do not create address phis. // // CHECK-LABEL: sil [ossa] @addressPhiFixUp : $@convention(thin) (Builtin.RawPointer) -> Builtin.RawPointer { // CHECK: bb1: // CHECK: cond_br {{%.*}}, bb3, bb2 // // CHECK: bb2: // CHECK-NEXT: br bb7 // // CHECK: bb3: // CHECK-NEXT: br bb4 // // CHECK: bb4([[ARG:%.*]] : // CHECK: [[CAST_BACK:%.*]] = pointer_to_address [[ARG]] : $Builtin.RawPointer to [strict] $*UInt8 // CHECK: [[GEP:%.*]] = index_addr [[CAST_BACK]] : // CHECK: cond_br {{%.*}}, bb6, bb5 // // CHECK: bb5: // CHECK-NEXT: br bb7 // // CHECK: bb6: // CHECK-NEXT: br bb4 // // CHECK: bb7([[RESULT:%.*]] : // CHECK-NEXT: return [[RESULT]] // CHECK: } // end sil function 'addressPhiFixUp' sil [ossa] @addressPhiFixUp : $@convention(thin) (Builtin.RawPointer) -> Builtin.RawPointer { bb0(%0 : $Builtin.RawPointer): br bb1 bb1: br bb2(%0 : $Builtin.RawPointer) bb2(%1 : $Builtin.RawPointer): %2 = pointer_to_address %1 : $Builtin.RawPointer to [strict] $*UInt8 %3 = load [trivial] %2 : $*UInt8 %4 = destructure_struct %3 : $UInt8 %5 = integer_literal $Builtin.Int64, 0 %6 = builtin "zextOrBitCast_Int8_Int64"(%4 : $Builtin.Int8) : $Builtin.Int64 %7 = builtin "cmp_eq_Int64"(%6 : $Builtin.Int64, %5 : $Builtin.Int64) : $Builtin.Int1 cond_br %7, bb3, bb4 bb3: %8 = integer_literal $Builtin.Word, 1 %9 = index_addr %2 : $*UInt8, %8 : $Builtin.Word %10 = address_to_pointer %9 : $*UInt8 to $Builtin.RawPointer br bb2(%10 : $Builtin.RawPointer) bb4: return %1 : $Builtin.RawPointer } // CHECK-LABEL: sil [ossa] @looprotate_copy_move_borrow : // CHECK: bb0(%0 : $Int32, %1 : @guaranteed $Bar): // CHECK: copy_value // CHECK: move_value // CHECK: begin_borrow // CHECK: cond_br {{.*}}, bb2, bb1 // CHECK: copy_value // CHECK: move_value // CHECK: begin_borrow // CHECK-LABEL: } // end sil function 'looprotate_copy_move_borrow' sil [ossa] @looprotate_copy_move_borrow : $@convention(thin) (Int32, @guaranteed Bar) -> Int32 { bb0(%0 : $Int32, %1 : @guaranteed $Bar): %2 = struct_extract %0 : $Int32, #Int32._value %3 = integer_literal $Builtin.Int32, 0 br bb1(%2 : $Builtin.Int32, %3 : $Builtin.Int32) bb1(%5 : $Builtin.Int32, %6 : $Builtin.Int32): %c = copy_value %1 : $Bar %m = move_value %c : $Bar %7 = begin_borrow %m : $Bar %8 = class_method %7 : $Bar, #Bar.foo : (Bar) -> () -> (), $@convention(method) (@guaranteed Bar) -> () %9 = apply %8(%7) : $@convention(method) (@guaranteed Bar) -> () %10 = struct $Int32 (%6 : $Builtin.Int32) %11 = builtin "cmp_eq_Word"(%6 : $Builtin.Int32, %2 : $Builtin.Int32) : $Builtin.Int1 cond_br %11, bb3, bb2 bb2: end_borrow %7 : $Bar destroy_value %m : $Bar %14 = integer_literal $Builtin.Int32, 1 %15 = integer_literal $Builtin.Int1, -1 %16 = builtin "sadd_with_overflow_Word"(%6 : $Builtin.Int32, %14 : $Builtin.Int32, %15 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) %17 = tuple_extract %16 : $(Builtin.Int32, Builtin.Int1), 0 %18 = enum $Optional, #Optional.some!enumelt, %10 : $Int32 %19 = unchecked_enum_data %18 : $Optional, #Optional.some!enumelt %20 = struct_extract %19 : $Int32, #Int32._value %21 = integer_literal $Builtin.Int1, -1 %22 = builtin "sadd_with_overflow_Word"(%5 : $Builtin.Int32, %20 : $Builtin.Int32, %21 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) %23 = tuple_extract %22 : $(Builtin.Int32, Builtin.Int1), 0 br bb1(%23 : $Builtin.Int32, %17 : $Builtin.Int32) bb3: end_borrow %7 : $Bar destroy_value %m : $Bar %26 = struct $Int32 (%5 : $Builtin.Int32) return %26 : $Int32 } // Make sure that no unnecessary phis are inserted which would cause an ownership error. // CHECK-LABEL: sil [ossa] @test_ssa_updater_owned : // CHECK: begin_borrow // CHECK-NOT: bb({{.*@owned.*}}): // CHECK: end_borrow // CHECK-LABEL: } // end sil function 'test_ssa_updater_owned' sil [ossa] @test_ssa_updater_owned : $@convention(thin) (@owned String, @guaranteed String) -> () { bb0(%0 : @owned $String, %1 : @guaranteed $String): %2 = integer_literal $Builtin.Int64, 0 br bb1(%0, %2) bb1(%4 : @owned $String, %5 : $Builtin.Int64): cond_br undef, bb14, bb2 bb2: %7 = integer_literal $Builtin.Int64, 1 %8 = begin_borrow %4 cond_br undef, bb4, bb3 bb3: br bb5 bb4: cond_br undef, bb7, bb8 bb5: cond_br undef, bb10, bb6 bb6: br bb9 bb7: br bb9 bb8: br bb12 bb9: br bb11 bb10: br bb11 bb11: end_borrow %8 destroy_value %4 br bb13 bb12: end_borrow %8 destroy_value [dead_end] %4 unreachable bb13: %24 = copy_value %1 br bb1(%24, %7) bb14: destroy_value %4 %27 = tuple () return %27 } // Make sure that no unnecessary phis are inserted which would cause an ownership error. // CHECK-LABEL: sil [ossa] @test_ssa_updater_guaranteed : // CHECK: begin_borrow // CHECK: begin_borrow // CHECK-NOT: bb({{.*@reborrow.*}}): // CHECK: end_borrow // CHECK-LABEL: } // end sil function 'test_ssa_updater_guaranteed' sil [ossa] @test_ssa_updater_guaranteed : $@convention(thin) (@owned String) -> () { bb0(%0 : @owned $String): %2 = integer_literal $Builtin.Int64, 0 %3 = begin_borrow %0 br bb1(%3, %2) bb1(%4 : @reborrow $String, %5 : $Builtin.Int64): %6 = borrowed %4 from (%0) cond_br undef, bb14, bb2 bb2: %7 = integer_literal $Builtin.Int64, 1 %8 = begin_borrow %6 cond_br undef, bb4, bb3 bb3: br bb5 bb4: cond_br undef, bb7, bb8 bb5: cond_br undef, bb10, bb6 bb6: br bb9 bb7: br bb9 bb8: br bb12 bb9: br bb11 bb10: br bb11 bb11: end_borrow %8 end_borrow %6 br bb13 bb12: end_borrow %8 end_borrow %6 destroy_value [dead_end] %0 unreachable bb13: %24 = begin_borrow %0 br bb1(%24, %7) bb14: end_borrow %6 destroy_value %0 %27 = tuple () return %27 } // Incomplete liveranges in dead-end exit blocks can cause a missing phi in the rotated loop. // CHECK-LABEL: sil [ossa] @incomplete_liverange_in_dead_end_exit : // CHECK: bb1: // CHECK: apply // CHECK: bb2: // CHECK-LABEL: } // end sil function 'incomplete_liverange_in_dead_end_exit' sil [ossa] @incomplete_liverange_in_dead_end_exit : $@convention(thin) () -> () { bb0: br bb1 bb1: %1 = function_ref @getBar : $@convention(thin) () -> @owned Bar %2 = apply %1() : $@convention(thin) () -> @owned Bar %3 = begin_borrow %2 cond_br undef, bb3, bb2 bb2: br bb4 bb3: end_borrow %3 unreachable bb4: end_borrow %3 destroy_value %2 cond_br undef, bb6, bb5 bb5: br bb1 bb6: %12 = tuple () return %12 }