blob: adabd7ec58bcfedc82a7353e185a3a8dda25e312 [file] [log] [blame]
// RUN: %target-sil-opt -enable-sil-verify-all %s -diagnose-unreachable | FileCheck %s
import Builtin
import Swift
sil private @test1 : $() -> () {
bb0:
%5 = integer_literal $Builtin.Int1, 1
%7 = cond_br %5, bb1, bb2
bb1: // Preds: bb0
%8 = br bb2
bb2: // Preds: bb1 bb0
%9 = tuple ()
%10 = return %9 : $()
}
// CHECK-LABEL:@test1
// CHECK: bb0:
// CHECK-NEXT: br bb1
// CHECK: bb1:
// CHECK-NEXT: br bb2
// CHECK: bb2:
// CHECK-NEXT: tuple ()
// CHECK-NEXT: return
// CHECK-NEXT: }
sil @test2 : $@convention(thin) () -> () {
bb0:
%11 = integer_literal $Builtin.Int1, 0
%13 = cond_br %11, bb1, bb2
bb1: // Preds: bb0
%22 = br bb2
bb2: // Preds: bb1 bb0
%32 = tuple ()
%33 = return %32 : $()
}
// CHECK-LABEL:sil @test2
// CHECK: bb0:
// CHECK-NEXT: br bb1
// CHECK:bb1: // Preds: bb0
// CHECK-NEXT: tuple ()
// CHECK-NEXT: return
// CHECK-NEXT: }
// func loopWithFalse() -> () {
// while false {
// if (false)
// return
// }
//}
sil @loopWithFalse : $@convention(thin) () -> () {
bb0:
%6 = br bb1
bb1: // Preds: bb4 bb0
%12 = integer_literal $Builtin.Int1, 0
%14 = cond_br %12, bb2, bb5
bb2: // Preds: bb1
%20 = integer_literal $Builtin.Int1, 0
%22 = cond_br %20, bb3, bb4
bb3: // Preds: bb2
br bb6
bb4: // Preds: bb2
%26 = br bb1
bb5: // Preds: bb1
br bb6
bb6:
%28 = tuple ()
%29 = return %28 : $()
}
// CHECK-LABEL: sil @loopWithFalse
// CHECK: bb0:
// CHECK-NEXT: br bb1
// CHECK:bb1: // Preds: bb0
// CHECK-NEXT: br bb2
// CHECK:bb2: // Preds: bb1
// CHECK:br bb3
// CHECK:bb3:
// CHECK-NEXT: tuple ()
// CHECK-NEXT: return
// CHECK-NEXT:}
// func InfLoop() -> () {
// while true {
// if (false)
// return
// }
//}
sil @InfLoop : $@convention(thin) () -> () {
bb0:
%6 = br bb1
bb1: // Preds: bb4 bb0
%12 = integer_literal $Builtin.Int1, 1
%14 = cond_br %12, bb2, bb5
bb2: // Preds: bb1
%20 = integer_literal $Builtin.Int1, 0
%22 = cond_br %20, bb3, bb4
bb3: // Preds: bb2
br bb6
bb4: // Preds: bb2
%26 = br bb1
bb5: // Preds: bb1
br bb6
bb6:
%28 = tuple ()
%29 = return %28 : $()
}
// CHECK-LABEL:sil @InfLoop
// CHECK: bb0:
// CHECK-NEXT: br bb1
// CHECK:bb1: // Preds: bb3 bb0
// CHECK-NEXT: br bb2
// CHECK:bb2: // Preds: bb1
// CHECK-NEXT: br bb3
// CHECK:bb3: // Preds: bb2
// CHECK-NEXT: br bb1
// CHECK-NEXT: }
class B { }
class E : B { }
sil @exit : $@convention(thin) () -> Never {
bb0:
br bb0
}
// CHECK-LABEL: sil @removeTriviallyDeadInstructions
sil @removeTriviallyDeadInstructions : $@convention(thin) (@owned B) -> () {
bb0(%0 : $B):
%1 = alloc_box $B
%1a = project_box %1 : $@box B
%2 = store %0 to %1a : $*B // CHECK: store
%3 = load %1a : $*B
%4 = strong_retain %3 : $B // CHECK: strong_retain
%5 = unchecked_ref_cast %3 : $B to $Builtin.NativeObject // CHECK-NOT: unchecked_ref_cast
%7 = strong_release %3 : $B // CHECK: strong_release
%8 = strong_release %1 : $@box B // CHECK-NEXT: strong_release
%9 = function_ref @exit : $@convention(thin) () -> Never
%10 = apply %9() : $@convention(thin) () -> Never
%6 = unchecked_ref_cast %5 : $Builtin.NativeObject to $B // CHECK-NOT: unchecked_ref_cast
%11 = tuple()
%12 = return %11 : $()
}
// CHECK-LABEL: sil @removeTriviallyDeadButUsedByUnreachableBlock
sil @removeTriviallyDeadButUsedByUnreachableBlock : $@convention(thin) (@owned B) -> () {
bb0(%0 : $B):
%5 = unchecked_ref_cast %0 : $B to $Builtin.NativeObject // CHECK-NOT: unchecked_ref_cast
%11 = integer_literal $Builtin.Int1, 0 // CHECK-NOT: integer_literal
%13 = cond_br %11, bb1, bb2 // CHECK: br
bb1:
%21 = unchecked_ref_cast %5 : $Builtin.NativeObject to $B // CHECK-NOT: unchecked_ref_cast
%22 = br bb2
bb2:
%32 = tuple ()
%33 = return %32 : $() // CHECK: return
} // CHECK: }
// CHECK-LABEL: sil @removeTriviallyDeadCrossBasicBlocks
sil @removeTriviallyDeadCrossBasicBlocks : $@convention(thin) (@owned B, Builtin.Int1) -> () {
bb0(%0: $B, %1: $Builtin.Int1):
%5 = unchecked_ref_cast %0 : $B to $Builtin.NativeObject // CHECK-NOT: unchecked_ref_cast
%13 = cond_br %1, bb1, bb2 // CHECK: cond_br
bb1:
%22 = br bb2
bb2:
%9 = function_ref @exit : $@convention(thin) () -> Never
%10 = apply %9() : $@convention(thin) () -> Never
%21 = unchecked_ref_cast %5 : $Builtin.NativeObject to $B // CHECK-NOT: unchecked_ref_cast
%32 = tuple ()
%33 = return %32 : $()
} // CHECK: }
sil @testCondBranchBBArgs : $@convention(thin) (Int, Int) -> Int {
bb0(%0 : $Int, %1 : $Int):
%2 = integer_literal $Builtin.Int1, 0
cond_br %2, bb1(%0 : $Int), bb2(%1 : $Int)
bb1(%3 : $Int):
br bb3(%3 : $Int)
bb2(%4 : $Int):
br bb3(%4 : $Int)
bb3(%5 : $Int):
return %5 : $Int
}
// CHECK-LABEL: sil @testCondBranchBBArgs
// CHECK: bb0
// CHECK-NEXT: br bb1
// CHECK: bb1:
// CHECK-NEXT: br bb2
// CHECK: bb2:
// CHECK-NEXT: return
// CHECK: }
sil @removePredecessorWithBBArgs : $@convention(thin) (Int, Int) -> Int {
bb0(%0 : $Int, %1 : $Int):
%2 = integer_literal $Builtin.Int1, 0
%3 = cond_br %2, bb2(%0 : $Int), bb3(%1 : $Int)
bb2(%4 : $Int):
br bb4(%4 : $Int)
bb3(%5 : $Int):
br bb4(%5 : $Int)
bb4(%6 : $Int):
return %6 : $Int
}
// CHECK-LABEL:sil @removePredecessorWithBBArgs
// CHECK: bb0(%{{[0-9]+}} : $Int, %{{[0-9]+}} : $Int):
// CHECK-NEXT: br bb1
// CHECK: bb1:
// CHECK-NEXT: br bb2
// CHECK: bb2:
// CHECK-NEXT: return
// CHECK: }
sil @code_removed_after_a_call_to_noreturn : $@convention(thin) (Int, Builtin.Int1) -> () {
bb0(%0 : $Int, %1 : $Builtin.Int1):
%6 = function_ref @exit : $@convention(thin) () -> Never
%7 = apply %6() : $@convention(thin) () -> Never
cond_br %1, bb1, bb2
bb1: // Preds: bb0
br bb2
bb2: // Preds: bb1 bb0
%20 = tuple () // user: %21
return %20 : $()
}
// CHECK-LABEL: sil @code_removed_after_a_call_to_noreturn
// CHECK: bb0
// CHECK-NEXT: exit
// CHECK-NEXT: function_ref
// CHECK-NEXT: apply
// CHECK-NEXT: {{ unreachable}}
// CHECK: }
sil @dead_use_of_alloc_stack : $@convention(thin) () -> () {
bb0:
%1 = alloc_stack $((), (), ())
%2 = tuple_element_addr %1 : $*((), (), ()), 0
dealloc_stack %1 : $*((), (), ())
%3 = tuple ()
return %3 : $()
}
// CHECK-LABEL: sil @dead_use_of_alloc_stack
// CHECK: bb
// CHECK: alloc_stack
// CHECK: dealloc_stack
// CHECK: }
enum BoolLike { case true_, false_ }
sil @constant_fold_switch_enum : $@convention(thin) (Int) -> Int {
bb0(%0 : $Int):
%6 = enum $BoolLike, #BoolLike.false_!enumelt // user: %9
switch_enum %6 : $BoolLike, case #BoolLike.true_!enumelt: bb1, case #BoolLike.false_!enumelt: bb2
bb1:
br bb3
bb2:
br bb3
bb3:
return %0 : $Int
// CHECK-LABEL: sil @constant_fold_switch_enum
// CHECK: bb0(%0 : $Int):
// CHECK-NEXT: br bb1
// CHECK-NOT: switch_enum
// CHECK: }
}
enum Singleton {
case x(Int, UnicodeScalar)
};
sil @constant_fold_switch_enum_with_payload : $@convention(thin) (Int, UnicodeScalar) -> (Int, UnicodeScalar) {
bb0(%6 : $Int, %10 : $UnicodeScalar):
%11 = tuple (%6 : $Int, %10 : $UnicodeScalar)
%12 = enum $Singleton, #Singleton.x!enumelt.1, %11 : $(Int, UnicodeScalar)
switch_enum %12 : $Singleton, case #Singleton.x!enumelt.1: bb1
bb1(%15 : $(Int, UnicodeScalar)):
return %15 : $(Int, UnicodeScalar)
b2:
%111 = tuple (%6 : $Int, %10 : $UnicodeScalar)
br bb1(%111 : $(Int, UnicodeScalar))
// CHECK-LABEL: sil @constant_fold_switch_enum_with_payload
// CHECK: bb0(%{{[0-9]+}} : $Int, %{{[0-9]+}} : $UnicodeScalar):
// CHECK: br bb1
// CHECK: bb1:
// CHECK: return
}
sil @constant_fold_switch_value : $@convention(thin) (Int) -> Int {
bb0(%0 : $Int):
%1 = integer_literal $Builtin.Word, 2
%2 = integer_literal $Builtin.Word, 1
%3 = integer_literal $Builtin.Word, 2
switch_value %1 : $Builtin.Word, case %2: bb1, case %3: bb2
bb1:
br bb3
bb2:
br bb3
bb3:
return %0 : $Int
// CHECK-LABEL: sil @constant_fold_switch_value
// CHECK: bb0(%0 : $Int):
// CHECK-NEXT: br bb1
// CHECK-NOT: switch_value
// CHECK: }
}
sil @propagate_BB_args : $@convention(thin) (Int) -> Int {
bb0(%0 : $Int):
%1 = integer_literal $Builtin.Int1, 0
br bb1(%1 : $Builtin.Int1)
bb1(%2 : $Builtin.Int1):
br bb2(%2 : $Builtin.Int1)
bb2(%3 : $Builtin.Int1):
cond_br %3, bb4, bb3
bb3:
br bb5
bb4:
br bb5
bb5:
return %0 : $Int
// CHECK-LABEL:sil @propagate_BB_args
// CHECK: bb0(%0 : $Int):
// CHECK-NEXT: br bb1
// CHECK: bb1:
// CHECK-NOT: cond_br
}
sil @propagate_BB_mult_args : $@convention(thin) () -> Builtin.Int1 {
bb0:
%0 = integer_literal $Builtin.Int1, 0
%1 = integer_literal $Builtin.Int1, 1
br bb1(%0 : $Builtin.Int1, %1 : $Builtin.Int1)
bb1(%3 : $Builtin.Int1, %4 : $Builtin.Int1):
return %3 : $Builtin.Int1
// CHECK-LABEL:sil @propagate_BB_mult_args
// CHECK: bb0:
// CHECK-NEXT: integer_literal
// CHECK-NEXT: br bb1
// CHECK: bb1:
// CHECK-NOT: cond_br
// CHECK: return
}
sil @builtin_unreachable : $@convention(thin) () -> () {
bb0:
%z = builtin "unreachable"() : $()
unreachable
}
sil @throwing_noreturn : $@convention(thin) () -> (Never, @error Error)
// CHECK-LABEL:sil @try_apply_1
// CHECK: bb1(
// CHECK-NEXT: {{ unreachable}}
// CHECK: bb2(
// CHECK-NEXT: throw
sil @try_apply_1 : $@convention(thin) () -> @error Error {
bb0:
%0 = function_ref @throwing_noreturn : $@convention(thin) () -> (Never, @error Error)
try_apply %0() : $@convention(thin) () -> (Never, @error Error), normal bb1, error bb2
bb1(%1 : $Never):
%2 = tuple ()
return %2 : $()
bb2(%3 : $Error):
throw %3 : $Error
}
// CHECK-LABEL:sil @try_apply_2
// CHECK: bb3(
// CHECK-NEXT: {{ unreachable}}
// CHECK: bb4(
// CHECK-NEXT: throw
sil @try_apply_2 : $@convention(thin) (Builtin.Int1) -> @error Error {
bb0(%0 : $Builtin.Int1):
%1 = function_ref @throwing_noreturn : $@convention(thin) () -> (Never, @error Error)
cond_br %0, bb1, bb2
bb1:
try_apply %1() : $@convention(thin) () -> (Never, @error Error), normal bb3, error bb4
bb2:
try_apply %1() : $@convention(thin) () -> (Never, @error Error), normal bb3, error bb4
bb3(%2 : $Never):
%3 = tuple ()
return %3 : $()
bb4(%4 : $Error):
throw %4 : $Error
}
// This should arguably be ill-formed.
// CHECK-LABEL:sil @try_apply_3
// CHECK: br bb1
// CHECK: bb1(
// CHECK-NOT: {{ unreachable}}
// CHECK: try_apply
// CHECK: bb2(
// CHECK-NEXT: throw
sil @try_apply_3 : $@convention(thin) (Never) -> @error Error {
bb0(%0 : $Never):
br bb1(%0 : $Never)
bb1(%1 : $Never):
%2 = function_ref @throwing_noreturn : $@convention(thin) () -> (Never, @error Error)
try_apply %2() : $@convention(thin) () -> (Never, @error Error), normal bb1, error bb2
bb2(%3 : $Error):
throw %3 : $Error
}