Files
swift-mirror/test/SILOptimizer/simplify_cfg_ossa_switch_enum.sil
Erik Eckstein 18063707b5 Optimizer: enable complete OSSA lifetimes throughout the pass pipeline
This new OSSA invariant simplifies many optimizations because they don't have to take care of the corner case of incomplete lifetimes in dead-end blocks.

The implementation basically consists of these changes:
* add the lifetime completion utility
* add a flag in SILFunction which tells optimization that they need to run the lifetime completion utility
* let all optimizations complete lifetimes if necessary
* enable the ownership verifier to check complete lifetimes
2026-01-22 17:41:48 +01:00

358 lines
11 KiB
Plaintext

// RUN: %target-sil-opt -test-runner %s | %FileCheck %s
class Klass {
}
enum FakeOptional<T> {
case some(T)
case none
}
enum E1 {
case A(Klass)
case B(Klass)
case C(Klass)
}
enum E2 {
case A(Klass)
case B(Klass)
case C
}
// CHECK-LABEL: sil [ossa] @test_canonicalize_switch_enum1 :
// CHECK-NOT: default
// CHECK-LABEL: } // end sil function 'test_canonicalize_switch_enum1'
sil [ossa] @test_canonicalize_switch_enum1 : $@convention(thin) (@owned FakeOptional<Klass>) -> () {
bb0(%0 : @owned $FakeOptional<Klass>):
specify_test "simplify_cfg_canonicalize_switch_enum"
switch_enum %0 : $FakeOptional<Klass>, case #FakeOptional.none!enumelt: bb1, default bb2
bb1:
br bb3
bb2(%5 : @owned $Klass):
destroy_value %5 : $Klass
br bb3
bb3:
%t = tuple ()
return %t : $()
}
// CHECK-LABEL: sil [ossa] @test_canonicalize_switch_enum2 :
// CHECK: default
// CHECK-LABEL: } // end sil function 'test_canonicalize_switch_enum2'
sil [ossa] @test_canonicalize_switch_enum2 : $@convention(thin) (@owned E1) -> () {
bb0(%0 : @owned $E1):
specify_test "simplify_cfg_canonicalize_switch_enum"
switch_enum %0 : $E1, case #E1.A!enumelt: bb1, default bb2
bb1(%2 : @owned $Klass):
destroy_value %2 : $Klass
br bb3
bb2(%5 : @owned $E1):
destroy_value %5 : $E1
br bb3
bb3:
%t = tuple ()
return %t : $()
}
// CHECK-LABEL: sil [ossa] @test_canonicalize_switch_enum3 :
// CHECK: default
// CHECK-LABEL: } // end sil function 'test_canonicalize_switch_enum3'
sil [ossa] @test_canonicalize_switch_enum3 : $@convention(thin) (@owned E2) -> () {
bb0(%0 : @owned $E2):
specify_test "simplify_cfg_canonicalize_switch_enum"
switch_enum %0 : $E2, case #E2.A!enumelt: bb1, default bb2
bb1(%2 : @owned $Klass):
destroy_value %2 : $Klass
br bb3
bb2(%5 : @owned $E2):
destroy_value %5 : $E2
br bb3
bb3:
%t = tuple ()
return %t : $()
}
// CHECK-LABEL: sil [ossa] @test_simplify_switch_enum1 :
// CHECK-NOT: switch_enum
// CHECK-LABEL: } // end sil function 'test_simplify_switch_enum1'
sil [ossa] @test_simplify_switch_enum1 : $@convention(thin) (@owned Klass) -> () {
bb0(%0 : @owned $Klass):
specify_test "simplify_cfg_simplify_switch_enum_block @instruction[1]"
%1 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %0 : $Klass
switch_enum %1 : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2
bb2:
br bb3
bb1(%3 : @owned $Klass):
destroy_value %3 : $Klass
br bb3
bb3:
%t = tuple ()
return %t : $()
}
// CHECK-LABEL: sil [ossa] @test_simplify_switch_enum2 :
// CHECK-NOT: switch_enum
// CHECK-LABEL: } // end sil function 'test_simplify_switch_enum2'
sil [ossa] @test_simplify_switch_enum2 : $@convention(thin) (@guaranteed Klass) -> () {
bb0(%0 : @guaranteed $Klass):
specify_test "simplify_cfg_simplify_switch_enum_block @instruction[1]"
%1 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %0 : $Klass
switch_enum %1 : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2
bb2:
br bb3
bb1(%3 : @guaranteed $Klass):
br bb3
bb3:
%t = tuple ()
return %t : $()
}
// CHECK-LABEL: sil [ossa] @test_simplify_switch_enum3 :
// CHECK-NOT: switch_enum
// CHECK-LABEL: } // end sil function 'test_simplify_switch_enum3'
sil [ossa] @test_simplify_switch_enum3 : $@convention(thin) (@owned Klass) -> () {
bb0(%0 : @owned $Klass):
specify_test "simplify_cfg_simplify_switch_enum_block @instruction[2]"
%b = begin_borrow %0 : $Klass
%1 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %b : $Klass
switch_enum %1 : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2
bb2:
br bb3
bb1(%3 : @guaranteed $Klass):
br bb3
bb3:
end_borrow %b : $Klass
destroy_value %0 : $Klass
%t = tuple ()
return %t : $()
}
sil @use_optional : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
// CHECK-LABEL: sil [ossa] @test_simplify_switch_enum4 :
// CHECK-NOT: switch_enum
// CHECK-LABEL: } // end sil function 'test_simplify_switch_enum4'
sil [ossa] @test_simplify_switch_enum4 : $@convention(thin) (@guaranteed Klass) -> () {
bb0(%0 : @guaranteed $Klass):
specify_test "simplify_cfg_simplify_switch_enum_block @instruction[3]"
%1 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %0 : $Klass
%f = function_ref @use_optional : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
%c = apply %f(%1) : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
switch_enum %1 : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2
bb2:
br bb3
bb1(%3 : @guaranteed $Klass):
br bb3
bb3:
%t = tuple ()
return %t : $()
}
// CHECK-LABEL: sil [ossa] @test_simplify_switch_enum5 :
// CHECK-NOT: switch_enum
// CHECK-LABEL: } // end sil function 'test_simplify_switch_enum5'
sil [ossa] @test_simplify_switch_enum5 : $@convention(thin) (@owned Klass) -> () {
bb0(%0 : @owned $Klass):
specify_test "simplify_cfg_simplify_switch_enum_block @instruction[4]"
%b = begin_borrow %0 : $Klass
%1 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %b : $Klass
%f = function_ref @use_optional : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
%c = apply %f(%1) : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
switch_enum %1 : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2
bb2:
br bb3
bb1(%3 : @guaranteed $Klass):
br bb3
bb3:
end_borrow %b : $Klass
destroy_value %0 : $Klass
%t = tuple ()
return %t : $()
}
// CHECK-LABEL: sil [ossa] @test_simplify_switch_enum6 :
// CHECK-NOT: switch_enum
// CHECK-LABEL: } // end sil function 'test_simplify_switch_enum6'
sil [ossa] @test_simplify_switch_enum6 : $@convention(thin) (@owned Klass) -> () {
bb0(%0 : @owned $Klass):
cond_br undef, bb1, bb2
bb1:
%2 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %0 : $Klass
br bb3(%2 : $FakeOptional<Klass>)
bb2:
%4 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %0 : $Klass
br bb3(%4 : $FakeOptional<Klass>)
bb3(%6 :@owned $FakeOptional<Klass>):
specify_test "simplify_cfg_simplify_switch_enum_block @instruction[5]"
switch_enum %6 : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb4, case #FakeOptional.none!enumelt: bb5
bb4(%8 : @owned $Klass):
destroy_value %8 : $Klass
br bb6
bb5:
br bb6
bb6:
%t = tuple ()
return %t : $()
}
// CHECK-LABEL: sil [ossa] @test_simplify_switch_enum_unreachable2 :
// CHECK-NOT: switch_enum
// CHECK-LABEL: } // end sil function 'test_simplify_switch_enum_unreachable2'
sil [ossa] @test_simplify_switch_enum_unreachable2 : $@convention(thin) (@owned Klass) -> () {
bb0(%0 : @owned $Klass):
specify_test "simplify_cfg_simplify_switch_enum_unreachable_blocks @instruction[1]"
%1 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %0 : $Klass
switch_enum %1 : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2
bb2:
unreachable
bb1(%3 : @owned $Klass):
destroy_value %3 : $Klass
br bb3
bb3:
%t = tuple ()
return %t : $()
}
// CHECK-LABEL: sil [ossa] @test_simplify_switch_enum_unreachable3 :
// CHECK-NOT: switch_enum
// CHECK-LABEL: } // end sil function 'test_simplify_switch_enum_unreachable3'
sil [ossa] @test_simplify_switch_enum_unreachable3 : $@convention(thin) (@owned Klass) -> () {
bb0(%0 : @owned $Klass):
specify_test "simplify_cfg_simplify_switch_enum_unreachable_blocks @instruction[1]"
%1 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %0 : $Klass
switch_enum %1 : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2
bb2:
br bb3
bb1(%3 : @owned $Klass):
destroy_value %3 : $Klass
unreachable
bb3:
%t = tuple ()
return %t : $()
}
// CHECK-LABEL: sil [ossa] @test_simplify_switch_enum_unreachable4 :
// CHECK-NOT: switch_enum
// CHECK-LABEL: } // end sil function 'test_simplify_switch_enum_unreachable4'
sil [ossa] @test_simplify_switch_enum_unreachable4 : $@convention(thin) (@guaranteed Klass) -> () {
bb0(%0 : @guaranteed $Klass):
specify_test "simplify_cfg_simplify_switch_enum_unreachable_blocks @instruction[1]"
%1 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %0 : $Klass
switch_enum %1 : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2
bb2:
unreachable
bb1(%3 : @guaranteed $Klass):
unreachable
bb3:
%t = tuple ()
return %t : $()
}
// CHECK-LABEL: sil [ossa] @test_simplify_switch_enum_unreachable5 :
// CHECK-NOT: switch_enum
// CHECK-LABEL: } // end sil function 'test_simplify_switch_enum_unreachable5'
sil [ossa] @test_simplify_switch_enum_unreachable5 : $@convention(thin) (@owned Klass) -> () {
bb0(%0 : @owned $Klass):
specify_test "simplify_cfg_simplify_switch_enum_unreachable_blocks @instruction[2]"
%b = begin_borrow %0 : $Klass
%1 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %b : $Klass
switch_enum %1 : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2
bb2:
end_borrow %b
destroy_value [dead_end] %0
unreachable
bb1(%3 : @guaranteed $Klass):
end_borrow %b
destroy_value [dead_end] %0
unreachable
}
// CHECK-LABEL: sil [ossa] @test_simplify_switch_enum_unreachable6 :
// CHECK-NOT: switch_enum
// CHECK-LABEL: } // end sil function 'test_simplify_switch_enum_unreachable6'
sil [ossa] @test_simplify_switch_enum_unreachable6 : $@convention(thin) (@guaranteed Klass) -> () {
bb0(%0 : @guaranteed $Klass):
specify_test "simplify_cfg_simplify_switch_enum_unreachable_blocks @instruction[1]"
%1 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %0 : $Klass
switch_enum %1 : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2
bb2:
unreachable
bb1(%3 : @guaranteed $Klass):
br bb3
bb3:
%t = tuple ()
return %t : $()
}
// CHECK-LABEL: sil [ossa] @test_simplify_switch_enum_unreachable7 :
// CHECK-NOT: switch_enum
// CHECK-LABEL: } // end sil function 'test_simplify_switch_enum_unreachable7'
sil [ossa] @test_simplify_switch_enum_unreachable7 : $@convention(thin) (@owned Klass) -> () {
bb0(%0 : @owned $Klass):
specify_test "simplify_cfg_simplify_switch_enum_unreachable_blocks @instruction[2]"
%b = begin_borrow %0 : $Klass
%1 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %b : $Klass
switch_enum %1 : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2
bb2:
end_borrow %b
destroy_value [dead_end] %0
unreachable
bb1(%3 : @guaranteed $Klass):
br bb3
bb3:
end_borrow %b : $Klass
destroy_value %0 : $Klass
%t = tuple ()
return %t : $()
}