// 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 @_TFC4main3Bar3foofS0_FT_T_ : $@convention(method) (@guaranteed Bar) -> () sil @_TFC4main3Bar3boofS0_FT_T_ : $@convention(method) (@guaranteed Bar) -> Int64 sil @_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: looprotate // CHECK: bb0(%0 : $Int32, %1 : $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) // CHECK: bb6({{.*}} : $Builtin.Int32): // CHECK: [[STRUCT:%.*]] = struct $Int32 ({{%.*}} : $Builtin.Int32) // CHECK: return [[STRUCT]] : $Int32 // CHECK: } // end sil function 'looprotate' sil @looprotate : $@convention(thin) (Int32, @owned Bar) -> Int32 { bb0(%0 : $Int32, %25: $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: $Bar, %31 : $<τ_0_0> { var τ_0_0 } ): %24 = class_method %26 : $Bar, #Bar.foo : (Bar) -> () -> (), $@convention(method) (@guaranteed Bar) -> () // user: %6 %27 = apply %24(%25) : $@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: %23 = struct $Int32 (%4 : $Builtin.Int32) return %23 : $Int32 } // CHECK-LABEL: dont_duplicate_large_block // CHECK: bb0(%0 : $Int32, %1 : $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 @dont_duplicate_large_block : $@convention(thin) (Int32, @owned Bar) -> Int32 { bb0(%0 : $Int32, %25: $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: $Bar, %31 : $<τ_0_0> { var τ_0_0 } ): %24 = class_method %26 : $Bar, #Bar.foo : (Bar) -> () -> (), $@convention(method) (@guaranteed Bar) -> () // user: %6 %27 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> () %28 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> () %29 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> () %33 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> () %34 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> () %35 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> () %36 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> () %37 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> () %38 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> () %39 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> () %40 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> () %41 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> () %42 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> () %43 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> () %44 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> () %45 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> () %46 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> () %47 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> () %48 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> () %49 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> () %50 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> () %51 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> () %52 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> () %53 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> () %54 = apply %24(%25) : $@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: %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: looprotate2 // CHECK: return sil @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(%4 : $Builtin.Int32), 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 (%23 : $Builtin.Int32) : %24 = struct $Int32 (%23 : $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 @looprotate_with_opened_archetype // CHECK: return sil @looprotate_with_opened_archetype : $@convention(thin) (Int32, @in 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 : $<τ_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: %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: @testnested // CHECK: return sil @testnested : $@convention(thin) () -> () { bb0: br bb1(undef : $Builtin.Int32, undef : $Builtin.Int32) // id: %0 bb1(%1 : $Builtin.Int32, %2 : $Builtin.Int32): // Preds: bb0 bb2 %3 = integer_literal $Builtin.Int1, 0 // user: %4 cond_br %3, bb2(%1 : $Builtin.Int32, %2 : $Builtin.Int32), bb10 // id: %4 bb2(%5 : $Builtin.Int32, %6 : $Builtin.Int32): // Preds: bb1 bb8 %7 = integer_literal $Builtin.Int1, -1 // user: %8 cond_br %7, bb3, bb1(%5 : $Builtin.Int32, %6 : $Builtin.Int32) // id: %8 bb3: // Preds: bb2 %9 = integer_literal $Builtin.Int32, 0 // user: %11 %10 = integer_literal $Builtin.Int32, 1 // users: %14, %23 br bb4(%9 : $Builtin.Int32) // id: %11 bb4(%12 : $Builtin.Int32): // Preds: bb3 bb7 %14 = builtin "cmp_eq_Word"(%12 : $Builtin.Int32, %10 : $Builtin.Int32) : $Builtin.Int1 // user: %15 cond_br %14, bb5, bb9 // id: %15 bb5: // Preds: bb4 %16 = enum $Optional, #Optional.none!enumelt // user: %17 br bb6(%12 : $Builtin.Int32, %16 : $Optional) // id: %17 bb6(%18 : $Builtin.Int32, %19 : $Optional): // Preds: bb5 bb9 switch_enum %19 : $Optional, case #Optional.some!enumelt: bb7, case #Optional.none!enumelt: bb8 // id: %20 bb7: // Preds: bb6 %21 = unchecked_enum_data %19 : $Optional, #Optional.some!enumelt br bb4(%18 : $Builtin.Int32) // id: %22 bb8: // Preds: bb6 br bb2(%18 : $Builtin.Int32, %10 : $Builtin.Int32) // id: %23 bb9: // Preds: bb4 %24 = struct $Int32 (%12 : $Builtin.Int32) // user: %32 %25 = integer_literal $Builtin.Int32, 1 // user: %28 %27 = integer_literal $Builtin.Int1, -1 // user: %28 %28 = builtin "sadd_with_overflow_Word"(%12 : $Builtin.Int32, %25 : $Builtin.Int32, %27 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) // users: %29, %30 %29 = tuple_extract %28 : $(Builtin.Int32, Builtin.Int1), 0 // user: %33 %30 = tuple_extract %28 : $(Builtin.Int32, Builtin.Int1), 1 // user: %31 cond_fail %30 : $Builtin.Int1 // id: %31 %32 = enum $Optional, #Optional.some!enumelt, %24 : $Int32 // user: %33 br bb6(%29 : $Builtin.Int32, %32 : $Optional) // id: %33 bb10: // Preds: bb1 %34 = tuple () // user: %35 return %34 : $() // id: %35 } // CHECK-LABEL: dont_looprotate_objc // CHECK: bb0{{.*}}: // CHECK: br bb1 // CHECK: bb1{{.*}}: // CHECK: cond_br {{.*}}, bb3, bb2 // CHECK: bb2: // CHECK: br bb1 // CHECK: bb3: // CHECK: return sil @dont_looprotate_objc : $@convention(thin) (Int32, @owned Bar) -> Int32 { bb0(%0 : $Int32, %25: $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: $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: %23 = struct $Int32 (%4 : $Builtin.Int32) return %23 : $Int32 } sil @readInt : $@convention(thin) (Int32) -> () { bb0(%a0 : $Int32): %t1 = tuple () return %t1 : $() } // Test LoopRotate insertBackedgeBlock. // // CHECK-LABEL: 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 sil @insert_backedge_block : $@convention(thin) (@owned @callee_owned () -> Builtin.Int32) -> () { bb0(%0 : $@callee_owned () -> Builtin.Int32): %r0 = apply %0() : $@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: %r1 = apply %0() : $@callee_owned () -> Builtin.Int32 br bb1(%r1: $Builtin.Int32) bb4: %r2 = apply %0() : $@callee_owned () -> Builtin.Int32 br bb1(%r2: $Builtin.Int32) bb5: %r3 = tuple () return %r3 : $() } // CHECK-LABEL: sil @dont_rotate_single_basic_block_loop // CHECK: bb0({{.*}}): // CHECK: br bb1 // CHECK: bb1: // CHECK: cond_br {{.*}}, bb1, bb2 // CHECK: bb2: // CHECK: return sil @dont_rotate_single_basic_block_loop : $@convention(thin) (Builtin.Int1) -> () { bb0(%0 : $Builtin.Int1): br bb1 bb1: cond_br %0, bb1, bb2 bb2: %1 = tuple () return %1 : $() } // CHECK-LABEL: sil @dont_rotate_single_basic_block_loop_split_backedge // CHECK: bb0({{.*}}): // CHECK: br bb1 // CHECK: bb1: // CHECK: cond_br {{.*}}, bb2, bb3 // CHECK: bb2: // CHECK: br bb1 // CHECK: bb3: // CHECK: return sil @dont_rotate_single_basic_block_loop_split_backedge : $@convention(thin) (Builtin.Int1) -> () { bb0(%0 : $Builtin.Int1): br bb1 bb1: cond_br %0, bb2, bb3 bb2: br bb1 bb3: %1 = tuple () return %1 : $() } struct Wrapper : Sendable { let id: Int } // CHECK-LABEL: sil @test_open_pack_element : // CHECK: bb0{{.*}}: // CHECK-NOT: open_pack_element // CHECK: br bb2 // CHECK: } // end sil function 'test_open_pack_element' sil @test_open_pack_element : $@convention(thin) (@pack_guaranteed Pack{KeyPath}) -> () { bb0(%0 : $*Pack{KeyPath}): %5 = alloc_stack $KeyPath %6 = integer_literal $Builtin.Word, 0 // user: %8 br bb2(%6 : $Builtin.Word) bb1: dealloc_stack %5 : $*KeyPath %35 = tuple () return %35 : $() bb2(%37 : $Builtin.Word): %38 = dynamic_pack_index %37 of $Pack{KeyPath} %39 = open_pack_element %38 of at , shape $each Value, uuid "94218A22-3595-11EF-8496-4EA2A866E4C5" %40 = pack_element_get %38 of %0 : $*Pack{KeyPath} as $*KeyPath %41 = unchecked_addr_cast %5 : $*KeyPath to $*KeyPath %42 = load %40 : $*KeyPath store %42 to %41 : $*KeyPath %7 = integer_literal $Builtin.Word, 1 // users: %45, %44 %44 = builtin "add_Word"(%37 : $Builtin.Word, %7 : $Builtin.Word) : $Builtin.Word // users: %48, %45 cond_br undef, bb1, bb3 bb3: strong_retain %42 : $KeyPath br bb2(%44 : $Builtin.Word) }