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 64; FIXME: We could handle this case even though we don't know %M. The 65; faulting instruction is already outside the loop! 66define void @icmp_zero_urem_invariant(i64 %N, i64 %M, ptr %p) { 67; CHECK-LABEL: @icmp_zero_urem_invariant( 68; CHECK-NEXT: entry: 69; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], [[M:%.*]] 70; CHECK-NEXT: br label [[VECTOR_BODY:%.*]] 71; CHECK: vector.body: 72; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[VECTOR_BODY]] ] 73; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8 74; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 2 75; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[IV_NEXT]], [[UREM]] 76; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]] 77; CHECK: exit: 78; CHECK-NEXT: ret void 79; 80entry: 81 %urem = urem i64 %N, %M 82 br label %vector.body 83 84vector.body: 85 %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ] 86 store i64 0, ptr %p 87 %iv.next = add i64 %iv, 2 88 %done = icmp eq i64 %iv.next, %urem 89 br i1 %done, label %exit, label %vector.body 90 91exit: 92 ret void 93} 94 95; Negative test - We can not hoist because we don't know value of %M. 96define void @icmp_zero_urem_nohoist(i64 %N, i64 %M, ptr %p) { 97; CHECK-LABEL: @icmp_zero_urem_nohoist( 98; CHECK-NEXT: entry: 99; CHECK-NEXT: br label [[VECTOR_BODY:%.*]] 100; CHECK: vector.body: 101; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[VECTOR_BODY]] ] 102; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8 103; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 2 104; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], [[M:%.*]] 105; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[IV_NEXT]], [[UREM]] 106; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]] 107; CHECK: exit: 108; CHECK-NEXT: ret void 109; 110entry: 111 br label %vector.body 112 113vector.body: 114 %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ] 115 store i64 0, ptr %p 116 %iv.next = add i64 %iv, 2 117 %urem = urem i64 %N, %M 118 %done = icmp eq i64 %iv.next, %urem 119 br i1 %done, label %exit, label %vector.body 120 121exit: 122 ret void 123} 124 125define void @icmp_zero_urem_nonzero(i64 %N, i64 %M, ptr %p) { 126; CHECK-LABEL: @icmp_zero_urem_nonzero( 127; CHECK-NEXT: entry: 128; CHECK-NEXT: [[NONZERO:%.*]] = add nuw i64 [[M:%.*]], 1 129; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], [[NONZERO]] 130; CHECK-NEXT: br label [[VECTOR_BODY:%.*]] 131; CHECK: vector.body: 132; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[VECTOR_BODY]] ], [ [[UREM]], [[ENTRY:%.*]] ] 133; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8 134; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -2 135; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0 136; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]] 137; CHECK: exit: 138; CHECK-NEXT: ret void 139; 140entry: 141 %nonzero = add nuw i64 %M, 1 142 %urem = urem i64 %N, %nonzero 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 %done = icmp eq i64 %iv.next, %urem 150 br i1 %done, label %exit, label %vector.body 151 152exit: 153 ret void 154} 155 156define void @icmp_zero_urem_vscale(i64 %N, ptr %p) { 157; CHECK-LABEL: @icmp_zero_urem_vscale( 158; CHECK-NEXT: entry: 159; CHECK-NEXT: [[VSCALE:%.*]] = call i64 @llvm.vscale.i64() 160; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], [[VSCALE]] 161; CHECK-NEXT: br label [[VECTOR_BODY:%.*]] 162; CHECK: vector.body: 163; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[VECTOR_BODY]] ], [ [[UREM]], [[ENTRY:%.*]] ] 164; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8 165; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -2 166; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0 167; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]] 168; CHECK: exit: 169; CHECK-NEXT: ret void 170; 171entry: 172 %vscale = call i64 @llvm.vscale.i64() 173 %urem = urem i64 %N, %vscale 174 br label %vector.body 175 176vector.body: 177 %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ] 178 store i64 0, ptr %p 179 %iv.next = add i64 %iv, 2 180 %done = icmp eq i64 %iv.next, %urem 181 br i1 %done, label %exit, label %vector.body 182 183exit: 184 ret void 185} 186 187define void @icmp_zero_urem_vscale_mul8(i64 %N, ptr %p) { 188; CHECK-LABEL: @icmp_zero_urem_vscale_mul8( 189; CHECK-NEXT: entry: 190; CHECK-NEXT: [[VSCALE:%.*]] = call i64 @llvm.vscale.i64() 191; CHECK-NEXT: [[MUL:%.*]] = mul nuw nsw i64 [[VSCALE]], 8 192; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], [[MUL]] 193; CHECK-NEXT: br label [[VECTOR_BODY:%.*]] 194; CHECK: vector.body: 195; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[VECTOR_BODY]] ] 196; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8 197; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 2 198; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[IV_NEXT]], [[UREM]] 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 %mul = mul nuw nsw i64 %vscale, 8 206 %urem = urem i64 %N, %mul 207 br label %vector.body 208 209vector.body: 210 %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ] 211 store i64 0, ptr %p 212 %iv.next = add i64 %iv, 2 213 %done = icmp eq i64 %iv.next, %urem 214 br i1 %done, label %exit, label %vector.body 215 216exit: 217 ret void 218} 219 220 221define void @icmp_zero_urem_vscale_mul64(i64 %N, ptr %p) { 222; CHECK-LABEL: @icmp_zero_urem_vscale_mul64( 223; CHECK-NEXT: entry: 224; CHECK-NEXT: [[VSCALE:%.*]] = call i64 @llvm.vscale.i64() 225; CHECK-NEXT: [[MUL:%.*]] = mul nuw nsw i64 [[VSCALE]], 64 226; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], [[MUL]] 227; CHECK-NEXT: br label [[VECTOR_BODY:%.*]] 228; CHECK: vector.body: 229; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[VECTOR_BODY]] ] 230; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8 231; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 2 232; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[IV_NEXT]], [[UREM]] 233; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]] 234; CHECK: exit: 235; CHECK-NEXT: ret void 236; 237entry: 238 %vscale = call i64 @llvm.vscale.i64() 239 %mul = mul nuw nsw i64 %vscale, 64 240 %urem = urem i64 %N, %mul 241 br label %vector.body 242 243vector.body: 244 %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ] 245 store i64 0, ptr %p 246 %iv.next = add i64 %iv, 2 247 %done = icmp eq i64 %iv.next, %urem 248 br i1 %done, label %exit, label %vector.body 249 250exit: 251 ret void 252} 253 254define void @icmp_zero_urem_vscale_shl3(i64 %N, ptr %p) { 255; CHECK-LABEL: @icmp_zero_urem_vscale_shl3( 256; CHECK-NEXT: entry: 257; CHECK-NEXT: [[VSCALE:%.*]] = call i64 @llvm.vscale.i64() 258; CHECK-NEXT: [[SHL:%.*]] = shl i64 [[VSCALE]], 3 259; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], [[SHL]] 260; CHECK-NEXT: br label [[VECTOR_BODY:%.*]] 261; CHECK: vector.body: 262; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[VECTOR_BODY]] ] 263; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8 264; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 2 265; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[IV_NEXT]], [[UREM]] 266; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]] 267; CHECK: exit: 268; CHECK-NEXT: ret void 269; 270entry: 271 %vscale = call i64 @llvm.vscale.i64() 272 %shl = shl i64 %vscale, 3 273 %urem = urem i64 %N, %shl 274 br label %vector.body 275 276vector.body: 277 %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ] 278 store i64 0, ptr %p 279 %iv.next = add i64 %iv, 2 280 %done = icmp eq i64 %iv.next, %urem 281 br i1 %done, label %exit, label %vector.body 282 283exit: 284 ret void 285} 286 287define void @icmp_zero_urem_vscale_shl6(i64 %N, ptr %p) { 288; CHECK-LABEL: @icmp_zero_urem_vscale_shl6( 289; CHECK-NEXT: entry: 290; CHECK-NEXT: [[VSCALE:%.*]] = call i64 @llvm.vscale.i64() 291; CHECK-NEXT: [[SHL:%.*]] = shl i64 [[VSCALE]], 6 292; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], [[SHL]] 293; CHECK-NEXT: br label [[VECTOR_BODY:%.*]] 294; CHECK: vector.body: 295; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[VECTOR_BODY]] ] 296; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8 297; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 2 298; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[IV_NEXT]], [[UREM]] 299; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]] 300; CHECK: exit: 301; CHECK-NEXT: ret void 302; 303entry: 304 %vscale = call i64 @llvm.vscale.i64() 305 %shl = shl i64 %vscale, 6 306 %urem = urem i64 %N, %shl 307 br label %vector.body 308 309vector.body: 310 %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ] 311 store i64 0, ptr %p 312 %iv.next = add i64 %iv, 2 313 %done = icmp eq i64 %iv.next, %urem 314 br i1 %done, label %exit, label %vector.body 315 316exit: 317 ret void 318} 319 320declare i64 @llvm.vscale.i64() 321