| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt %s -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s |
| |
| define i32 @default_branch_proves_operand_value(i8 %x) { |
| ; CHECK-LABEL: @default_branch_proves_operand_value( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: switch i8 [[X:%.*]], label [[ENTRY_UNREACHABLEDEFAULT:%.*]] [ |
| ; CHECK-NEXT: i8 -1, label [[RETURN:%.*]] |
| ; CHECK-NEXT: i8 0, label [[CASE_ZERO:%.*]] |
| ; CHECK-NEXT: i8 1, label [[DEFAULT:%.*]] |
| ; CHECK-NEXT: ] |
| ; CHECK: entry.unreachabledefault: |
| ; CHECK-NEXT: unreachable |
| ; CHECK: default: |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X]], 1 |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) |
| ; CHECK-NEXT: br label [[RETURN]] |
| ; CHECK: case_zero: |
| ; CHECK-NEXT: br label [[RETURN]] |
| ; CHECK: return: |
| ; CHECK-NEXT: [[RETVAL:%.*]] = phi i32 [ 1, [[DEFAULT]] ], [ 0, [[CASE_ZERO]] ], [ -1, [[ENTRY:%.*]] ] |
| ; CHECK-NEXT: ret i32 [[RETVAL]] |
| ; |
| entry: |
| switch i8 %x, label %default [ |
| i8 -1, label %case_neg_one |
| i8 0, label %case_zero |
| ] |
| default: |
| %cmp = icmp eq i8 %x, 1 |
| call void @llvm.assume(i1 %cmp) |
| br label %return |
| |
| case_neg_one: |
| br label %return |
| |
| case_zero: |
| br label %return |
| |
| return: |
| %retval = phi i32 [ 1, %default ], [ -1, %case_neg_one ], [ 0, %case_zero ] |
| ret i32 %retval |
| } |
| |
| define i32 @default_branch_with_weight_proves_operand_value(i8 %x) { |
| ; CHECK-LABEL: @default_branch_with_weight_proves_operand_value( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: switch i8 [[X:%.*]], label [[ENTRY_UNREACHABLEDEFAULT:%.*]] [ |
| ; CHECK-NEXT: i8 -1, label [[RETURN:%.*]] |
| ; CHECK-NEXT: i8 0, label [[CASE_ZERO:%.*]] |
| ; CHECK-NEXT: i8 1, label [[DEFAULT:%.*]] |
| ; CHECK-NEXT: ], !prof [[PROF0:![0-9]+]] |
| ; CHECK: entry.unreachabledefault: |
| ; CHECK-NEXT: unreachable |
| ; CHECK: default: |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X]], 1 |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) |
| ; CHECK-NEXT: br label [[RETURN]] |
| ; CHECK: case_zero: |
| ; CHECK-NEXT: br label [[RETURN]] |
| ; CHECK: return: |
| ; CHECK-NEXT: [[RETVAL:%.*]] = phi i32 [ 1, [[DEFAULT]] ], [ 0, [[CASE_ZERO]] ], [ -1, [[ENTRY:%.*]] ] |
| ; CHECK-NEXT: ret i32 [[RETVAL]] |
| ; |
| entry: |
| switch i8 %x, label %default [ |
| i8 -1, label %case_neg_one |
| i8 0, label %case_zero |
| ], !prof !0 |
| |
| default: |
| %cmp = icmp eq i8 %x, 1 |
| call void @llvm.assume(i1 %cmp) |
| br label %return |
| |
| case_neg_one: |
| br label %return |
| |
| case_zero: |
| br label %return |
| |
| return: |
| %retval = phi i32 [ 1, %default ], [ -1, %case_neg_one ], [ 0, %case_zero ] |
| ret i32 %retval |
| } |
| |
| define i32 @default_branch_proves_operand_value_different_blocks(i8 %x) { |
| ; CHECK-LABEL: @default_branch_proves_operand_value_different_blocks( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], 1 |
| ; CHECK-NEXT: switch i8 [[X]], label [[ENTRY_UNREACHABLEDEFAULT:%.*]] [ |
| ; CHECK-NEXT: i8 -1, label [[RETURN:%.*]] |
| ; CHECK-NEXT: i8 0, label [[CASE_ZERO:%.*]] |
| ; CHECK-NEXT: i8 1, label [[DEFAULT:%.*]] |
| ; CHECK-NEXT: ] |
| ; CHECK: entry.unreachabledefault: |
| ; CHECK-NEXT: unreachable |
| ; CHECK: default: |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) |
| ; CHECK-NEXT: br label [[RETURN]] |
| ; CHECK: case_zero: |
| ; CHECK-NEXT: br label [[RETURN]] |
| ; CHECK: return: |
| ; CHECK-NEXT: [[RETVAL:%.*]] = phi i32 [ 1, [[DEFAULT]] ], [ 0, [[CASE_ZERO]] ], [ -1, [[ENTRY:%.*]] ] |
| ; CHECK-NEXT: ret i32 [[RETVAL]] |
| ; |
| entry: |
| %cmp = icmp eq i8 %x, 1 |
| switch i8 %x, label %default [ |
| i8 -1, label %case_neg_one |
| i8 0, label %case_zero |
| ] |
| default: |
| call void @llvm.assume(i1 %cmp) |
| br label %return |
| |
| case_neg_one: |
| br label %return |
| |
| case_zero: |
| br label %return |
| |
| return: |
| %retval = phi i32 [ 1, %default ], [ -1, %case_neg_one ], [ 0, %case_zero ] |
| ret i32 %retval |
| } |
| |
| declare void @foo(i8 %bar) nounwind |
| define i32 @default_branch_proves_operand_value_assume_operand_not_ephemeral(i8 %x) { |
| ; CHECK-LABEL: @default_branch_proves_operand_value_assume_operand_not_ephemeral( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: switch i8 [[X:%.*]], label [[ENTRY_UNREACHABLEDEFAULT:%.*]] [ |
| ; CHECK-NEXT: i8 -1, label [[RETURN:%.*]] |
| ; CHECK-NEXT: i8 0, label [[CASE_ZERO:%.*]] |
| ; CHECK-NEXT: i8 1, label [[DEFAULT:%.*]] |
| ; CHECK-NEXT: ] |
| ; CHECK: entry.unreachabledefault: |
| ; CHECK-NEXT: unreachable |
| ; CHECK: default: |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X]], 1 |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) |
| ; CHECK-NEXT: call void @foo(i1 [[CMP]]) |
| ; CHECK-NEXT: br label [[RETURN]] |
| ; CHECK: case_zero: |
| ; CHECK-NEXT: br label [[RETURN]] |
| ; CHECK: return: |
| ; CHECK-NEXT: [[RETVAL:%.*]] = phi i32 [ 1, [[DEFAULT]] ], [ 0, [[CASE_ZERO]] ], [ -1, [[ENTRY:%.*]] ] |
| ; CHECK-NEXT: ret i32 [[RETVAL]] |
| ; |
| entry: |
| switch i8 %x, label %default [ |
| i8 -1, label %case_neg_one |
| i8 0, label %case_zero |
| ] |
| default: |
| %cmp = icmp eq i8 %x, 1 |
| call void @llvm.assume(i1 %cmp) |
| call void @foo(i1 %cmp) |
| br label %return |
| |
| case_neg_one: |
| br label %return |
| |
| case_zero: |
| br label %return |
| |
| return: |
| %retval = phi i32 [ 1, %default ], [ -1, %case_neg_one ], [ 0, %case_zero ] |
| ret i32 %retval |
| } |
| |
| define i32 @default_branch_proves_operand_value_but_has_existing_case(i8 %x) { |
| ; CHECK-LABEL: @default_branch_proves_operand_value_but_has_existing_case( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: switch i8 [[X:%.*]], label [[ENTRY_UNREACHABLEDEFAULT:%.*]] [ |
| ; CHECK-NEXT: i8 -1, label [[RETURN:%.*]] |
| ; CHECK-NEXT: i8 0, label [[CASE_ZERO:%.*]] |
| ; CHECK-NEXT: i8 1, label [[CASE_ONE:%.*]] |
| ; CHECK-NEXT: ] |
| ; CHECK: entry.unreachabledefault: |
| ; CHECK-NEXT: unreachable |
| ; CHECK: case_zero: |
| ; CHECK-NEXT: br label [[RETURN]] |
| ; CHECK: case_one: |
| ; CHECK-NEXT: br label [[RETURN]] |
| ; CHECK: return: |
| ; CHECK-NEXT: [[RETVAL:%.*]] = phi i32 [ 1, [[CASE_ONE]] ], [ 0, [[CASE_ZERO]] ], [ -1, [[ENTRY:%.*]] ] |
| ; CHECK-NEXT: ret i32 [[RETVAL]] |
| ; |
| entry: |
| switch i8 %x, label %default [ |
| i8 -1, label %case_neg_one |
| i8 0, label %case_zero |
| i8 1, label %case_one |
| ] |
| |
| default: |
| %cmp = icmp eq i8 %x, 1 |
| call void @llvm.assume(i1 %cmp) |
| br label %return |
| |
| case_neg_one: |
| br label %return |
| |
| case_zero: |
| br label %return |
| |
| case_one: |
| br label %return |
| |
| return: |
| %retval = phi i32 [ 1, %default ], [ -1, %case_neg_one ], [ 0, %case_zero ], [1, %case_one ] |
| ret i32 %retval |
| } |
| |
| define i32 @default_branch_assume_doesnt_prove_all_bits(i8 %x) { |
| ; CHECK-LABEL: @default_branch_assume_doesnt_prove_all_bits( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: switch i8 [[X:%.*]], label [[DEFAULT:%.*]] [ |
| ; CHECK-NEXT: i8 -1, label [[RETURN:%.*]] |
| ; CHECK-NEXT: i8 0, label [[CASE_ZERO:%.*]] |
| ; CHECK-NEXT: ] |
| ; CHECK: default: |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[X]], 10 |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) |
| ; CHECK-NEXT: br label [[RETURN]] |
| ; CHECK: case_zero: |
| ; CHECK-NEXT: br label [[RETURN]] |
| ; CHECK: return: |
| ; CHECK-NEXT: [[RETVAL:%.*]] = phi i32 [ 1, [[DEFAULT]] ], [ 0, [[CASE_ZERO]] ], [ -1, [[ENTRY:%.*]] ] |
| ; CHECK-NEXT: ret i32 [[RETVAL]] |
| ; |
| entry: |
| switch i8 %x, label %default [ |
| i8 -1, label %case_neg_one |
| i8 0, label %case_zero |
| ] |
| |
| default: |
| %cmp = icmp ule i8 %x, 10 |
| call void @llvm.assume(i1 %cmp) |
| br label %return |
| |
| case_neg_one: |
| br label %return |
| |
| case_zero: |
| br label %return |
| |
| return: |
| %retval = phi i32 [ 1, %default ], [ -1, %case_neg_one ], [ 0, %case_zero ] |
| ret i32 %retval |
| } |
| |
| declare void @foo_may_unwind() |
| define i32 @default_branch_may_throw_before_assume(i8 %x) { |
| ; CHECK-LABEL: @default_branch_may_throw_before_assume( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: switch i8 [[X:%.*]], label [[ENTRY_UNREACHABLEDEFAULT:%.*]] [ |
| ; CHECK-NEXT: i8 -1, label [[RETURN:%.*]] |
| ; CHECK-NEXT: i8 0, label [[CASE_ZERO:%.*]] |
| ; CHECK-NEXT: ] |
| ; CHECK: default: |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X]], 1 |
| ; CHECK-NEXT: call void @foo_may_unwind() |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) |
| ; CHECK-NEXT: br label [[RETURN]] |
| ; CHECK: case_zero: |
| ; CHECK-NEXT: br label [[RETURN]] |
| ; CHECK: return: |
| ; CHECK-NEXT: [[RETVAL:%.*]] = phi i32 [ 1, [[ENTRY_UNREACHABLEDEFAULT]] ], [ 0, [[CASE_ZERO]] ], [ -1, [[ENTRY:%.*]] ] |
| ; CHECK-NEXT: ret i32 [[RETVAL]] |
| ; |
| entry: |
| switch i8 %x, label %default [ |
| i8 -1, label %case_neg_one |
| i8 0, label %case_zero |
| ] |
| default: |
| %cmp = icmp eq i8 %x, 1 |
| call void @foo_may_unwind() |
| call void @llvm.assume(i1 %cmp) |
| br label %return |
| |
| case_neg_one: |
| br label %return |
| |
| case_zero: |
| br label %return |
| |
| return: |
| %retval = phi i32 [ 1, %default ], [ -1, %case_neg_one ], [ 0, %case_zero ] |
| ret i32 %retval |
| } |
| |
| ; Make sure to properly update PHINode block entries if the default branch |
| ; happens to have them. |
| declare i1 @some_use(i8) |
| define i32 @default_branch_has_phi_and_will_be_moved(i8 %x, i1 %y) { |
| ; CHECK-LABEL: @default_branch_has_phi_and_will_be_moved( |
| ; CHECK-NEXT: pre-entry: |
| ; CHECK-NEXT: br i1 [[Y:%.*]], label [[ENTRY:%.*]], label [[DEFAULT:%.*]] |
| ; CHECK: entry: |
| ; CHECK-NEXT: switch i8 [[X:%.*]], label [[ENTRY_UNREACHABLEDEFAULT:%.*]] [ |
| ; CHECK-NEXT: i8 -1, label [[RETURN:%.*]] |
| ; CHECK-NEXT: i8 0, label [[CASE_ZERO:%.*]] |
| ; CHECK-NEXT: i8 1, label [[DEFAULT]] |
| ; CHECK-NEXT: ] |
| ; CHECK: entry.unreachabledefault: |
| ; CHECK-NEXT: unreachable |
| ; CHECK: default: |
| ; CHECK-NEXT: [[Z:%.*]] = phi i8 [ 2, [[PRE_ENTRY:%.*]] ], [ 3, [[ENTRY]] ] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X]], 1 |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) |
| ; CHECK-NEXT: call void @some_use(i8 [[Z]]) |
| ; CHECK-NEXT: br label [[RETURN]] |
| ; CHECK: case_zero: |
| ; CHECK-NEXT: br label [[RETURN]] |
| ; CHECK: return: |
| ; CHECK-NEXT: [[RETVAL:%.*]] = phi i32 [ 1, [[DEFAULT]] ], [ 0, [[CASE_ZERO]] ], [ -1, [[ENTRY]] ] |
| ; CHECK-NEXT: ret i32 [[RETVAL]] |
| ; |
| pre-entry: |
| br i1 %y, label %entry, label %default |
| |
| entry: |
| switch i8 %x, label %default [ |
| i8 -1, label %case_neg_one |
| i8 0, label %case_zero |
| ] |
| default: |
| %z = phi i8 [ 2, %pre-entry], [ 3, %entry] |
| %cmp = icmp eq i8 %x, 1 |
| call void @llvm.assume(i1 %cmp) |
| call void @some_use(i8 %z) |
| br label %return |
| |
| case_neg_one: |
| br label %return |
| |
| case_zero: |
| br label %return |
| |
| return: |
| %retval = phi i32 [ 1, %default ], [ -1, %case_neg_one ], [ 0, %case_zero ] |
| ret i32 %retval |
| } |
| |
| define i32 @default_branch_has_phi_and_will_be_removed(i8 %x, i1 %y) { |
| ; CHECK-LABEL: @default_branch_has_phi_and_will_be_removed( |
| ; CHECK-NEXT: pre-entry: |
| ; CHECK-NEXT: br i1 [[Y:%.*]], label [[ENTRY:%.*]], label [[DEFAULT:%.*]] |
| ; CHECK: entry: |
| ; CHECK-NEXT: switch i8 [[X:%.*]], label [[ENTRY_UNREACHABLEDEFAULT:%.*]] [ |
| ; CHECK-NEXT: i8 -1, label [[RETURN:%.*]] |
| ; CHECK-NEXT: i8 0, label [[CASE_ZERO:%.*]] |
| ; CHECK-NEXT: i8 1, label [[CASE_ONE:%.*]] |
| ; CHECK-NEXT: ] |
| ; CHECK: entry.unreachabledefault: |
| ; CHECK-NEXT: unreachable |
| ; CHECK: default: |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X]], 1 |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) |
| ; CHECK-NEXT: call void @some_use(i8 2) |
| ; CHECK-NEXT: br label [[RETURN]] |
| ; CHECK: case_zero: |
| ; CHECK-NEXT: br label [[RETURN]] |
| ; CHECK: case_one: |
| ; CHECK-NEXT: br label [[RETURN]] |
| ; CHECK: return: |
| ; CHECK-NEXT: [[RETVAL:%.*]] = phi i32 [ 1, [[DEFAULT]] ], [ 1, [[CASE_ONE]] ], [ 0, [[CASE_ZERO]] ], [ -1, [[ENTRY]] ] |
| ; CHECK-NEXT: ret i32 [[RETVAL]] |
| ; |
| pre-entry: |
| br i1 %y, label %entry, label %default |
| |
| entry: |
| switch i8 %x, label %default [ |
| i8 -1, label %case_neg_one |
| i8 0, label %case_zero |
| i8 1, label %case_one |
| ] |
| default: |
| %z = phi i8 [ 2, %pre-entry], [ 3, %entry] |
| %cmp = icmp eq i8 %x, 1 |
| call void @llvm.assume(i1 %cmp) |
| call void @some_use(i8 %z) |
| br label %return |
| |
| case_neg_one: |
| br label %return |
| |
| case_zero: |
| br label %return |
| |
| case_one: |
| br label %return |
| |
| return: |
| %retval = phi i32 [ 1, %default ], [ -1, %case_neg_one ], [ 0, %case_zero ], [ 1, %case_one ] |
| ret i32 %retval |
| } |
| |
| define i32 @default_branch_has_phi_and_will_be_removed_duplicate_phi_entries(i8 %x, i1 %y) { |
| ; CHECK-LABEL: @default_branch_has_phi_and_will_be_removed_duplicate_phi_entries( |
| ; CHECK-NEXT: pre-entry: |
| ; CHECK-NEXT: br i1 [[Y:%.*]], label [[ENTRY:%.*]], label [[DEFAULT:%.*]] |
| ; CHECK: entry: |
| ; CHECK-NEXT: switch i8 [[X:%.*]], label [[ENTRY_UNREACHABLEDEFAULT:%.*]] [ |
| ; CHECK-NEXT: i8 -1, label [[RETURN:%.*]] |
| ; CHECK-NEXT: i8 0, label [[CASE_ZERO:%.*]] |
| ; CHECK-NEXT: i8 1, label [[DEFAULT]] |
| ; CHECK-NEXT: ] |
| ; CHECK: entry.unreachabledefault: |
| ; CHECK-NEXT: unreachable |
| ; CHECK: default: |
| ; CHECK-NEXT: [[Z:%.*]] = phi i8 [ 2, [[PRE_ENTRY:%.*]] ], [ 3, [[ENTRY]] ] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X]], 1 |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) |
| ; CHECK-NEXT: call void @some_use(i8 [[Z]]) |
| ; CHECK-NEXT: br label [[RETURN]] |
| ; CHECK: case_zero: |
| ; CHECK-NEXT: br label [[RETURN]] |
| ; CHECK: return: |
| ; CHECK-NEXT: [[RETVAL:%.*]] = phi i32 [ 1, [[DEFAULT]] ], [ 0, [[CASE_ZERO]] ], [ -1, [[ENTRY]] ] |
| ; CHECK-NEXT: ret i32 [[RETVAL]] |
| ; |
| pre-entry: |
| br i1 %y, label %entry, label %default |
| |
| entry: |
| switch i8 %x, label %default [ |
| i8 -1, label %case_neg_one |
| i8 0, label %case_zero |
| i8 1, label %default |
| ] |
| default: |
| %z = phi i8 [ 2, %pre-entry], [ 3, %entry], [ 3, %entry ] |
| %cmp = icmp eq i8 %x, 1 |
| call void @llvm.assume(i1 %cmp) |
| call void @some_use(i8 %z) |
| br label %return |
| |
| case_neg_one: |
| br label %return |
| |
| case_zero: |
| br label %return |
| |
| return: |
| %retval = phi i32 [ 1, %default ], [ -1, %case_neg_one ], [ 0, %case_zero ] |
| ret i32 %retval |
| } |
| |
| ; CHECK: [[PROF0]] = !{!"branch_weights", i32 0, i32 4, i32 2, i32 8} |
| !0 = !{!"branch_weights", i32 8, i32 4, i32 2} |