mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Incomplete liveranges in the dead-end exit block can cause a missing adjacent phi-argument for a re-borrow if there is a borrow-scope is in the loop. But even when we have complete lifetimes, it's probably not worth rotating a loop where the header block branches to a dead-end block. Fixes a SIL verifier crash
753 lines
26 KiB
Plaintext
753 lines
26 KiB
Plaintext
// 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 } <Bool>)
|
|
|
|
// CHECK: bb6({{.*}} : $Builtin.Int32, {{.*}} : @owned $Bar, {{.*}} : @owned $<τ_0_0> { var τ_0_0 } <Bool>):
|
|
// 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 } <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>)
|
|
|
|
bb1(%4 : $Builtin.Int32, %5 : $Builtin.Int32, %26: @owned $Bar, %31 : @owned $<τ_0_0> { var τ_0_0 } <Bool>):
|
|
%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<Int32>, #Optional.some!enumelt, %6 : $Int32
|
|
%16 = unchecked_enum_data %15 : $Optional<Int32>, #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 } <Bool>)
|
|
|
|
bb3:
|
|
destroy_value %26 : $Bar
|
|
destroy_value %31 : $<τ_0_0> { var τ_0_0 } <Bool>
|
|
%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 } <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>)
|
|
|
|
bb1(%4 : $Builtin.Int32, %5 : $Builtin.Int32, %26: @owned $Bar, %31 : @owned $<τ_0_0> { var τ_0_0 } <Bool>):
|
|
%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<Int32>, #Optional.some!enumelt, %6 : $Int32
|
|
%16 = unchecked_enum_data %15 : $Optional<Int32>, #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 } <Bool>)
|
|
|
|
bb4:
|
|
br bb6
|
|
|
|
bb5:
|
|
br bb6
|
|
|
|
bb6:
|
|
destroy_value %26 : $Bar
|
|
destroy_value %31 : $<τ_0_0> { var τ_0_0 } <Bool>
|
|
%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 } <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>)
|
|
|
|
bb1(%4 : $Builtin.Int32, %5 : $Builtin.Int32, %26: @owned $Bar, %31 : @owned $<τ_0_0> { var τ_0_0 } <Bool>):
|
|
%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<Int32>, #Optional.some!enumelt, %6 : $Int32
|
|
%16 = unchecked_enum_data %15 : $Optional<Int32>, #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 } <Bool>)
|
|
|
|
bb3:
|
|
destroy_value %26 : $Bar
|
|
destroy_value %31 : $<τ_0_0> { var τ_0_0 } <Bool>
|
|
%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<Int32>, #Optional.some!enumelt, %6 : $Int32
|
|
%16 = unchecked_enum_data %15 : $Optional<Int32>, #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 } <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) Self
|
|
br bb1(%1 : $Builtin.Int32, %2 : $Builtin.Int32, %30 : $<τ_0_0> { var τ_0_0 } <Bool>)
|
|
|
|
bb1(%4 : $Builtin.Int32, %5 : $Builtin.Int32, %31 : @owned $<τ_0_0> { var τ_0_0 } <Bool>):
|
|
%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<Int32>, #Optional.some!enumelt, %6 : $Int32
|
|
%16 = unchecked_enum_data %15 : $Optional<Int32>, #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 } <Bool>)
|
|
|
|
bb3:
|
|
destroy_value %31 : $<τ_0_0> { var τ_0_0 } <Bool>
|
|
%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<Int32>, #Optional.none!enumelt
|
|
br bb6(%12 : $Builtin.Int32, %16 : $Optional<Int32>)
|
|
|
|
bb6(%18 : $Builtin.Int32, %19 : $Optional<Int32>):
|
|
switch_enum %19 : $Optional<Int32>, case #Optional.some!enumelt: bb7, case #Optional.none!enumelt: bb8
|
|
|
|
bb7(%arg : $Int32):
|
|
%21 = unchecked_enum_data %19 : $Optional<Int32>, #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<Int32>, #Optional.some!enumelt, %24 : $Int32
|
|
br bb6(%29 : $Builtin.Int32, %32 : $Optional<Int32>)
|
|
|
|
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<Int32>, #Optional.some!enumelt, %6 : $Int32
|
|
%16 = unchecked_enum_data %15 : $Optional<Int32>, #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<Int32>, #Optional.some!enumelt, %10 : $Int32
|
|
%19 = unchecked_enum_data %18 : $Optional<Int32>, #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
|
|
}
|
|
|