1; RUN: opt < %s -indvars -indvars-post-increment-ranges -S | FileCheck %s 2 3target datalayout = "p:64:64:64-n32:64" 4 5; When the IV in this loop is widened we want to widen this use as well: 6; icmp slt i32 %i.inc, %limit 7; In order to do this indvars need to prove that the narrow IV def (%i.inc) 8; is not-negative from the range check inside of the loop. 9define void @test(i32* %base, i32 %limit, i32 %start) { 10; CHECK-LABEL: @test( 11; CHECK-NOT: trunc 12 13for.body.lr.ph: 14 br label %for.body 15 16for.body: 17 %i = phi i32 [ %start, %for.body.lr.ph ], [ %i.inc, %for.inc ] 18 %within_limits = icmp ult i32 %i, 64 19 br i1 %within_limits, label %continue, label %for.end 20 21continue: 22 %i.i64 = zext i32 %i to i64 23 %arrayidx = getelementptr inbounds i32, i32* %base, i64 %i.i64 24 %val = load i32, i32* %arrayidx, align 4 25 br label %for.inc 26 27for.inc: 28 %i.inc = add nsw nuw i32 %i, 1 29 %cmp = icmp slt i32 %i.inc, %limit 30 br i1 %cmp, label %for.body, label %for.end 31 32for.end: 33 br label %exit 34 35exit: 36 ret void 37} 38 39define void @test_false_edge(i32* %base, i32 %limit, i32 %start) { 40; CHECK-LABEL: @test_false_edge( 41; CHECK-NOT: trunc 42 43for.body.lr.ph: 44 br label %for.body 45 46for.body: 47 %i = phi i32 [ %start, %for.body.lr.ph ], [ %i.inc, %for.inc ] 48 %out_of_bounds = icmp ugt i32 %i, 64 49 br i1 %out_of_bounds, label %for.end, label %continue 50 51continue: 52 %i.i64 = zext i32 %i to i64 53 %arrayidx = getelementptr inbounds i32, i32* %base, i64 %i.i64 54 %val = load i32, i32* %arrayidx, align 4 55 br label %for.inc 56 57for.inc: 58 %i.inc = add nsw nuw i32 %i, 1 59 %cmp = icmp slt i32 %i.inc, %limit 60 br i1 %cmp, label %for.body, label %for.end 61 62for.end: 63 br label %exit 64 65exit: 66 ret void 67} 68 69define void @test_range_metadata(i32* %array_length_ptr, i32* %base, 70 i32 %limit, i32 %start) { 71; CHECK-LABEL: @test_range_metadata( 72; CHECK-NOT: trunc 73 74for.body.lr.ph: 75 br label %for.body 76 77for.body: 78 %i = phi i32 [ %start, %for.body.lr.ph ], [ %i.inc, %for.inc ] 79 %array_length = load i32, i32* %array_length_ptr, !range !{i32 0, i32 64 } 80 %within_limits = icmp ult i32 %i, %array_length 81 br i1 %within_limits, label %continue, label %for.end 82 83continue: 84 %i.i64 = zext i32 %i to i64 85 %arrayidx = getelementptr inbounds i32, i32* %base, i64 %i.i64 86 %val = load i32, i32* %arrayidx, align 4 87 br label %for.inc 88 89for.inc: 90 %i.inc = add nsw nuw i32 %i, 1 91 %cmp = icmp slt i32 %i.inc, %limit 92 br i1 %cmp, label %for.body, label %for.end 93 94for.end: 95 br label %exit 96 97exit: 98 ret void 99} 100 101; Negative version of the test above, we don't know anything about 102; array_length_ptr range. 103define void @test_neg(i32* %array_length_ptr, i32* %base, 104 i32 %limit, i32 %start) { 105; CHECK-LABEL: @test_neg( 106; CHECK: trunc i64 107 108for.body.lr.ph: 109 br label %for.body 110 111for.body: 112 %i = phi i32 [ %start, %for.body.lr.ph ], [ %i.inc, %for.inc ] 113 %array_length = load i32, i32* %array_length_ptr 114 %within_limits = icmp ult i32 %i, %array_length 115 br i1 %within_limits, label %continue, label %for.end 116 117continue: 118 %i.i64 = zext i32 %i to i64 119 %arrayidx = getelementptr inbounds i32, i32* %base, i64 %i.i64 120 %val = load i32, i32* %arrayidx, align 4 121 br label %for.inc 122 123for.inc: 124 %i.inc = add nsw nuw i32 %i, 1 125 %cmp = icmp slt i32 %i.inc, %limit 126 br i1 %cmp, label %for.body, label %for.end 127 128for.end: 129 br label %exit 130 131exit: 132 ret void 133} 134 135define void @test_transitive_use(i32* %base, i32 %limit, i32 %start) { 136; CHECK-LABEL: @test_transitive_use( 137; CHECK-NOT: trunc 138; CHECK: %result = icmp slt i64 139 140for.body.lr.ph: 141 br label %for.body 142 143for.body: 144 %i = phi i32 [ %start, %for.body.lr.ph ], [ %i.inc, %for.inc ] 145 %within_limits = icmp ult i32 %i, 64 146 br i1 %within_limits, label %continue, label %for.end 147 148continue: 149 %i.mul.3 = mul nsw nuw i32 %i, 3 150 %mul_within = icmp ult i32 %i.mul.3, 64 151 br i1 %mul_within, label %guarded, label %continue.2 152 153guarded: 154 %i.mul.3.inc = add nsw nuw i32 %i.mul.3, 1 155 %result = icmp slt i32 %i.mul.3.inc, %limit 156 br i1 %result, label %continue.2, label %for.end 157 158continue.2: 159 %i.i64 = zext i32 %i to i64 160 %arrayidx = getelementptr inbounds i32, i32* %base, i64 %i.i64 161 %val = load i32, i32* %arrayidx, align 4 162 br label %for.inc 163 164for.inc: 165 %i.inc = add nsw nuw i32 %i, 1 166 %cmp = icmp slt i32 %i.inc, %limit 167 br i1 %cmp, label %for.body, label %for.end 168 169 170for.end: 171 br label %exit 172 173exit: 174 ret void 175} 176 177declare void @llvm.experimental.guard(i1, ...) 178 179define void @test_guard_one_bb(i32* %base, i32 %limit, i32 %start) { 180; CHECK-LABEL: @test_guard_one_bb( 181; CHECK-NOT: trunc 182; CHECK-NOT: icmp slt i32 183 184for.body.lr.ph: 185 br label %for.body 186 187for.body: 188 %i = phi i32 [ %start, %for.body.lr.ph ], [ %i.inc, %for.body ] 189 %within_limits = icmp ult i32 %i, 64 190 %i.i64 = zext i32 %i to i64 191 %arrayidx = getelementptr inbounds i32, i32* %base, i64 %i.i64 192 %val = load i32, i32* %arrayidx, align 4 193 call void(i1, ...) @llvm.experimental.guard(i1 %within_limits) [ "deopt"() ] 194 %i.inc = add nsw nuw i32 %i, 1 195 %cmp = icmp slt i32 %i.inc, %limit 196 br i1 %cmp, label %for.body, label %for.end 197 198for.end: 199 br label %exit 200 201exit: 202 ret void 203} 204 205define void @test_guard_in_the_same_bb(i32* %base, i32 %limit, i32 %start) { 206; CHECK-LABEL: @test_guard_in_the_same_bb( 207; CHECK-NOT: trunc 208; CHECK-NOT: icmp slt i32 209 210for.body.lr.ph: 211 br label %for.body 212 213for.body: 214 %i = phi i32 [ %start, %for.body.lr.ph ], [ %i.inc, %for.inc ] 215 %within_limits = icmp ult i32 %i, 64 216 %i.i64 = zext i32 %i to i64 217 %arrayidx = getelementptr inbounds i32, i32* %base, i64 %i.i64 218 %val = load i32, i32* %arrayidx, align 4 219 br label %for.inc 220 221for.inc: 222 call void(i1, ...) @llvm.experimental.guard(i1 %within_limits) [ "deopt"() ] 223 %i.inc = add nsw nuw i32 %i, 1 224 %cmp = icmp slt i32 %i.inc, %limit 225 br i1 %cmp, label %for.body, label %for.end 226 227for.end: 228 br label %exit 229 230exit: 231 ret void 232} 233 234define void @test_guard_in_idom(i32* %base, i32 %limit, i32 %start) { 235; CHECK-LABEL: @test_guard_in_idom( 236; CHECK-NOT: trunc 237; CHECK-NOT: icmp slt i32 238 239for.body.lr.ph: 240 br label %for.body 241 242for.body: 243 %i = phi i32 [ %start, %for.body.lr.ph ], [ %i.inc, %for.inc ] 244 %within_limits = icmp ult i32 %i, 64 245 call void(i1, ...) @llvm.experimental.guard(i1 %within_limits) [ "deopt"() ] 246 %i.i64 = zext i32 %i to i64 247 %arrayidx = getelementptr inbounds i32, i32* %base, i64 %i.i64 248 %val = load i32, i32* %arrayidx, align 4 249 br label %for.inc 250 251for.inc: 252 %i.inc = add nsw nuw i32 %i, 1 253 %cmp = icmp slt i32 %i.inc, %limit 254 br i1 %cmp, label %for.body, label %for.end 255 256for.end: 257 br label %exit 258 259exit: 260 ret void 261} 262 263define void @test_guard_merge_ranges(i32* %base, i32 %limit, i32 %start) { 264; CHECK-LABEL: @test_guard_merge_ranges( 265; CHECK-NOT: trunc 266; CHECK-NOT: icmp slt i32 267 268for.body.lr.ph: 269 br label %for.body 270 271for.body: 272 %i = phi i32 [ %start, %for.body.lr.ph ], [ %i.inc, %for.body ] 273 %within_limits.1 = icmp ult i32 %i, 64 274 call void(i1, ...) @llvm.experimental.guard(i1 %within_limits.1) [ "deopt"() ] 275 %within_limits.2 = icmp ult i32 %i, 2147483647 276 call void(i1, ...) @llvm.experimental.guard(i1 %within_limits.2) [ "deopt"() ] 277 %i.i64 = zext i32 %i to i64 278 %arrayidx = getelementptr inbounds i32, i32* %base, i64 %i.i64 279 %val = load i32, i32* %arrayidx, align 4 280 %i.inc = add nsw nuw i32 %i, 1 281 %cmp = icmp slt i32 %i.inc, %limit 282 br i1 %cmp, label %for.body, label %for.end 283 284for.end: 285 br label %exit 286 287exit: 288 ret void 289} 290