mirror of
https://github.com/apple/swift.git
synced 2026-06-27 12:25:55 +02:00
cf962e0148
As a structural SIL property, we disallow address-type block arguments. Supporting them would prevent reliably reasoning about the underlying storage of memory access. This reasoning is important for diagnosing violations of memory access rules and supporting future optimizations such as bitfield packing. Address-type block arguments also create unnecessary complexity for SIL optimization passes that need to reason about memory aliasing. This must be enforced in RAW SIL for diagnosing exclusive memory access. The optimizer currently breaks the invariant in three places: 1. Normal Simplify CFG during conditional branch simplification (sneaky jump threading). 2. Simplify CFG via Jump Threading. 3. Loop Rotation.
389 lines
15 KiB
Plaintext
389 lines
15 KiB
Plaintext
// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -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
|
|
|
|
// CHECK-LABEL: looprotate
|
|
// CHECK: bb0(%0 : $Int32, %1 : $Bar):
|
|
// CHECK: class_method
|
|
// CHECK: cond_br {{.*}}, bb3({{.*}} : $Builtin.Int32), bb1
|
|
|
|
// CHECK: bb1:
|
|
// CHECK: br bb2({{.*}} : $Builtin.Int32, {{.*}} : $Builtin.Int32, {{.*}}: $Int32)
|
|
|
|
// CHECK: bb2({{.*}}: $Builtin.Int32, {{.*}} : $Builtin.Int32, {{.*}} : $Int32):
|
|
// CHECK: class_method
|
|
// CHECK: cond_br {{%.*}}, bb3({{.*}} : $Builtin.Int32), bb2({{.*}} : $Builtin.Int32, {{.*}} : $Builtin.Int32, {{.*}} : $Int32)
|
|
|
|
// CHECK: bb3({{.*}} : $Builtin.Int32):
|
|
// CHECK: [[STRUCT:%.*]] = struct $Int32 ({{%.*}} : $Builtin.Int32)
|
|
// CHECK: return [[STRUCT]] : $Int32
|
|
|
|
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!1: @_TFC4main3Bar3boofS0_FT_T_
|
|
#Bar.foo!1: @_TFC4main3Bar3foofS0_FT_T_
|
|
#Bar.foo_objc!1: @_TFC4main3Bar3foofS0_FT_T_
|
|
}
|
|
|
|
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 } <Bool>
|
|
%30a = project_box %30 : $<τ_0_0> { var τ_0_0 } <Bool>, 0
|
|
br bb1(%1 : $Builtin.Int32, %2 : $Builtin.Int32, %25: $Bar, %30 : $<τ_0_0> { var τ_0_0 } <Bool>, %30a : $*Bool)
|
|
|
|
bb1(%4 : $Builtin.Int32, %5 : $Builtin.Int32, %26: $Bar, %31 : $<τ_0_0> { var τ_0_0 } <Bool>, %32 : $*Bool):
|
|
%24 = class_method %26 : $Bar, #Bar.foo!1 : (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<Int32>, #Optional.some!enumelt.1, %6 : $Int32
|
|
%16 = unchecked_enum_data %15 : $Optional<Int32>, #Optional.some!enumelt.1
|
|
%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 } <Bool>, %32 : $*Bool)
|
|
|
|
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<Int32>, #Optional.some!enumelt.1, %6 : $Int32
|
|
%16 = unchecked_enum_data %15 : $Optional<Int32>, #Optional.some!enumelt.1
|
|
%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 } <Bool>
|
|
%30a = project_box %30 : $<τ_0_0> { var τ_0_0 } <Bool>, 0
|
|
%40 = open_existential_addr immutable_access %25 : $*P to $*@opened("C22498FA-CABF-11E5-B9A9-685B35C48C83") P
|
|
br bb1(%1 : $Builtin.Int32, %2 : $Builtin.Int32, %25: $*P, %30 : $<τ_0_0> { var τ_0_0 } <Bool>, %30a : $*Bool)
|
|
|
|
bb1(%4 : $Builtin.Int32, %5 : $Builtin.Int32, %26: $*P, %31 : $<τ_0_0> { var τ_0_0 } <Bool>, %32 : $*Bool):
|
|
%111 = witness_method $@opened("C22498FA-CABF-11E5-B9A9-685B35C48C83") P, #P.boo!1, %40 : $*@opened("C22498FA-CABF-11E5-B9A9-685B35C48C83") P : $@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>(%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<Int32>, #Optional.some!enumelt.1, %6 : $Int32
|
|
%16 = unchecked_enum_data %15 : $Optional<Int32>, #Optional.some!enumelt.1
|
|
%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: $*P, %31 : $<τ_0_0> { var τ_0_0 } <Bool>, %32 : $*Bool)
|
|
|
|
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<Int32>, #Optional.none!enumelt // user: %17
|
|
br bb6(%12 : $Builtin.Int32, %16 : $Optional<Int32>) // id: %17
|
|
|
|
bb6(%18 : $Builtin.Int32, %19 : $Optional<Int32>): // Preds: bb5 bb9
|
|
switch_enum %19 : $Optional<Int32>, case #Optional.some!enumelt.1: bb7, case #Optional.none!enumelt: bb8 // id: %20
|
|
|
|
bb7: // Preds: bb6
|
|
%21 = unchecked_enum_data %19 : $Optional<Int32>, #Optional.some!enumelt.1
|
|
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<Int32>, #Optional.some!enumelt.1, %24 : $Int32 // user: %33
|
|
br bb6(%29 : $Builtin.Int32, %32 : $Optional<Int32>) // 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!1.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<Int32>, #Optional.some!enumelt.1, %6 : $Int32
|
|
%16 = unchecked_enum_data %15 : $Optional<Int32>, #Optional.some!enumelt.1
|
|
%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 the SSA Updater utility: replaceBBArgWithCast().
|
|
//
|
|
// CHECK-LABEL: struct_arg
|
|
// CHECK: bb0:
|
|
// CHECK: cond_br
|
|
// CHECK: bb1:
|
|
// CHECK: br bb2
|
|
// CHECK: bb2({{%.*}} : $Builtin.Int32, [[WORD:%.*]] : $Builtin.Int32
|
|
// CHECK: [[STRUCT:%[0-9]+]] = struct $Int32 ([[WORD]]
|
|
// CHECK: apply {{.*}}([[STRUCT]])
|
|
// CHECK: cond_br
|
|
// CHECK: bb3({{.*}}):
|
|
// CHECK: return
|
|
sil @struct_arg : $@convention(thin) () -> () {
|
|
bb0:
|
|
%c0 = integer_literal $Builtin.Int32, 0
|
|
%c100 = integer_literal $Builtin.Int32, 100
|
|
br bb1(%c0 : $Builtin.Int32, %c0 : $Builtin.Int32)
|
|
|
|
bb1(%a1 : $Builtin.Int32, %a0 : $Builtin.Int32):
|
|
%s0 = struct $Int32 (%a0 : $Builtin.Int32)
|
|
%z1 = builtin "cmp_eq_Word"(%a0 : $Builtin.Int32, %c100 : $Builtin.Int32) : $Builtin.Int1
|
|
cond_br %z1, bb2, bb3
|
|
|
|
bb3:
|
|
%c1 = integer_literal $Builtin.Int32, 1
|
|
%z2 = integer_literal $Builtin.Int1, 0
|
|
%d1 = builtin "sadd_with_overflow_Word"(%a0 : $Builtin.Int32, %c1 : $Builtin.Int32, %z2 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
|
|
%t1 = tuple_extract %d1 : $(Builtin.Int32, Builtin.Int1), 0
|
|
%d2 = builtin "sadd_with_overflow_Word"(%a1 : $Builtin.Int32, %c1 : $Builtin.Int32, %z2 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
|
|
%t2 = tuple_extract %d2 : $(Builtin.Int32, Builtin.Int1), 0
|
|
%f1 = function_ref @readInt : $@convention(thin) (Int32) -> ()
|
|
%l1 = apply %f1(%s0) : $@convention(thin) (Int32) -> ()
|
|
br bb1(%t2 : $Builtin.Int32, %t1 : $Builtin.Int32)
|
|
|
|
bb2:
|
|
%14 = struct $Int32 (%a1 : $Builtin.Int32)
|
|
%t3 = tuple ()
|
|
return %t3 : $()
|
|
|
|
}
|
|
|
|
// Test LoopRotate insertBackedgeBlock.
|
|
//
|
|
// CHECK-LABEL: insert_backedge_block
|
|
// PreLoop Check
|
|
// CHECK: bb0(%
|
|
// CHECK: cond_br
|
|
// Loop Header
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: br bb2
|
|
// CHECK: bb2:
|
|
// CHECK: cond_br %{{.*}}, bb3, bb5
|
|
// CHECK: bb3:
|
|
// CHECK: apply
|
|
// CHECK: br bb4(
|
|
// CHECK: bb4(%[[ARG:[0-9]*]]
|
|
// CHECK-NEXT: cond_br %{{.*}}, bb6, bb2
|
|
// CHECK: bb5:
|
|
// CHECK: apply
|
|
// CHECK: br bb4(%
|
|
// CHECK: bb6
|
|
// 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 : $()
|
|
}
|