1 ; RUN: opt -S -guard-widening < %s | FileCheck %s 2 3 declare void @llvm.experimental.guard(i1,...) 4 5 define 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 11 entry: 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 30 define 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 36 entry: 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 55 define 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 61 entry: 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 81 define 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 87 entry: 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 107 define 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 115 entry: 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 134 define 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 140 entry: 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 ; 171 define 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"() ] 178 entry: 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 198 define 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 206 entry: 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