1; RUN: opt -mtriple=thumbv8.1m.main-none-none-eabi -hardware-loops %s -S -o - | \ 2; RUN: FileCheck %s 3; RUN: opt -mtriple=thumbv8.1m.main -loop-unroll -unroll-remainder=false -S < %s | \ 4; RUN: llc -mtriple=thumbv8.1m.main | FileCheck %s --check-prefix=CHECK-UNROLL 5; RUN: opt -mtriple=thumbv8.1m.main-none-none-eabi -hardware-loops \ 6; RUN: -pass-remarks-analysis=hardware-loops %s -S -o - 2>&1 | \ 7; RUN: FileCheck %s --check-prefix=CHECK-REMARKS 8 9 10; CHECK-REMARKS: remark: <unknown>:0:0: hardware-loop not created: it's not profitable to create a hardware-loop 11; CHECK-REMARKS: remark: <unknown>:0:0: hardware-loop not created: nested hardware-loops not supported 12; CHECK-REMARKS: remark: <unknown>:0:0: hardware-loop not created: it's not profitable to create a hardware-loop 13; CHECK-REMARKS: remark: <unknown>:0:0: hardware-loop not created: it's not profitable to create a hardware-loop 14; CHECK-REMARKS: remark: <unknown>:0:0: hardware-loop not created: it's not profitable to create a hardware-loop 15; CHECK-REMARKS: remark: <unknown>:0:0: hardware-loop not created: it's not profitable to create a hardware-loop 16; CHECK-REMARKS: remark: <unknown>:0:0: hardware-loop not created: loop is not a candidate 17; CHECK-REMARKS: remark: <unknown>:0:0: hardware-loop not created: nested hardware-loops not supported 18; CHECK-REMARKS: remark: <unknown>:0:0: hardware-loop not created: it's not profitable to create a hardware-loop 19; CHECK-REMARKS: remark: <unknown>:0:0: hardware-loop not created: it's not profitable to create a hardware-loop 20 21 22; CHECK-LABEL: early_exit 23; CHECK-NOT: llvm.set.loop.iterations 24; CHECK-NOT: llvm.loop.decrement 25define i32 @early_exit(i32* nocapture readonly %a, i32 %max, i32 %n) { 26entry: 27 br label %do.body 28 29do.body: 30 %i.0 = phi i32 [ 0, %entry ], [ %inc, %if.end ] 31 %arrayidx = getelementptr inbounds i32, i32* %a, i32 %i.0 32 %0 = load i32, i32* %arrayidx, align 4 33 %cmp = icmp sgt i32 %0, %max 34 br i1 %cmp, label %do.end, label %if.end 35 36if.end: 37 %inc = add nuw i32 %i.0, 1 38 %cmp1 = icmp ult i32 %inc, %n 39 br i1 %cmp1, label %do.body, label %if.end.do.end_crit_edge 40 41if.end.do.end_crit_edge: 42 %arrayidx2.phi.trans.insert = getelementptr inbounds i32, i32* %a, i32 %inc 43 %.pre = load i32, i32* %arrayidx2.phi.trans.insert, align 4 44 br label %do.end 45 46do.end: 47 %1 = phi i32 [ %.pre, %if.end.do.end_crit_edge ], [ %0, %do.body ] 48 ret i32 %1 49} 50 51; CHECK-LABEL: nested 52; CHECK-NOT: call i32 @llvm.start.loop.iterations.i32(i32 %N) 53; CHECK: br i1 %cmp20, label %while.end7, label %while.cond1.preheader.us 54 55; CHECK: [[START:%[^ ]+]] = call i32 @llvm.start.loop.iterations.i32(i32 %N) 56; CHECK: br label %while.body3.us 57 58; CHECK: [[REM:%[^ ]+]] = phi i32 [ [[START]], %while.cond1.preheader.us ], [ [[LOOP_DEC:%[^ ]+]], %while.body3.us ] 59; CHECK: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32(i32 [[REM]], i32 1) 60; CHECK: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0 61; CHECK: br i1 [[CMP]], label %while.body3.us, label %while.cond1.while.end_crit_edge.us 62 63; CHECK-NOT: [[LOOP_DEC1:%[^ ]+]] = call i1 @llvm.loop.decrement.i32(i32 1) 64; CHECK-NOT: br i1 [[LOOP_DEC1]], label %while.cond1.preheader.us, label %while.end7 65 66define void @nested(i32* nocapture %A, i32 %N) { 67entry: 68 %cmp20 = icmp eq i32 %N, 0 69 br i1 %cmp20, label %while.end7, label %while.cond1.preheader.us 70 71while.cond1.preheader.us: 72 %i.021.us = phi i32 [ %inc6.us, %while.cond1.while.end_crit_edge.us ], [ 0, %entry ] 73 %mul.us = mul i32 %i.021.us, %N 74 br label %while.body3.us 75 76while.body3.us: 77 %j.019.us = phi i32 [ 0, %while.cond1.preheader.us ], [ %inc.us, %while.body3.us ] 78 %add.us = add i32 %j.019.us, %mul.us 79 %arrayidx.us = getelementptr inbounds i32, i32* %A, i32 %add.us 80 store i32 %add.us, i32* %arrayidx.us, align 4 81 %inc.us = add nuw i32 %j.019.us, 1 82 %exitcond = icmp eq i32 %inc.us, %N 83 br i1 %exitcond, label %while.cond1.while.end_crit_edge.us, label %while.body3.us 84 85while.cond1.while.end_crit_edge.us: 86 %inc6.us = add nuw i32 %i.021.us, 1 87 %exitcond23 = icmp eq i32 %inc6.us, %N 88 br i1 %exitcond23, label %while.end7, label %while.cond1.preheader.us 89 90while.end7: 91 ret void 92} 93 94; CHECK-LABEL: pre_existing 95; CHECK: llvm.start.loop.iterations 96; CHECK-NOT: llvm.start.loop.iterations 97; CHECK: call i32 @llvm.loop.decrement.reg.i32(i32 %0, i32 1) 98; CHECK-NOT: call i32 @llvm.loop.decrement.reg 99define i32 @pre_existing(i32 %n, i32* nocapture %p, i32* nocapture readonly %q) { 100entry: 101 %start = call i32 @llvm.start.loop.iterations.i32(i32 %n) 102 br label %while.body 103 104while.body: ; preds = %while.body, %entry 105 %q.addr.05 = phi i32* [ %incdec.ptr, %while.body ], [ %q, %entry ] 106 %p.addr.04 = phi i32* [ %incdec.ptr1, %while.body ], [ %p, %entry ] 107 %0 = phi i32 [ %start, %entry ], [ %2, %while.body ] 108 %incdec.ptr = getelementptr inbounds i32, i32* %q.addr.05, i32 1 109 %1 = load i32, i32* %q.addr.05, align 4 110 %incdec.ptr1 = getelementptr inbounds i32, i32* %p.addr.04, i32 1 111 store i32 %1, i32* %p.addr.04, align 4 112 %2 = call i32 @llvm.loop.decrement.reg.i32(i32 %0, i32 1) 113 %3 = icmp ne i32 %2, 0 114 br i1 %3, label %while.body, label %while.end 115 116while.end: ; preds = %while.body 117 ret i32 0 118} 119 120; CHECK-LABEL: pre_existing_test_set 121; CHECK: call { i32, i1 } @llvm.test.start.loop.iterations 122; CHECK-NOT: llvm.set{{.*}}.loop.iterations 123; CHECK: call i32 @llvm.loop.decrement.reg.i32(i32 %0, i32 1) 124; CHECK-NOT: call i32 @llvm.loop.decrement.reg 125define i32 @pre_existing_test_set(i32 %n, i32* nocapture %p, i32* nocapture readonly %q) { 126entry: 127 %guard = call { i32, i1 } @llvm.test.start.loop.iterations.i32(i32 %n) 128 %g0 = extractvalue { i32, i1 } %guard, 0 129 %g1 = extractvalue { i32, i1 } %guard, 1 130 br i1 %g1, label %while.preheader, label %while.end 131 132while.preheader: 133 br label %while.body 134 135while.body: ; preds = %while.body, %entry 136 %q.addr.05 = phi i32* [ %incdec.ptr, %while.body ], [ %q, %while.preheader ] 137 %p.addr.04 = phi i32* [ %incdec.ptr1, %while.body ], [ %p, %while.preheader ] 138 %0 = phi i32 [ %g0, %while.preheader ], [ %2, %while.body ] 139 %incdec.ptr = getelementptr inbounds i32, i32* %q.addr.05, i32 1 140 %1 = load i32, i32* %q.addr.05, align 4 141 %incdec.ptr1 = getelementptr inbounds i32, i32* %p.addr.04, i32 1 142 store i32 %1, i32* %p.addr.04, align 4 143 %2 = call i32 @llvm.loop.decrement.reg.i32(i32 %0, i32 1) 144 %3 = icmp ne i32 %2, 0 145 br i1 %3, label %while.body, label %while.end 146 147while.end: ; preds = %while.body 148 ret i32 0 149} 150 151; CHECK-LABEL: pre_existing_inner 152; CHECK-NOT: llvm.start.loop.iterations 153; CHECK: while.cond1.preheader.us: 154; CHECK: call i32 @llvm.start.loop.iterations.i32(i32 %N) 155; CHECK: call i32 @llvm.loop.decrement.reg.i32(i32 %0, i32 1) 156; CHECK: br i1 157; CHECK-NOT: call i32 @llvm.loop.decrement 158define void @pre_existing_inner(i32* nocapture %A, i32 %N) { 159entry: 160 %cmp20 = icmp eq i32 %N, 0 161 br i1 %cmp20, label %while.end7, label %while.cond1.preheader.us 162 163while.cond1.preheader.us: 164 %i.021.us = phi i32 [ %inc6.us, %while.cond1.while.end_crit_edge.us ], [ 0, %entry ] 165 %mul.us = mul i32 %i.021.us, %N 166 %start = call i32 @llvm.start.loop.iterations.i32(i32 %N) 167 br label %while.body3.us 168 169while.body3.us: 170 %j.019.us = phi i32 [ 0, %while.cond1.preheader.us ], [ %inc.us, %while.body3.us ] 171 %0 = phi i32 [ %start, %while.cond1.preheader.us ], [ %1, %while.body3.us ] 172 %add.us = add i32 %j.019.us, %mul.us 173 %arrayidx.us = getelementptr inbounds i32, i32* %A, i32 %add.us 174 store i32 %add.us, i32* %arrayidx.us, align 4 175 %inc.us = add nuw i32 %j.019.us, 1 176 %1 = call i32 @llvm.loop.decrement.reg.i32(i32 %0, i32 1) 177 %2 = icmp ne i32 %1, 0 178 br i1 %2, label %while.body3.us, label %while.cond1.while.end_crit_edge.us 179 180while.cond1.while.end_crit_edge.us: 181 %inc6.us = add nuw i32 %i.021.us, 1 182 %exitcond23 = icmp eq i32 %inc6.us, %N 183 br i1 %exitcond23, label %while.end7, label %while.cond1.preheader.us 184 185while.end7: 186 ret void 187} 188 189; CHECK-LABEL: not_rotated 190; CHECK-NOT: call i32 @llvm.start.loop.iterations 191; CHECK-NOT: call i32 @llvm.loop.decrement.i32 192define void @not_rotated(i32, i16* nocapture, i16 signext) { 193 br label %4 194 1954: 196 %5 = phi i32 [ 0, %3 ], [ %19, %18 ] 197 %6 = icmp eq i32 %5, %0 198 br i1 %6, label %20, label %7 199 2007: 201 %8 = mul i32 %5, %0 202 br label %9 203 2049: 205 %10 = phi i32 [ %17, %12 ], [ 0, %7 ] 206 %11 = icmp eq i32 %10, %0 207 br i1 %11, label %18, label %12 208 20912: 210 %13 = add i32 %10, %8 211 %14 = getelementptr inbounds i16, i16* %1, i32 %13 212 %15 = load i16, i16* %14, align 2 213 %16 = add i16 %15, %2 214 store i16 %16, i16* %14, align 2 215 %17 = add i32 %10, 1 216 br label %9 217 21818: 219 %19 = add i32 %5, 1 220 br label %4 221 22220: 223 ret void 224} 225 226; CHECK-LABEL: multi_latch 227; CHECK-NOT: call i32 @llvm.start.loop.iterations 228; CHECK-NOT: call i32 @llvm.loop.decrement 229define void @multi_latch(i32* %a, i32* %b, i32 %N) { 230entry: 231 %half = lshr i32 %N, 1 232 br label %header 233 234header: 235 %iv = phi i32 [ 0, %entry ], [ %count.next, %latch.0 ], [ %count.next, %latch.1 ] 236 %cmp = icmp ult i32 %iv, %half 237 %addr.a = getelementptr i32, i32* %a, i32 %iv 238 %addr.b = getelementptr i32, i32* %b, i32 %iv 239 br i1 %cmp, label %if.then, label %if.else 240 241if.then: 242 store i32 %iv, i32* %addr.a 243 br label %latch.0 244 245if.else: 246 store i32 %iv, i32* %addr.b 247 br label %latch.0 248 249latch.0: 250 %count.next = add nuw i32 %iv, 1 251 %cmp.1 = icmp ult i32 %count.next, %half 252 br i1 %cmp.1, label %header, label %latch.1 253 254latch.1: 255 %ld = load i32, i32* %addr.a 256 store i32 %ld, i32* %addr.b 257 %cmp.2 = icmp ult i32 %count.next, %N 258 br i1 %cmp.2, label %header, label %latch.1 259 260exit: 261 ret void 262} 263 264; CHECK-LABEL: search 265; CHECK: entry: 266; CHECK: [[TEST1:%[^ ]+]] = call { i32, i1 } @llvm.test.start.loop.iterations.i32(i32 %N) 267; CHECK: [[TEST:%[^ ]+]] = extractvalue { i32, i1 } [[TEST1]], 1 268; CHECK: br i1 [[TEST]], label %for.body.preheader, label %for.cond.cleanup 269; CHECK: for.body.preheader: 270; CHECK: br label %for.body 271; CHECK: for.body: 272; CHECK: for.inc: 273; CHECK: [[LOOP_DEC:%[^ ]+]] = call i32 @llvm.loop.decrement.reg.i32( 274; CHECK: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0 275; CHECK: br i1 [[CMP]], label %for.body, label %for.cond.cleanup 276define i32 @search(i8* nocapture readonly %c, i32 %N) { 277entry: 278 %cmp11 = icmp eq i32 %N, 0 279 br i1 %cmp11, label %for.cond.cleanup, label %for.body 280 281for.cond.cleanup: 282 %found.0.lcssa = phi i32 [ 0, %entry ], [ %found.1, %for.inc ] 283 %spaces.0.lcssa = phi i32 [ 0, %entry ], [ %spaces.1, %for.inc ] 284 %sub = sub nsw i32 %found.0.lcssa, %spaces.0.lcssa 285 ret i32 %sub 286 287for.body: 288 %i.014 = phi i32 [ %inc3, %for.inc ], [ 0, %entry ] 289 %spaces.013 = phi i32 [ %spaces.1, %for.inc ], [ 0, %entry ] 290 %found.012 = phi i32 [ %found.1, %for.inc ], [ 0, %entry ] 291 %arrayidx = getelementptr inbounds i8, i8* %c, i32 %i.014 292 %0 = load i8, i8* %arrayidx, align 1 293 switch i8 %0, label %for.inc [ 294 i8 108, label %sw.bb 295 i8 111, label %sw.bb 296 i8 112, label %sw.bb 297 i8 32, label %sw.bb1 298 ] 299 300sw.bb: ; preds = %for.body, %for.body, %for.body 301 %inc = add nsw i32 %found.012, 1 302 br label %for.inc 303 304sw.bb1: ; preds = %for.body 305 %inc2 = add nsw i32 %spaces.013, 1 306 br label %for.inc 307 308for.inc: ; preds = %sw.bb, %sw.bb1, %for.body 309 %found.1 = phi i32 [ %found.012, %for.body ], [ %found.012, %sw.bb1 ], [ %inc, %sw.bb ] 310 %spaces.1 = phi i32 [ %spaces.013, %for.body ], [ %inc2, %sw.bb1 ], [ %spaces.013, %sw.bb ] 311 %inc3 = add nuw i32 %i.014, 1 312 %exitcond = icmp eq i32 %inc3, %N 313 br i1 %exitcond, label %for.cond.cleanup, label %for.body 314} 315 316; CHECK-LABEL: unroll_inc_int 317; CHECK: call i32 @llvm.start.loop.iterations.i32(i32 %N) 318; CHECK: call i32 @llvm.loop.decrement.reg.i32( 319 320; TODO: We should be able to support the unrolled loop body. 321; CHECK-UNROLL-LABEL: unroll_inc_int 322; CHECK-UNROLL: [[PREHEADER:.LBB[0-9_]+]]: @ %for.body.preheader 323; CHECK-UNROLL-NOT: dls 324; CHECK-UNROLL: [[LOOP:.LBB[0-9_]+]]: @ %for.body 325; CHECK-UNROLL-NOT: le lr, [[LOOP]] 326; CHECK-UNROLL: bne [[LOOP]] 327; CHECK-UNROLL: wls lr, r12, [[EXIT:.LBB[0-9_]+]] 328; CHECK-UNROLL: [[EPIL:.LBB[0-9_]+]]: 329; CHECK-UNROLL: le lr, [[EPIL]] 330; CHECK-UNROLL-NEXT: [[EXIT]] 331 332define void @unroll_inc_int(i32* nocapture %a, i32* nocapture readonly %b, i32* nocapture readonly %c, i32 %N) { 333entry: 334 %cmp8 = icmp sgt i32 %N, 0 335 br i1 %cmp8, label %for.body, label %for.cond.cleanup 336 337for.cond.cleanup: 338 ret void 339 340for.body: 341 %i.09 = phi i32 [ %inc, %for.body ], [ 0, %entry ] 342 %arrayidx = getelementptr inbounds i32, i32* %b, i32 %i.09 343 %0 = load i32, i32* %arrayidx, align 4 344 %arrayidx1 = getelementptr inbounds i32, i32* %c, i32 %i.09 345 %1 = load i32, i32* %arrayidx1, align 4 346 %mul = mul nsw i32 %1, %0 347 %arrayidx2 = getelementptr inbounds i32, i32* %a, i32 %i.09 348 store i32 %mul, i32* %arrayidx2, align 4 349 %inc = add nuw nsw i32 %i.09, 1 350 %exitcond = icmp eq i32 %inc, %N 351 br i1 %exitcond, label %for.cond.cleanup, label %for.body 352} 353 354; CHECK-LABEL: unroll_inc_unsigned 355; CHECK: call { i32, i1 } @llvm.test.start.loop.iterations.i32(i32 %N) 356; CHECK: call i32 @llvm.loop.decrement.reg.i32( 357 358; TODO: We should be able to support the unrolled loop body. 359; CHECK-UNROLL-LABEL: unroll_inc_unsigned 360; CHECK-UNROLL: [[PREHEADER:.LBB[0-9_]+]]: @ %for.body.preheader 361; CHECK-UNROLL-NOT: dls 362; CHECK-UNROLL: [[LOOP:.LBB[0-9_]+]]: @ %for.body 363; CHECK-UNROLL-NOT: le lr, [[LOOP]] 364; CHECK-UNROLL: bne [[LOOP]] 365; CHECK-UNROLL: wls lr, r12, [[EPIL_EXIT:.LBB[0-9_]+]] 366; CHECK-UNROLL: [[EPIL:.LBB[0-9_]+]]: 367; CHECK-UNROLL: le lr, [[EPIL]] 368; CHECK-UNROLL: [[EPIL_EXIT]]: 369; CHECK-UNROLL: pop 370define void @unroll_inc_unsigned(i32* nocapture %a, i32* nocapture readonly %b, i32* nocapture readonly %c, i32 %N) { 371entry: 372 %cmp8 = icmp eq i32 %N, 0 373 br i1 %cmp8, label %for.cond.cleanup, label %for.body 374 375for.cond.cleanup: 376 ret void 377 378for.body: 379 %i.09 = phi i32 [ %inc, %for.body ], [ 0, %entry ] 380 %arrayidx = getelementptr inbounds i32, i32* %b, i32 %i.09 381 %0 = load i32, i32* %arrayidx, align 4 382 %arrayidx1 = getelementptr inbounds i32, i32* %c, i32 %i.09 383 %1 = load i32, i32* %arrayidx1, align 4 384 %mul = mul nsw i32 %1, %0 385 %arrayidx2 = getelementptr inbounds i32, i32* %a, i32 %i.09 386 store i32 %mul, i32* %arrayidx2, align 4 387 %inc = add nuw i32 %i.09, 1 388 %exitcond = icmp eq i32 %inc, %N 389 br i1 %exitcond, label %for.cond.cleanup, label %for.body 390} 391 392; CHECK-LABEL: unroll_dec_int 393; CHECK: call i32 @llvm.start.loop.iterations.i32(i32 %N) 394; CHECK: call i32 @llvm.loop.decrement.reg.i32( 395 396; CHECK-UNROLL-LABEL: unroll_dec_int: 397; CHECK-UNROLL: wls lr, {{.*}}, [[PROLOGUE_EXIT:.LBB[0-9_]+]] 398; CHECK-UNROLL-NEXT: [[PROLOGUE:.LBB[0-9_]+]]: 399; CHECK-UNROLL: le lr, [[PROLOGUE]] 400; CHECK-UNROLL-NEXT: [[PROLOGUE_EXIT:.LBB[0-9_]+]]: 401; CHECK-UNROLL: [[BODY:.LBB[0-9_]+]]: 402; CHECK-UNROLL: le lr, [[BODY]] 403; CHECK-UNROLL-NOT: b 404; CHECK-UNROLL: pop 405define void @unroll_dec_int(i32* nocapture %a, i32* nocapture readonly %b, i32* nocapture readonly %c, i32 %N) { 406entry: 407 %cmp8 = icmp sgt i32 %N, 0 408 br i1 %cmp8, label %for.body, label %for.cond.cleanup 409 410for.cond.cleanup: 411 ret void 412 413for.body: 414 %i.09 = phi i32 [ %dec, %for.body ], [ %N, %entry ] 415 %arrayidx = getelementptr inbounds i32, i32* %b, i32 %i.09 416 %0 = load i32, i32* %arrayidx, align 4 417 %arrayidx1 = getelementptr inbounds i32, i32* %c, i32 %i.09 418 %1 = load i32, i32* %arrayidx1, align 4 419 %mul = mul nsw i32 %1, %0 420 %arrayidx2 = getelementptr inbounds i32, i32* %a, i32 %i.09 421 store i32 %mul, i32* %arrayidx2, align 4 422 %dec = add nsw i32 %i.09, -1 423 %cmp = icmp sgt i32 %dec, 0 424 br i1 %cmp, label %for.body, label %for.cond.cleanup 425} 426 427declare i32 @llvm.start.loop.iterations.i32(i32) #0 428declare { i32, i1 } @llvm.test.start.loop.iterations.i32(i32) #0 429declare i32 @llvm.loop.decrement.reg.i32(i32, i32) #0 430 431