1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -S -passes="loop-mssa(guard-widening)" -verify-memoryssa < %s | FileCheck %s 3 4declare void @llvm.experimental.guard(i1,...) 5 6@G = external global i32 7 8; Show that we can widen into early checks within a loop, and in the process 9; expose optimization oppurtunities. 10define void @widen_within_loop(i1 %cond_0, i1 %cond_1, i1 %cond_2) { 11; CHECK-LABEL: @widen_within_loop( 12; CHECK-NEXT: entry: 13; CHECK-NEXT: br label [[LOOP:%.*]] 14; CHECK: loop: 15; CHECK-NEXT: store i32 0, i32* @G 16; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]] 17; CHECK-NEXT: [[WIDE_CHK1:%.*]] = and i1 [[WIDE_CHK]], [[COND_2:%.*]] 18; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK1]]) [ "deopt"(i32 0) ] 19; CHECK-NEXT: store i32 1, i32* @G 20; CHECK-NEXT: store i32 2, i32* @G 21; CHECK-NEXT: store i32 3, i32* @G 22; CHECK-NEXT: br label [[LOOP]] 23; 24entry: 25 br label %loop 26 27loop: 28 store i32 0, i32* @G 29 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ] 30 store i32 1, i32* @G 31 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"(i32 1) ] 32 store i32 2, i32* @G 33 call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ] 34 store i32 3, i32* @G 35 br label %loop 36} 37 38define void @widen_into_preheader(i1 %cond_0, i1 %cond_1, i1 %cond_2) { 39; CHECK-LABEL: @widen_into_preheader( 40; CHECK-NEXT: entry: 41; CHECK-NEXT: store i32 0, i32* @G 42; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]] 43; CHECK-NEXT: [[WIDE_CHK1:%.*]] = and i1 [[WIDE_CHK]], [[COND_2:%.*]] 44; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK1]]) [ "deopt"(i32 0) ] 45; CHECK-NEXT: br label [[LOOP:%.*]] 46; CHECK: loop: 47; CHECK-NEXT: store i32 1, i32* @G 48; CHECK-NEXT: store i32 2, i32* @G 49; CHECK-NEXT: store i32 3, i32* @G 50; CHECK-NEXT: br label [[LOOP]] 51; 52entry: 53 store i32 0, i32* @G 54 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ] 55 br label %loop 56 57loop: 58 store i32 1, i32* @G 59 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"(i32 1) ] 60 store i32 2, i32* @G 61 call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ] 62 store i32 3, i32* @G 63 br label %loop 64} 65 66define void @dont_widen_over_common_exit(i1 %cond_0, i1 %cond_1, i1 %cond_2) { 67; CHECK-LABEL: @dont_widen_over_common_exit( 68; CHECK-NEXT: entry: 69; CHECK-NEXT: br label [[LOOP:%.*]] 70; CHECK: loop: 71; CHECK-NEXT: store i32 0, i32* @G 72; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0:%.*]]) [ "deopt"(i32 0) ] 73; CHECK-NEXT: store i32 1, i32* @G 74; CHECK-NEXT: br i1 [[COND_1:%.*]], label [[BACKEDGE:%.*]], label [[EXIT:%.*]] 75; CHECK: backedge: 76; CHECK-NEXT: store i32 2, i32* @G 77; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_2:%.*]]) [ "deopt"(i32 2) ] 78; CHECK-NEXT: store i32 3, i32* @G 79; CHECK-NEXT: br label [[LOOP]] 80; CHECK: exit: 81; CHECK-NEXT: ret void 82; 83entry: 84 br label %loop 85 86loop: 87 store i32 0, i32* @G 88 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ] 89 store i32 1, i32* @G 90 br i1 %cond_1, label %backedge, label %exit 91 92backedge: 93 store i32 2, i32* @G 94 call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ] 95 store i32 3, i32* @G 96 br label %loop 97 98exit: 99 ret void 100} 101 102define void @widen_over_common_exit_to_ph(i1 %cond_0, i1 %cond_1, i1 %cond_2) { 103; CHECK-LABEL: @widen_over_common_exit_to_ph( 104; CHECK-NEXT: entry: 105; CHECK-NEXT: store i32 0, i32* @G 106; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_2:%.*]] 107; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"(i32 0) ] 108; CHECK-NEXT: br label [[LOOP:%.*]] 109; CHECK: loop: 110; CHECK-NEXT: store i32 1, i32* @G 111; CHECK-NEXT: br i1 [[COND_1:%.*]], label [[BACKEDGE:%.*]], label [[EXIT:%.*]] 112; CHECK: backedge: 113; CHECK-NEXT: store i32 2, i32* @G 114; CHECK-NEXT: store i32 3, i32* @G 115; CHECK-NEXT: br label [[LOOP]] 116; CHECK: exit: 117; CHECK-NEXT: ret void 118; 119entry: 120 store i32 0, i32* @G 121 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ] 122 br label %loop 123 124loop: 125 store i32 1, i32* @G 126 br i1 %cond_1, label %backedge, label %exit 127 128backedge: 129 store i32 2, i32* @G 130 call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ] 131 store i32 3, i32* @G 132 br label %loop 133 134exit: 135 ret void 136} 137 138