1; RUN: opt -S -guard-widening < %s | FileCheck %s 2 3declare void @llvm.experimental.guard(i1,...) 4 5define void @f_0(i32 %x, i32* %length_buf) { 6; CHECK-LABEL: @f_0( 7; CHECK-NOT: @llvm.experimental.guard 8; CHECK: %wide.chk2 = and i1 %chk3, %chk0 9; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 %wide.chk2) [ "deopt"() ] 10; CHECK: ret void 11entry: 12 %length = load i32, i32* %length_buf, !range !0 13 %chk0 = icmp ult i32 %x, %length 14 call void(i1, ...) @llvm.experimental.guard(i1 %chk0) [ "deopt"() ] 15 16 %x.inc1 = add i32 %x, 1 17 %chk1 = icmp ult i32 %x.inc1, %length 18 call void(i1, ...) @llvm.experimental.guard(i1 %chk1) [ "deopt"() ] 19 20 %x.inc2 = add i32 %x, 2 21 %chk2 = icmp ult i32 %x.inc2, %length 22 call void(i1, ...) @llvm.experimental.guard(i1 %chk2) [ "deopt"() ] 23 24 %x.inc3 = add i32 %x, 3 25 %chk3 = icmp ult i32 %x.inc3, %length 26 call void(i1, ...) @llvm.experimental.guard(i1 %chk3) [ "deopt"() ] 27 ret void 28} 29 30define void @f_1(i32 %x, i32* %length_buf) { 31; CHECK-LABEL: @f_1( 32; CHECK-NOT: llvm.experimental.guard 33; CHECK: %wide.chk2 = and i1 %chk3, %chk0 34; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 %wide.chk2) [ "deopt"() ] 35; CHECK: ret void 36entry: 37 %length = load i32, i32* %length_buf, !range !0 38 %chk0 = icmp ult i32 %x, %length 39 call void(i1, ...) @llvm.experimental.guard(i1 %chk0) [ "deopt"() ] 40 41 %x.inc1 = add i32 %x, 1 42 %chk1 = icmp ult i32 %x.inc1, %length 43 call void(i1, ...) @llvm.experimental.guard(i1 %chk1) [ "deopt"() ] 44 45 %x.inc2 = add i32 %x.inc1, 2 46 %chk2 = icmp ult i32 %x.inc2, %length 47 call void(i1, ...) @llvm.experimental.guard(i1 %chk2) [ "deopt"() ] 48 49 %x.inc3 = add i32 %x.inc2, 3 50 %chk3 = icmp ult i32 %x.inc3, %length 51 call void(i1, ...) @llvm.experimental.guard(i1 %chk3) [ "deopt"() ] 52 ret void 53} 54 55define void @f_2(i32 %a, i32* %length_buf) { 56; CHECK-LABEL: @f_2( 57; CHECK-NOT: llvm.experimental.guard 58; CHECK: %wide.chk2 = and i1 %chk3, %chk0 59; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 %wide.chk2) [ "deopt"() ] 60; CHECK: ret void 61entry: 62 %x = and i32 %a, 4294967040 ;; 4294967040 == 0xffffff00 63 %length = load i32, i32* %length_buf, !range !0 64 %chk0 = icmp ult i32 %x, %length 65 call void(i1, ...) @llvm.experimental.guard(i1 %chk0) [ "deopt"() ] 66 67 %x.inc1 = or i32 %x, 1 68 %chk1 = icmp ult i32 %x.inc1, %length 69 call void(i1, ...) @llvm.experimental.guard(i1 %chk1) [ "deopt"() ] 70 71 %x.inc2 = or i32 %x, 2 72 %chk2 = icmp ult i32 %x.inc2, %length 73 call void(i1, ...) @llvm.experimental.guard(i1 %chk2) [ "deopt"() ] 74 75 %x.inc3 = or i32 %x, 3 76 %chk3 = icmp ult i32 %x.inc3, %length 77 call void(i1, ...) @llvm.experimental.guard(i1 %chk3) [ "deopt"() ] 78 ret void 79} 80 81define void @f_3(i32 %a, i32* %length_buf) { 82; CHECK-LABEL: @f_3( 83; CHECK-NOT: llvm.experimental.guard 84; CHECK: %wide.chk2 = and i1 %chk3, %chk0 85; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 %wide.chk2) [ "deopt"() ] 86; CHECK: ret void 87entry: 88 %x = and i32 %a, 4294967040 ;; 4294967040 == 0xffffff00 89 %length = load i32, i32* %length_buf, !range !0 90 %chk0 = icmp ult i32 %x, %length 91 call void(i1, ...) @llvm.experimental.guard(i1 %chk0) [ "deopt"() ] 92 93 %x.inc1 = add i32 %x, 1 94 %chk1 = icmp ult i32 %x.inc1, %length 95 call void(i1, ...) @llvm.experimental.guard(i1 %chk1) [ "deopt"() ] 96 97 %x.inc2 = or i32 %x.inc1, 2 98 %chk2 = icmp ult i32 %x.inc2, %length 99 call void(i1, ...) @llvm.experimental.guard(i1 %chk2) [ "deopt"() ] 100 101 %x.inc3 = add i32 %x.inc2, 3 102 %chk3 = icmp ult i32 %x.inc3, %length 103 call void(i1, ...) @llvm.experimental.guard(i1 %chk3) [ "deopt"() ] 104 ret void 105} 106 107define void @f_4(i32 %x, i32* %length_buf) { 108; CHECK-LABEL: @f_4( 109; CHECK-NOT: llvm.experimental.guard 110 111; Note: we NOT guarding on "and i1 %chk3, %chk0", that would be incorrect. 112; CHECK: %wide.chk2 = and i1 %chk3, %chk1 113; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 %wide.chk2) [ "deopt"() ] 114; CHECK: ret void 115entry: 116 %length = load i32, i32* %length_buf, !range !0 117 %chk0 = icmp ult i32 %x, %length 118 call void(i1, ...) @llvm.experimental.guard(i1 %chk0) [ "deopt"() ] 119 120 %x.inc1 = add i32 %x, -1024 121 %chk1 = icmp ult i32 %x.inc1, %length 122 call void(i1, ...) @llvm.experimental.guard(i1 %chk1) [ "deopt"() ] 123 124 %x.inc2 = add i32 %x, 2 125 %chk2 = icmp ult i32 %x.inc2, %length 126 call void(i1, ...) @llvm.experimental.guard(i1 %chk2) [ "deopt"() ] 127 128 %x.inc3 = add i32 %x, 3 129 %chk3 = icmp ult i32 %x.inc3, %length 130 call void(i1, ...) @llvm.experimental.guard(i1 %chk3) [ "deopt"() ] 131 ret void 132} 133 134define void @f_5(i32 %x, i32* %length_buf) { 135; CHECK-LABEL: @f_5( 136; CHECK-NOT: llvm.experimental.guard 137; CHECK: %wide.chk2 = and i1 %chk1, %chk2 138; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 %wide.chk2) [ "deopt"() ] 139; CHECK: ret void 140entry: 141 %length = load i32, i32* %length_buf, !range !0 142 %chk0 = icmp ult i32 %x, %length 143 call void(i1, ...) @llvm.experimental.guard(i1 %chk0) [ "deopt"() ] 144 145 %x.inc1 = add i32 %x, 1 146 %chk1 = icmp ult i32 %x.inc1, %length 147 call void(i1, ...) @llvm.experimental.guard(i1 %chk1) [ "deopt"() ] 148 149 %x.inc2 = add i32 %x.inc1, -200 150 %chk2 = icmp ult i32 %x.inc2, %length 151 call void(i1, ...) @llvm.experimental.guard(i1 %chk2) [ "deopt"() ] 152 153 %x.inc3 = add i32 %x.inc2, 3 154 %chk3 = icmp ult i32 %x.inc3, %length 155 call void(i1, ...) @llvm.experimental.guard(i1 %chk3) [ "deopt"() ] 156 ret void 157} 158 159 160; Negative test: we can't merge these checks into 161; 162; (%x + -2147483647) u< L && (%x + 3) u< L 163; 164; because if %length == INT_MAX and %x == -3 then 165; 166; (%x + -2147483647) == i32 2147483646 u< L (L is 2147483647) 167; (%x + 3) == 0 u< L 168; 169; But (%x + 2) == -1 is not u< L 170; 171define void @f_6(i32 %x, i32* %length_buf) { 172; CHECK-LABEL: @f_6( 173; CHECK-NOT: llvm.experimental.guard 174; CHECK: %wide.chk = and i1 %chk0, %chk1 175; CHECK: %wide.chk1 = and i1 %wide.chk, %chk2 176; CHECK: %wide.chk2 = and i1 %wide.chk1, %chk3 177; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 %wide.chk2) [ "deopt"() ] 178entry: 179 %length = load i32, i32* %length_buf, !range !0 180 %chk0 = icmp ult i32 %x, %length 181 call void(i1, ...) @llvm.experimental.guard(i1 %chk0) [ "deopt"() ] 182 183 %x.inc1 = add i32 %x, -2147483647 ;; -2147483647 == (i32 INT_MIN)+1 == -(i32 INT_MAX) 184 %chk1 = icmp ult i32 %x.inc1, %length 185 call void(i1, ...) @llvm.experimental.guard(i1 %chk1) [ "deopt"() ] 186 187 %x.inc2 = add i32 %x, 2 188 %chk2 = icmp ult i32 %x.inc2, %length 189 call void(i1, ...) @llvm.experimental.guard(i1 %chk2) [ "deopt"() ] 190 191 %x.inc3 = add i32 %x, 3 192 %chk3 = icmp ult i32 %x.inc3, %length 193 call void(i1, ...) @llvm.experimental.guard(i1 %chk3) [ "deopt"() ] 194 ret void 195} 196 197 198define void @f_7(i32 %x, i32* %length_buf) { 199; CHECK-LABEL: @f_7( 200 201; CHECK: [[COND_0:%[^ ]+]] = and i1 %chk3.b, %chk0.b 202; CHECK: [[COND_1:%[^ ]+]] = and i1 %chk0.a, [[COND_0]] 203; CHECK: [[COND_2:%[^ ]+]] = and i1 %chk3.a, [[COND_1]] 204; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_2]]) [ "deopt"() ] 205 206entry: 207 %length_a = load volatile i32, i32* %length_buf, !range !0 208 %length_b = load volatile i32, i32* %length_buf, !range !0 209 %chk0.a = icmp ult i32 %x, %length_a 210 %chk0.b = icmp ult i32 %x, %length_b 211 %chk0 = and i1 %chk0.a, %chk0.b 212 call void(i1, ...) @llvm.experimental.guard(i1 %chk0) [ "deopt"() ] 213 214 %x.inc1 = add i32 %x, 1 215 %chk1.a = icmp ult i32 %x.inc1, %length_a 216 %chk1.b = icmp ult i32 %x.inc1, %length_b 217 %chk1 = and i1 %chk1.a, %chk1.b 218 call void(i1, ...) @llvm.experimental.guard(i1 %chk1) [ "deopt"() ] 219 220 %x.inc2 = add i32 %x, 2 221 %chk2.a = icmp ult i32 %x.inc2, %length_a 222 %chk2.b = icmp ult i32 %x.inc2, %length_b 223 %chk2 = and i1 %chk2.a, %chk2.b 224 call void(i1, ...) @llvm.experimental.guard(i1 %chk2) [ "deopt"() ] 225 226 %x.inc3 = add i32 %x, 3 227 %chk3.a = icmp ult i32 %x.inc3, %length_a 228 %chk3.b = icmp ult i32 %x.inc3, %length_b 229 %chk3 = and i1 %chk3.a, %chk3.b 230 call void(i1, ...) @llvm.experimental.guard(i1 %chk3) [ "deopt"() ] 231 ret void 232} 233 234 235!0 = !{i32 0, i32 2147483648} 236