1; RUN: opt < %s -passes="loop-vectorize" -force-vector-interleave=1 -force-vector-width=4 -S | FileCheck %s 2 3target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" 4 5; This test checks that we can vectorize loop with reduction variable 6; stored in an invariant address. 7; 8; int sum = 0; 9; for(i=0..N) { 10; sum += src[i]; 11; dst[42] = sum; 12; } 13; CHECK-LABEL: @reduc_store 14; CHECK: vector.body: 15; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, [[VECTOR_PH:%.*]] ], [ [[INDEX_NEXT:%.*]], [[VECTOR_BODY:%.*]] ] 16; CHECK-NEXT: [[VEC_PHI:%.*]] = phi <4 x i32> [ zeroinitializer, [[VECTOR_PH]] ], [ [[TMP4:%.*]], [[VECTOR_BODY]] ] 17; CHECK-NEXT: [[TMP0:%.*]] = add i64 [[INDEX]], 0 18; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, i32* [[SRC:%.*]], i64 [[TMP0]] 19; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds i32, i32* [[TMP1]], i32 0 20; CHECK-NEXT: [[TMP3:%.*]] = bitcast i32* [[TMP2]] to <4 x i32>* 21; CHECK-NEXT: [[WIDE_LOAD:%.*]] = load <4 x i32>, <4 x i32>* [[TMP3]], align 4, !alias.scope !0 22; CHECK-NEXT: [[TMP4]] = add <4 x i32> [[VEC_PHI]], [[WIDE_LOAD]] 23; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4 24; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i64 [[INDEX_NEXT]], 1000 25; CHECK-NEXT: br i1 [[TMP5]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP3:![0-9]+]] 26; CHECK: middle.block: 27; CHECK-NEXT: [[TMP6:%.*]] = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> [[TMP4]]) 28; CHECK-NEXT: store i32 [[TMP6]], i32* [[GEP_DST:%.*]], align 4 29; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 1000, 1000 30; CHECK-NEXT: br i1 [[CMP_N]], label [[EXIT:%.*]], label [[SCALAR_PH:%.*]] 31define void @reduc_store(i32* %dst, i32* readonly %src) { 32entry: 33 %gep.dst = getelementptr inbounds i32, i32* %dst, i64 42 34 store i32 0, i32* %gep.dst, align 4 35 br label %for.body 36 37for.body: 38 %sum = phi i32 [ 0, %entry ], [ %add, %for.body ] 39 %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ] 40 %gep.src = getelementptr inbounds i32, i32* %src, i64 %iv 41 %0 = load i32, i32* %gep.src, align 4 42 %add = add nsw i32 %sum, %0 43 store i32 %add, i32* %gep.dst, align 4 44 %iv.next = add nuw nsw i64 %iv, 1 45 %exitcond = icmp eq i64 %iv.next, 1000 46 br i1 %exitcond, label %exit, label %for.body 47 48exit: 49 ret void 50} 51 52; Same as above but with floating point numbers instead. 53; 54; float sum = 0; 55; for(i=0..N) { 56; sum += src[i]; 57; dst[42] = sum; 58; } 59; CHECK-LABEL: @reduc_store_fadd_fast 60; CHECK: vector.body: 61; CHECK: phi <4 x float> 62; CHECK: load <4 x float> 63; CHECK: fadd fast <4 x float> 64; CHECK-NOT: store float %{{[0-9]+}}, float* %gep.dst 65; CHECK: middle.block: 66; CHECK-NEXT: [[TMP:%.*]] = call fast float @llvm.vector.reduce.fadd.v4f32 67; CHECK-NEXT: store float %{{[0-9]+}}, float* %gep.dst 68define void @reduc_store_fadd_fast(float* %dst, float* readonly %src) { 69entry: 70 %gep.dst = getelementptr inbounds float, float* %dst, i64 42 71 store float 0.000000e+00, float* %gep.dst, align 4 72 br label %for.body 73 74for.body: 75 %sum = phi float [ 0.000000e+00, %entry ], [ %add, %for.body ] 76 %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ] 77 %gep.src = getelementptr inbounds float, float* %src, i64 %iv 78 %0 = load float, float* %gep.src, align 4 79 %add = fadd fast float %sum, %0 80 store float %add, float* %gep.dst, align 4 81 %iv.next = add nuw nsw i64 %iv, 1 82 %exitcond = icmp eq i64 %iv.next, 1000 83 br i1 %exitcond, label %exit, label %for.body 84 85exit: 86 ret void 87} 88 89; Check that if we have a read from an invariant address, we do not vectorize. 90; 91; int sum = 0; 92; for(i=0..N) { 93; sum += src[i]; 94; dst.2[i] = dst[42]; 95; dst[42] = sum; 96; } 97; CHECK-LABEL: @reduc_store_load 98; CHECK-NOT: vector.body 99define void @reduc_store_load(i32* %dst, i32* readonly %src, i32* noalias %dst.2) { 100entry: 101 %gep.dst = getelementptr inbounds i32, i32* %dst, i64 42 102 store i32 0, i32* %gep.dst, align 4 103 br label %for.body 104 105for.body: 106 %sum = phi i32 [ 0, %entry ], [ %add, %for.body ] 107 %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ] 108 %gep.src = getelementptr inbounds i32, i32* %src, i64 %iv 109 %0 = load i32, i32* %gep.src, align 4 110 %add = add nsw i32 %sum, %0 111 %lv = load i32, i32* %gep.dst 112 %gep.dst.2 = getelementptr inbounds i32, i32* %dst.2, i64 %iv 113 store i32 %lv, i32* %gep.dst.2, align 4 114 store i32 %add, i32* %gep.dst, align 4 115 %iv.next = add nuw nsw i64 %iv, 1 116 %exitcond = icmp eq i64 %iv.next, 1000 117 br i1 %exitcond, label %exit, label %for.body 118 119exit: 120 ret void 121} 122 123; Final value is not guaranteed to be stored in an invariant address. 124; We don't vectorize in that case. 125; 126; int sum = 0; 127; for(i=0..N) { 128; int diff = y[i] - x[i]; 129; if (diff > 0) { 130; sum = += diff; 131; *t = sum; 132; } 133; } 134; CHECK-LABEL: @reduc_cond_store 135; CHECK-NOT: vector.body 136define void @reduc_cond_store(i32* %t, i32* readonly %x, i32* readonly %y) { 137entry: 138 store i32 0, i32* %t, align 4 139 br label %for.body 140 141for.body: 142 %sum = phi i32 [ 0, %entry ], [ %sum.2, %if.end ] 143 %iv = phi i64 [ 0, %entry ], [ %iv.next, %if.end ] 144 %gep.y = getelementptr inbounds i32, i32* %y, i64 %iv 145 %0 = load i32, i32* %gep.y, align 4 146 %gep.x = getelementptr inbounds i32, i32* %x, i64 %iv 147 %1 = load i32, i32* %gep.x, align 4 148 %diff = sub nsw i32 %0, %1 149 %cmp2 = icmp sgt i32 %diff, 0 150 br i1 %cmp2, label %if.then, label %if.end 151 152if.then: 153 %sum.1 = add nsw i32 %diff, %sum 154 store i32 %sum.1, i32* %t, align 4 155 br label %if.end 156 157if.end: 158 %sum.2 = phi i32 [ %sum.1, %if.then ], [ %0, %for.body ] 159 %iv.next = add nuw nsw i64 %iv, 1 160 %exitcond = icmp eq i64 %iv.next, 1000 161 br i1 %exitcond, label %for.end, label %for.body 162 163for.end: 164 ret void 165} 166 167; Check that we can vectorize code with several stores to an invariant address 168; with condition that final reduction value is stored too. 169; 170; int sum = 0; 171; for(int i=0; i < 1000; i+=2) { 172; sum += src[i]; 173; dst[42] = sum; 174; sum += src[i+1]; 175; dst[42] = sum; 176; } 177; CHECK-LABEL: @reduc_store_inside_unrolled 178; CHECK: vector.body: 179; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, [[VECTOR_PH:%.*]] ], [ [[INDEX_NEXT:%.*]], [[VECTOR_BODY:%.*]] ] 180; CHECK-NEXT: [[VEC_IND:%.*]] = phi <4 x i64> [ <i64 0, i64 2, i64 4, i64 6>, [[VECTOR_PH]] ], [ [[VEC_IND_NEXT:%.*]], [[VECTOR_BODY]] ] 181; CHECK-NEXT: [[VEC_PHI:%.*]] = phi <4 x i32> [ zeroinitializer, [[VECTOR_PH]] ], [ [[TMP34:%.*]], [[VECTOR_BODY]] ] 182; CHECK-NEXT: [[OFFSET_IDX:%.*]] = mul i64 [[INDEX]], 2 183; CHECK-NEXT: [[TMP0:%.*]] = add i64 [[OFFSET_IDX]], 0 184; CHECK-NEXT: [[TMP1:%.*]] = add i64 [[OFFSET_IDX]], 2 185; CHECK-NEXT: [[TMP2:%.*]] = add i64 [[OFFSET_IDX]], 4 186; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[OFFSET_IDX]], 6 187; CHECK-NEXT: [[TMP4:%.*]] = getelementptr inbounds i32, i32* [[SRC:%.*]], i64 [[TMP0]] 188; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i32, i32* [[SRC]], i64 [[TMP1]] 189; CHECK-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, i32* [[SRC]], i64 [[TMP2]] 190; CHECK-NEXT: [[TMP7:%.*]] = getelementptr inbounds i32, i32* [[SRC]], i64 [[TMP3]] 191; CHECK-NEXT: [[TMP8:%.*]] = load i32, i32* [[TMP4]], align 4, !alias.scope !11 192; CHECK-NEXT: [[TMP9:%.*]] = load i32, i32* [[TMP5]], align 4, !alias.scope !11 193; CHECK-NEXT: [[TMP10:%.*]] = load i32, i32* [[TMP6]], align 4, !alias.scope !11 194; CHECK-NEXT: [[TMP11:%.*]] = load i32, i32* [[TMP7]], align 4, !alias.scope !11 195; CHECK-NEXT: [[TMP12:%.*]] = insertelement <4 x i32> poison, i32 [[TMP8]], i32 0 196; CHECK-NEXT: [[TMP13:%.*]] = insertelement <4 x i32> [[TMP12]], i32 [[TMP9]], i32 1 197; CHECK-NEXT: [[TMP14:%.*]] = insertelement <4 x i32> [[TMP13]], i32 [[TMP10]], i32 2 198; CHECK-NEXT: [[TMP15:%.*]] = insertelement <4 x i32> [[TMP14]], i32 [[TMP11]], i32 3 199; CHECK-NEXT: [[TMP16:%.*]] = add <4 x i32> [[TMP15]], [[VEC_PHI]] 200; CHECK-NEXT: [[TMP17:%.*]] = or <4 x i64> [[VEC_IND]], <i64 1, i64 1, i64 1, i64 1> 201; CHECK-NEXT: [[TMP18:%.*]] = extractelement <4 x i64> [[TMP17]], i32 0 202; CHECK-NEXT: [[TMP19:%.*]] = getelementptr inbounds i32, i32* [[SRC]], i64 [[TMP18]] 203; CHECK-NEXT: [[TMP20:%.*]] = extractelement <4 x i64> [[TMP17]], i32 1 204; CHECK-NEXT: [[TMP21:%.*]] = getelementptr inbounds i32, i32* [[SRC]], i64 [[TMP20]] 205; CHECK-NEXT: [[TMP22:%.*]] = extractelement <4 x i64> [[TMP17]], i32 2 206; CHECK-NEXT: [[TMP23:%.*]] = getelementptr inbounds i32, i32* [[SRC]], i64 [[TMP22]] 207; CHECK-NEXT: [[TMP24:%.*]] = extractelement <4 x i64> [[TMP17]], i32 3 208; CHECK-NEXT: [[TMP25:%.*]] = getelementptr inbounds i32, i32* [[SRC]], i64 [[TMP24]] 209; CHECK-NEXT: [[TMP26:%.*]] = load i32, i32* [[TMP19]], align 4, !alias.scope !11 210; CHECK-NEXT: [[TMP27:%.*]] = load i32, i32* [[TMP21]], align 4, !alias.scope !11 211; CHECK-NEXT: [[TMP28:%.*]] = load i32, i32* [[TMP23]], align 4, !alias.scope !11 212; CHECK-NEXT: [[TMP29:%.*]] = load i32, i32* [[TMP25]], align 4, !alias.scope !11 213; CHECK-NEXT: [[TMP30:%.*]] = insertelement <4 x i32> poison, i32 [[TMP26]], i32 0 214; CHECK-NEXT: [[TMP31:%.*]] = insertelement <4 x i32> [[TMP30]], i32 [[TMP27]], i32 1 215; CHECK-NEXT: [[TMP32:%.*]] = insertelement <4 x i32> [[TMP31]], i32 [[TMP28]], i32 2 216; CHECK-NEXT: [[TMP33:%.*]] = insertelement <4 x i32> [[TMP32]], i32 [[TMP29]], i32 3 217; CHECK-NEXT: [[TMP34]] = add <4 x i32> [[TMP33]], [[TMP16]] 218; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4 219; CHECK-NEXT: [[VEC_IND_NEXT]] = add <4 x i64> [[VEC_IND]], <i64 8, i64 8, i64 8, i64 8> 220; CHECK-NEXT: [[TMP35:%.*]] = icmp eq i64 [[INDEX_NEXT]], 500 221; CHECK-NEXT: br i1 [[TMP35]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP14:![0-9]+]] 222; CHECK: middle.block: 223; CHECK-NEXT: [[TMP36:%.*]] = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> [[TMP34]]) 224; CHECK-NEXT: store i32 [[TMP36]], i32* [[GEP_DST:%.*]], align 4 225; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 500, 500 226; CHECK-NEXT: br i1 [[CMP_N]], label [[EXIT:%.*]], label [[SCALAR_PH:%.*]] 227define void @reduc_store_inside_unrolled(i32* %dst, i32* readonly %src) { 228entry: 229 %gep.dst = getelementptr inbounds i32, i32* %dst, i64 42 230 br label %for.body 231 232for.body: 233 %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ] 234 %sum = phi i32 [ 0, %entry ], [ %sum.2, %for.body ] 235 %gep.src = getelementptr inbounds i32, i32* %src, i64 %iv 236 %0 = load i32, i32* %gep.src, align 4 237 %sum.1 = add nsw i32 %0, %sum 238 store i32 %sum.1, i32* %gep.dst, align 4 239 %1 = or i64 %iv, 1 240 %gep.src.1 = getelementptr inbounds i32, i32* %src, i64 %1 241 %2 = load i32, i32* %gep.src.1, align 4 242 %sum.2 = add nsw i32 %2, %sum.1 243 store i32 %sum.2, i32* %gep.dst, align 4 244 %iv.next = add nuw nsw i64 %iv, 2 245 %cmp = icmp slt i64 %iv.next, 1000 246 br i1 %cmp, label %for.body, label %exit 247 248exit: 249 ret void 250} 251 252; Check that we cannot vectorize code if stored value is not the final reduction 253; value 254; 255; int sum = 0; 256; for(int i=0; i < 1000; i++) { 257; sum += src[i]; 258; dst[42] = sum + 1; 259; } 260; CHECK-LABEL: @reduc_store_not_final_value 261; CHECK-NOT: vector.body: 262define void @reduc_store_not_final_value(i32* %dst, i32* readonly %src) { 263entry: 264 %gep.dst = getelementptr inbounds i32, i32* %dst, i64 42 265 store i32 0, i32* %gep.dst, align 4 266 br label %for.body 267 268for.body: 269 %sum = phi i32 [ 0, %entry ], [ %add, %for.body ] 270 %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ] 271 %gep.src = getelementptr inbounds i32, i32* %src, i64 %iv 272 %0 = load i32, i32* %gep.src, align 4 273 %add = add nsw i32 %sum, %0 274 %sum_plus_one = add i32 %add, 1 275 store i32 %sum_plus_one, i32* %gep.dst, align 4 276 %iv.next = add nuw nsw i64 %iv, 1 277 %exitcond = icmp eq i64 %iv.next, 1000 278 br i1 %exitcond, label %exit, label %for.body 279 280exit: 281 ret void 282} 283 284; We cannot vectorize if two (or more) invariant stores exist in a loop. 285; 286; int sum = 0; 287; for(int i=0; i < 1000; i+=2) { 288; sum += src[i]; 289; dst[42] = sum; 290; sum += src[i+1]; 291; other_dst[42] = sum; 292; } 293; CHECK-LABEL: @reduc_double_invariant_store 294; CHECK-NOT: vector.body: 295define void @reduc_double_invariant_store(i32* %dst, i32* %other_dst, i32* readonly %src) { 296entry: 297 %gep.dst = getelementptr inbounds i32, i32* %dst, i64 42 298 %gep.other_dst = getelementptr inbounds i32, i32* %other_dst, i64 42 299 br label %for.body 300 301for.body: 302 %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ] 303 %sum = phi i32 [ 0, %entry ], [ %sum.2, %for.body ] 304 %arrayidx = getelementptr inbounds i32, i32* %src, i64 %iv 305 %0 = load i32, i32* %arrayidx, align 4 306 %sum.1 = add nsw i32 %0, %sum 307 store i32 %sum.1, i32* %gep.dst, align 4 308 %1 = or i64 %iv, 1 309 %arrayidx4 = getelementptr inbounds i32, i32* %src, i64 %1 310 %2 = load i32, i32* %arrayidx4, align 4 311 %sum.2 = add nsw i32 %2, %sum.1 312 store i32 %sum.2, i32* %gep.other_dst, align 4 313 %iv.next = add nuw nsw i64 %iv, 2 314 %cmp = icmp slt i64 %iv.next, 1000 315 br i1 %cmp, label %for.body, label %exit 316 317exit: 318 ret void 319} 320 321; int sum = 0; 322; for(int i=0; i < 1000; i+=2) { 323; sum += src[i]; 324; if (src[i+1] > 0) 325; dst[42] = sum; 326; sum += src[i+1]; 327; dst[42] = sum; 328; } 329; CHECK-LABEL: @reduc_store_middle_store_predicated 330; CHECK: vector.body: 331; CHECK-NOT: store i32 %{{[0-9]+}}, i32* %gep.dst 332; CHECK: middle.block: 333; CHECK-NEXT: [[TMP:%.*]] = call i32 @llvm.vector.reduce.add.v4i32 334; CHECK-NEXT: store i32 [[TMP]], i32* %gep.dst 335; CHECK: ret void 336define void @reduc_store_middle_store_predicated(i32* %dst, i32* readonly %src) { 337entry: 338 %gep.dst = getelementptr inbounds i32, i32* %dst, i64 42 339 br label %for.body 340 341for.body: ; preds = %latch, %entry 342 %iv = phi i64 [ 0, %entry ], [ %iv.next, %latch ] 343 %sum = phi i32 [ 0, %entry ], [ %sum.2, %latch ] 344 %gep.src = getelementptr inbounds i32, i32* %src, i64 %iv 345 %0 = load i32, i32* %gep.src, align 4 346 %sum.1 = add nsw i32 %0, %sum 347 %cmp = icmp sgt i32 %0, 0 348 br i1 %cmp, label %predicated, label %latch 349 350predicated: ; preds = %for.body 351 store i32 %sum.1, i32* %gep.dst, align 4 352 br label %latch 353 354latch: ; preds = %predicated, %for.body 355 %1 = or i64 %iv, 1 356 %gep.src.1 = getelementptr inbounds i32, i32* %src, i64 %1 357 %2 = load i32, i32* %gep.src.1, align 4 358 %sum.2 = add nsw i32 %2, %sum.1 359 store i32 %sum.2, i32* %gep.dst, align 4 360 %iv.next = add nuw nsw i64 %iv, 2 361 %cmp.1 = icmp slt i64 %iv.next, 1000 362 br i1 %cmp.1, label %for.body, label %exit 363 364exit: ; preds = %latch 365 ret void 366} 367 368; int sum = 0; 369; for(int i=0; i < 1000; i+=2) { 370; sum += src[i]; 371; dst[42] = sum; 372; sum += src[i+1]; 373; if (src[i+1] > 0) 374; dst[42] = sum; 375; } 376; CHECK-LABEL: @reduc_store_final_store_predicated 377; CHECK-NOT: vector.body: 378define void @reduc_store_final_store_predicated(i32* %dst, i32* readonly %src) { 379entry: 380 %gep.dst = getelementptr inbounds i32, i32* %dst, i64 42 381 br label %for.body 382 383for.body: ; preds = %latch, %entry 384 %iv = phi i64 [ 0, %entry ], [ %iv.next, %latch ] 385 %sum = phi i32 [ 0, %entry ], [ %sum.1, %latch ] 386 %arrayidx = getelementptr inbounds i32, i32* %src, i64 %iv 387 %0 = load i32, i32* %arrayidx, align 4 388 %sum.1 = add nsw i32 %0, %sum 389 store i32 %sum.1, i32* %gep.dst, align 4 390 %1 = or i64 %iv, 1 391 %gep.src.1 = getelementptr inbounds i32, i32* %src, i64 %1 392 %2 = load i32, i32* %gep.src.1, align 4 393 %sum.2 = add nsw i32 %2, %sum.1 394 %cmp1 = icmp sgt i32 %2, 0 395 br i1 %cmp1, label %predicated, label %latch 396 397predicated: ; preds = %for.body 398 store i32 %sum.2, i32* %gep.dst, align 4 399 br label %latch 400 401latch: ; preds = %predicated, %for.body 402 %iv.next = add nuw nsw i64 %iv, 2 403 %cmp = icmp slt i64 %iv.next, 1000 404 br i1 %cmp, label %for.body, label %exit 405 406exit: ; preds = %latch 407 ret void 408} 409 410; Final reduction value is overwritten inside loop 411; 412; for(int i=0; i < 1000; i++) { 413; sum += src[i]; 414; dst[42] = sum; 415; dst[42] = 0; 416; } 417; CHECK-LABEL: @reduc_store_final_store_overwritten 418; CHECK-NOT: vector.body: 419define void @reduc_store_final_store_overwritten(i32* %dst, i32* readonly %src) { 420entry: 421 %gep.dst = getelementptr inbounds i32, i32* %dst, i64 42 422 br label %for.body 423 424for.body: 425 %sum = phi i32 [ 0, %entry ], [ %add, %for.body ] 426 %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ] 427 %gep.src = getelementptr inbounds i32, i32* %src, i64 %iv 428 %0 = load i32, i32* %gep.src, align 4 429 %add = add nsw i32 %sum, %0 430 store i32 %add, i32* %gep.dst, align 4 431 store i32 0, i32* %gep.dst, align 4 432 %iv.next = add nuw nsw i64 %iv, 1 433 %exitcond = icmp eq i64 %iv.next, 1000 434 br i1 %exitcond, label %exit, label %for.body 435 436exit: 437 ret void 438} 439 440; Final value used outside of loop does not prevent vectorization 441; 442; int sum = 0; 443; for(int i=0; i < 1000; i++) { 444; sum += src[i]; 445; dst[42] = sum; 446; } 447; dst[43] = sum; 448; CHECK-LABEL: @reduc_store_inoutside 449; CHECK: vector.body: 450; CHECK-NOT: store i32 %{{[0-9]+}}, i32* %gep.src 451; CHECK: middle.block: 452; CHECK-NEXT: [[TMP:%.*]] = call i32 @llvm.vector.reduce.add.v4i32 453; CHECK-NEXT: store i32 [[TMP]], i32* %gep.dst 454; CHECK: exit: 455; CHECK: [[PHI:%.*]] = phi i32 [ [[TMP1:%.*]], %for.body ], [ [[TMP2:%.*]], %middle.block ] 456; CHECK: [[ADDR:%.*]] = getelementptr inbounds i32, i32* %dst, i64 43 457; CHECK: store i32 [[PHI]], i32* [[ADDR]] 458; CHECK: ret void 459define void @reduc_store_inoutside(i32* %dst, i32* readonly %src) { 460entry: 461 %gep.dst = getelementptr inbounds i32, i32* %dst, i64 42 462 br label %for.body 463 464for.body: 465 %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ] 466 %sum = phi i32 [ 0, %entry ], [ %sum.1, %for.body ] 467 %arrayidx = getelementptr inbounds i32, i32* %src, i64 %iv 468 %0 = load i32, i32* %arrayidx, align 4 469 %sum.1 = add nsw i32 %0, %sum 470 store i32 %sum.1, i32* %gep.dst, align 4 471 %iv.next = add nuw nsw i64 %iv, 1 472 %exitcond = icmp eq i64 %iv.next, 1000 473 br i1 %exitcond, label %exit, label %for.body 474 475exit: 476 %sum.lcssa = phi i32 [ %sum.1, %for.body ] 477 %gep.dst.1 = getelementptr inbounds i32, i32* %dst, i64 43 478 store i32 %sum.lcssa, i32* %gep.dst.1, align 4 479 ret void 480} 481