| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 |
| ; RUN: opt < %s -passes=simplifycfg -S | FileCheck %s |
| |
| ; The compared value 4 has no explicit case, and the remapped value 6 maps to |
| ; a real (non-default) case, so switching on %x needs a new explicit case for |
| ; 4 pointing to bb2. |
| define void @test_remap_add_case(i8 %x) !prof !0 { |
| ; CHECK-LABEL: define void @test_remap_add_case( |
| ; CHECK-SAME: i8 [[X:%.*]]) !prof [[PROF0:![0-9]+]] { |
| ; CHECK-NEXT: switch i8 [[X]], label %[[BB1:.*]] [ |
| ; CHECK-NEXT: i8 6, label %[[BB2:.*]] |
| ; CHECK-NEXT: i8 10, label %[[BB3:.*]] |
| ; CHECK-NEXT: i8 4, label %[[BB2]] |
| ; CHECK-NEXT: ], !prof [[PROF1:![0-9]+]] |
| ; CHECK: [[BB1]]: |
| ; CHECK-NEXT: call void @func1() |
| ; CHECK-NEXT: unreachable |
| ; CHECK: [[BB2]]: |
| ; CHECK-NEXT: call void @func2() |
| ; CHECK-NEXT: unreachable |
| ; CHECK: [[BB3]]: |
| ; CHECK-NEXT: call void @func3() |
| ; CHECK-NEXT: unreachable |
| ; |
| %cmp = icmp eq i8 %x, 4 |
| %key = select i1 %cmp, i8 6, i8 %x, !prof !1 |
| switch i8 %key, label %bb1 [ |
| i8 6, label %bb2 |
| i8 10, label %bb3 |
| ], !prof !2 |
| |
| bb1: |
| call void @func1() |
| unreachable |
| bb2: |
| call void @func2() |
| unreachable |
| bb3: |
| call void @func3() |
| unreachable |
| } |
| |
| define void @test_remap_profile_undeflow(i8 %x) !prof !0 { |
| ; CHECK-LABEL: define void @test_remap_profile_undeflow( |
| ; CHECK-SAME: i8 [[X:%.*]]) !prof [[PROF0]] { |
| ; CHECK-NEXT: switch i8 [[X]], label %[[BB1:.*]] [ |
| ; CHECK-NEXT: i8 6, label %[[BB2:.*]] |
| ; CHECK-NEXT: i8 10, label %[[BB3:.*]] |
| ; CHECK-NEXT: i8 4, label %[[BB2]] |
| ; CHECK-NEXT: ], !prof [[PROF2:![0-9]+]] |
| ; CHECK: [[BB1]]: |
| ; CHECK-NEXT: call void @func1() |
| ; CHECK-NEXT: unreachable |
| ; CHECK: [[BB2]]: |
| ; CHECK-NEXT: call void @func2() |
| ; CHECK-NEXT: unreachable |
| ; CHECK: [[BB3]]: |
| ; CHECK-NEXT: call void @func3() |
| ; CHECK-NEXT: unreachable |
| ; |
| %cmp = icmp eq i8 %x, 4 |
| %key = select i1 %cmp, i8 6, i8 %x, !prof !1 |
| switch i8 %key, label %bb1 [ |
| i8 6, label %bb2 |
| i8 10, label %bb3 |
| ], !prof !5 |
| |
| bb1: |
| call void @func1() |
| unreachable |
| bb2: |
| call void @func2() |
| unreachable |
| bb3: |
| call void @func3() |
| unreachable |
| } |
| |
| define void @test_remap_only_switch_profile(i8 %x) !prof !0 { |
| ; CHECK-LABEL: define void @test_remap_only_switch_profile( |
| ; CHECK-SAME: i8 [[X:%.*]]) !prof [[PROF0]] { |
| ; CHECK-NEXT: switch i8 [[X]], label %[[BB1:.*]] [ |
| ; CHECK-NEXT: i8 6, label %[[BB2:.*]] |
| ; CHECK-NEXT: i8 10, label %[[BB3:.*]] |
| ; CHECK-NEXT: i8 4, label %[[BB2]] |
| ; CHECK-NEXT: ], !prof [[PROF3:![0-9]+]] |
| ; CHECK: [[BB1]]: |
| ; CHECK-NEXT: call void @func1() |
| ; CHECK-NEXT: unreachable |
| ; CHECK: [[BB2]]: |
| ; CHECK-NEXT: call void @func2() |
| ; CHECK-NEXT: unreachable |
| ; CHECK: [[BB3]]: |
| ; CHECK-NEXT: call void @func3() |
| ; CHECK-NEXT: unreachable |
| ; |
| %cmp = icmp eq i8 %x, 4 |
| %key = select i1 %cmp, i8 6, i8 %x |
| switch i8 %key, label %bb1 [ |
| i8 6, label %bb2 |
| i8 10, label %bb3 |
| ], !prof !2 |
| |
| bb1: |
| call void @func1() |
| unreachable |
| bb2: |
| call void @func2() |
| unreachable |
| bb3: |
| call void @func3() |
| unreachable |
| } |
| |
| define void @test_remap_only_switch_profile_unprofiled_function(i8 %x) { |
| ; CHECK-LABEL: define void @test_remap_only_switch_profile_unprofiled_function( |
| ; CHECK-SAME: i8 [[X:%.*]]) { |
| ; CHECK-NEXT: switch i8 [[X]], label %[[BB1:.*]] [ |
| ; CHECK-NEXT: i8 6, label %[[BB2:.*]] |
| ; CHECK-NEXT: i8 10, label %[[BB3:.*]] |
| ; CHECK-NEXT: i8 4, label %[[BB2]] |
| ; CHECK-NEXT: ] |
| ; CHECK: [[BB1]]: |
| ; CHECK-NEXT: call void @func1() |
| ; CHECK-NEXT: unreachable |
| ; CHECK: [[BB2]]: |
| ; CHECK-NEXT: call void @func2() |
| ; CHECK-NEXT: unreachable |
| ; CHECK: [[BB3]]: |
| ; CHECK-NEXT: call void @func3() |
| ; CHECK-NEXT: unreachable |
| ; |
| %cmp = icmp eq i8 %x, 4 |
| %key = select i1 %cmp, i8 6, i8 %x |
| switch i8 %key, label %bb1 [ |
| i8 6, label %bb2 |
| i8 10, label %bb3 |
| ], !prof !2 |
| |
| bb1: |
| call void @func1() |
| unreachable |
| bb2: |
| call void @func2() |
| unreachable |
| bb3: |
| call void @func3() |
| unreachable |
| } |
| |
| ; The value 4 already has an explicit case pointing to bb4, but %key can never |
| ; actually be 4 (it's remapped to 6 whenever %x is 4), so that case is really |
| ; dead and should be retargeted to wherever the remapped value 6 dispatches to |
| ; (bb2). Unlike the old InstCombine version of this fold, bb4 and its now-dead |
| ; body are removed in the same run: this pass edits the CFG through a |
| ; DomTreeUpdater, so a follow-up SimplifyCFG iteration cleans it up |
| ; immediately instead of needing a separate pass. |
| define void @test_remap_retarget_case(i8 %x) !prof !0 { |
| ; CHECK-LABEL: define void @test_remap_retarget_case( |
| ; CHECK-SAME: i8 [[X:%.*]]) !prof [[PROF0]] { |
| ; CHECK-NEXT: switch i8 [[X]], label %[[BB1:.*]] [ |
| ; CHECK-NEXT: i8 4, label %[[BB2:.*]] |
| ; CHECK-NEXT: i8 6, label %[[BB2]] |
| ; CHECK-NEXT: i8 10, label %[[BB3:.*]] |
| ; CHECK-NEXT: ], !prof [[PROF4:![0-9]+]] |
| ; CHECK: [[BB1]]: |
| ; CHECK-NEXT: call void @func1() |
| ; CHECK-NEXT: unreachable |
| ; CHECK: [[BB2]]: |
| ; CHECK-NEXT: call void @func2() |
| ; CHECK-NEXT: unreachable |
| ; CHECK: [[BB3]]: |
| ; CHECK-NEXT: call void @func3() |
| ; CHECK-NEXT: unreachable |
| ; |
| %cmp = icmp eq i8 %x, 4 |
| %key = select i1 %cmp, i8 6, i8 %x, !prof !1 |
| switch i8 %key, label %bb1 [ |
| i8 4, label %bb4 |
| i8 6, label %bb2 |
| i8 10, label %bb3 |
| ], !prof !3 |
| |
| bb1: |
| call void @func1() |
| unreachable |
| bb2: |
| call void @func2() |
| unreachable |
| bb3: |
| call void @func3() |
| unreachable |
| bb4: |
| call void @func4() |
| unreachable |
| } |
| |
| ; Same remap expressed with icmp ne / select(cond, %x, 6). The remapped value 6 |
| ; maps to a real (non-default) case, so switching on %x needs a new explicit |
| ; case for 4 pointing to bb2, same as test_remap_add_case but via the NE arm. |
| define void @test_remap_ne_add_case(i8 %x) !prof !0 { |
| ; CHECK-LABEL: define void @test_remap_ne_add_case( |
| ; CHECK-SAME: i8 [[X:%.*]]) !prof [[PROF0]] { |
| ; CHECK-NEXT: switch i8 [[X]], label %[[BB1:.*]] [ |
| ; CHECK-NEXT: i8 6, label %[[BB2:.*]] |
| ; CHECK-NEXT: i8 10, label %[[BB3:.*]] |
| ; CHECK-NEXT: i8 4, label %[[BB2]] |
| ; CHECK-NEXT: ], !prof [[PROF1]] |
| ; CHECK: [[BB1]]: |
| ; CHECK-NEXT: call void @func1() |
| ; CHECK-NEXT: unreachable |
| ; CHECK: [[BB2]]: |
| ; CHECK-NEXT: call void @func2() |
| ; CHECK-NEXT: unreachable |
| ; CHECK: [[BB3]]: |
| ; CHECK-NEXT: call void @func3() |
| ; CHECK-NEXT: unreachable |
| ; |
| %cmp = icmp ne i8 %x, 4 |
| %key = select i1 %cmp, i8 %x, i8 6, !prof !4 |
| switch i8 %key, label %bb1 [ |
| i8 6, label %bb2 |
| i8 10, label %bb3 |
| ], !prof !2 |
| |
| bb1: |
| call void @func1() |
| unreachable |
| bb2: |
| call void @func2() |
| unreachable |
| bb3: |
| call void @func3() |
| unreachable |
| } |
| |
| ; Same shape as test_remap_add_case, but the target of the remapped case (bb2) |
| ; has a PHI node. Adding the new case for 4 creates a second edge from this |
| ; block into bb2, so the PHI needs a matching second incoming entry - without |
| ; it this used to hit "Invalid basic block argument to remove!" deep in a |
| ; later pass once something tried to prune one of the two entry edges. |
| define void @test_remap_add_case_phi(i8 %x, i32 %a) { |
| ; CHECK-LABEL: define void @test_remap_add_case_phi( |
| ; CHECK-SAME: i8 [[X:%.*]], i32 [[A:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*]]: |
| ; CHECK-NEXT: switch i8 [[X]], label %[[BB1:.*]] [ |
| ; CHECK-NEXT: i8 6, label %[[BB2:.*]] |
| ; CHECK-NEXT: i8 10, label %[[BB3:.*]] |
| ; CHECK-NEXT: i8 4, label %[[BB2]] |
| ; CHECK-NEXT: ] |
| ; CHECK: [[BB1]]: |
| ; CHECK-NEXT: call void @func1() |
| ; CHECK-NEXT: unreachable |
| ; CHECK: [[BB2]]: |
| ; CHECK-NEXT: [[V:%.*]] = phi i32 [ [[A]], %[[ENTRY]] ], [ [[A]], %[[ENTRY]] ] |
| ; CHECK-NEXT: call void @use(i32 [[V]]) |
| ; CHECK-NEXT: unreachable |
| ; CHECK: [[BB3]]: |
| ; CHECK-NEXT: call void @func3() |
| ; CHECK-NEXT: unreachable |
| ; |
| entry: |
| %cmp = icmp eq i8 %x, 4 |
| %key = select i1 %cmp, i8 6, i8 %x |
| switch i8 %key, label %bb1 [ |
| i8 6, label %bb2 |
| i8 10, label %bb3 |
| ] |
| |
| bb1: |
| call void @func1() |
| unreachable |
| bb2: |
| %v = phi i32 [%a, %entry] |
| call void @use(i32 %v) |
| unreachable |
| bb3: |
| call void @func3() |
| unreachable |
| } |
| |
| ; Same shape as test_remap_retarget_case, but both the remapped case's target |
| ; (bb2) and the retargeted-away-from block (bb4) have PHI nodes: bb2 needs a |
| ; second incoming entry for the new edge, and bb4 (along with its now-stale |
| ; PHI entry) is removed once it becomes unreachable. |
| define void @test_remap_retarget_case_phi(i8 %x, i32 %a, i32 %c4) { |
| ; CHECK-LABEL: define void @test_remap_retarget_case_phi( |
| ; CHECK-SAME: i8 [[X:%.*]], i32 [[A:%.*]], i32 [[C4:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*]]: |
| ; CHECK-NEXT: switch i8 [[X]], label %[[BB1:.*]] [ |
| ; CHECK-NEXT: i8 4, label %[[BB2:.*]] |
| ; CHECK-NEXT: i8 6, label %[[BB2]] |
| ; CHECK-NEXT: i8 10, label %[[BB3:.*]] |
| ; CHECK-NEXT: ] |
| ; CHECK: [[BB1]]: |
| ; CHECK-NEXT: call void @func1() |
| ; CHECK-NEXT: unreachable |
| ; CHECK: [[BB2]]: |
| ; CHECK-NEXT: [[V:%.*]] = phi i32 [ [[A]], %[[ENTRY]] ], [ [[A]], %[[ENTRY]] ] |
| ; CHECK-NEXT: call void @use(i32 [[V]]) |
| ; CHECK-NEXT: unreachable |
| ; CHECK: [[BB3]]: |
| ; CHECK-NEXT: call void @func3() |
| ; CHECK-NEXT: unreachable |
| ; |
| entry: |
| %cmp = icmp eq i8 %x, 4 |
| %key = select i1 %cmp, i8 6, i8 %x |
| switch i8 %key, label %bb1 [ |
| i8 4, label %bb4 |
| i8 6, label %bb2 |
| i8 10, label %bb3 |
| ] |
| |
| bb1: |
| call void @func1() |
| unreachable |
| bb2: |
| %v = phi i32 [%a, %entry] |
| call void @use(i32 %v) |
| unreachable |
| bb3: |
| call void @func3() |
| unreachable |
| bb4: |
| %w = phi i32 [%c4, %entry] |
| call void @use(i32 %w) |
| unreachable |
| } |
| |
| ; K (the remapped-to value) has no explicit case of its own, so it already |
| ; dispatches to the default destination - same as the (also absent) compared |
| ; value C would. %x can be switched on directly with no case-list change. |
| define void @test_remap_k_default_add(i8 %x) !prof !0 { |
| ; CHECK-LABEL: define void @test_remap_k_default_add( |
| ; CHECK-SAME: i8 [[X:%.*]]) !prof [[PROF0]] { |
| ; CHECK-NEXT: switch i8 [[X]], label %[[DEFAULT:.*]] [ |
| ; CHECK-NEXT: i8 1, label %[[BB1:.*]] |
| ; CHECK-NEXT: i8 2, label %[[BB2:.*]] |
| ; CHECK-NEXT: ], !prof [[PROF5:![0-9]+]] |
| ; CHECK: [[BB1]]: |
| ; CHECK-NEXT: call void @func1() |
| ; CHECK-NEXT: unreachable |
| ; CHECK: [[BB2]]: |
| ; CHECK-NEXT: call void @func2() |
| ; CHECK-NEXT: unreachable |
| ; CHECK: [[DEFAULT]]: |
| ; CHECK-NEXT: call void @func3() |
| ; CHECK-NEXT: unreachable |
| ; |
| %cmp = icmp eq i8 %x, 4 |
| %key = select i1 %cmp, i8 6, i8 %x, !prof !1 |
| switch i8 %key, label %default [ |
| i8 1, label %bb1 |
| i8 2, label %bb2 |
| ], !prof !2 |
| |
| bb1: |
| call void @func1() |
| unreachable |
| bb2: |
| call void @func2() |
| unreachable |
| default: |
| call void @func3() |
| unreachable |
| } |
| |
| ; Same as above, but C (4) already has an explicit (and, before the fold, |
| ; unreachable) case pointing to bb4. Since K dispatches to the default |
| ; destination, that stale case must be retargeted there too rather than left |
| ; on bb4 - otherwise a now-reachable X == 4 would wrongly branch to bb4 |
| ; instead of falling through to default like case K does. (SimplifyCFG then |
| ; goes on to fold the resulting two-arm switch into a plain icmp/br, which is |
| ; an unrelated, separate simplification.) |
| define void @test_remap_k_default_retarget(i8 %x) { |
| ; CHECK-LABEL: define void @test_remap_k_default_retarget( |
| ; CHECK-SAME: i8 [[X:%.*]]) { |
| ; CHECK-NEXT: [[COND:%.*]] = icmp eq i8 [[X]], 1 |
| ; CHECK-NEXT: br i1 [[COND]], label %[[BB1:.*]], label %[[DEFAULT:.*]] |
| ; CHECK: [[BB1]]: |
| ; CHECK-NEXT: call void @func1() |
| ; CHECK-NEXT: unreachable |
| ; CHECK: [[DEFAULT]]: |
| ; CHECK-NEXT: call void @func3() |
| ; CHECK-NEXT: unreachable |
| ; |
| %cmp = icmp eq i8 %x, 4 |
| %key = select i1 %cmp, i8 6, i8 %x |
| switch i8 %key, label %default [ |
| i8 4, label %bb4 |
| i8 1, label %bb1 |
| ] |
| |
| bb4: |
| call void @func4() |
| unreachable |
| bb1: |
| call void @func1() |
| unreachable |
| default: |
| call void @func3() |
| unreachable |
| } |
| |
| ; %x is a PHI in the switch's own block and the stale case for 4 branches back |
| ; to it. Retargeting that case removes the self-edge and folds the PHI away; |
| ; the switch used to be left pointing at the erased PHI (GH223138). |
| define void @test_remap_retarget_self_loop_phi(i8 %a, i8 %b) { |
| ; CHECK-LABEL: define void @test_remap_retarget_self_loop_phi( |
| ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*]]: |
| ; CHECK-NEXT: switch i8 [[A]], label %[[BB1:.*]] [ |
| ; CHECK-NEXT: i8 4, label %[[BB2:.*]] |
| ; CHECK-NEXT: i8 6, label %[[BB2]] |
| ; CHECK-NEXT: i8 10, label %[[BB3:.*]] |
| ; CHECK-NEXT: ] |
| ; CHECK: [[BB1]]: |
| ; CHECK-NEXT: call void @func1() |
| ; CHECK-NEXT: unreachable |
| ; CHECK: [[BB2]]: |
| ; CHECK-NEXT: call void @func2() |
| ; CHECK-NEXT: unreachable |
| ; CHECK: [[BB3]]: |
| ; CHECK-NEXT: call void @func3() |
| ; CHECK-NEXT: unreachable |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %x = phi i8 [ %a, %entry ], [ %b, %loop ] |
| %cmp = icmp eq i8 %x, 4 |
| %key = select i1 %cmp, i8 6, i8 %x |
| switch i8 %key, label %bb1 [ |
| i8 4, label %loop |
| i8 6, label %bb2 |
| i8 10, label %bb3 |
| ] |
| |
| bb1: |
| call void @func1() |
| unreachable |
| bb2: |
| call void @func2() |
| unreachable |
| bb3: |
| call void @func3() |
| unreachable |
| } |
| |
| ; Negative test: %key (the select) is used by more than just the switch, so |
| ; folding it away wouldn't actually remove the compare/select sequence - |
| ; leave it alone. |
| define void @test_remap_multiuse_select(i8 %x, ptr %p) { |
| ; CHECK-LABEL: define void @test_remap_multiuse_select( |
| ; CHECK-SAME: i8 [[X:%.*]], ptr [[P:%.*]]) { |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X]], 4 |
| ; CHECK-NEXT: [[KEY:%.*]] = select i1 [[CMP]], i8 6, i8 [[X]] |
| ; CHECK-NEXT: store i8 [[KEY]], ptr [[P]], align 1 |
| ; CHECK-NEXT: switch i8 [[KEY]], label %[[BB1:.*]] [ |
| ; CHECK-NEXT: i8 6, label %[[BB2:.*]] |
| ; CHECK-NEXT: i8 10, label %[[BB3:.*]] |
| ; CHECK-NEXT: ] |
| ; CHECK: [[BB1]]: |
| ; CHECK-NEXT: call void @func1() |
| ; CHECK-NEXT: unreachable |
| ; CHECK: [[BB2]]: |
| ; CHECK-NEXT: call void @func2() |
| ; CHECK-NEXT: unreachable |
| ; CHECK: [[BB3]]: |
| ; CHECK-NEXT: call void @func3() |
| ; CHECK-NEXT: unreachable |
| ; |
| %cmp = icmp eq i8 %x, 4 |
| %key = select i1 %cmp, i8 6, i8 %x |
| store i8 %key, ptr %p |
| switch i8 %key, label %bb1 [ |
| i8 6, label %bb2 |
| i8 10, label %bb3 |
| ] |
| |
| bb1: |
| call void @func1() |
| unreachable |
| bb2: |
| call void @func2() |
| unreachable |
| bb3: |
| call void @func3() |
| unreachable |
| } |
| |
| ; The compare (%cmp) is used by more than just the select, but that's fine - |
| ; only the select itself needs to be single-use for the fold to remove it; |
| ; %cmp is left alone for its other use. |
| define void @test_remap_multiuse_icmp(i8 %x, ptr %p) { |
| ; CHECK-LABEL: define void @test_remap_multiuse_icmp( |
| ; CHECK-SAME: i8 [[X:%.*]], ptr [[P:%.*]]) { |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X]], 4 |
| ; CHECK-NEXT: store i1 [[CMP]], ptr [[P]], align 1 |
| ; CHECK-NEXT: switch i8 [[X]], label %[[BB1:.*]] [ |
| ; CHECK-NEXT: i8 6, label %[[BB2:.*]] |
| ; CHECK-NEXT: i8 10, label %[[BB3:.*]] |
| ; CHECK-NEXT: i8 4, label %[[BB2]] |
| ; CHECK-NEXT: ] |
| ; CHECK: [[BB1]]: |
| ; CHECK-NEXT: call void @func1() |
| ; CHECK-NEXT: unreachable |
| ; CHECK: [[BB2]]: |
| ; CHECK-NEXT: call void @func2() |
| ; CHECK-NEXT: unreachable |
| ; CHECK: [[BB3]]: |
| ; CHECK-NEXT: call void @func3() |
| ; CHECK-NEXT: unreachable |
| ; |
| %cmp = icmp eq i8 %x, 4 |
| store i1 %cmp, ptr %p |
| %key = select i1 %cmp, i8 6, i8 %x |
| switch i8 %key, label %bb1 [ |
| i8 6, label %bb2 |
| i8 10, label %bb3 |
| ] |
| |
| bb1: |
| call void @func1() |
| unreachable |
| bb2: |
| call void @func2() |
| unreachable |
| bb3: |
| call void @func3() |
| unreachable |
| } |
| |
| ; Negative test: the select's non-constant arm (%y) doesn't match the icmp's |
| ; non-constant operand (%x), so this isn't a same-value remap and must not |
| ; be folded. |
| define void @test_remap_mismatched_operand(i8 %x, i8 %y) { |
| ; CHECK-LABEL: define void @test_remap_mismatched_operand( |
| ; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) { |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X]], 4 |
| ; CHECK-NEXT: [[KEY:%.*]] = select i1 [[CMP]], i8 6, i8 [[Y]] |
| ; CHECK-NEXT: switch i8 [[KEY]], label %[[BB1:.*]] [ |
| ; CHECK-NEXT: i8 6, label %[[BB2:.*]] |
| ; CHECK-NEXT: i8 10, label %[[BB3:.*]] |
| ; CHECK-NEXT: ] |
| ; CHECK: [[BB1]]: |
| ; CHECK-NEXT: call void @func1() |
| ; CHECK-NEXT: unreachable |
| ; CHECK: [[BB2]]: |
| ; CHECK-NEXT: call void @func2() |
| ; CHECK-NEXT: unreachable |
| ; CHECK: [[BB3]]: |
| ; CHECK-NEXT: call void @func3() |
| ; CHECK-NEXT: unreachable |
| ; |
| %cmp = icmp eq i8 %x, 4 |
| %key = select i1 %cmp, i8 6, i8 %y |
| switch i8 %key, label %bb1 [ |
| i8 6, label %bb2 |
| i8 10, label %bb3 |
| ] |
| |
| bb1: |
| call void @func1() |
| unreachable |
| bb2: |
| call void @func2() |
| unreachable |
| bb3: |
| call void @func3() |
| unreachable |
| } |
| |
| declare void @func1() |
| declare void @func2() |
| declare void @func3() |
| declare void @func4() |
| declare void @use(i32) |
| |
| !0 = !{!"function_entry_count", i32 10} |
| !1 = !{!"branch_weights", i32 2, i32 3} |
| !2 = !{!"branch_weights", i32 5, i32 11, i32 7} |
| !3 = !{!"branch_weights", i32 5, i32 0, i32 11, i32 7} |
| !4 = !{!"branch_weights", i32 3, i32 2} |
| !5 = !{!"branch_weights", i32 5, i32 7, i32 11} |
| ;. |
| ; CHECK: [[PROF0]] = !{!"function_entry_count", i32 10} |
| ; CHECK: [[PROF1]] = !{!"branch_weights", i32 25, i32 9, i32 35, i32 46} |
| ; CHECK: [[PROF2]] = !{!"branch_weights", i32 25, i32 0, i32 55, i32 46} |
| ; CHECK: [[PROF3]] = !{!"unknown", !"simplifycfg"} |
| ; CHECK: [[PROF4]] = !{!"branch_weights", i32 25, i32 46, i32 9, i32 35} |
| ; CHECK: [[PROF5]] = !{!"branch_weights", i32 5, i32 11, i32 7} |
| ;. |