blob: 86a7be4a4e8d6e4d118533a1b61a7859a50fc00b [file] [log] [blame]
// RUN: %target-sil-opt -enable-sil-verify-all %s -diagnose-unreachable -sil-print-debuginfo | %FileCheck %s
import Builtin
import Swift
sil @guaranteed_nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
sil private @test1 : $() -> () {
bb0:
%5 = integer_literal $Builtin.Int1, 1
cond_br %5, bb1, bb2
bb1: // Preds: bb0
br bb2
bb2: // Preds: bb1 bb0
%9 = tuple ()
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
cond_br %11, bb1, bb2
bb1: // Preds: bb0
br bb2
bb2: // Preds: bb1 bb0
%32 = tuple ()
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:
br bb1
bb1: // Preds: bb4 bb0
%12 = integer_literal $Builtin.Int1, 0
cond_br %12, bb2, bb5
bb2: // Preds: bb1
%20 = integer_literal $Builtin.Int1, 0
cond_br %20, bb3, bb4
bb3: // Preds: bb2
br bb6
bb4: // Preds: bb2
br bb1
bb5: // Preds: bb1
br bb6
bb6:
%28 = tuple ()
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:
br bb1
bb1: // Preds: bb4 bb0
%12 = integer_literal $Builtin.Int1, 1
cond_br %12, bb2, bb5
bb2: // Preds: bb1
%20 = integer_literal $Builtin.Int1, 0
cond_br %20, bb3, bb4
bb3: // Preds: bb2
br bb6
bb4: // Preds: bb2
br bb1
bb5: // Preds: bb1
br bb6
bb6:
%28 = tuple ()
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 bb1
bb1:
br bb1
}
// 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
store %0 to %1a : $*B // CHECK: store
%3 = load %1a : $*B
strong_retain %3 : $B // CHECK: strong_retain
%5 = unchecked_ref_cast %3 : $B to $Builtin.NativeObject // CHECK-NOT: unchecked_ref_cast
strong_release %3 : $B // CHECK: strong_release
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()
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
cond_br %11, bb1, bb2 // CHECK: br
bb1:
%21 = unchecked_ref_cast %5 : $Builtin.NativeObject to $B // CHECK-NOT: unchecked_ref_cast
br bb2
bb2:
%32 = tuple ()
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
cond_br %1, bb1, bb2 // CHECK: cond_br
bb1:
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 ()
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
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)):
br bb2(%15 : $(Int, UnicodeScalar))
bb2(%16 : $(Int, UnicodeScalar)):
return %16 : $(Int, UnicodeScalar)
b3:
%111 = tuple (%6 : $Int, %10 : $UnicodeScalar)
br bb2(%111 : $(Int, UnicodeScalar))
// CHECK-LABEL: sil @constant_fold_switch_enum_with_payload
// CHECK: bb0(%{{[0-9]+}} : $Int, %{{[0-9]+}} : $Unicode.Scalar):
// 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
}
sil_scope 0 { loc "f.swift":1:1 parent @try_apply_2 : $@convention(thin) (Builtin.Int1) -> @error Error }
// CHECK: sil_scope [[F:[0-9]+]] { loc "f.swift":1:1 parent @try_apply_2
sil_scope 1 { loc "f.swift":2:1 parent 0 }
// CHECK: sil_scope [[S:[0-9]+]] { loc "f.swift":2:1 parent [[F]] }
// CHECK-LABEL:sil @try_apply_2
// CHECK: bb3({{.*}}$Never):
// CHECK-NEXT: {{ unreachable }}, scope [[F]]
// CHECK: bb5({{.*}}$Never):
// CHECK-NEXT: {{ unreachable }}, scope [[S]]
// CHECK: bb7({{.*}} : $Error):
// CHECK-NEXT: throw
// CHECK-LABEL: } // end sil function 'try_apply_2'
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, scope 0
bb2:
try_apply %1() : $@convention(thin) () -> (Never, @error Error), normal bb5, error bb6, scope 1
bb3(%2 : $Never):
br bb7
bb4(%4 : $Error):
br bb8(%4 : $Error)
bb5(%5 : $Never):
br bb7
bb6(%7 : $Error):
br bb8(%7 : $Error)
bb7:
%8 = tuple ()
return %8 : $()
bb8(%9 : $Error):
throw %9 : $Error
}
// CHECK-LABEL:sil @try_apply_3
// CHECK: br bb1
// CHECK: bb1:
// CHECK-NOT: {{ unreachable}}
// CHECK: try_apply
// CHECK: bb3({{.*}} : $Error):
// 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 bb2, error bb3
bb2(%3 : $Never):
br bb1(%3 : $Never)
bb3(%4 : $Error):
throw %4 : $Error
}
enum Either<L, R> {
case left(L)
case right(R)
}
class Klass1 {}
class Klass2 {}
// CHECK-LABEL: sil [ossa] @constant_fold_diagnose_unreachable_succ_match : $@convention(thin) (@owned Klass1) -> () {
// CHECK: bb0([[ARG:%.*]] :
// CHECK: destroy_value [[ARG]]
// CHECK: } // end sil function 'constant_fold_diagnose_unreachable_succ_match'
sil [ossa] @constant_fold_diagnose_unreachable_succ_match : $@convention(thin) (@owned Klass1) -> () {
bb0(%0 : @owned $Klass1):
%1 = enum $Either<Klass1, Klass2>, #Either.left!enumelt.1, %0 : $Klass1
switch_enum %1 : $Either<Klass1, Klass2>, case #Either.left!enumelt.1: bb1, default bb2
bb1(%2 : @owned $Klass1):
destroy_value %2 : $Klass1
br bb3
bb2(%3 : @owned $Either<Klass1, Klass2>):
destroy_value %3 : $Either<Klass1, Klass2>
br bb3
bb3:
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @constant_fold_diagnose_unreachable_default : $@convention(thin) (@owned Klass2) -> () {
// CHECK: bb0([[ARG:%.*]] :
// CHECK: [[ENUM:%.*]] = enum $Either<Klass1, Klass2>, #Either.right!enumelt.1, [[ARG]]
// CHECK: destroy_value [[ENUM]]
// CHECK: } // end sil function 'constant_fold_diagnose_unreachable_default'
sil [ossa] @constant_fold_diagnose_unreachable_default : $@convention(thin) (@owned Klass2) -> () {
bb0(%0 : @owned $Klass2):
%1 = enum $Either<Klass1, Klass2>, #Either.right!enumelt.1, %0 : $Klass2
switch_enum %1 : $Either<Klass1, Klass2>, case #Either.left!enumelt.1: bb1, default bb2
bb1(%2 : @owned $Klass1):
destroy_value %2 : $Klass1
br bb3
bb2(%3 : @owned $Either<Klass1, Klass2>):
destroy_value %3 : $Either<Klass1, Klass2>
br bb3
bb3:
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @eliminate_end_borrow_when_propagating_bb_args : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
// CHECK-NOT: end_borrow
// CHECK: [[FUNC_REF:%.*]] = function_ref @guaranteed_nativeobject_user
// CHECK-NEXT: apply [[FUNC_REF]](%0) :
// CHECK-NOT: end_borrow
// CHECK: } // end sil function 'eliminate_end_borrow_when_propagating_bb_args'
sil [ossa] @eliminate_end_borrow_when_propagating_bb_args : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
bb0(%0 : @guaranteed $Builtin.NativeObject):
br bb1(%0 : $Builtin.NativeObject)
bb1(%1 : @guaranteed $Builtin.NativeObject):
%2 = function_ref @guaranteed_nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %2(%1) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
end_borrow %1 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}