| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 |
| ; RUN: opt -S -passes=instcombine < %s | FileCheck %s --check-prefixes=CHECK,DEFAULT_ITER |
| ; RUN: opt -S -passes='instcombine<max-iterations=1>' < %s | FileCheck %s --check-prefixes=CHECK,MAX1 |
| |
| declare void @dummy() |
| declare void @llvm.assume(i1) |
| |
| define i32 @br_true(i1 %x) { |
| ; CHECK-LABEL: define i32 @br_true |
| ; CHECK-SAME: (i1 [[X:%.*]]) { |
| ; CHECK-NEXT: br i1 true, label [[IF:%.*]], label [[ELSE:%.*]] |
| ; CHECK: if: |
| ; CHECK-NEXT: call void @dummy() |
| ; CHECK-NEXT: br label [[JOIN:%.*]] |
| ; CHECK: else: |
| ; CHECK-NEXT: br label [[JOIN]] |
| ; CHECK: join: |
| ; CHECK-NEXT: ret i32 1 |
| ; |
| %c = or i1 %x, true |
| br i1 %c, label %if, label %else |
| |
| if: |
| call void @dummy() |
| br label %join |
| |
| else: |
| call void @dummy() |
| br label %join |
| |
| join: |
| %phi = phi i32 [ 1, %if ], [ 2, %else ] |
| ret i32 %phi |
| } |
| |
| define i32 @br_false(i1 %x) { |
| ; CHECK-LABEL: define i32 @br_false |
| ; CHECK-SAME: (i1 [[X:%.*]]) { |
| ; CHECK-NEXT: br i1 false, label [[IF:%.*]], label [[ELSE:%.*]] |
| ; CHECK: if: |
| ; CHECK-NEXT: br label [[JOIN:%.*]] |
| ; CHECK: else: |
| ; CHECK-NEXT: call void @dummy() |
| ; CHECK-NEXT: br label [[JOIN]] |
| ; CHECK: join: |
| ; CHECK-NEXT: ret i32 2 |
| ; |
| %c = and i1 %x, false |
| br i1 %c, label %if, label %else |
| |
| if: |
| call void @dummy() |
| br label %join |
| |
| else: |
| call void @dummy() |
| br label %join |
| |
| join: |
| %phi = phi i32 [ 1, %if ], [ 2, %else ] |
| ret i32 %phi |
| } |
| |
| define i32 @br_undef(i1 %x) { |
| ; CHECK-LABEL: define i32 @br_undef |
| ; CHECK-SAME: (i1 [[X:%.*]]) { |
| ; CHECK-NEXT: br i1 undef, label [[IF:%.*]], label [[ELSE:%.*]] |
| ; CHECK: if: |
| ; CHECK-NEXT: br label [[JOIN:%.*]] |
| ; CHECK: else: |
| ; CHECK-NEXT: br label [[JOIN]] |
| ; CHECK: join: |
| ; CHECK-NEXT: ret i32 poison |
| ; |
| %c = xor i1 %x, undef |
| br i1 %c, label %if, label %else |
| |
| if: |
| call void @dummy() |
| br label %join |
| |
| else: |
| call void @dummy() |
| br label %join |
| |
| join: |
| %phi = phi i32 [ 1, %if ], [ 2, %else ] |
| ret i32 %phi |
| } |
| |
| define i32 @br_true_phi_with_repeated_preds(i1 %x) { |
| ; CHECK-LABEL: define i32 @br_true_phi_with_repeated_preds |
| ; CHECK-SAME: (i1 [[X:%.*]]) { |
| ; CHECK-NEXT: br i1 true, label [[IF:%.*]], label [[ELSE:%.*]] |
| ; CHECK: if: |
| ; CHECK-NEXT: call void @dummy() |
| ; CHECK-NEXT: br label [[JOIN:%.*]] |
| ; CHECK: else: |
| ; CHECK-NEXT: br i1 false, label [[JOIN]], label [[JOIN]] |
| ; CHECK: join: |
| ; CHECK-NEXT: ret i32 1 |
| ; |
| %c = or i1 %x, true |
| br i1 %c, label %if, label %else |
| |
| if: |
| call void @dummy() |
| br label %join |
| |
| else: |
| br i1 false, label %join, label %join |
| |
| join: |
| %phi = phi i32 [ 1, %if ], [ 2, %else ], [ 2, %else ] |
| ret i32 %phi |
| } |
| |
| define i32 @br_true_const_phi_direct_edge(i1 %x) { |
| ; CHECK-LABEL: define i32 @br_true_const_phi_direct_edge |
| ; CHECK-SAME: (i1 [[X:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br i1 true, label [[IF:%.*]], label [[JOIN:%.*]] |
| ; CHECK: if: |
| ; CHECK-NEXT: call void @dummy() |
| ; CHECK-NEXT: br label [[JOIN]] |
| ; CHECK: join: |
| ; CHECK-NEXT: ret i32 2 |
| ; |
| entry: |
| br i1 true, label %if, label %join |
| |
| if: |
| call void @dummy() |
| br label %join |
| |
| join: |
| %phi = phi i32 [ 1, %entry ], [ 2, %if ] |
| ret i32 %phi |
| } |
| |
| define i32 @br_true_var_phi_direct_edge(i1 %x) { |
| ; CHECK-LABEL: define i32 @br_true_var_phi_direct_edge |
| ; CHECK-SAME: (i1 [[X:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br i1 true, label [[IF:%.*]], label [[JOIN:%.*]] |
| ; CHECK: if: |
| ; CHECK-NEXT: call void @dummy() |
| ; CHECK-NEXT: br label [[JOIN]] |
| ; CHECK: join: |
| ; CHECK-NEXT: ret i32 2 |
| ; |
| entry: |
| %c = or i1 %x, true |
| br i1 %c, label %if, label %join |
| |
| if: |
| call void @dummy() |
| br label %join |
| |
| join: |
| %phi = phi i32 [ 1, %entry ], [ 2, %if ] |
| ret i32 %phi |
| } |
| |
| define void @switch_case(i32 %x) { |
| ; CHECK-LABEL: define void @switch_case |
| ; CHECK-SAME: (i32 [[X:%.*]]) { |
| ; CHECK-NEXT: switch i32 0, label [[DEFAULT:%.*]] [ |
| ; CHECK-NEXT: i32 0, label [[CASE0:%.*]] |
| ; CHECK-NEXT: ] |
| ; CHECK: case0: |
| ; CHECK-NEXT: call void @dummy() |
| ; CHECK-NEXT: ret void |
| ; CHECK: default: |
| ; CHECK-NEXT: ret void |
| ; |
| %v = and i32 %x, 0 |
| switch i32 %v, label %default [ |
| i32 0, label %case0 |
| ] |
| |
| case0: |
| call void @dummy() |
| ret void |
| |
| default: |
| call void @dummy() |
| ret void |
| } |
| |
| define void @switch_default(i32 %x) { |
| ; CHECK-LABEL: define void @switch_default |
| ; CHECK-SAME: (i32 [[X:%.*]]) { |
| ; CHECK-NEXT: switch i32 -1, label [[DEFAULT:%.*]] [ |
| ; CHECK-NEXT: i32 0, label [[CASE0:%.*]] |
| ; CHECK-NEXT: ] |
| ; CHECK: case0: |
| ; CHECK-NEXT: ret void |
| ; CHECK: default: |
| ; CHECK-NEXT: call void @dummy() |
| ; CHECK-NEXT: ret void |
| ; |
| %v = or i32 %x, -1 |
| switch i32 %v, label %default [ |
| i32 0, label %case0 |
| ] |
| |
| case0: |
| call void @dummy() |
| ret void |
| |
| default: |
| call void @dummy() |
| ret void |
| } |
| |
| define void @switch_undef(i32 %x) { |
| ; CHECK-LABEL: define void @switch_undef |
| ; CHECK-SAME: (i32 [[X:%.*]]) { |
| ; CHECK-NEXT: switch i32 undef, label [[DEFAULT:%.*]] [ |
| ; CHECK-NEXT: i32 0, label [[CASE0:%.*]] |
| ; CHECK-NEXT: ] |
| ; CHECK: case0: |
| ; CHECK-NEXT: ret void |
| ; CHECK: default: |
| ; CHECK-NEXT: ret void |
| ; |
| %v = xor i32 %x, undef |
| switch i32 %v, label %default [ |
| i32 0, label %case0 |
| ] |
| |
| case0: |
| call void @dummy() |
| ret void |
| |
| default: |
| call void @dummy() |
| ret void |
| } |
| |
| define void @non_term_unreachable() { |
| ; CHECK-LABEL: define void @non_term_unreachable() { |
| ; CHECK-NEXT: call void @dummy() |
| ; CHECK-NEXT: store i1 true, ptr poison, align 1 |
| ; CHECK-NEXT: ret void |
| ; |
| call void @dummy() |
| call void @dummy() nounwind willreturn |
| store i1 true, ptr poison |
| call void @dummy() |
| ret void |
| } |
| |
| define i32 @non_term_unreachable_phi(i1 %c) { |
| ; CHECK-LABEL: define i32 @non_term_unreachable_phi |
| ; CHECK-SAME: (i1 [[C:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[JOIN:%.*]] |
| ; CHECK: if: |
| ; CHECK-NEXT: store i1 true, ptr poison, align 1 |
| ; CHECK-NEXT: br label [[JOIN]] |
| ; CHECK: join: |
| ; CHECK-NEXT: ret i32 2 |
| ; |
| entry: |
| br i1 %c, label %if, label %join |
| |
| if: |
| store i1 true, ptr poison |
| call void @dummy() |
| br label %join |
| |
| join: |
| %phi = phi i32 [ 1, %if], [ 2, %entry ] |
| ret i32 %phi |
| } |
| |
| define void @non_term_unreachable_following_blocks() { |
| ; CHECK-LABEL: define void @non_term_unreachable_following_blocks() { |
| ; CHECK-NEXT: call void @dummy() |
| ; CHECK-NEXT: store i1 true, ptr poison, align 1 |
| ; CHECK-NEXT: br label [[SPLIT:%.*]] |
| ; CHECK: split: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: br label [[LOOP]] |
| ; |
| call void @dummy() |
| store i1 true, ptr poison |
| call void @dummy() |
| br label %split |
| |
| split: |
| call void @dummy() |
| br label %loop |
| |
| loop: |
| call void @dummy() |
| br label %loop |
| } |
| |
| define void @br_not_into_loop(i1 %x) { |
| ; CHECK-LABEL: define void @br_not_into_loop |
| ; CHECK-SAME: (i1 [[X:%.*]]) { |
| ; CHECK-NEXT: br i1 true, label [[EXIT:%.*]], label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: br label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: call void @dummy() |
| ; CHECK-NEXT: ret void |
| ; |
| %c = or i1 %x, true |
| br i1 %c, label %exit, label %loop |
| |
| loop: |
| call void @dummy() |
| br label %loop |
| |
| exit: |
| call void @dummy() |
| ret void |
| } |
| |
| define void @br_into_loop(i1 %x) { |
| ; CHECK-LABEL: define void @br_into_loop |
| ; CHECK-SAME: (i1 [[X:%.*]]) { |
| ; CHECK-NEXT: br i1 true, label [[LOOP:%.*]], label [[EXIT:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: call void @dummy() |
| ; CHECK-NEXT: br label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| %c = or i1 %x, true |
| br i1 %c, label %loop, label %exit |
| |
| loop: |
| call void @dummy() |
| br label %loop |
| |
| exit: |
| call void @dummy() |
| ret void |
| } |
| |
| define void @two_br_not_into_loop(i1 %x) { |
| ; CHECK-LABEL: define void @two_br_not_into_loop |
| ; CHECK-SAME: (i1 [[X:%.*]]) { |
| ; CHECK-NEXT: br i1 true, label [[BB2:%.*]], label [[LOOP:%.*]] |
| ; CHECK: bb2: |
| ; CHECK-NEXT: br i1 true, label [[EXIT:%.*]], label [[LOOP]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: br label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: call void @dummy() |
| ; CHECK-NEXT: ret void |
| ; |
| %c = or i1 %x, true |
| br i1 %c, label %bb2, label %loop |
| |
| bb2: |
| %c2 = or i1 %x, true |
| br i1 %c2, label %exit, label %loop |
| |
| loop: |
| call void @dummy() |
| br label %loop |
| |
| exit: |
| call void @dummy() |
| ret void |
| } |
| |
| define void @one_br_into_loop_one_not(i1 %x, i1 %c2) { |
| ; CHECK-LABEL: define void @one_br_into_loop_one_not |
| ; CHECK-SAME: (i1 [[X:%.*]], i1 [[C2:%.*]]) { |
| ; CHECK-NEXT: br i1 true, label [[BB2:%.*]], label [[LOOP:%.*]] |
| ; CHECK: bb2: |
| ; CHECK-NEXT: br i1 [[C2]], label [[EXIT:%.*]], label [[LOOP]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: call void @dummy() |
| ; CHECK-NEXT: br label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: call void @dummy() |
| ; CHECK-NEXT: ret void |
| ; |
| %c = or i1 %x, true |
| br i1 %c, label %bb2, label %loop |
| |
| bb2: |
| br i1 %c2, label %exit, label %loop |
| |
| loop: |
| call void @dummy() |
| br label %loop |
| |
| exit: |
| call void @dummy() |
| ret void |
| } |
| |
| define void @two_br_not_into_loop_with_split(i1 %x) { |
| ; CHECK-LABEL: define void @two_br_not_into_loop_with_split |
| ; CHECK-SAME: (i1 [[X:%.*]]) { |
| ; CHECK-NEXT: br i1 true, label [[BB2:%.*]], label [[SPLIT1:%.*]] |
| ; CHECK: bb2: |
| ; CHECK-NEXT: br i1 true, label [[EXIT:%.*]], label [[SPLIT2:%.*]] |
| ; CHECK: split1: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: split2: |
| ; CHECK-NEXT: br label [[LOOP]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: br label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: call void @dummy() |
| ; CHECK-NEXT: ret void |
| ; |
| %c = or i1 %x, true |
| br i1 %c, label %bb2, label %split1 |
| |
| bb2: |
| %c2 = or i1 %x, true |
| br i1 %c2, label %exit, label %split2 |
| |
| split1: |
| call void @dummy() |
| br label %loop |
| |
| split2: |
| call void @dummy() |
| br label %loop |
| |
| loop: |
| call void @dummy() |
| br label %loop |
| |
| exit: |
| call void @dummy() |
| ret void |
| } |
| |
| define void @irreducible() { |
| ; CHECK-LABEL: define void @irreducible() { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br i1 false, label [[LOOP2:%.*]], label [[LOOP1:%.*]] |
| ; CHECK: loop1: |
| ; CHECK-NEXT: call void @dummy() |
| ; CHECK-NEXT: br label [[LOOP2]] |
| ; CHECK: loop2: |
| ; CHECK-NEXT: call void @dummy() |
| ; CHECK-NEXT: br i1 true, label [[EXIT:%.*]], label [[LOOP1]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: call void @dummy() |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br i1 false, label %loop2, label %loop1 |
| |
| loop1: |
| call void @dummy() |
| br label %loop2 |
| |
| loop2: |
| call void @dummy() |
| br i1 true, label %exit, label %loop1 |
| |
| exit: |
| call void @dummy() |
| ret void |
| } |
| |
| define void @really_unreachable() { |
| ; CHECK-LABEL: define void @really_unreachable() { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: ret void |
| ; CHECK: unreachable: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| ret void |
| |
| unreachable: |
| call void @dummy() |
| ret void |
| } |
| |
| define void @really_unreachable_predecessor() { |
| ; CHECK-LABEL: define void @really_unreachable_predecessor() { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br i1 false, label [[BB:%.*]], label [[EXIT:%.*]] |
| ; CHECK: unreachable: |
| ; CHECK-NEXT: br label [[BB]] |
| ; CHECK: bb: |
| ; CHECK-NEXT: ret void |
| ; CHECK: exit: |
| ; CHECK-NEXT: call void @dummy() |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br i1 false, label %bb, label %exit |
| |
| unreachable: |
| call void @dummy() |
| br label %bb |
| |
| bb: |
| call void @dummy() |
| ret void |
| |
| exit: |
| call void @dummy() |
| ret void |
| } |
| |
| define i32 @pr64235() { |
| ; CHECK-LABEL: define i32 @pr64235() { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br i1 false, label [[BB:%.*]], label [[BB3:%.*]] |
| ; CHECK: bb3: |
| ; CHECK-NEXT: store i1 true, ptr poison, align 1 |
| ; CHECK-NEXT: br label [[BB2:%.*]] |
| ; CHECK: bb: |
| ; CHECK-NEXT: br label [[BB2]] |
| ; CHECK: bb2: |
| ; CHECK-NEXT: br label [[BB]] |
| ; |
| entry: |
| br i1 false, label %bb, label %bb3 |
| |
| bb3: |
| call void @llvm.assume(i1 false) |
| br label %bb2 |
| |
| bb: |
| br label %bb2 |
| |
| bb2: |
| call void @llvm.assume(i1 false) |
| br label %bb |
| } |
| |
| ;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: |
| ; DEFAULT_ITER: {{.*}} |
| ; MAX1: {{.*}} |