1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -S -make-guards-explicit -basic-aa -licm < %s | FileCheck %s 3; RUN: opt -S -aa-pipeline=basic-aa -passes='require<opt-remark-emit>,make-guards-explicit,loop-mssa(licm)' < %s | FileCheck %s 4 5declare void @llvm.experimental.guard(i1,...) 6declare void @maythrow() 7 8; Make sure that we do not hoist widenable_cond out of loop. 9define void @hoist_widenable_cond(i1 %cond, i32 %N, i32 %M) { 10; CHECK-LABEL: @hoist_widenable_cond( 11; CHECK-NEXT: entry: 12; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition() 13; CHECK-NEXT: br label [[LOOP:%.*]] 14; CHECK: loop: 15; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[GUARDED:%.*]] ] 16; CHECK-NEXT: [[GUARD_COND:%.*]] = icmp slt i32 [[IV]], [[N:%.*]] 17; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[GUARD_COND]], [[WIDENABLE_COND]] 18; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED]], label [[DEOPT:%.*]], !prof !0 19; CHECK: deopt: 20; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ] 21; CHECK-NEXT: ret void 22; CHECK: guarded: 23; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV]], [[M:%.*]] 24; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 25; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] 26; CHECK: exit: 27; CHECK-NEXT: ret void 28; 29entry: 30 br label %loop 31 32loop: 33 %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] 34 %guard_cond = icmp slt i32 %iv, %N 35 call void(i1, ...) @llvm.experimental.guard(i1 %guard_cond) [ "deopt"() ] 36 %loop_cond = icmp slt i32 %iv, %M 37 %iv.next = add i32 %iv, 1 38 br i1 %loop_cond, label %loop, label %exit 39 40exit: 41 ret void 42} 43 44define void @hoist_widenable_cond_speculate(i1 %cond, i32 %N, i32 %M) { 45; CHECK-LABEL: @hoist_widenable_cond_speculate( 46; CHECK-NEXT: entry: 47; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition() 48; CHECK-NEXT: br label [[LOOP:%.*]] 49; CHECK: loop: 50; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[GUARDED:%.*]] ] 51; CHECK-NEXT: [[GUARD_COND:%.*]] = icmp slt i32 [[IV]], [[N:%.*]] 52; CHECK-NEXT: call void @maythrow() 53; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[GUARD_COND]], [[WIDENABLE_COND]] 54; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED]], label [[DEOPT:%.*]], !prof !0 55; CHECK: deopt: 56; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ] 57; CHECK-NEXT: ret void 58; CHECK: guarded: 59; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV]], [[M:%.*]] 60; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 61; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] 62; CHECK: exit: 63; CHECK-NEXT: ret void 64; 65entry: 66 br label %loop 67 68loop: 69 %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] 70 %guard_cond = icmp slt i32 %iv, %N 71 call void @maythrow() 72 call void(i1, ...) @llvm.experimental.guard(i1 %guard_cond) [ "deopt"() ] 73 %loop_cond = icmp slt i32 %iv, %M 74 %iv.next = add i32 %iv, 1 75 br i1 %loop_cond, label %loop, label %exit 76 77exit: 78 ret void 79} 80 81 82define void @hoist_invariant_load(i1 %cond, i32* %np, i32 %M) { 83; CHECK-LABEL: @hoist_invariant_load( 84; CHECK-NEXT: entry: 85; CHECK-NEXT: [[N:%.*]] = load i32, i32* [[NP:%.*]] 86; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition() 87; CHECK-NEXT: br label [[LOOP:%.*]] 88; CHECK: loop: 89; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[GUARDED:%.*]] ] 90; CHECK-NEXT: [[GUARD_COND:%.*]] = icmp slt i32 [[IV]], [[N]] 91; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[GUARD_COND]], [[WIDENABLE_COND]] 92; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED]], label [[DEOPT:%.*]], !prof !0 93; CHECK: deopt: 94; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ] 95; CHECK-NEXT: ret void 96; CHECK: guarded: 97; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV]], [[M:%.*]] 98; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 99; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] 100; CHECK: exit: 101; CHECK-NEXT: ret void 102; 103entry: 104 br label %loop 105 106loop: 107 %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] 108 %N = load i32, i32* %np 109 %guard_cond = icmp slt i32 %iv, %N 110 call void(i1, ...) @llvm.experimental.guard(i1 %guard_cond) [ "deopt"() ] 111 %loop_cond = icmp slt i32 %iv, %M 112 %iv.next = add i32 %iv, 1 113 br i1 %loop_cond, label %loop, label %exit 114 115exit: 116 ret void 117} 118