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: [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2:%.*]] 14; CHECK-NEXT: [[COND_1_GW_FR:%.*]] = freeze i1 [[COND_1:%.*]] 15; CHECK-NEXT: br label [[LOOP:%.*]] 16; CHECK: loop: 17; CHECK-NEXT: store i32 0, ptr @G, align 4 18; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1_GW_FR]] 19; CHECK-NEXT: [[WIDE_CHK1:%.*]] = and i1 [[WIDE_CHK]], [[COND_2_GW_FR]] 20; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK1]]) [ "deopt"(i32 0) ] 21; CHECK-NEXT: store i32 1, ptr @G, align 4 22; CHECK-NEXT: store i32 2, ptr @G, align 4 23; CHECK-NEXT: store i32 3, ptr @G, align 4 24; CHECK-NEXT: br label [[LOOP]] 25; 26entry: 27 br label %loop 28 29loop: 30 store i32 0, ptr @G 31 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ] 32 store i32 1, ptr @G 33 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"(i32 1) ] 34 store i32 2, ptr @G 35 call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ] 36 store i32 3, ptr @G 37 br label %loop 38} 39 40define void @widen_into_preheader(i1 %cond_0, i1 %cond_1, i1 %cond_2) { 41; CHECK-LABEL: @widen_into_preheader( 42; CHECK-NEXT: entry: 43; CHECK-NEXT: [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2:%.*]] 44; CHECK-NEXT: [[COND_1_GW_FR:%.*]] = freeze i1 [[COND_1:%.*]] 45; CHECK-NEXT: store i32 0, ptr @G, align 4 46; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1_GW_FR]] 47; CHECK-NEXT: [[WIDE_CHK1:%.*]] = and i1 [[WIDE_CHK]], [[COND_2_GW_FR]] 48; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK1]]) [ "deopt"(i32 0) ] 49; CHECK-NEXT: br label [[LOOP:%.*]] 50; CHECK: loop: 51; CHECK-NEXT: store i32 1, ptr @G, align 4 52; CHECK-NEXT: store i32 2, ptr @G, align 4 53; CHECK-NEXT: store i32 3, ptr @G, align 4 54; CHECK-NEXT: br label [[LOOP]] 55; 56entry: 57 store i32 0, ptr @G 58 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ] 59 br label %loop 60 61loop: 62 store i32 1, ptr @G 63 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"(i32 1) ] 64 store i32 2, ptr @G 65 call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ] 66 store i32 3, ptr @G 67 br label %loop 68} 69 70define void @dont_widen_over_common_exit(i1 %cond_0, i1 %cond_1, i1 %cond_2) { 71; CHECK-LABEL: @dont_widen_over_common_exit( 72; CHECK-NEXT: entry: 73; CHECK-NEXT: br label [[LOOP:%.*]] 74; CHECK: loop: 75; CHECK-NEXT: store i32 0, ptr @G, align 4 76; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0:%.*]]) [ "deopt"(i32 0) ] 77; CHECK-NEXT: store i32 1, ptr @G, align 4 78; CHECK-NEXT: br i1 [[COND_1:%.*]], label [[BACKEDGE:%.*]], label [[EXIT:%.*]] 79; CHECK: backedge: 80; CHECK-NEXT: store i32 2, ptr @G, align 4 81; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_2:%.*]]) [ "deopt"(i32 2) ] 82; CHECK-NEXT: store i32 3, ptr @G, align 4 83; CHECK-NEXT: br label [[LOOP]] 84; CHECK: exit: 85; CHECK-NEXT: ret void 86; 87entry: 88 br label %loop 89 90loop: 91 store i32 0, ptr @G 92 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ] 93 store i32 1, ptr @G 94 br i1 %cond_1, label %backedge, label %exit 95 96backedge: 97 store i32 2, ptr @G 98 call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ] 99 store i32 3, ptr @G 100 br label %loop 101 102exit: 103 ret void 104} 105 106define void @widen_over_common_exit_to_ph(i1 %cond_0, i1 %cond_1, i1 %cond_2) { 107; CHECK-LABEL: @widen_over_common_exit_to_ph( 108; CHECK-NEXT: entry: 109; CHECK-NEXT: [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2:%.*]] 110; CHECK-NEXT: store i32 0, ptr @G, align 4 111; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_2_GW_FR]] 112; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"(i32 0) ] 113; CHECK-NEXT: br label [[LOOP:%.*]] 114; CHECK: loop: 115; CHECK-NEXT: store i32 1, ptr @G, align 4 116; CHECK-NEXT: br i1 [[COND_1:%.*]], label [[BACKEDGE:%.*]], label [[EXIT:%.*]] 117; CHECK: backedge: 118; CHECK-NEXT: store i32 2, ptr @G, align 4 119; CHECK-NEXT: store i32 3, ptr @G, align 4 120; CHECK-NEXT: br label [[LOOP]] 121; CHECK: exit: 122; CHECK-NEXT: ret void 123; 124entry: 125 store i32 0, ptr @G 126 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ] 127 br label %loop 128 129loop: 130 store i32 1, ptr @G 131 br i1 %cond_1, label %backedge, label %exit 132 133backedge: 134 store i32 2, ptr @G 135 call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ] 136 store i32 3, ptr @G 137 br label %loop 138 139exit: 140 ret void 141} 142 143