| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 |
| ; RUN: opt -S -passes="guard-widening,make-guards-explicit,simplifycfg" < %s | FileCheck %s --check-prefixes=INTRINSIC_FORM |
| ; RUN: opt -S -passes="make-guards-explicit,guard-widening,simplifycfg" < %s | FileCheck %s --check-prefixes=BRANCH_FORM |
| ; RUN: opt -S -passes="make-guards-explicit,loop-mssa(licm),guard-widening,simplifycfg" < %s | FileCheck %s --check-prefixes=BRANCH_FORM_LICM |
| |
| declare i1 @cond() readonly |
| |
| ; FIXME We want to make sure that guard widening works in the same way, no matter what form of |
| ; guards it is dealing with. |
| ; We also want to make sure that LICM doesn't mess with widenable conditions, what might |
| ; make things more complex. |
| |
| define void @test_01(i32 %a, i32 %b, i32 %c, i32 %d) { |
| ; INTRINSIC_FORM-LABEL: define void @test_01 |
| ; INTRINSIC_FORM-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32 [[D:%.*]]) { |
| ; INTRINSIC_FORM-NEXT: entry: |
| ; INTRINSIC_FORM-NEXT: [[D_GW_FR:%.*]] = freeze i32 [[D]] |
| ; INTRINSIC_FORM-NEXT: [[C_GW_FR:%.*]] = freeze i32 [[C]] |
| ; INTRINSIC_FORM-NEXT: [[B_GW_FR:%.*]] = freeze i32 [[B]] |
| ; INTRINSIC_FORM-NEXT: br label [[LOOP:%.*]] |
| ; INTRINSIC_FORM: loop: |
| ; INTRINSIC_FORM-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[GUARDED:%.*]] ] |
| ; INTRINSIC_FORM-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; INTRINSIC_FORM-NEXT: [[C1:%.*]] = icmp ult i32 [[IV]], [[A]] |
| ; INTRINSIC_FORM-NEXT: [[C2:%.*]] = icmp ult i32 [[IV]], [[B_GW_FR]] |
| ; INTRINSIC_FORM-NEXT: [[WIDE_CHK:%.*]] = and i1 [[C1]], [[C2]] |
| ; INTRINSIC_FORM-NEXT: [[C3:%.*]] = icmp ult i32 [[IV]], [[C_GW_FR]] |
| ; INTRINSIC_FORM-NEXT: [[WIDE_CHK1:%.*]] = and i1 [[WIDE_CHK]], [[C3]] |
| ; INTRINSIC_FORM-NEXT: [[C4:%.*]] = icmp ult i32 [[IV]], [[D_GW_FR]] |
| ; INTRINSIC_FORM-NEXT: [[WIDE_CHK2:%.*]] = and i1 [[WIDE_CHK1]], [[C4]] |
| ; INTRINSIC_FORM-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition() |
| ; INTRINSIC_FORM-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDE_CHK2]], [[WIDENABLE_COND]] |
| ; INTRINSIC_FORM-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED]], label [[DEOPT:%.*]], !prof [[PROF0:![0-9]+]] |
| ; INTRINSIC_FORM: deopt: |
| ; INTRINSIC_FORM-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ] |
| ; INTRINSIC_FORM-NEXT: ret void |
| ; INTRINSIC_FORM: guarded: |
| ; INTRINSIC_FORM-NEXT: [[LOOP_COND:%.*]] = call i1 @cond() |
| ; INTRINSIC_FORM-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; INTRINSIC_FORM: exit: |
| ; INTRINSIC_FORM-NEXT: ret void |
| ; |
| ; BRANCH_FORM-LABEL: define void @test_01 |
| ; BRANCH_FORM-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32 [[D:%.*]]) { |
| ; BRANCH_FORM-NEXT: entry: |
| ; BRANCH_FORM-NEXT: [[D_GW_FR:%.*]] = freeze i32 [[D]] |
| ; BRANCH_FORM-NEXT: [[C_GW_FR:%.*]] = freeze i32 [[C]] |
| ; BRANCH_FORM-NEXT: [[B_GW_FR:%.*]] = freeze i32 [[B]] |
| ; BRANCH_FORM-NEXT: br label [[LOOP:%.*]] |
| ; BRANCH_FORM: loop: |
| ; BRANCH_FORM-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[GUARDED:%.*]] ] |
| ; BRANCH_FORM-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; BRANCH_FORM-NEXT: [[C1:%.*]] = icmp ult i32 [[IV]], [[A]] |
| ; BRANCH_FORM-NEXT: [[C2:%.*]] = icmp ult i32 [[IV]], [[B_GW_FR]] |
| ; BRANCH_FORM-NEXT: [[WIDE_CHK:%.*]] = and i1 [[C1]], [[C2]] |
| ; BRANCH_FORM-NEXT: [[C3:%.*]] = icmp ult i32 [[IV]], [[C_GW_FR]] |
| ; BRANCH_FORM-NEXT: [[WIDE_CHK13:%.*]] = and i1 [[WIDE_CHK]], [[C3]] |
| ; BRANCH_FORM-NEXT: [[C4:%.*]] = icmp ult i32 [[IV]], [[D_GW_FR]] |
| ; BRANCH_FORM-NEXT: [[WIDE_CHK14:%.*]] = and i1 [[WIDE_CHK13]], [[C4]] |
| ; BRANCH_FORM-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition() |
| ; BRANCH_FORM-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDE_CHK14]], [[WIDENABLE_COND]] |
| ; BRANCH_FORM-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED]], label [[DEOPT:%.*]], !prof [[PROF0:![0-9]+]] |
| ; BRANCH_FORM: deopt: |
| ; BRANCH_FORM-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ] |
| ; BRANCH_FORM-NEXT: ret void |
| ; BRANCH_FORM: guarded: |
| ; BRANCH_FORM-NEXT: [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition() |
| ; BRANCH_FORM-NEXT: [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[C2]], [[WIDENABLE_COND3]] |
| ; BRANCH_FORM-NEXT: [[WIDENABLE_COND7:%.*]] = call i1 @llvm.experimental.widenable.condition() |
| ; BRANCH_FORM-NEXT: [[EXIPLICIT_GUARD_COND8:%.*]] = and i1 [[C3]], [[WIDENABLE_COND7]] |
| ; BRANCH_FORM-NEXT: [[WIDENABLE_COND11:%.*]] = call i1 @llvm.experimental.widenable.condition() |
| ; BRANCH_FORM-NEXT: [[EXIPLICIT_GUARD_COND12:%.*]] = and i1 [[C4]], [[WIDENABLE_COND11]] |
| ; BRANCH_FORM-NEXT: [[LOOP_COND:%.*]] = call i1 @cond() |
| ; BRANCH_FORM-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; BRANCH_FORM: exit: |
| ; BRANCH_FORM-NEXT: ret void |
| ; |
| ; BRANCH_FORM_LICM-LABEL: define void @test_01 |
| ; BRANCH_FORM_LICM-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32 [[D:%.*]]) { |
| ; BRANCH_FORM_LICM-NEXT: entry: |
| ; BRANCH_FORM_LICM-NEXT: [[D_GW_FR:%.*]] = freeze i32 [[D]] |
| ; BRANCH_FORM_LICM-NEXT: [[C_GW_FR:%.*]] = freeze i32 [[C]] |
| ; BRANCH_FORM_LICM-NEXT: [[B_GW_FR:%.*]] = freeze i32 [[B]] |
| ; BRANCH_FORM_LICM-NEXT: br label [[LOOP:%.*]] |
| ; BRANCH_FORM_LICM: loop: |
| ; BRANCH_FORM_LICM-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[GUARDED:%.*]] ] |
| ; BRANCH_FORM_LICM-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; BRANCH_FORM_LICM-NEXT: [[C1:%.*]] = icmp ult i32 [[IV]], [[A]] |
| ; BRANCH_FORM_LICM-NEXT: [[C2:%.*]] = icmp ult i32 [[IV]], [[B_GW_FR]] |
| ; BRANCH_FORM_LICM-NEXT: [[WIDE_CHK:%.*]] = and i1 [[C1]], [[C2]] |
| ; BRANCH_FORM_LICM-NEXT: [[C3:%.*]] = icmp ult i32 [[IV]], [[C_GW_FR]] |
| ; BRANCH_FORM_LICM-NEXT: [[WIDE_CHK13:%.*]] = and i1 [[WIDE_CHK]], [[C3]] |
| ; BRANCH_FORM_LICM-NEXT: [[C4:%.*]] = icmp ult i32 [[IV]], [[D_GW_FR]] |
| ; BRANCH_FORM_LICM-NEXT: [[WIDE_CHK14:%.*]] = and i1 [[WIDE_CHK13]], [[C4]] |
| ; BRANCH_FORM_LICM-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition() |
| ; BRANCH_FORM_LICM-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDE_CHK14]], [[WIDENABLE_COND]] |
| ; BRANCH_FORM_LICM-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED]], label [[DEOPT:%.*]], !prof [[PROF0:![0-9]+]] |
| ; BRANCH_FORM_LICM: deopt: |
| ; BRANCH_FORM_LICM-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ] |
| ; BRANCH_FORM_LICM-NEXT: ret void |
| ; BRANCH_FORM_LICM: guarded: |
| ; BRANCH_FORM_LICM-NEXT: [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition() |
| ; BRANCH_FORM_LICM-NEXT: [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[C2]], [[WIDENABLE_COND3]] |
| ; BRANCH_FORM_LICM-NEXT: [[WIDENABLE_COND7:%.*]] = call i1 @llvm.experimental.widenable.condition() |
| ; BRANCH_FORM_LICM-NEXT: [[EXIPLICIT_GUARD_COND8:%.*]] = and i1 [[C3]], [[WIDENABLE_COND7]] |
| ; BRANCH_FORM_LICM-NEXT: [[WIDENABLE_COND11:%.*]] = call i1 @llvm.experimental.widenable.condition() |
| ; BRANCH_FORM_LICM-NEXT: [[EXIPLICIT_GUARD_COND12:%.*]] = and i1 [[C4]], [[WIDENABLE_COND11]] |
| ; BRANCH_FORM_LICM-NEXT: [[LOOP_COND:%.*]] = call i1 @cond() |
| ; BRANCH_FORM_LICM-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; BRANCH_FORM_LICM: exit: |
| ; BRANCH_FORM_LICM-NEXT: ret void |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [0, %entry], [%iv.next, %loop] |
| %iv.next = add i32 %iv, 1 |
| %c1 = icmp ult i32 %iv, %a |
| call void(i1, ...) @llvm.experimental.guard(i1 %c1) [ "deopt"() ] |
| %c2 = icmp ult i32 %iv, %b |
| call void(i1, ...) @llvm.experimental.guard(i1 %c2) [ "deopt"() ] |
| %c3 = icmp ult i32 %iv, %c |
| call void(i1, ...) @llvm.experimental.guard(i1 %c3) [ "deopt"() ] |
| %c4 = icmp ult i32 %iv, %d |
| call void(i1, ...) @llvm.experimental.guard(i1 %c4) [ "deopt"() ] |
| %loop_cond = call i1 @cond() |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret void |
| } |
| |
| declare void @llvm.experimental.guard(i1, ...) |