| // RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -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 $<τ_0_0> { var τ_0_0 } <B> |
| %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <B>, 0 |
| %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 : $<τ_0_0> { var τ_0_0 } <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 |
| } |