1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -S -make-guards-explicit -basicaa -licm < %s | FileCheck %s 3; RUN: opt -S -aa-pipeline=basic-aa -passes='require<opt-remark-emit>,make-guards-explicit,loop(licm)' < %s | FileCheck %s 4 5; Test interaction between explicit guards and LICM: make sure that we do not 6; hoist explicit conditions while we can hoist invariant loads in presence of 7; explicit guards. 8 9declare void @llvm.experimental.guard(i1,...) 10 11; Make sure that we do not hoist widenable_cond out of loop. 12define void @do_not_hoist_widenable_cond(i1 %cond, i32 %N, i32 %M) { 13; CHECK-LABEL: @do_not_hoist_widenable_cond( 14; CHECK-NEXT: entry: 15; CHECK-NEXT: br label [[LOOP:%.*]] 16; CHECK: loop: 17; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[GUARDED:%.*]] ] 18; CHECK-NEXT: [[GUARD_COND:%.*]] = icmp slt i32 [[IV]], [[N:%.*]] 19; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition() 20; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[GUARD_COND]], [[WIDENABLE_COND]] 21; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED]], label [[DEOPT:%.*]], !prof !0 22; CHECK: deopt: 23; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ] 24; CHECK-NEXT: ret void 25; CHECK: guarded: 26; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV]], [[M:%.*]] 27; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 28; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] 29; CHECK: exit: 30; CHECK-NEXT: ret void 31; 32entry: 33 br label %loop 34 35loop: 36 %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] 37 %guard_cond = icmp slt i32 %iv, %N 38 call void(i1, ...) @llvm.experimental.guard(i1 %guard_cond) [ "deopt"() ] 39 %loop_cond = icmp slt i32 %iv, %M 40 %iv.next = add i32 %iv, 1 41 br i1 %loop_cond, label %loop, label %exit 42 43exit: 44 ret void 45} 46 47define void @hoist_invariant_load(i1 %cond, i32* %np, i32 %M) { 48; CHECK-LABEL: @hoist_invariant_load( 49; CHECK-NEXT: entry: 50; CHECK-NEXT: [[N:%.*]] = load i32, i32* [[NP:%.*]] 51; CHECK-NEXT: br label [[LOOP:%.*]] 52; CHECK: loop: 53; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[GUARDED:%.*]] ] 54; CHECK-NEXT: [[GUARD_COND:%.*]] = icmp slt i32 [[IV]], [[N]] 55; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition() 56; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[GUARD_COND]], [[WIDENABLE_COND]] 57; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED]], label [[DEOPT:%.*]], !prof !0 58; CHECK: deopt: 59; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ] 60; CHECK-NEXT: ret void 61; CHECK: guarded: 62; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV]], [[M:%.*]] 63; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 64; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] 65; CHECK: exit: 66; CHECK-NEXT: ret void 67; 68entry: 69 br label %loop 70 71loop: 72 %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] 73 %N = load i32, i32* %np 74 %guard_cond = icmp slt i32 %iv, %N 75 call void(i1, ...) @llvm.experimental.guard(i1 %guard_cond) [ "deopt"() ] 76 %loop_cond = icmp slt i32 %iv, %M 77 %iv.next = add i32 %iv, 1 78 br i1 %loop_cond, label %loop, label %exit 79 80exit: 81 ret void 82} 83