1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -loop-reduce -S | FileCheck %s 3 4target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n64-S128" 5target triple = "riscv64" 6 7 8define void @icmp_zero(i64 %N, ptr %p) { 9; CHECK-LABEL: @icmp_zero( 10; CHECK-NEXT: entry: 11; CHECK-NEXT: br label [[VECTOR_BODY:%.*]] 12; CHECK: vector.body: 13; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[VECTOR_BODY]] ], [ [[N:%.*]], [[ENTRY:%.*]] ] 14; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8 15; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -2 16; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0 17; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]] 18; CHECK: exit: 19; CHECK-NEXT: ret void 20; 21entry: 22 br label %vector.body 23 24vector.body: 25 %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ] 26 store i64 0, ptr %p 27 %iv.next = add i64 %iv, 2 28 %done = icmp eq i64 %iv.next, %N 29 br i1 %done, label %exit, label %vector.body 30 31exit: 32 ret void 33} 34 35define void @icmp_zero_urem_nonzero_con(i64 %N, ptr %p) { 36; CHECK-LABEL: @icmp_zero_urem_nonzero_con( 37; CHECK-NEXT: entry: 38; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], 16 39; CHECK-NEXT: br label [[VECTOR_BODY:%.*]] 40; CHECK: vector.body: 41; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[VECTOR_BODY]] ], [ [[UREM]], [[ENTRY:%.*]] ] 42; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8 43; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -2 44; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0 45; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]] 46; CHECK: exit: 47; CHECK-NEXT: ret void 48; 49entry: 50 %urem = urem i64 %N, 16 51 br label %vector.body 52 53vector.body: 54 %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ] 55 store i64 0, ptr %p 56 %iv.next = add i64 %iv, 2 57 %done = icmp eq i64 %iv.next, %urem 58 br i1 %done, label %exit, label %vector.body 59 60exit: 61 ret void 62} 63 64define void @icmp_zero_urem_invariant(i64 %N, i64 %M, ptr %p) { 65; CHECK-LABEL: @icmp_zero_urem_invariant( 66; CHECK-NEXT: entry: 67; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], [[M:%.*]] 68; CHECK-NEXT: br label [[VECTOR_BODY:%.*]] 69; CHECK: vector.body: 70; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[VECTOR_BODY]] ], [ [[UREM]], [[ENTRY:%.*]] ] 71; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8 72; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -2 73; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0 74; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]] 75; CHECK: exit: 76; CHECK-NEXT: ret void 77; 78entry: 79 %urem = urem i64 %N, %M 80 br label %vector.body 81 82vector.body: 83 %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ] 84 store i64 0, ptr %p 85 %iv.next = add i64 %iv, 2 86 %done = icmp eq i64 %iv.next, %urem 87 br i1 %done, label %exit, label %vector.body 88 89exit: 90 ret void 91} 92 93; We have to be careful here as SCEV can only compute a subtraction from 94; two pointers with the same base. If we hide %end inside a unknown, we 95; can no longer compute the subtract. 96define void @icmp_zero_urem_invariant_ptr(i64 %N, i64 %M, ptr %p) { 97; CHECK-LABEL: @icmp_zero_urem_invariant_ptr( 98; CHECK-NEXT: entry: 99; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], [[M:%.*]] 100; CHECK-NEXT: [[END:%.*]] = getelementptr i64, ptr [[P:%.*]], i64 [[UREM]] 101; CHECK-NEXT: br label [[VECTOR_BODY:%.*]] 102; CHECK: vector.body: 103; CHECK-NEXT: [[IV:%.*]] = phi ptr [ [[P]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[VECTOR_BODY]] ] 104; CHECK-NEXT: store i64 0, ptr [[P]], align 8 105; CHECK-NEXT: [[IV_NEXT]] = getelementptr i64, ptr [[IV]], i64 1 106; CHECK-NEXT: [[DONE:%.*]] = icmp eq ptr [[IV_NEXT]], [[END]] 107; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]] 108; CHECK: exit: 109; CHECK-NEXT: ret void 110; 111entry: 112 %urem = urem i64 %N, %M 113 %end = getelementptr i64, ptr %p, i64 %urem 114 br label %vector.body 115 116vector.body: 117 %iv = phi ptr [ %p, %entry ], [ %iv.next, %vector.body ] 118 store i64 0, ptr %p 119 %iv.next = getelementptr i64, ptr %iv, i64 1 120 %done = icmp eq ptr %iv.next, %end 121 br i1 %done, label %exit, label %vector.body 122 123exit: 124 ret void 125} 126 127; Negative test - We can not hoist because we don't know value of %M. 128define void @icmp_zero_urem_nohoist(i64 %N, i64 %M, ptr %p) { 129; CHECK-LABEL: @icmp_zero_urem_nohoist( 130; CHECK-NEXT: entry: 131; CHECK-NEXT: br label [[VECTOR_BODY:%.*]] 132; CHECK: vector.body: 133; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[VECTOR_BODY]] ] 134; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8 135; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 2 136; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], [[M:%.*]] 137; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[IV_NEXT]], [[UREM]] 138; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]] 139; CHECK: exit: 140; CHECK-NEXT: ret void 141; 142entry: 143 br label %vector.body 144 145vector.body: 146 %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ] 147 store i64 0, ptr %p 148 %iv.next = add i64 %iv, 2 149 %urem = urem i64 %N, %M 150 %done = icmp eq i64 %iv.next, %urem 151 br i1 %done, label %exit, label %vector.body 152 153exit: 154 ret void 155} 156 157define void @icmp_zero_urem_nonzero(i64 %N, i64 %M, ptr %p) { 158; CHECK-LABEL: @icmp_zero_urem_nonzero( 159; CHECK-NEXT: entry: 160; CHECK-NEXT: [[NONZERO:%.*]] = add nuw i64 [[M:%.*]], 1 161; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], [[NONZERO]] 162; CHECK-NEXT: br label [[VECTOR_BODY:%.*]] 163; CHECK: vector.body: 164; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[VECTOR_BODY]] ], [ [[UREM]], [[ENTRY:%.*]] ] 165; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8 166; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -2 167; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0 168; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]] 169; CHECK: exit: 170; CHECK-NEXT: ret void 171; 172entry: 173 %nonzero = add nuw i64 %M, 1 174 %urem = urem i64 %N, %nonzero 175 br label %vector.body 176 177vector.body: 178 %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ] 179 store i64 0, ptr %p 180 %iv.next = add i64 %iv, 2 181 %done = icmp eq i64 %iv.next, %urem 182 br i1 %done, label %exit, label %vector.body 183 184exit: 185 ret void 186} 187 188define void @icmp_zero_urem_vscale(i64 %N, ptr %p) { 189; CHECK-LABEL: @icmp_zero_urem_vscale( 190; CHECK-NEXT: entry: 191; CHECK-NEXT: [[VSCALE:%.*]] = call i64 @llvm.vscale.i64() 192; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], [[VSCALE]] 193; CHECK-NEXT: br label [[VECTOR_BODY:%.*]] 194; CHECK: vector.body: 195; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[VECTOR_BODY]] ], [ [[UREM]], [[ENTRY:%.*]] ] 196; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8 197; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -2 198; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0 199; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]] 200; CHECK: exit: 201; CHECK-NEXT: ret void 202; 203entry: 204 %vscale = call i64 @llvm.vscale.i64() 205 %urem = urem i64 %N, %vscale 206 br label %vector.body 207 208vector.body: 209 %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ] 210 store i64 0, ptr %p 211 %iv.next = add i64 %iv, 2 212 %done = icmp eq i64 %iv.next, %urem 213 br i1 %done, label %exit, label %vector.body 214 215exit: 216 ret void 217} 218 219define void @icmp_zero_urem_vscale_mul8(i64 %N, ptr %p) { 220; CHECK-LABEL: @icmp_zero_urem_vscale_mul8( 221; CHECK-NEXT: entry: 222; CHECK-NEXT: [[VSCALE:%.*]] = call i64 @llvm.vscale.i64() 223; CHECK-NEXT: [[MUL:%.*]] = mul nuw nsw i64 [[VSCALE]], 8 224; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], [[MUL]] 225; CHECK-NEXT: br label [[VECTOR_BODY:%.*]] 226; CHECK: vector.body: 227; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[VECTOR_BODY]] ], [ [[UREM]], [[ENTRY:%.*]] ] 228; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8 229; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -2 230; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0 231; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]] 232; CHECK: exit: 233; CHECK-NEXT: ret void 234; 235entry: 236 %vscale = call i64 @llvm.vscale.i64() 237 %mul = mul nuw nsw i64 %vscale, 8 238 %urem = urem i64 %N, %mul 239 br label %vector.body 240 241vector.body: 242 %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ] 243 store i64 0, ptr %p 244 %iv.next = add i64 %iv, 2 245 %done = icmp eq i64 %iv.next, %urem 246 br i1 %done, label %exit, label %vector.body 247 248exit: 249 ret void 250} 251 252 253define void @icmp_zero_urem_vscale_mul64(i64 %N, ptr %p) { 254; CHECK-LABEL: @icmp_zero_urem_vscale_mul64( 255; CHECK-NEXT: entry: 256; CHECK-NEXT: [[VSCALE:%.*]] = call i64 @llvm.vscale.i64() 257; CHECK-NEXT: [[MUL:%.*]] = mul nuw nsw i64 [[VSCALE]], 64 258; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], [[MUL]] 259; CHECK-NEXT: br label [[VECTOR_BODY:%.*]] 260; CHECK: vector.body: 261; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[VECTOR_BODY]] ], [ [[UREM]], [[ENTRY:%.*]] ] 262; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8 263; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -2 264; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0 265; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]] 266; CHECK: exit: 267; CHECK-NEXT: ret void 268; 269entry: 270 %vscale = call i64 @llvm.vscale.i64() 271 %mul = mul nuw nsw i64 %vscale, 64 272 %urem = urem i64 %N, %mul 273 br label %vector.body 274 275vector.body: 276 %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ] 277 store i64 0, ptr %p 278 %iv.next = add i64 %iv, 2 279 %done = icmp eq i64 %iv.next, %urem 280 br i1 %done, label %exit, label %vector.body 281 282exit: 283 ret void 284} 285 286define void @icmp_zero_urem_vscale_shl3(i64 %N, ptr %p) { 287; CHECK-LABEL: @icmp_zero_urem_vscale_shl3( 288; CHECK-NEXT: entry: 289; CHECK-NEXT: [[VSCALE:%.*]] = call i64 @llvm.vscale.i64() 290; CHECK-NEXT: [[SHL:%.*]] = shl i64 [[VSCALE]], 3 291; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], [[SHL]] 292; CHECK-NEXT: br label [[VECTOR_BODY:%.*]] 293; CHECK: vector.body: 294; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[VECTOR_BODY]] ], [ [[UREM]], [[ENTRY:%.*]] ] 295; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8 296; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -2 297; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0 298; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]] 299; CHECK: exit: 300; CHECK-NEXT: ret void 301; 302entry: 303 %vscale = call i64 @llvm.vscale.i64() 304 %shl = shl i64 %vscale, 3 305 %urem = urem i64 %N, %shl 306 br label %vector.body 307 308vector.body: 309 %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ] 310 store i64 0, ptr %p 311 %iv.next = add i64 %iv, 2 312 %done = icmp eq i64 %iv.next, %urem 313 br i1 %done, label %exit, label %vector.body 314 315exit: 316 ret void 317} 318 319define void @icmp_zero_urem_vscale_shl6(i64 %N, ptr %p) { 320; CHECK-LABEL: @icmp_zero_urem_vscale_shl6( 321; CHECK-NEXT: entry: 322; CHECK-NEXT: [[VSCALE:%.*]] = call i64 @llvm.vscale.i64() 323; CHECK-NEXT: [[SHL:%.*]] = shl i64 [[VSCALE]], 6 324; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], [[SHL]] 325; CHECK-NEXT: br label [[VECTOR_BODY:%.*]] 326; CHECK: vector.body: 327; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[VECTOR_BODY]] ], [ [[UREM]], [[ENTRY:%.*]] ] 328; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8 329; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -2 330; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0 331; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]] 332; CHECK: exit: 333; CHECK-NEXT: ret void 334; 335entry: 336 %vscale = call i64 @llvm.vscale.i64() 337 %shl = shl i64 %vscale, 6 338 %urem = urem i64 %N, %shl 339 br label %vector.body 340 341vector.body: 342 %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ] 343 store i64 0, ptr %p 344 %iv.next = add i64 %iv, 2 345 %done = icmp eq i64 %iv.next, %urem 346 br i1 %done, label %exit, label %vector.body 347 348exit: 349 ret void 350} 351 352; Loop invariant does not neccessarily mean dominating the loop. Forming 353; an ICmpZero from this example would be illegal even though the operands 354; to the compare are loop invariant. 355define void @loop_invariant_definition(i64 %arg) { 356; CHECK-LABEL: @loop_invariant_definition( 357; CHECK-NEXT: entry: 358; CHECK-NEXT: br label [[T1:%.*]] 359; CHECK: t1: 360; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[T1]] ], [ -1, [[ENTRY:%.*]] ] 361; CHECK-NEXT: [[LSR_IV_NEXT]] = add nsw i64 [[LSR_IV]], 1 362; CHECK-NEXT: br i1 true, label [[T4:%.*]], label [[T1]] 363; CHECK: t4: 364; CHECK-NEXT: [[T5:%.*]] = trunc i64 [[LSR_IV_NEXT]] to i32 365; CHECK-NEXT: [[T6:%.*]] = add i32 [[T5]], 1 366; CHECK-NEXT: [[T7:%.*]] = icmp eq i32 [[T5]], [[T6]] 367; CHECK-NEXT: ret void 368; 369entry: 370 br label %t1 371 372t1: ; preds = %1, %0 373 %t2 = phi i64 [ %t3, %t1 ], [ 0, %entry ] 374 %t3 = add nuw i64 %t2, 1 375 br i1 true, label %t4, label %t1 376 377t4: ; preds = %1 378 %t5 = trunc i64 %t2 to i32 379 %t6 = add i32 %t5, 1 380 %t7 = icmp eq i32 %t5, %t6 381 ret void 382} 383 384declare i64 @llvm.vscale.i64() 385