| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals none --version 5 |
| ; RUN: opt -passes=loop-vectorize -mtriple=aarch64 -mattr=+sve -S < %s | FileCheck --check-prefix=CHECK-NOTF %s |
| ; RUN: opt -passes=loop-vectorize -tail-folding-policy=prefer-fold-tail \ |
| ; RUN: -mtriple=aarch64 -mattr=+sve -S < %s | FileCheck --check-prefix=CHECK-TF %s |
| |
| target triple = "aarch64-linux-gnu" |
| |
| ; Original loop has trip count 17, but contains interleave groups with gaps, so |
| ; the last iteration must execute in the scalar loop. Thus the vector loop can |
| ; only execute up to 16 iterations. |
| define i64 @vector_loop_with_remaining_iterations(ptr %src, ptr noalias %dst, i32 %x) #0 { |
| ; CHECK-NOTF-LABEL: define i64 @vector_loop_with_remaining_iterations( |
| ; CHECK-NOTF-SAME: ptr [[SRC:%.*]], ptr noalias [[DST:%.*]], i32 [[X:%.*]]) #[[ATTR0:[0-9]+]] { |
| ; CHECK-NOTF-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NOTF-NEXT: br label %[[VECTOR_PH:.*]] |
| ; CHECK-NOTF: [[VECTOR_PH]]: |
| ; CHECK-NOTF-NEXT: [[BROADCAST_SPLATINSERT:%.*]] = insertelement <16 x i32> poison, i32 [[X]], i64 0 |
| ; CHECK-NOTF-NEXT: [[BROADCAST_SPLAT:%.*]] = shufflevector <16 x i32> [[BROADCAST_SPLATINSERT]], <16 x i32> poison, <16 x i32> zeroinitializer |
| ; CHECK-NOTF-NEXT: [[TMP0:%.*]] = call <16 x i32> @llvm.abs.v16i32(<16 x i32> [[BROADCAST_SPLAT]], i1 false) |
| ; CHECK-NOTF-NEXT: br label %[[VECTOR_BODY:.*]] |
| ; CHECK-NOTF: [[VECTOR_BODY]]: |
| ; CHECK-NOTF-NEXT: [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[VEC_PHI:%.*]] = phi <16 x i64> [ zeroinitializer, %[[VECTOR_PH]] ], [ [[TMP7:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[TMP1:%.*]] = getelementptr { [4 x i8] }, ptr [[SRC]], i64 [[INDEX]], i32 0, i64 3 |
| ; CHECK-NOTF-NEXT: [[WIDE_VEC:%.*]] = load <64 x i8>, ptr [[TMP1]], align 1 |
| ; CHECK-NOTF-NEXT: [[STRIDED_VEC:%.*]] = shufflevector <64 x i8> [[WIDE_VEC]], <64 x i8> poison, <16 x i32> <i32 0, i32 4, i32 8, i32 12, i32 16, i32 20, i32 24, i32 28, i32 32, i32 36, i32 40, i32 44, i32 48, i32 52, i32 56, i32 60> |
| ; CHECK-NOTF-NEXT: [[TMP2:%.*]] = zext <16 x i8> [[STRIDED_VEC]] to <16 x i32> |
| ; CHECK-NOTF-NEXT: [[TMP3:%.*]] = call <16 x i32> @llvm.umin.v16i32(<16 x i32> [[TMP0]], <16 x i32> [[TMP2]]) |
| ; CHECK-NOTF-NEXT: [[TMP4:%.*]] = call <16 x i32> @llvm.umin.v16i32(<16 x i32> [[TMP0]], <16 x i32> [[TMP3]]) |
| ; CHECK-NOTF-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[DST]], i64 [[INDEX]] |
| ; CHECK-NOTF-NEXT: store <16 x i8> zeroinitializer, ptr [[TMP5]], align 1 |
| ; CHECK-NOTF-NEXT: [[TMP6:%.*]] = zext <16 x i32> [[TMP4]] to <16 x i64> |
| ; CHECK-NOTF-NEXT: [[TMP7]] = or <16 x i64> [[VEC_PHI]], [[TMP6]] |
| ; CHECK-NOTF-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 16 |
| ; CHECK-NOTF-NEXT: [[TMP8:%.*]] = icmp eq i64 [[INDEX_NEXT]], 16 |
| ; CHECK-NOTF-NEXT: br i1 [[TMP8]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP0:![0-9]+]] |
| ; CHECK-NOTF: [[MIDDLE_BLOCK]]: |
| ; CHECK-NOTF-NEXT: [[TMP9:%.*]] = call i64 @llvm.vector.reduce.or.v16i64(<16 x i64> [[TMP7]]) |
| ; CHECK-NOTF-NEXT: br label %[[SCALAR_PH:.*]] |
| ; CHECK-NOTF: [[SCALAR_PH]]: |
| ; CHECK-NOTF-NEXT: br label %[[LOOP:.*]] |
| ; CHECK-NOTF: [[LOOP]]: |
| ; CHECK-NOTF-NEXT: [[IV:%.*]] = phi i64 [ 16, %[[SCALAR_PH]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ] |
| ; CHECK-NOTF-NEXT: [[RED:%.*]] = phi i64 [ [[TMP9]], %[[SCALAR_PH]] ], [ [[RED_NEXT:%.*]], %[[LOOP]] ] |
| ; CHECK-NOTF-NEXT: [[GEP_SRC_I_I:%.*]] = getelementptr { [4 x i8] }, ptr [[SRC]], i64 [[IV]], i32 0, i64 3 |
| ; CHECK-NOTF-NEXT: [[L:%.*]] = load i8, ptr [[GEP_SRC_I_I]], align 1 |
| ; CHECK-NOTF-NEXT: [[L_EXT:%.*]] = zext i8 [[L]] to i32 |
| ; CHECK-NOTF-NEXT: [[ABS_0:%.*]] = call i32 @llvm.abs.i32(i32 [[X]], i1 false) |
| ; CHECK-NOTF-NEXT: [[MIN_0:%.*]] = call i32 @llvm.umin.i32(i32 [[ABS_0]], i32 [[L_EXT]]) |
| ; CHECK-NOTF-NEXT: [[ABS_1:%.*]] = call i32 @llvm.abs.i32(i32 [[X]], i1 false) |
| ; CHECK-NOTF-NEXT: [[MIN_1:%.*]] = call i32 @llvm.umin.i32(i32 [[ABS_1]], i32 [[MIN_0]]) |
| ; CHECK-NOTF-NEXT: [[GEP_DST:%.*]] = getelementptr inbounds i8, ptr [[DST]], i64 [[IV]] |
| ; CHECK-NOTF-NEXT: store i8 0, ptr [[GEP_DST]], align 1 |
| ; CHECK-NOTF-NEXT: [[MIN_EXT:%.*]] = zext i32 [[MIN_1]] to i64 |
| ; CHECK-NOTF-NEXT: [[RED_NEXT]] = or i64 [[RED]], [[MIN_EXT]] |
| ; CHECK-NOTF-NEXT: [[IV_NEXT]] = add i64 [[IV]], 1 |
| ; CHECK-NOTF-NEXT: [[EXITCOND_NOT_I_I:%.*]] = icmp eq i64 [[IV_NEXT]], 17 |
| ; CHECK-NOTF-NEXT: br i1 [[EXITCOND_NOT_I_I]], label %[[EXIT:.*]], label %[[LOOP]], !llvm.loop [[LOOP3:![0-9]+]] |
| ; CHECK-NOTF: [[EXIT]]: |
| ; CHECK-NOTF-NEXT: [[RED_NEXT_LCSSA:%.*]] = phi i64 [ [[RED_NEXT]], %[[LOOP]] ] |
| ; CHECK-NOTF-NEXT: ret i64 [[RED_NEXT_LCSSA]] |
| ; |
| ; CHECK-TF-LABEL: define i64 @vector_loop_with_remaining_iterations( |
| ; CHECK-TF-SAME: ptr [[SRC:%.*]], ptr noalias [[DST:%.*]], i32 [[X:%.*]]) #[[ATTR0:[0-9]+]] { |
| ; CHECK-TF-NEXT: [[ENTRY:.*]]: |
| ; CHECK-TF-NEXT: br label %[[LOOP:.*]] |
| ; CHECK-TF: [[LOOP]]: |
| ; CHECK-TF-NEXT: [[IV:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ] |
| ; CHECK-TF-NEXT: [[RED:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[RED_NEXT:%.*]], %[[LOOP]] ] |
| ; CHECK-TF-NEXT: [[GEP_SRC_I_I:%.*]] = getelementptr { [4 x i8] }, ptr [[SRC]], i64 [[IV]], i32 0, i64 3 |
| ; CHECK-TF-NEXT: [[L:%.*]] = load i8, ptr [[GEP_SRC_I_I]], align 1 |
| ; CHECK-TF-NEXT: [[L_EXT:%.*]] = zext i8 [[L]] to i32 |
| ; CHECK-TF-NEXT: [[ABS_0:%.*]] = call i32 @llvm.abs.i32(i32 [[X]], i1 false) |
| ; CHECK-TF-NEXT: [[MIN_0:%.*]] = call i32 @llvm.umin.i32(i32 [[ABS_0]], i32 [[L_EXT]]) |
| ; CHECK-TF-NEXT: [[ABS_1:%.*]] = call i32 @llvm.abs.i32(i32 [[X]], i1 false) |
| ; CHECK-TF-NEXT: [[MIN_1:%.*]] = call i32 @llvm.umin.i32(i32 [[ABS_1]], i32 [[MIN_0]]) |
| ; CHECK-TF-NEXT: [[GEP_DST:%.*]] = getelementptr inbounds i8, ptr [[DST]], i64 [[IV]] |
| ; CHECK-TF-NEXT: store i8 0, ptr [[GEP_DST]], align 1 |
| ; CHECK-TF-NEXT: [[MIN_EXT:%.*]] = zext i32 [[MIN_1]] to i64 |
| ; CHECK-TF-NEXT: [[RED_NEXT]] = or i64 [[RED]], [[MIN_EXT]] |
| ; CHECK-TF-NEXT: [[IV_NEXT]] = add i64 [[IV]], 1 |
| ; CHECK-TF-NEXT: [[EXITCOND_NOT_I_I:%.*]] = icmp eq i64 [[IV_NEXT]], 17 |
| ; CHECK-TF-NEXT: br i1 [[EXITCOND_NOT_I_I]], label %[[EXIT:.*]], label %[[LOOP]] |
| ; CHECK-TF: [[EXIT]]: |
| ; CHECK-TF-NEXT: [[RED_NEXT_LCSSA:%.*]] = phi i64 [ [[RED_NEXT]], %[[LOOP]] ] |
| ; CHECK-TF-NEXT: ret i64 [[RED_NEXT_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] |
| %red = phi i64 [ 0, %entry ], [ %red.next, %loop ] |
| %gep.src.i.i = getelementptr { [4 x i8] }, ptr %src, i64 %iv, i32 0, i64 3 |
| %l = load i8, ptr %gep.src.i.i, align 1 |
| %l.ext = zext i8 %l to i32 |
| %abs.0 = call i32 @llvm.abs.i32(i32 %x, i1 false) |
| %min.0 = call i32 @llvm.umin.i32(i32 %abs.0, i32 %l.ext) |
| %abs.1 = call i32 @llvm.abs.i32(i32 %x, i1 false) |
| %min.1 = call i32 @llvm.umin.i32(i32 %abs.1, i32 %min.0) |
| %gep.dst = getelementptr inbounds i8, ptr %dst, i64 %iv |
| store i8 0, ptr %gep.dst, align 1 |
| %min.ext = zext i32 %min.1 to i64 |
| %red.next = or i64 %red, %min.ext |
| %iv.next = add i64 %iv, 1 |
| %exitcond.not.i.i = icmp eq i64 %iv.next, 17 |
| br i1 %exitcond.not.i.i, label %exit, label %loop |
| |
| exit: |
| ret i64 %red.next |
| } |
| |
| ; Original loop has trip count 17, but contains interleave groups with gaps, so |
| ; the last iteration must execute in the scalar loop. Thus the vector loop can |
| ; only execute up to 16 iterations. |
| define i64 @main_vector_loop_fixed_with_no_remaining_iterations(ptr %src, ptr noalias %dst, i32 %x) #0 { |
| ; CHECK-NOTF-LABEL: define i64 @main_vector_loop_fixed_with_no_remaining_iterations( |
| ; CHECK-NOTF-SAME: ptr [[SRC:%.*]], ptr noalias [[DST:%.*]], i32 [[X:%.*]]) #[[ATTR0]] { |
| ; CHECK-NOTF-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NOTF-NEXT: br label %[[VECTOR_PH:.*]] |
| ; CHECK-NOTF: [[VECTOR_PH]]: |
| ; CHECK-NOTF-NEXT: [[BROADCAST_SPLATINSERT:%.*]] = insertelement <16 x i32> poison, i32 [[X]], i64 0 |
| ; CHECK-NOTF-NEXT: [[BROADCAST_SPLAT:%.*]] = shufflevector <16 x i32> [[BROADCAST_SPLATINSERT]], <16 x i32> poison, <16 x i32> zeroinitializer |
| ; CHECK-NOTF-NEXT: [[TMP0:%.*]] = call <16 x i32> @llvm.abs.v16i32(<16 x i32> [[BROADCAST_SPLAT]], i1 false) |
| ; CHECK-NOTF-NEXT: br label %[[VECTOR_BODY:.*]] |
| ; CHECK-NOTF: [[VECTOR_BODY]]: |
| ; CHECK-NOTF-NEXT: [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[VEC_PHI:%.*]] = phi <16 x i64> [ zeroinitializer, %[[VECTOR_PH]] ], [ [[TMP7:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[TMP1:%.*]] = getelementptr { [4 x i8] }, ptr [[SRC]], i64 [[INDEX]], i32 0, i64 3 |
| ; CHECK-NOTF-NEXT: [[WIDE_VEC:%.*]] = load <64 x i8>, ptr [[TMP1]], align 1 |
| ; CHECK-NOTF-NEXT: [[STRIDED_VEC:%.*]] = shufflevector <64 x i8> [[WIDE_VEC]], <64 x i8> poison, <16 x i32> <i32 0, i32 4, i32 8, i32 12, i32 16, i32 20, i32 24, i32 28, i32 32, i32 36, i32 40, i32 44, i32 48, i32 52, i32 56, i32 60> |
| ; CHECK-NOTF-NEXT: [[TMP2:%.*]] = zext <16 x i8> [[STRIDED_VEC]] to <16 x i32> |
| ; CHECK-NOTF-NEXT: [[TMP3:%.*]] = call <16 x i32> @llvm.umin.v16i32(<16 x i32> [[TMP0]], <16 x i32> [[TMP2]]) |
| ; CHECK-NOTF-NEXT: [[TMP4:%.*]] = call <16 x i32> @llvm.umin.v16i32(<16 x i32> [[TMP0]], <16 x i32> [[TMP3]]) |
| ; CHECK-NOTF-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[DST]], i64 [[INDEX]] |
| ; CHECK-NOTF-NEXT: store <16 x i8> zeroinitializer, ptr [[TMP5]], align 1 |
| ; CHECK-NOTF-NEXT: [[TMP6:%.*]] = zext <16 x i32> [[TMP4]] to <16 x i64> |
| ; CHECK-NOTF-NEXT: [[TMP7]] = or <16 x i64> [[VEC_PHI]], [[TMP6]] |
| ; CHECK-NOTF-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 16 |
| ; CHECK-NOTF-NEXT: [[TMP8:%.*]] = icmp eq i64 [[INDEX_NEXT]], 16 |
| ; CHECK-NOTF-NEXT: br i1 [[TMP8]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP4:![0-9]+]] |
| ; CHECK-NOTF: [[MIDDLE_BLOCK]]: |
| ; CHECK-NOTF-NEXT: [[TMP9:%.*]] = call i64 @llvm.vector.reduce.or.v16i64(<16 x i64> [[TMP7]]) |
| ; CHECK-NOTF-NEXT: br label %[[SCALAR_PH:.*]] |
| ; CHECK-NOTF: [[SCALAR_PH]]: |
| ; CHECK-NOTF-NEXT: br label %[[LOOP:.*]] |
| ; CHECK-NOTF: [[LOOP]]: |
| ; CHECK-NOTF-NEXT: [[IV:%.*]] = phi i64 [ 16, %[[SCALAR_PH]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ] |
| ; CHECK-NOTF-NEXT: [[RED:%.*]] = phi i64 [ [[TMP9]], %[[SCALAR_PH]] ], [ [[RED_NEXT:%.*]], %[[LOOP]] ] |
| ; CHECK-NOTF-NEXT: [[GEP_SRC_I_I:%.*]] = getelementptr { [4 x i8] }, ptr [[SRC]], i64 [[IV]], i32 0, i64 3 |
| ; CHECK-NOTF-NEXT: [[L:%.*]] = load i8, ptr [[GEP_SRC_I_I]], align 1 |
| ; CHECK-NOTF-NEXT: [[L_EXT:%.*]] = zext i8 [[L]] to i32 |
| ; CHECK-NOTF-NEXT: [[ABS_0:%.*]] = call i32 @llvm.abs.i32(i32 [[X]], i1 false) |
| ; CHECK-NOTF-NEXT: [[MIN_0:%.*]] = call i32 @llvm.umin.i32(i32 [[ABS_0]], i32 [[L_EXT]]) |
| ; CHECK-NOTF-NEXT: [[ABS_1:%.*]] = call i32 @llvm.abs.i32(i32 [[X]], i1 false) |
| ; CHECK-NOTF-NEXT: [[MIN_1:%.*]] = call i32 @llvm.umin.i32(i32 [[ABS_1]], i32 [[MIN_0]]) |
| ; CHECK-NOTF-NEXT: [[GEP_DST:%.*]] = getelementptr inbounds i8, ptr [[DST]], i64 [[IV]] |
| ; CHECK-NOTF-NEXT: store i8 0, ptr [[GEP_DST]], align 1 |
| ; CHECK-NOTF-NEXT: [[MIN_EXT:%.*]] = zext i32 [[MIN_1]] to i64 |
| ; CHECK-NOTF-NEXT: [[RED_NEXT]] = or i64 [[RED]], [[MIN_EXT]] |
| ; CHECK-NOTF-NEXT: [[IV_NEXT]] = add i64 [[IV]], 1 |
| ; CHECK-NOTF-NEXT: [[EXITCOND_NOT_I_I:%.*]] = icmp eq i64 [[IV_NEXT]], 17 |
| ; CHECK-NOTF-NEXT: br i1 [[EXITCOND_NOT_I_I]], label %[[EXIT:.*]], label %[[LOOP]], !llvm.loop [[LOOP5:![0-9]+]] |
| ; CHECK-NOTF: [[EXIT]]: |
| ; CHECK-NOTF-NEXT: [[RED_NEXT_LCSSA:%.*]] = phi i64 [ [[RED_NEXT]], %[[LOOP]] ] |
| ; CHECK-NOTF-NEXT: ret i64 [[RED_NEXT_LCSSA]] |
| ; |
| ; CHECK-TF-LABEL: define i64 @main_vector_loop_fixed_with_no_remaining_iterations( |
| ; CHECK-TF-SAME: ptr [[SRC:%.*]], ptr noalias [[DST:%.*]], i32 [[X:%.*]]) #[[ATTR0]] { |
| ; CHECK-TF-NEXT: [[ENTRY:.*]]: |
| ; CHECK-TF-NEXT: br label %[[LOOP:.*]] |
| ; CHECK-TF: [[LOOP]]: |
| ; CHECK-TF-NEXT: [[IV:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ] |
| ; CHECK-TF-NEXT: [[RED:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[RED_NEXT:%.*]], %[[LOOP]] ] |
| ; CHECK-TF-NEXT: [[GEP_SRC_I_I:%.*]] = getelementptr { [4 x i8] }, ptr [[SRC]], i64 [[IV]], i32 0, i64 3 |
| ; CHECK-TF-NEXT: [[L:%.*]] = load i8, ptr [[GEP_SRC_I_I]], align 1 |
| ; CHECK-TF-NEXT: [[L_EXT:%.*]] = zext i8 [[L]] to i32 |
| ; CHECK-TF-NEXT: [[ABS_0:%.*]] = call i32 @llvm.abs.i32(i32 [[X]], i1 false) |
| ; CHECK-TF-NEXT: [[MIN_0:%.*]] = call i32 @llvm.umin.i32(i32 [[ABS_0]], i32 [[L_EXT]]) |
| ; CHECK-TF-NEXT: [[ABS_1:%.*]] = call i32 @llvm.abs.i32(i32 [[X]], i1 false) |
| ; CHECK-TF-NEXT: [[MIN_1:%.*]] = call i32 @llvm.umin.i32(i32 [[ABS_1]], i32 [[MIN_0]]) |
| ; CHECK-TF-NEXT: [[GEP_DST:%.*]] = getelementptr inbounds i8, ptr [[DST]], i64 [[IV]] |
| ; CHECK-TF-NEXT: store i8 0, ptr [[GEP_DST]], align 1 |
| ; CHECK-TF-NEXT: [[MIN_EXT:%.*]] = zext i32 [[MIN_1]] to i64 |
| ; CHECK-TF-NEXT: [[RED_NEXT]] = or i64 [[RED]], [[MIN_EXT]] |
| ; CHECK-TF-NEXT: [[IV_NEXT]] = add i64 [[IV]], 1 |
| ; CHECK-TF-NEXT: [[EXITCOND_NOT_I_I:%.*]] = icmp eq i64 [[IV_NEXT]], 17 |
| ; CHECK-TF-NEXT: br i1 [[EXITCOND_NOT_I_I]], label %[[EXIT:.*]], label %[[LOOP]] |
| ; CHECK-TF: [[EXIT]]: |
| ; CHECK-TF-NEXT: [[RED_NEXT_LCSSA:%.*]] = phi i64 [ [[RED_NEXT]], %[[LOOP]] ] |
| ; CHECK-TF-NEXT: ret i64 [[RED_NEXT_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] |
| %red = phi i64 [ 0, %entry ], [ %red.next, %loop ] |
| %gep.src.i.i = getelementptr { [4 x i8] }, ptr %src, i64 %iv, i32 0, i64 3 |
| %l = load i8, ptr %gep.src.i.i, align 1 |
| %l.ext = zext i8 %l to i32 |
| %abs.0 = call i32 @llvm.abs.i32(i32 %x, i1 false) |
| %min.0 = call i32 @llvm.umin.i32(i32 %abs.0, i32 %l.ext) |
| %abs.1 = call i32 @llvm.abs.i32(i32 %x, i1 false) |
| %min.1 = call i32 @llvm.umin.i32(i32 %abs.1, i32 %min.0) |
| %gep.dst = getelementptr inbounds i8, ptr %dst, i64 %iv |
| store i8 0, ptr %gep.dst, align 1 |
| %min.ext = zext i32 %min.1 to i64 |
| %red.next = or i64 %red, %min.ext |
| %iv.next = add i64 %iv, 1 |
| %exitcond.not.i.i = icmp eq i64 %iv.next, 17 |
| br i1 %exitcond.not.i.i, label %exit, label %loop |
| |
| exit: |
| ret i64 %red.next |
| } |
| |
| ; Test case for https://github.com/llvm/llvm-project/issues/149726. |
| define void @main_vector_loop_fixed_single_vector_iteration_with_runtime_checks(ptr noalias %A, ptr noalias %B, ptr noalias %C, ptr noalias %D, ptr noalias %E, ptr noalias %F, ptr noalias %G, ptr noalias %H, ptr noalias %I, ptr noalias %J, ptr noalias %K, ptr %L) #1 { |
| ; CHECK-NOTF-LABEL: define void @main_vector_loop_fixed_single_vector_iteration_with_runtime_checks( |
| ; CHECK-NOTF-SAME: ptr noalias [[A:%.*]], ptr noalias [[B:%.*]], ptr noalias [[C:%.*]], ptr noalias [[D:%.*]], ptr noalias [[E:%.*]], ptr noalias [[F:%.*]], ptr noalias [[G:%.*]], ptr noalias [[H:%.*]], ptr noalias [[I:%.*]], ptr noalias [[J:%.*]], ptr noalias [[K:%.*]], ptr [[L:%.*]]) #[[ATTR1:[0-9]+]] { |
| ; CHECK-NOTF-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NOTF-NEXT: br label %[[VECTOR_PH:.*]] |
| ; CHECK-NOTF: [[VECTOR_PH]]: |
| ; CHECK-NOTF-NEXT: br label %[[VECTOR_BODY:.*]] |
| ; CHECK-NOTF: [[VECTOR_BODY]]: |
| ; CHECK-NOTF-NEXT: [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[TMP0:%.*]] = shl i64 [[INDEX]], 1 |
| ; CHECK-NOTF-NEXT: [[TMP1:%.*]] = add i64 [[TMP0]], 2 |
| ; CHECK-NOTF-NEXT: [[TMP2:%.*]] = add i64 [[TMP0]], 4 |
| ; CHECK-NOTF-NEXT: [[TMP3:%.*]] = add i64 [[TMP0]], 6 |
| ; CHECK-NOTF-NEXT: [[TMP4:%.*]] = getelementptr i64, ptr [[J]], i64 [[TMP0]] |
| ; CHECK-NOTF-NEXT: [[WIDE_VEC:%.*]] = load <8 x i64>, ptr [[TMP4]], align 8 |
| ; CHECK-NOTF-NEXT: [[STRIDED_VEC:%.*]] = shufflevector <8 x i64> [[WIDE_VEC]], <8 x i64> poison, <4 x i32> <i32 0, i32 2, i32 4, i32 6> |
| ; CHECK-NOTF-NEXT: [[TMP5:%.*]] = trunc <4 x i64> [[STRIDED_VEC]] to <4 x i16> |
| ; CHECK-NOTF-NEXT: [[TMP10:%.*]] = getelementptr i16, ptr [[K]], i64 [[TMP0]] |
| ; CHECK-NOTF-NEXT: [[TMP11:%.*]] = getelementptr i16, ptr [[K]], i64 [[TMP1]] |
| ; CHECK-NOTF-NEXT: [[TMP12:%.*]] = getelementptr i16, ptr [[K]], i64 [[TMP2]] |
| ; CHECK-NOTF-NEXT: [[TMP13:%.*]] = getelementptr i16, ptr [[K]], i64 [[TMP3]] |
| ; CHECK-NOTF-NEXT: [[TMP6:%.*]] = extractelement <4 x i16> [[TMP5]], i64 0 |
| ; CHECK-NOTF-NEXT: store i16 [[TMP6]], ptr [[TMP10]], align 2 |
| ; CHECK-NOTF-NEXT: [[TMP7:%.*]] = extractelement <4 x i16> [[TMP5]], i64 1 |
| ; CHECK-NOTF-NEXT: store i16 [[TMP7]], ptr [[TMP11]], align 2 |
| ; CHECK-NOTF-NEXT: [[TMP8:%.*]] = extractelement <4 x i16> [[TMP5]], i64 2 |
| ; CHECK-NOTF-NEXT: store i16 [[TMP8]], ptr [[TMP12]], align 2 |
| ; CHECK-NOTF-NEXT: [[TMP9:%.*]] = extractelement <4 x i16> [[TMP5]], i64 3 |
| ; CHECK-NOTF-NEXT: store i16 [[TMP9]], ptr [[TMP13]], align 2 |
| ; CHECK-NOTF-NEXT: store i64 0, ptr [[A]], align 8 |
| ; CHECK-NOTF-NEXT: store i64 0, ptr [[B]], align 8 |
| ; CHECK-NOTF-NEXT: store i64 0, ptr [[C]], align 8 |
| ; CHECK-NOTF-NEXT: store i64 0, ptr [[D]], align 8 |
| ; CHECK-NOTF-NEXT: store i64 0, ptr [[E]], align 8 |
| ; CHECK-NOTF-NEXT: store i64 0, ptr [[F]], align 8 |
| ; CHECK-NOTF-NEXT: store i64 0, ptr [[G]], align 8 |
| ; CHECK-NOTF-NEXT: store i64 0, ptr [[H]], align 8 |
| ; CHECK-NOTF-NEXT: store i64 0, ptr [[I]], align 8 |
| ; CHECK-NOTF-NEXT: store i64 0, ptr [[L]], align 8 |
| ; CHECK-NOTF-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4 |
| ; CHECK-NOTF-NEXT: [[TMP14:%.*]] = icmp eq i64 [[INDEX_NEXT]], 4 |
| ; CHECK-NOTF-NEXT: br i1 [[TMP14]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP6:![0-9]+]] |
| ; CHECK-NOTF: [[MIDDLE_BLOCK]]: |
| ; CHECK-NOTF-NEXT: br label %[[SCALAR_PH:.*]] |
| ; CHECK-NOTF: [[SCALAR_PH]]: |
| ; CHECK-NOTF-NEXT: br label %[[LOOP:.*]] |
| ; CHECK-NOTF: [[LOOP]]: |
| ; CHECK-NOTF-NEXT: [[IV:%.*]] = phi i64 [ 8, %[[SCALAR_PH]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ] |
| ; CHECK-NOTF-NEXT: [[GEP_J:%.*]] = getelementptr i64, ptr [[J]], i64 [[IV]] |
| ; CHECK-NOTF-NEXT: [[L_J:%.*]] = load i64, ptr [[GEP_J]], align 8 |
| ; CHECK-NOTF-NEXT: [[L_TRUNC:%.*]] = trunc i64 [[L_J]] to i16 |
| ; CHECK-NOTF-NEXT: [[GEP_K:%.*]] = getelementptr i16, ptr [[K]], i64 [[IV]] |
| ; CHECK-NOTF-NEXT: store i16 [[L_TRUNC]], ptr [[GEP_K]], align 2 |
| ; CHECK-NOTF-NEXT: store i64 0, ptr [[A]], align 8 |
| ; CHECK-NOTF-NEXT: store i64 0, ptr [[B]], align 8 |
| ; CHECK-NOTF-NEXT: store i64 0, ptr [[C]], align 8 |
| ; CHECK-NOTF-NEXT: store i64 0, ptr [[D]], align 8 |
| ; CHECK-NOTF-NEXT: store i64 0, ptr [[E]], align 8 |
| ; CHECK-NOTF-NEXT: store i64 0, ptr [[F]], align 8 |
| ; CHECK-NOTF-NEXT: store i64 0, ptr [[G]], align 8 |
| ; CHECK-NOTF-NEXT: store i64 0, ptr [[H]], align 8 |
| ; CHECK-NOTF-NEXT: store i64 0, ptr [[I]], align 8 |
| ; CHECK-NOTF-NEXT: store i64 0, ptr [[L]], align 8 |
| ; CHECK-NOTF-NEXT: [[IV_NEXT]] = add i64 [[IV]], 2 |
| ; CHECK-NOTF-NEXT: [[EC:%.*]] = icmp ult i64 [[IV]], 14 |
| ; CHECK-NOTF-NEXT: br i1 [[EC]], label %[[LOOP]], label %[[EXIT:.*]], !llvm.loop [[LOOP8:![0-9]+]] |
| ; CHECK-NOTF: [[EXIT]]: |
| ; CHECK-NOTF-NEXT: ret void |
| ; |
| ; CHECK-TF-LABEL: define void @main_vector_loop_fixed_single_vector_iteration_with_runtime_checks( |
| ; CHECK-TF-SAME: ptr noalias [[A:%.*]], ptr noalias [[B:%.*]], ptr noalias [[C:%.*]], ptr noalias [[D:%.*]], ptr noalias [[E:%.*]], ptr noalias [[F:%.*]], ptr noalias [[G:%.*]], ptr noalias [[H:%.*]], ptr noalias [[I:%.*]], ptr noalias [[J:%.*]], ptr noalias [[K:%.*]], ptr [[L:%.*]]) #[[ATTR1:[0-9]+]] { |
| ; CHECK-TF-NEXT: [[ENTRY:.*:]] |
| ; CHECK-TF-NEXT: br label %[[VECTOR_PH:.*]] |
| ; CHECK-TF: [[VECTOR_PH]]: |
| ; CHECK-TF-NEXT: [[TMP0:%.*]] = call i64 @llvm.vscale.i64() |
| ; CHECK-TF-NEXT: [[TMP1:%.*]] = shl nuw i64 [[TMP0]], 3 |
| ; CHECK-TF-NEXT: [[ACTIVE_LANE_MASK_ENTRY:%.*]] = call <vscale x 8 x i1> @llvm.get.active.lane.mask.nxv8i1.i64(i64 0, i64 8) |
| ; CHECK-TF-NEXT: [[TMP2:%.*]] = call <vscale x 8 x i64> @llvm.stepvector.nxv8i64() |
| ; CHECK-TF-NEXT: [[TMP3:%.*]] = mul <vscale x 8 x i64> [[TMP2]], splat (i64 2) |
| ; CHECK-TF-NEXT: [[TMP4:%.*]] = shl i64 [[TMP1]], 1 |
| ; CHECK-TF-NEXT: [[BROADCAST_SPLATINSERT:%.*]] = insertelement <vscale x 8 x i64> poison, i64 [[TMP4]], i64 0 |
| ; CHECK-TF-NEXT: [[BROADCAST_SPLAT:%.*]] = shufflevector <vscale x 8 x i64> [[BROADCAST_SPLATINSERT]], <vscale x 8 x i64> poison, <vscale x 8 x i32> zeroinitializer |
| ; CHECK-TF-NEXT: br label %[[VECTOR_BODY:.*]] |
| ; CHECK-TF: [[VECTOR_BODY]]: |
| ; CHECK-TF-NEXT: [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-TF-NEXT: [[ACTIVE_LANE_MASK:%.*]] = phi <vscale x 8 x i1> [ [[ACTIVE_LANE_MASK_ENTRY]], %[[VECTOR_PH]] ], [ [[ACTIVE_LANE_MASK_NEXT:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-TF-NEXT: [[VEC_IND:%.*]] = phi <vscale x 8 x i64> [ [[TMP3]], %[[VECTOR_PH]] ], [ [[VEC_IND_NEXT:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-TF-NEXT: [[WIDE_GEP:%.*]] = getelementptr i64, ptr [[J]], <vscale x 8 x i64> [[VEC_IND]] |
| ; CHECK-TF-NEXT: [[WIDE_MASKED_GATHER:%.*]] = call <vscale x 8 x i64> @llvm.masked.gather.nxv8i64.nxv8p0(<vscale x 8 x ptr> align 8 [[WIDE_GEP]], <vscale x 8 x i1> [[ACTIVE_LANE_MASK]], <vscale x 8 x i64> poison) |
| ; CHECK-TF-NEXT: [[TMP5:%.*]] = trunc <vscale x 8 x i64> [[WIDE_MASKED_GATHER]] to <vscale x 8 x i16> |
| ; CHECK-TF-NEXT: [[WIDE_GEP1:%.*]] = getelementptr i16, ptr [[K]], <vscale x 8 x i64> [[VEC_IND]] |
| ; CHECK-TF-NEXT: call void @llvm.masked.scatter.nxv8i16.nxv8p0(<vscale x 8 x i16> [[TMP5]], <vscale x 8 x ptr> align 2 [[WIDE_GEP1]], <vscale x 8 x i1> [[ACTIVE_LANE_MASK]]) |
| ; CHECK-TF-NEXT: store i64 0, ptr [[A]], align 8 |
| ; CHECK-TF-NEXT: store i64 0, ptr [[B]], align 8 |
| ; CHECK-TF-NEXT: store i64 0, ptr [[C]], align 8 |
| ; CHECK-TF-NEXT: store i64 0, ptr [[D]], align 8 |
| ; CHECK-TF-NEXT: store i64 0, ptr [[E]], align 8 |
| ; CHECK-TF-NEXT: store i64 0, ptr [[F]], align 8 |
| ; CHECK-TF-NEXT: store i64 0, ptr [[G]], align 8 |
| ; CHECK-TF-NEXT: store i64 0, ptr [[H]], align 8 |
| ; CHECK-TF-NEXT: store i64 0, ptr [[I]], align 8 |
| ; CHECK-TF-NEXT: store i64 0, ptr [[L]], align 8 |
| ; CHECK-TF-NEXT: [[INDEX_NEXT]] = add i64 [[INDEX]], [[TMP1]] |
| ; CHECK-TF-NEXT: [[ACTIVE_LANE_MASK_NEXT]] = call <vscale x 8 x i1> @llvm.get.active.lane.mask.nxv8i1.i64(i64 [[INDEX_NEXT]], i64 8) |
| ; CHECK-TF-NEXT: [[TMP6:%.*]] = extractelement <vscale x 8 x i1> [[ACTIVE_LANE_MASK_NEXT]], i64 0 |
| ; CHECK-TF-NEXT: [[TMP7:%.*]] = xor i1 [[TMP6]], true |
| ; CHECK-TF-NEXT: [[VEC_IND_NEXT]] = add <vscale x 8 x i64> [[VEC_IND]], [[BROADCAST_SPLAT]] |
| ; CHECK-TF-NEXT: br i1 [[TMP7]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP0:![0-9]+]] |
| ; CHECK-TF: [[MIDDLE_BLOCK]]: |
| ; CHECK-TF-NEXT: br label %[[EXIT:.*]] |
| ; CHECK-TF: [[EXIT]]: |
| ; CHECK-TF-NEXT: ret void |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] |
| %gep.J = getelementptr i64, ptr %J, i64 %iv |
| %l.J = load i64, ptr %gep.J, align 8 |
| %l.trunc = trunc i64 %l.J to i16 |
| %gep.K = getelementptr i16, ptr %K, i64 %iv |
| store i16 %l.trunc, ptr %gep.K, align 2 |
| store i64 0, ptr %A, align 8 |
| store i64 0, ptr %B, align 8 |
| store i64 0, ptr %C, align 8 |
| store i64 0, ptr %D, align 8 |
| store i64 0, ptr %E, align 8 |
| store i64 0, ptr %F, align 8 |
| store i64 0, ptr %G, align 8 |
| store i64 0, ptr %H, align 8 |
| store i64 0, ptr %I, align 8 |
| store i64 0, ptr %L, align 8 |
| %iv.next = add i64 %iv, 2 |
| %ec = icmp ult i64 %iv, 14 |
| br i1 %ec, label %loop, label %exit, !llvm.loop !0 |
| |
| exit: |
| ret void |
| } |
| |
| ; Interleaved group with gap but without tail gap |
| ; E.g. |
| ; int (*a)[4]; |
| ; int rdx = 0; |
| ; for (int i = 0; i < n; i++) { |
| ; rdx += a[i][0]; |
| ; rdx += a[i][1]; |
| ; // No access a[i][2] |
| ; rdx += a[i][3]; |
| ; } |
| ; |
| define i32 @load_factor_4_with_gap(i64 %n, ptr noalias %a) { |
| ; CHECK-NOTF-LABEL: define i32 @load_factor_4_with_gap( |
| ; CHECK-NOTF-SAME: i64 [[N:%.*]], ptr noalias [[A:%.*]]) #[[ATTR2:[0-9]+]] { |
| ; CHECK-NOTF-NEXT: [[ENTRY:.*]]: |
| ; CHECK-NOTF-NEXT: [[MIN_ITERS_CHECK1:%.*]] = icmp ult i64 [[N]], 4 |
| ; CHECK-NOTF-NEXT: br i1 [[MIN_ITERS_CHECK1]], label %[[VEC_EPILOG_SCALAR_PH:.*]], label %[[VECTOR_MAIN_LOOP_ITER_CHECK:.*]] |
| ; CHECK-NOTF: [[VECTOR_MAIN_LOOP_ITER_CHECK]]: |
| ; CHECK-NOTF-NEXT: [[TMP0:%.*]] = call i64 @llvm.vscale.i64() |
| ; CHECK-NOTF-NEXT: [[TMP1:%.*]] = shl nuw i64 [[TMP0]], 4 |
| ; CHECK-NOTF-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[N]], [[TMP1]] |
| ; CHECK-NOTF-NEXT: br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]] |
| ; CHECK-NOTF: [[VECTOR_PH]]: |
| ; CHECK-NOTF-NEXT: [[TMP2:%.*]] = shl nuw i64 [[TMP0]], 2 |
| ; CHECK-NOTF-NEXT: [[TMP3:%.*]] = shl nuw i64 [[TMP2]], 2 |
| ; CHECK-NOTF-NEXT: [[N_MOD_VF:%.*]] = urem i64 [[N]], [[TMP3]] |
| ; CHECK-NOTF-NEXT: [[N_VEC:%.*]] = sub i64 [[N]], [[N_MOD_VF]] |
| ; CHECK-NOTF-NEXT: br label %[[VECTOR_BODY:.*]] |
| ; CHECK-NOTF: [[VECTOR_BODY]]: |
| ; CHECK-NOTF-NEXT: [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[VEC_PHI:%.*]] = phi <vscale x 4 x i32> [ zeroinitializer, %[[VECTOR_PH]] ], [ [[TMP19:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[VEC_PHI1:%.*]] = phi <vscale x 4 x i32> [ zeroinitializer, %[[VECTOR_PH]] ], [ [[TMP20:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[VEC_PHI3:%.*]] = phi <vscale x 4 x i32> [ zeroinitializer, %[[VECTOR_PH]] ], [ [[TMP41:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[VEC_PHI4:%.*]] = phi <vscale x 4 x i32> [ zeroinitializer, %[[VECTOR_PH]] ], [ [[TMP42:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[TMP4:%.*]] = add i64 [[TMP2]], 0 |
| ; CHECK-NOTF-NEXT: [[TMP5:%.*]] = mul i64 [[TMP4]], 1 |
| ; CHECK-NOTF-NEXT: [[TMP6:%.*]] = add i64 [[INDEX]], [[TMP5]] |
| ; CHECK-NOTF-NEXT: [[TMP22:%.*]] = shl i64 [[TMP2]], 1 |
| ; CHECK-NOTF-NEXT: [[TMP23:%.*]] = add i64 [[TMP22]], 0 |
| ; CHECK-NOTF-NEXT: [[TMP24:%.*]] = mul i64 [[TMP23]], 1 |
| ; CHECK-NOTF-NEXT: [[TMP31:%.*]] = add i64 [[INDEX]], [[TMP24]] |
| ; CHECK-NOTF-NEXT: [[TMP32:%.*]] = mul i64 [[TMP2]], 3 |
| ; CHECK-NOTF-NEXT: [[TMP35:%.*]] = add i64 [[TMP32]], 0 |
| ; CHECK-NOTF-NEXT: [[TMP36:%.*]] = mul i64 [[TMP35]], 1 |
| ; CHECK-NOTF-NEXT: [[TMP39:%.*]] = add i64 [[INDEX]], [[TMP36]] |
| ; CHECK-NOTF-NEXT: [[TMP7:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[INDEX]], i32 0 |
| ; CHECK-NOTF-NEXT: [[TMP8:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP6]], i32 0 |
| ; CHECK-NOTF-NEXT: [[TMP40:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP31]], i32 0 |
| ; CHECK-NOTF-NEXT: [[TMP43:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP39]], i32 0 |
| ; CHECK-NOTF-NEXT: [[WIDE_VEC:%.*]] = load <vscale x 16 x i32>, ptr [[TMP7]], align 4 |
| ; CHECK-NOTF-NEXT: [[STRIDED_VEC:%.*]] = call { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } @llvm.vector.deinterleave4.nxv16i32(<vscale x 16 x i32> [[WIDE_VEC]]) |
| ; CHECK-NOTF-NEXT: [[TMP9:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC]], 0 |
| ; CHECK-NOTF-NEXT: [[TMP10:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC]], 1 |
| ; CHECK-NOTF-NEXT: [[TMP11:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC]], 3 |
| ; CHECK-NOTF-NEXT: [[WIDE_VEC2:%.*]] = load <vscale x 16 x i32>, ptr [[TMP8]], align 4 |
| ; CHECK-NOTF-NEXT: [[STRIDED_VEC3:%.*]] = call { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } @llvm.vector.deinterleave4.nxv16i32(<vscale x 16 x i32> [[WIDE_VEC2]]) |
| ; CHECK-NOTF-NEXT: [[TMP12:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC3]], 0 |
| ; CHECK-NOTF-NEXT: [[TMP13:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC3]], 1 |
| ; CHECK-NOTF-NEXT: [[TMP14:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC3]], 3 |
| ; CHECK-NOTF-NEXT: [[WIDE_VEC7:%.*]] = load <vscale x 16 x i32>, ptr [[TMP40]], align 4 |
| ; CHECK-NOTF-NEXT: [[STRIDED_VEC8:%.*]] = call { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } @llvm.vector.deinterleave4.nxv16i32(<vscale x 16 x i32> [[WIDE_VEC7]]) |
| ; CHECK-NOTF-NEXT: [[TMP25:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC8]], 0 |
| ; CHECK-NOTF-NEXT: [[TMP26:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC8]], 1 |
| ; CHECK-NOTF-NEXT: [[TMP27:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC8]], 3 |
| ; CHECK-NOTF-NEXT: [[WIDE_VEC9:%.*]] = load <vscale x 16 x i32>, ptr [[TMP43]], align 4 |
| ; CHECK-NOTF-NEXT: [[STRIDED_VEC10:%.*]] = call { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } @llvm.vector.deinterleave4.nxv16i32(<vscale x 16 x i32> [[WIDE_VEC9]]) |
| ; CHECK-NOTF-NEXT: [[TMP28:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC10]], 0 |
| ; CHECK-NOTF-NEXT: [[TMP29:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC10]], 1 |
| ; CHECK-NOTF-NEXT: [[TMP30:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC10]], 3 |
| ; CHECK-NOTF-NEXT: [[TMP15:%.*]] = add <vscale x 4 x i32> [[VEC_PHI]], [[TMP9]] |
| ; CHECK-NOTF-NEXT: [[TMP16:%.*]] = add <vscale x 4 x i32> [[VEC_PHI1]], [[TMP12]] |
| ; CHECK-NOTF-NEXT: [[TMP33:%.*]] = add <vscale x 4 x i32> [[VEC_PHI3]], [[TMP25]] |
| ; CHECK-NOTF-NEXT: [[TMP34:%.*]] = add <vscale x 4 x i32> [[VEC_PHI4]], [[TMP28]] |
| ; CHECK-NOTF-NEXT: [[TMP17:%.*]] = add <vscale x 4 x i32> [[TMP15]], [[TMP10]] |
| ; CHECK-NOTF-NEXT: [[TMP18:%.*]] = add <vscale x 4 x i32> [[TMP16]], [[TMP13]] |
| ; CHECK-NOTF-NEXT: [[TMP37:%.*]] = add <vscale x 4 x i32> [[TMP33]], [[TMP26]] |
| ; CHECK-NOTF-NEXT: [[TMP38:%.*]] = add <vscale x 4 x i32> [[TMP34]], [[TMP29]] |
| ; CHECK-NOTF-NEXT: [[TMP19]] = add <vscale x 4 x i32> [[TMP17]], [[TMP11]] |
| ; CHECK-NOTF-NEXT: [[TMP20]] = add <vscale x 4 x i32> [[TMP18]], [[TMP14]] |
| ; CHECK-NOTF-NEXT: [[TMP41]] = add <vscale x 4 x i32> [[TMP37]], [[TMP27]] |
| ; CHECK-NOTF-NEXT: [[TMP42]] = add <vscale x 4 x i32> [[TMP38]], [[TMP30]] |
| ; CHECK-NOTF-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], [[TMP3]] |
| ; CHECK-NOTF-NEXT: [[TMP21:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]] |
| ; CHECK-NOTF-NEXT: br i1 [[TMP21]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP9:![0-9]+]] |
| ; CHECK-NOTF: [[MIDDLE_BLOCK]]: |
| ; CHECK-NOTF-NEXT: [[BIN_RDX:%.*]] = add <vscale x 4 x i32> [[TMP20]], [[TMP19]] |
| ; CHECK-NOTF-NEXT: [[BIN_RDX11:%.*]] = add <vscale x 4 x i32> [[TMP41]], [[BIN_RDX]] |
| ; CHECK-NOTF-NEXT: [[BIN_RDX12:%.*]] = add <vscale x 4 x i32> [[TMP42]], [[BIN_RDX11]] |
| ; CHECK-NOTF-NEXT: [[TMP44:%.*]] = call i32 @llvm.vector.reduce.add.nxv4i32(<vscale x 4 x i32> [[BIN_RDX12]]) |
| ; CHECK-NOTF-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[N]], [[N_VEC]] |
| ; CHECK-NOTF-NEXT: br i1 [[CMP_N]], label %[[EXIT:.*]], label %[[VEC_EPILOG_ITER_CHECK:.*]] |
| ; CHECK-NOTF: [[VEC_EPILOG_ITER_CHECK]]: |
| ; CHECK-NOTF-NEXT: [[MIN_EPILOG_ITERS_CHECK:%.*]] = icmp ult i64 [[N_MOD_VF]], 4 |
| ; CHECK-NOTF-NEXT: br i1 [[MIN_EPILOG_ITERS_CHECK]], label %[[VEC_EPILOG_SCALAR_PH]], label %[[SCALAR_PH]], !prof [[PROF10:![0-9]+]] |
| ; CHECK-NOTF: [[SCALAR_PH]]: |
| ; CHECK-NOTF-NEXT: [[VEC_EPILOG_RESUME_VAL:%.*]] = phi i64 [ [[N_VEC]], %[[VEC_EPILOG_ITER_CHECK]] ], [ 0, %[[VECTOR_MAIN_LOOP_ITER_CHECK]] ] |
| ; CHECK-NOTF-NEXT: [[BC_MERGE_RDX:%.*]] = phi i32 [ [[TMP44]], %[[VEC_EPILOG_ITER_CHECK]] ], [ 0, %[[VECTOR_MAIN_LOOP_ITER_CHECK]] ] |
| ; CHECK-NOTF-NEXT: [[N_MOD_VF13:%.*]] = urem i64 [[N]], 4 |
| ; CHECK-NOTF-NEXT: [[N_VEC14:%.*]] = sub i64 [[N]], [[N_MOD_VF13]] |
| ; CHECK-NOTF-NEXT: [[TMP45:%.*]] = insertelement <4 x i32> zeroinitializer, i32 [[BC_MERGE_RDX]], i32 0 |
| ; CHECK-NOTF-NEXT: br label %[[LOOP:.*]] |
| ; CHECK-NOTF: [[LOOP]]: |
| ; CHECK-NOTF-NEXT: [[IV:%.*]] = phi i64 [ [[VEC_EPILOG_RESUME_VAL]], %[[SCALAR_PH]] ], [ [[INDEX_NEXT21:%.*]], %[[LOOP]] ] |
| ; CHECK-NOTF-NEXT: [[VEC_PHI16:%.*]] = phi <4 x i32> [ [[TMP45]], %[[SCALAR_PH]] ], [ [[TMP49:%.*]], %[[LOOP]] ] |
| ; CHECK-NOTF-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV]], i32 0 |
| ; CHECK-NOTF-NEXT: [[WIDE_VEC17:%.*]] = load <16 x i32>, ptr [[ARRAYIDX]], align 4 |
| ; CHECK-NOTF-NEXT: [[STRIDED_VEC18:%.*]] = shufflevector <16 x i32> [[WIDE_VEC17]], <16 x i32> poison, <4 x i32> <i32 0, i32 4, i32 8, i32 12> |
| ; CHECK-NOTF-NEXT: [[STRIDED_VEC19:%.*]] = shufflevector <16 x i32> [[WIDE_VEC17]], <16 x i32> poison, <4 x i32> <i32 1, i32 5, i32 9, i32 13> |
| ; CHECK-NOTF-NEXT: [[STRIDED_VEC20:%.*]] = shufflevector <16 x i32> [[WIDE_VEC17]], <16 x i32> poison, <4 x i32> <i32 3, i32 7, i32 11, i32 15> |
| ; CHECK-NOTF-NEXT: [[TMP47:%.*]] = add <4 x i32> [[VEC_PHI16]], [[STRIDED_VEC18]] |
| ; CHECK-NOTF-NEXT: [[TMP48:%.*]] = add <4 x i32> [[TMP47]], [[STRIDED_VEC19]] |
| ; CHECK-NOTF-NEXT: [[TMP49]] = add <4 x i32> [[TMP48]], [[STRIDED_VEC20]] |
| ; CHECK-NOTF-NEXT: [[INDEX_NEXT21]] = add nuw i64 [[IV]], 4 |
| ; CHECK-NOTF-NEXT: [[TMP50:%.*]] = icmp eq i64 [[INDEX_NEXT21]], [[N_VEC14]] |
| ; CHECK-NOTF-NEXT: br i1 [[TMP50]], label %[[VEC_EPILOG_MIDDLE_BLOCK:.*]], label %[[LOOP]], !llvm.loop [[LOOP11:![0-9]+]] |
| ; CHECK-NOTF: [[VEC_EPILOG_MIDDLE_BLOCK]]: |
| ; CHECK-NOTF-NEXT: [[TMP51:%.*]] = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> [[TMP49]]) |
| ; CHECK-NOTF-NEXT: [[CMP_N22:%.*]] = icmp eq i64 [[N]], [[N_VEC14]] |
| ; CHECK-NOTF-NEXT: br i1 [[CMP_N22]], label %[[EXIT]], label %[[VEC_EPILOG_SCALAR_PH]] |
| ; CHECK-NOTF: [[VEC_EPILOG_SCALAR_PH]]: |
| ; CHECK-NOTF-NEXT: [[BC_RESUME_VAL:%.*]] = phi i64 [ [[N_VEC14]], %[[VEC_EPILOG_MIDDLE_BLOCK]] ], [ [[N_VEC]], %[[VEC_EPILOG_ITER_CHECK]] ], [ 0, %[[ENTRY]] ] |
| ; CHECK-NOTF-NEXT: [[BC_MERGE_RDX23:%.*]] = phi i32 [ [[TMP51]], %[[VEC_EPILOG_MIDDLE_BLOCK]] ], [ [[TMP44]], %[[VEC_EPILOG_ITER_CHECK]] ], [ 0, %[[ENTRY]] ] |
| ; CHECK-NOTF-NEXT: br label %[[LOOP1:.*]] |
| ; CHECK-NOTF: [[LOOP1]]: |
| ; CHECK-NOTF-NEXT: [[IV1:%.*]] = phi i64 [ [[BC_RESUME_VAL]], %[[VEC_EPILOG_SCALAR_PH]] ], [ [[IV_NEXT:%.*]], %[[LOOP1]] ] |
| ; CHECK-NOTF-NEXT: [[RDX:%.*]] = phi i32 [ [[BC_MERGE_RDX23]], %[[VEC_EPILOG_SCALAR_PH]] ], [ [[RDX_NEXT:%.*]], %[[LOOP1]] ] |
| ; CHECK-NOTF-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV1]], i32 0 |
| ; CHECK-NOTF-NEXT: [[LD1:%.*]] = load i32, ptr [[ARRAYIDX3]], align 4 |
| ; CHECK-NOTF-NEXT: [[ADD:%.*]] = add nsw i32 [[RDX]], [[LD1]] |
| ; CHECK-NOTF-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV1]], i32 1 |
| ; CHECK-NOTF-NEXT: [[LD2:%.*]] = load i32, ptr [[ARRAYIDX1]], align 4 |
| ; CHECK-NOTF-NEXT: [[ADD1:%.*]] = add nsw i32 [[ADD]], [[LD2]] |
| ; CHECK-NOTF-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV1]], i32 3 |
| ; CHECK-NOTF-NEXT: [[LD3:%.*]] = load i32, ptr [[ARRAYIDX2]], align 4 |
| ; CHECK-NOTF-NEXT: [[RDX_NEXT]] = add nsw i32 [[ADD1]], [[LD3]] |
| ; CHECK-NOTF-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV1]], 1 |
| ; CHECK-NOTF-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]] |
| ; CHECK-NOTF-NEXT: br i1 [[EXITCOND_NOT]], label %[[EXIT]], label %[[LOOP1]], !llvm.loop [[LOOP12:![0-9]+]] |
| ; CHECK-NOTF: [[EXIT]]: |
| ; CHECK-NOTF-NEXT: [[RDX_NEXT_LCSSA:%.*]] = phi i32 [ [[RDX_NEXT]], %[[LOOP1]] ], [ [[TMP44]], %[[MIDDLE_BLOCK]] ], [ [[TMP51]], %[[VEC_EPILOG_MIDDLE_BLOCK]] ] |
| ; CHECK-NOTF-NEXT: ret i32 [[RDX_NEXT_LCSSA]] |
| ; |
| ; CHECK-TF-LABEL: define i32 @load_factor_4_with_gap( |
| ; CHECK-TF-SAME: i64 [[N:%.*]], ptr noalias [[A:%.*]]) #[[ATTR2:[0-9]+]] { |
| ; CHECK-TF-NEXT: [[ENTRY:.*:]] |
| ; CHECK-TF-NEXT: br label %[[VECTOR_PH:.*]] |
| ; CHECK-TF: [[VECTOR_PH]]: |
| ; CHECK-TF-NEXT: [[TMP0:%.*]] = call i64 @llvm.vscale.i64() |
| ; CHECK-TF-NEXT: [[TMP1:%.*]] = shl nuw i64 [[TMP0]], 2 |
| ; CHECK-TF-NEXT: [[ACTIVE_LANE_MASK_ENTRY:%.*]] = call <vscale x 4 x i1> @llvm.get.active.lane.mask.nxv4i1.i64(i64 0, i64 [[N]]) |
| ; CHECK-TF-NEXT: br label %[[VECTOR_BODY:.*]] |
| ; CHECK-TF: [[VECTOR_BODY]]: |
| ; CHECK-TF-NEXT: [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-TF-NEXT: [[ACTIVE_LANE_MASK:%.*]] = phi <vscale x 4 x i1> [ [[ACTIVE_LANE_MASK_ENTRY]], %[[VECTOR_PH]] ], [ [[ACTIVE_LANE_MASK_NEXT:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-TF-NEXT: [[VEC_PHI:%.*]] = phi <vscale x 4 x i32> [ zeroinitializer, %[[VECTOR_PH]] ], [ [[TMP9:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-TF-NEXT: [[TMP2:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[INDEX]], i32 0 |
| ; CHECK-TF-NEXT: [[INTERLEAVED_MASK:%.*]] = call <vscale x 16 x i1> @llvm.vector.interleave4.nxv16i1(<vscale x 4 x i1> [[ACTIVE_LANE_MASK]], <vscale x 4 x i1> [[ACTIVE_LANE_MASK]], <vscale x 4 x i1> [[ACTIVE_LANE_MASK]], <vscale x 4 x i1> [[ACTIVE_LANE_MASK]]) |
| ; CHECK-TF-NEXT: [[WIDE_MASKED_VEC:%.*]] = call <vscale x 16 x i32> @llvm.masked.load.nxv16i32.p0(ptr align 4 [[TMP2]], <vscale x 16 x i1> [[INTERLEAVED_MASK]], <vscale x 16 x i32> poison) |
| ; CHECK-TF-NEXT: [[STRIDED_VEC:%.*]] = call { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } @llvm.vector.deinterleave4.nxv16i32(<vscale x 16 x i32> [[WIDE_MASKED_VEC]]) |
| ; CHECK-TF-NEXT: [[TMP3:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC]], 0 |
| ; CHECK-TF-NEXT: [[TMP4:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC]], 1 |
| ; CHECK-TF-NEXT: [[TMP5:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC]], 3 |
| ; CHECK-TF-NEXT: [[TMP6:%.*]] = add <vscale x 4 x i32> [[VEC_PHI]], [[TMP3]] |
| ; CHECK-TF-NEXT: [[TMP7:%.*]] = add <vscale x 4 x i32> [[TMP6]], [[TMP4]] |
| ; CHECK-TF-NEXT: [[TMP8:%.*]] = add <vscale x 4 x i32> [[TMP7]], [[TMP5]] |
| ; CHECK-TF-NEXT: [[TMP9]] = select <vscale x 4 x i1> [[ACTIVE_LANE_MASK]], <vscale x 4 x i32> [[TMP8]], <vscale x 4 x i32> [[VEC_PHI]] |
| ; CHECK-TF-NEXT: [[INDEX_NEXT]] = add i64 [[INDEX]], [[TMP1]] |
| ; CHECK-TF-NEXT: [[ACTIVE_LANE_MASK_NEXT]] = call <vscale x 4 x i1> @llvm.get.active.lane.mask.nxv4i1.i64(i64 [[INDEX_NEXT]], i64 [[N]]) |
| ; CHECK-TF-NEXT: [[TMP10:%.*]] = extractelement <vscale x 4 x i1> [[ACTIVE_LANE_MASK_NEXT]], i64 0 |
| ; CHECK-TF-NEXT: [[TMP11:%.*]] = xor i1 [[TMP10]], true |
| ; CHECK-TF-NEXT: br i1 [[TMP11]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP4:![0-9]+]] |
| ; CHECK-TF: [[MIDDLE_BLOCK]]: |
| ; CHECK-TF-NEXT: [[TMP12:%.*]] = call i32 @llvm.vector.reduce.add.nxv4i32(<vscale x 4 x i32> [[TMP9]]) |
| ; CHECK-TF-NEXT: br label %[[EXIT:.*]] |
| ; CHECK-TF: [[EXIT]]: |
| ; CHECK-TF-NEXT: ret i32 [[TMP12]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] |
| %rdx = phi i32 [ 0, %entry ], [ %rdx.next, %loop ] |
| %arrayidx = getelementptr inbounds [4 x i32], ptr %a, i64 %iv, i32 0 |
| %ld1 = load i32, ptr %arrayidx, align 4 |
| %add = add nsw i32 %rdx, %ld1 |
| %arrayidx1 = getelementptr inbounds [4 x i32], ptr %a, i64 %iv, i32 1 |
| %ld2 = load i32, ptr %arrayidx1, align 4 |
| %add1 = add nsw i32 %add, %ld2 |
| %arrayidx2 = getelementptr inbounds [4 x i32], ptr %a, i64 %iv, i32 3 |
| %ld3 = load i32, ptr %arrayidx2, align 4 |
| %rdx.next = add nsw i32 %add1, %ld3 |
| %iv.next = add nuw nsw i64 %iv, 1 |
| %exitcond.not = icmp eq i64 %iv.next, %n |
| br i1 %exitcond.not, label %exit, label %loop |
| |
| exit: |
| ret i32 %rdx.next |
| } |
| |
| ; Interleaved group with gap but without tail gap |
| ; E.g. |
| ; int (*a)[4]; |
| ; for (int i = 0; i < n; i++) { |
| ; a[i][0] = i; |
| ; a[i][1] = i; |
| ; // No access a[i][2] |
| ; a[i][3] = i; |
| ; } |
| ; |
| define void @store_factor_4_with_gap(i32 %n, ptr noalias %a) { |
| ; CHECK-NOTF-LABEL: define void @store_factor_4_with_gap( |
| ; CHECK-NOTF-SAME: i32 [[N:%.*]], ptr noalias [[A:%.*]]) #[[ATTR2]] { |
| ; CHECK-NOTF-NEXT: [[ENTRY:.*]]: |
| ; CHECK-NOTF-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i32 [[N]], 4 |
| ; CHECK-NOTF-NEXT: br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]] |
| ; CHECK-NOTF: [[VECTOR_PH]]: |
| ; CHECK-NOTF-NEXT: [[N_MOD_VF:%.*]] = urem i32 [[N]], 4 |
| ; CHECK-NOTF-NEXT: [[N_VEC:%.*]] = sub i32 [[N]], [[N_MOD_VF]] |
| ; CHECK-NOTF-NEXT: br label %[[VECTOR_BODY:.*]] |
| ; CHECK-NOTF: [[VECTOR_BODY]]: |
| ; CHECK-NOTF-NEXT: [[INDEX:%.*]] = phi i32 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[TMP0:%.*]] = add i32 [[INDEX]], 1 |
| ; CHECK-NOTF-NEXT: [[TMP1:%.*]] = add i32 [[INDEX]], 2 |
| ; CHECK-NOTF-NEXT: [[TMP2:%.*]] = add i32 [[INDEX]], 3 |
| ; CHECK-NOTF-NEXT: [[TMP3:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[INDEX]], i32 0 |
| ; CHECK-NOTF-NEXT: [[TMP4:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[TMP0]], i32 0 |
| ; CHECK-NOTF-NEXT: [[TMP5:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[TMP1]], i32 0 |
| ; CHECK-NOTF-NEXT: [[TMP6:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[TMP2]], i32 0 |
| ; CHECK-NOTF-NEXT: store i32 [[INDEX]], ptr [[TMP3]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP0]], ptr [[TMP4]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP1]], ptr [[TMP5]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP2]], ptr [[TMP6]], align 4 |
| ; CHECK-NOTF-NEXT: [[TMP7:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[INDEX]], i32 1 |
| ; CHECK-NOTF-NEXT: [[TMP8:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[TMP0]], i32 1 |
| ; CHECK-NOTF-NEXT: [[TMP9:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[TMP1]], i32 1 |
| ; CHECK-NOTF-NEXT: [[TMP10:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[TMP2]], i32 1 |
| ; CHECK-NOTF-NEXT: store i32 [[INDEX]], ptr [[TMP7]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP0]], ptr [[TMP8]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP1]], ptr [[TMP9]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP2]], ptr [[TMP10]], align 4 |
| ; CHECK-NOTF-NEXT: [[TMP11:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[INDEX]], i32 3 |
| ; CHECK-NOTF-NEXT: [[TMP12:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[TMP0]], i32 3 |
| ; CHECK-NOTF-NEXT: [[TMP13:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[TMP1]], i32 3 |
| ; CHECK-NOTF-NEXT: [[TMP14:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[TMP2]], i32 3 |
| ; CHECK-NOTF-NEXT: store i32 [[INDEX]], ptr [[TMP11]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP0]], ptr [[TMP12]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP1]], ptr [[TMP13]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP2]], ptr [[TMP14]], align 4 |
| ; CHECK-NOTF-NEXT: [[INDEX_NEXT]] = add nuw i32 [[INDEX]], 4 |
| ; CHECK-NOTF-NEXT: [[TMP15:%.*]] = icmp eq i32 [[INDEX_NEXT]], [[N_VEC]] |
| ; CHECK-NOTF-NEXT: br i1 [[TMP15]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP13:![0-9]+]] |
| ; CHECK-NOTF: [[MIDDLE_BLOCK]]: |
| ; CHECK-NOTF-NEXT: [[CMP_N:%.*]] = icmp eq i32 [[N]], [[N_VEC]] |
| ; CHECK-NOTF-NEXT: br i1 [[CMP_N]], label %[[EXIT:.*]], label %[[SCALAR_PH]] |
| ; CHECK-NOTF: [[SCALAR_PH]]: |
| ; CHECK-NOTF-NEXT: [[BC_RESUME_VAL:%.*]] = phi i32 [ [[N_VEC]], %[[MIDDLE_BLOCK]] ], [ 0, %[[ENTRY]] ] |
| ; CHECK-NOTF-NEXT: br label %[[LOOP:.*]] |
| ; CHECK-NOTF: [[LOOP]]: |
| ; CHECK-NOTF-NEXT: [[IV:%.*]] = phi i32 [ [[BC_RESUME_VAL]], %[[SCALAR_PH]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ] |
| ; CHECK-NOTF-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[IV]], i32 0 |
| ; CHECK-NOTF-NEXT: store i32 [[IV]], ptr [[ARRAYIDX]], align 4 |
| ; CHECK-NOTF-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[IV]], i32 1 |
| ; CHECK-NOTF-NEXT: store i32 [[IV]], ptr [[ARRAYIDX1]], align 4 |
| ; CHECK-NOTF-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[IV]], i32 3 |
| ; CHECK-NOTF-NEXT: store i32 [[IV]], ptr [[ARRAYIDX2]], align 4 |
| ; CHECK-NOTF-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 |
| ; CHECK-NOTF-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i32 [[IV_NEXT]], [[N]] |
| ; CHECK-NOTF-NEXT: br i1 [[EXITCOND_NOT]], label %[[EXIT]], label %[[LOOP]], !llvm.loop [[LOOP14:![0-9]+]] |
| ; CHECK-NOTF: [[EXIT]]: |
| ; CHECK-NOTF-NEXT: ret void |
| ; |
| ; CHECK-TF-LABEL: define void @store_factor_4_with_gap( |
| ; CHECK-TF-SAME: i32 [[N:%.*]], ptr noalias [[A:%.*]]) #[[ATTR2]] { |
| ; CHECK-TF-NEXT: [[ENTRY:.*]]: |
| ; CHECK-TF-NEXT: br label %[[LOOP:.*]] |
| ; CHECK-TF: [[LOOP]]: |
| ; CHECK-TF-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ] |
| ; CHECK-TF-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[IV]], i32 0 |
| ; CHECK-TF-NEXT: store i32 [[IV]], ptr [[ARRAYIDX]], align 4 |
| ; CHECK-TF-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[IV]], i32 1 |
| ; CHECK-TF-NEXT: store i32 [[IV]], ptr [[ARRAYIDX1]], align 4 |
| ; CHECK-TF-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[IV]], i32 3 |
| ; CHECK-TF-NEXT: store i32 [[IV]], ptr [[ARRAYIDX2]], align 4 |
| ; CHECK-TF-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 |
| ; CHECK-TF-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i32 [[IV_NEXT]], [[N]] |
| ; CHECK-TF-NEXT: br i1 [[EXITCOND_NOT]], label %[[EXIT:.*]], label %[[LOOP]] |
| ; CHECK-TF: [[EXIT]]: |
| ; CHECK-TF-NEXT: ret void |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] |
| %arrayidx = getelementptr inbounds [4 x i32], ptr %a, i32 %iv, i32 0 |
| store i32 %iv, ptr %arrayidx, align 4 |
| %arrayidx1 = getelementptr inbounds [4 x i32], ptr %a, i32 %iv, i32 1 |
| store i32 %iv, ptr %arrayidx1, align 4 |
| %arrayidx2 = getelementptr inbounds [4 x i32], ptr %a, i32 %iv, i32 3 |
| store i32 %iv, ptr %arrayidx2, align 4 |
| %iv.next = add nuw nsw i32 %iv, 1 |
| %exitcond.not = icmp eq i32 %iv.next, %n |
| br i1 %exitcond.not, label %exit, label %loop |
| |
| exit: |
| ret void |
| } |
| |
| ; Interleaved group with tail gap |
| ; E.g. |
| ; int (*a)[4]; |
| ; int rdx = 0; |
| ; for (int i = 0; i < n; i++) { |
| ; rdx += a[i][0]; |
| ; rdx += a[i][1]; |
| ; rdx += a[i][2]; |
| ; // No access a[i][3] |
| ; } |
| ; |
| define i32 @load_factor_4_with_tail_gap(i64 %n, ptr noalias %a) { |
| ; CHECK-NOTF-LABEL: define i32 @load_factor_4_with_tail_gap( |
| ; CHECK-NOTF-SAME: i64 [[N:%.*]], ptr noalias [[A:%.*]]) #[[ATTR2]] { |
| ; CHECK-NOTF-NEXT: [[ENTRY:.*]]: |
| ; CHECK-NOTF-NEXT: [[MIN_ITERS_CHECK1:%.*]] = icmp ule i64 [[N]], 4 |
| ; CHECK-NOTF-NEXT: br i1 [[MIN_ITERS_CHECK1]], label %[[VEC_EPILOG_SCALAR_PH:.*]], label %[[VECTOR_MAIN_LOOP_ITER_CHECK:.*]] |
| ; CHECK-NOTF: [[VECTOR_MAIN_LOOP_ITER_CHECK]]: |
| ; CHECK-NOTF-NEXT: [[TMP0:%.*]] = call i64 @llvm.vscale.i64() |
| ; CHECK-NOTF-NEXT: [[TMP1:%.*]] = shl nuw i64 [[TMP0]], 4 |
| ; CHECK-NOTF-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ule i64 [[N]], [[TMP1]] |
| ; CHECK-NOTF-NEXT: br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]] |
| ; CHECK-NOTF: [[VECTOR_PH]]: |
| ; CHECK-NOTF-NEXT: [[TMP2:%.*]] = shl nuw i64 [[TMP0]], 2 |
| ; CHECK-NOTF-NEXT: [[TMP3:%.*]] = shl nuw i64 [[TMP2]], 2 |
| ; CHECK-NOTF-NEXT: [[N_MOD_VF:%.*]] = urem i64 [[N]], [[TMP3]] |
| ; CHECK-NOTF-NEXT: [[TMP4:%.*]] = icmp eq i64 [[N_MOD_VF]], 0 |
| ; CHECK-NOTF-NEXT: [[TMP5:%.*]] = select i1 [[TMP4]], i64 [[TMP3]], i64 [[N_MOD_VF]] |
| ; CHECK-NOTF-NEXT: [[N_VEC:%.*]] = sub i64 [[N]], [[TMP5]] |
| ; CHECK-NOTF-NEXT: br label %[[VECTOR_BODY:.*]] |
| ; CHECK-NOTF: [[VECTOR_BODY]]: |
| ; CHECK-NOTF-NEXT: [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[VEC_PHI:%.*]] = phi <vscale x 4 x i32> [ zeroinitializer, %[[VECTOR_PH]] ], [ [[TMP21:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[VEC_PHI1:%.*]] = phi <vscale x 4 x i32> [ zeroinitializer, %[[VECTOR_PH]] ], [ [[TMP22:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[VEC_PHI3:%.*]] = phi <vscale x 4 x i32> [ zeroinitializer, %[[VECTOR_PH]] ], [ [[TMP43:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[VEC_PHI4:%.*]] = phi <vscale x 4 x i32> [ zeroinitializer, %[[VECTOR_PH]] ], [ [[TMP44:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[TMP6:%.*]] = add i64 [[TMP2]], 0 |
| ; CHECK-NOTF-NEXT: [[TMP7:%.*]] = mul i64 [[TMP6]], 1 |
| ; CHECK-NOTF-NEXT: [[TMP8:%.*]] = add i64 [[INDEX]], [[TMP7]] |
| ; CHECK-NOTF-NEXT: [[TMP24:%.*]] = shl i64 [[TMP2]], 1 |
| ; CHECK-NOTF-NEXT: [[TMP25:%.*]] = add i64 [[TMP24]], 0 |
| ; CHECK-NOTF-NEXT: [[TMP26:%.*]] = mul i64 [[TMP25]], 1 |
| ; CHECK-NOTF-NEXT: [[TMP33:%.*]] = add i64 [[INDEX]], [[TMP26]] |
| ; CHECK-NOTF-NEXT: [[TMP34:%.*]] = mul i64 [[TMP2]], 3 |
| ; CHECK-NOTF-NEXT: [[TMP37:%.*]] = add i64 [[TMP34]], 0 |
| ; CHECK-NOTF-NEXT: [[TMP38:%.*]] = mul i64 [[TMP37]], 1 |
| ; CHECK-NOTF-NEXT: [[TMP41:%.*]] = add i64 [[INDEX]], [[TMP38]] |
| ; CHECK-NOTF-NEXT: [[TMP9:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[INDEX]], i32 0 |
| ; CHECK-NOTF-NEXT: [[TMP10:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP8]], i32 0 |
| ; CHECK-NOTF-NEXT: [[TMP42:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP33]], i32 0 |
| ; CHECK-NOTF-NEXT: [[TMP45:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP41]], i32 0 |
| ; CHECK-NOTF-NEXT: [[WIDE_VEC:%.*]] = load <vscale x 16 x i32>, ptr [[TMP9]], align 4 |
| ; CHECK-NOTF-NEXT: [[STRIDED_VEC:%.*]] = call { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } @llvm.vector.deinterleave4.nxv16i32(<vscale x 16 x i32> [[WIDE_VEC]]) |
| ; CHECK-NOTF-NEXT: [[TMP11:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC]], 0 |
| ; CHECK-NOTF-NEXT: [[TMP12:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC]], 1 |
| ; CHECK-NOTF-NEXT: [[TMP13:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC]], 2 |
| ; CHECK-NOTF-NEXT: [[WIDE_VEC2:%.*]] = load <vscale x 16 x i32>, ptr [[TMP10]], align 4 |
| ; CHECK-NOTF-NEXT: [[STRIDED_VEC3:%.*]] = call { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } @llvm.vector.deinterleave4.nxv16i32(<vscale x 16 x i32> [[WIDE_VEC2]]) |
| ; CHECK-NOTF-NEXT: [[TMP14:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC3]], 0 |
| ; CHECK-NOTF-NEXT: [[TMP15:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC3]], 1 |
| ; CHECK-NOTF-NEXT: [[TMP16:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC3]], 2 |
| ; CHECK-NOTF-NEXT: [[WIDE_VEC7:%.*]] = load <vscale x 16 x i32>, ptr [[TMP42]], align 4 |
| ; CHECK-NOTF-NEXT: [[STRIDED_VEC8:%.*]] = call { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } @llvm.vector.deinterleave4.nxv16i32(<vscale x 16 x i32> [[WIDE_VEC7]]) |
| ; CHECK-NOTF-NEXT: [[TMP27:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC8]], 0 |
| ; CHECK-NOTF-NEXT: [[TMP28:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC8]], 1 |
| ; CHECK-NOTF-NEXT: [[TMP29:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC8]], 2 |
| ; CHECK-NOTF-NEXT: [[WIDE_VEC9:%.*]] = load <vscale x 16 x i32>, ptr [[TMP45]], align 4 |
| ; CHECK-NOTF-NEXT: [[STRIDED_VEC10:%.*]] = call { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } @llvm.vector.deinterleave4.nxv16i32(<vscale x 16 x i32> [[WIDE_VEC9]]) |
| ; CHECK-NOTF-NEXT: [[TMP30:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC10]], 0 |
| ; CHECK-NOTF-NEXT: [[TMP31:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC10]], 1 |
| ; CHECK-NOTF-NEXT: [[TMP32:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC10]], 2 |
| ; CHECK-NOTF-NEXT: [[TMP17:%.*]] = add <vscale x 4 x i32> [[VEC_PHI]], [[TMP11]] |
| ; CHECK-NOTF-NEXT: [[TMP18:%.*]] = add <vscale x 4 x i32> [[VEC_PHI1]], [[TMP14]] |
| ; CHECK-NOTF-NEXT: [[TMP35:%.*]] = add <vscale x 4 x i32> [[VEC_PHI3]], [[TMP27]] |
| ; CHECK-NOTF-NEXT: [[TMP36:%.*]] = add <vscale x 4 x i32> [[VEC_PHI4]], [[TMP30]] |
| ; CHECK-NOTF-NEXT: [[TMP19:%.*]] = add <vscale x 4 x i32> [[TMP17]], [[TMP12]] |
| ; CHECK-NOTF-NEXT: [[TMP20:%.*]] = add <vscale x 4 x i32> [[TMP18]], [[TMP15]] |
| ; CHECK-NOTF-NEXT: [[TMP39:%.*]] = add <vscale x 4 x i32> [[TMP35]], [[TMP28]] |
| ; CHECK-NOTF-NEXT: [[TMP40:%.*]] = add <vscale x 4 x i32> [[TMP36]], [[TMP31]] |
| ; CHECK-NOTF-NEXT: [[TMP21]] = add <vscale x 4 x i32> [[TMP19]], [[TMP13]] |
| ; CHECK-NOTF-NEXT: [[TMP22]] = add <vscale x 4 x i32> [[TMP20]], [[TMP16]] |
| ; CHECK-NOTF-NEXT: [[TMP43]] = add <vscale x 4 x i32> [[TMP39]], [[TMP29]] |
| ; CHECK-NOTF-NEXT: [[TMP44]] = add <vscale x 4 x i32> [[TMP40]], [[TMP32]] |
| ; CHECK-NOTF-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], [[TMP3]] |
| ; CHECK-NOTF-NEXT: [[TMP23:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]] |
| ; CHECK-NOTF-NEXT: br i1 [[TMP23]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP15:![0-9]+]] |
| ; CHECK-NOTF: [[MIDDLE_BLOCK]]: |
| ; CHECK-NOTF-NEXT: [[BIN_RDX:%.*]] = add <vscale x 4 x i32> [[TMP22]], [[TMP21]] |
| ; CHECK-NOTF-NEXT: [[BIN_RDX11:%.*]] = add <vscale x 4 x i32> [[TMP43]], [[BIN_RDX]] |
| ; CHECK-NOTF-NEXT: [[BIN_RDX12:%.*]] = add <vscale x 4 x i32> [[TMP44]], [[BIN_RDX11]] |
| ; CHECK-NOTF-NEXT: [[TMP46:%.*]] = call i32 @llvm.vector.reduce.add.nxv4i32(<vscale x 4 x i32> [[BIN_RDX12]]) |
| ; CHECK-NOTF-NEXT: br label %[[VEC_EPILOG_ITER_CHECK:.*]] |
| ; CHECK-NOTF: [[VEC_EPILOG_ITER_CHECK]]: |
| ; CHECK-NOTF-NEXT: [[MIN_EPILOG_ITERS_CHECK:%.*]] = icmp ule i64 [[TMP5]], 4 |
| ; CHECK-NOTF-NEXT: br i1 [[MIN_EPILOG_ITERS_CHECK]], label %[[VEC_EPILOG_SCALAR_PH]], label %[[SCALAR_PH]], !prof [[PROF10]] |
| ; CHECK-NOTF: [[SCALAR_PH]]: |
| ; CHECK-NOTF-NEXT: [[VEC_EPILOG_RESUME_VAL:%.*]] = phi i64 [ [[N_VEC]], %[[VEC_EPILOG_ITER_CHECK]] ], [ 0, %[[VECTOR_MAIN_LOOP_ITER_CHECK]] ] |
| ; CHECK-NOTF-NEXT: [[BC_MERGE_RDX:%.*]] = phi i32 [ [[TMP46]], %[[VEC_EPILOG_ITER_CHECK]] ], [ 0, %[[VECTOR_MAIN_LOOP_ITER_CHECK]] ] |
| ; CHECK-NOTF-NEXT: [[N_MOD_VF13:%.*]] = urem i64 [[N]], 4 |
| ; CHECK-NOTF-NEXT: [[TMP47:%.*]] = icmp eq i64 [[N_MOD_VF13]], 0 |
| ; CHECK-NOTF-NEXT: [[TMP48:%.*]] = select i1 [[TMP47]], i64 4, i64 [[N_MOD_VF13]] |
| ; CHECK-NOTF-NEXT: [[N_VEC14:%.*]] = sub i64 [[N]], [[TMP48]] |
| ; CHECK-NOTF-NEXT: [[TMP49:%.*]] = insertelement <4 x i32> zeroinitializer, i32 [[BC_MERGE_RDX]], i32 0 |
| ; CHECK-NOTF-NEXT: br label %[[LOOP:.*]] |
| ; CHECK-NOTF: [[LOOP]]: |
| ; CHECK-NOTF-NEXT: [[IV:%.*]] = phi i64 [ [[VEC_EPILOG_RESUME_VAL]], %[[SCALAR_PH]] ], [ [[INDEX_NEXT21:%.*]], %[[LOOP]] ] |
| ; CHECK-NOTF-NEXT: [[VEC_PHI16:%.*]] = phi <4 x i32> [ [[TMP49]], %[[SCALAR_PH]] ], [ [[TMP53:%.*]], %[[LOOP]] ] |
| ; CHECK-NOTF-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV]], i32 0 |
| ; CHECK-NOTF-NEXT: [[WIDE_VEC17:%.*]] = load <16 x i32>, ptr [[ARRAYIDX]], align 4 |
| ; CHECK-NOTF-NEXT: [[STRIDED_VEC18:%.*]] = shufflevector <16 x i32> [[WIDE_VEC17]], <16 x i32> poison, <4 x i32> <i32 0, i32 4, i32 8, i32 12> |
| ; CHECK-NOTF-NEXT: [[STRIDED_VEC19:%.*]] = shufflevector <16 x i32> [[WIDE_VEC17]], <16 x i32> poison, <4 x i32> <i32 1, i32 5, i32 9, i32 13> |
| ; CHECK-NOTF-NEXT: [[STRIDED_VEC20:%.*]] = shufflevector <16 x i32> [[WIDE_VEC17]], <16 x i32> poison, <4 x i32> <i32 2, i32 6, i32 10, i32 14> |
| ; CHECK-NOTF-NEXT: [[TMP51:%.*]] = add <4 x i32> [[VEC_PHI16]], [[STRIDED_VEC18]] |
| ; CHECK-NOTF-NEXT: [[TMP52:%.*]] = add <4 x i32> [[TMP51]], [[STRIDED_VEC19]] |
| ; CHECK-NOTF-NEXT: [[TMP53]] = add <4 x i32> [[TMP52]], [[STRIDED_VEC20]] |
| ; CHECK-NOTF-NEXT: [[INDEX_NEXT21]] = add nuw i64 [[IV]], 4 |
| ; CHECK-NOTF-NEXT: [[TMP54:%.*]] = icmp eq i64 [[INDEX_NEXT21]], [[N_VEC14]] |
| ; CHECK-NOTF-NEXT: br i1 [[TMP54]], label %[[VEC_EPILOG_MIDDLE_BLOCK:.*]], label %[[LOOP]], !llvm.loop [[LOOP16:![0-9]+]] |
| ; CHECK-NOTF: [[VEC_EPILOG_MIDDLE_BLOCK]]: |
| ; CHECK-NOTF-NEXT: [[TMP55:%.*]] = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> [[TMP53]]) |
| ; CHECK-NOTF-NEXT: br label %[[VEC_EPILOG_SCALAR_PH]] |
| ; CHECK-NOTF: [[VEC_EPILOG_SCALAR_PH]]: |
| ; CHECK-NOTF-NEXT: [[BC_RESUME_VAL:%.*]] = phi i64 [ [[N_VEC14]], %[[VEC_EPILOG_MIDDLE_BLOCK]] ], [ [[N_VEC]], %[[VEC_EPILOG_ITER_CHECK]] ], [ 0, %[[ENTRY]] ] |
| ; CHECK-NOTF-NEXT: [[BC_MERGE_RDX22:%.*]] = phi i32 [ [[TMP55]], %[[VEC_EPILOG_MIDDLE_BLOCK]] ], [ [[TMP46]], %[[VEC_EPILOG_ITER_CHECK]] ], [ 0, %[[ENTRY]] ] |
| ; CHECK-NOTF-NEXT: br label %[[LOOP1:.*]] |
| ; CHECK-NOTF: [[LOOP1]]: |
| ; CHECK-NOTF-NEXT: [[IV1:%.*]] = phi i64 [ [[BC_RESUME_VAL]], %[[VEC_EPILOG_SCALAR_PH]] ], [ [[IV_NEXT:%.*]], %[[LOOP1]] ] |
| ; CHECK-NOTF-NEXT: [[RDX:%.*]] = phi i32 [ [[BC_MERGE_RDX22]], %[[VEC_EPILOG_SCALAR_PH]] ], [ [[RDX_NEXT:%.*]], %[[LOOP1]] ] |
| ; CHECK-NOTF-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV1]], i32 0 |
| ; CHECK-NOTF-NEXT: [[LD1:%.*]] = load i32, ptr [[ARRAYIDX3]], align 4 |
| ; CHECK-NOTF-NEXT: [[ADD:%.*]] = add nsw i32 [[RDX]], [[LD1]] |
| ; CHECK-NOTF-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV1]], i32 1 |
| ; CHECK-NOTF-NEXT: [[LD2:%.*]] = load i32, ptr [[ARRAYIDX1]], align 4 |
| ; CHECK-NOTF-NEXT: [[ADD1:%.*]] = add nsw i32 [[ADD]], [[LD2]] |
| ; CHECK-NOTF-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV1]], i32 2 |
| ; CHECK-NOTF-NEXT: [[LD3:%.*]] = load i32, ptr [[ARRAYIDX2]], align 4 |
| ; CHECK-NOTF-NEXT: [[RDX_NEXT]] = add nsw i32 [[ADD1]], [[LD3]] |
| ; CHECK-NOTF-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV1]], 1 |
| ; CHECK-NOTF-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]] |
| ; CHECK-NOTF-NEXT: br i1 [[EXITCOND_NOT]], label %[[EXIT:.*]], label %[[LOOP1]], !llvm.loop [[LOOP17:![0-9]+]] |
| ; CHECK-NOTF: [[EXIT]]: |
| ; CHECK-NOTF-NEXT: [[RDX_NEXT_LCSSA:%.*]] = phi i32 [ [[RDX_NEXT]], %[[LOOP1]] ] |
| ; CHECK-NOTF-NEXT: ret i32 [[RDX_NEXT_LCSSA]] |
| ; |
| ; CHECK-TF-LABEL: define i32 @load_factor_4_with_tail_gap( |
| ; CHECK-TF-SAME: i64 [[N:%.*]], ptr noalias [[A:%.*]]) #[[ATTR2]] { |
| ; CHECK-TF-NEXT: [[ENTRY:.*]]: |
| ; CHECK-TF-NEXT: br label %[[LOOP:.*]] |
| ; CHECK-TF: [[LOOP]]: |
| ; CHECK-TF-NEXT: [[IV:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ] |
| ; CHECK-TF-NEXT: [[RDX:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[RDX_NEXT:%.*]], %[[LOOP]] ] |
| ; CHECK-TF-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV]], i32 0 |
| ; CHECK-TF-NEXT: [[LD1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4 |
| ; CHECK-TF-NEXT: [[ADD:%.*]] = add nsw i32 [[RDX]], [[LD1]] |
| ; CHECK-TF-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV]], i32 1 |
| ; CHECK-TF-NEXT: [[LD2:%.*]] = load i32, ptr [[ARRAYIDX1]], align 4 |
| ; CHECK-TF-NEXT: [[ADD1:%.*]] = add nsw i32 [[ADD]], [[LD2]] |
| ; CHECK-TF-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV]], i32 2 |
| ; CHECK-TF-NEXT: [[LD3:%.*]] = load i32, ptr [[ARRAYIDX2]], align 4 |
| ; CHECK-TF-NEXT: [[RDX_NEXT]] = add nsw i32 [[ADD1]], [[LD3]] |
| ; CHECK-TF-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 |
| ; CHECK-TF-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]] |
| ; CHECK-TF-NEXT: br i1 [[EXITCOND_NOT]], label %[[EXIT:.*]], label %[[LOOP]] |
| ; CHECK-TF: [[EXIT]]: |
| ; CHECK-TF-NEXT: [[RDX_NEXT_LCSSA:%.*]] = phi i32 [ [[RDX_NEXT]], %[[LOOP]] ] |
| ; CHECK-TF-NEXT: ret i32 [[RDX_NEXT_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] |
| %rdx = phi i32 [ 0, %entry ], [ %rdx.next, %loop ] |
| %arrayidx = getelementptr inbounds [4 x i32], ptr %a, i64 %iv, i32 0 |
| %ld1 = load i32, ptr %arrayidx, align 4 |
| %add = add nsw i32 %rdx, %ld1 |
| %arrayidx1 = getelementptr inbounds [4 x i32], ptr %a, i64 %iv, i32 1 |
| %ld2 = load i32, ptr %arrayidx1, align 4 |
| %add1 = add nsw i32 %add, %ld2 |
| %arrayidx2 = getelementptr inbounds [4 x i32], ptr %a, i64 %iv, i32 2 |
| %ld3 = load i32, ptr %arrayidx2, align 4 |
| %rdx.next = add nsw i32 %add1, %ld3 |
| %iv.next = add nuw nsw i64 %iv, 1 |
| %exitcond.not = icmp eq i64 %iv.next, %n |
| br i1 %exitcond.not, label %exit, label %loop |
| |
| exit: |
| ret i32 %rdx.next |
| } |
| |
| ; Interleaved group with tail gap |
| ; E.g. |
| ; int (*a)[4]; |
| ; int rdx = 0; |
| ; for (int i = 0; i < n; i++) { |
| ; a[i][0] = i; |
| ; a[i][1] = i; |
| ; a[i][2] = i; |
| ; // No access a[i][3] |
| ; } |
| ; |
| define void @store_factor_4_with_tail_gap(i32 %n, ptr noalias %a) { |
| ; CHECK-NOTF-LABEL: define void @store_factor_4_with_tail_gap( |
| ; CHECK-NOTF-SAME: i32 [[N:%.*]], ptr noalias [[A:%.*]]) #[[ATTR2]] { |
| ; CHECK-NOTF-NEXT: [[ENTRY:.*]]: |
| ; CHECK-NOTF-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i32 [[N]], 4 |
| ; CHECK-NOTF-NEXT: br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]] |
| ; CHECK-NOTF: [[VECTOR_PH]]: |
| ; CHECK-NOTF-NEXT: [[N_MOD_VF:%.*]] = urem i32 [[N]], 4 |
| ; CHECK-NOTF-NEXT: [[N_VEC:%.*]] = sub i32 [[N]], [[N_MOD_VF]] |
| ; CHECK-NOTF-NEXT: br label %[[VECTOR_BODY:.*]] |
| ; CHECK-NOTF: [[VECTOR_BODY]]: |
| ; CHECK-NOTF-NEXT: [[INDEX:%.*]] = phi i32 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[TMP0:%.*]] = add i32 [[INDEX]], 1 |
| ; CHECK-NOTF-NEXT: [[TMP1:%.*]] = add i32 [[INDEX]], 2 |
| ; CHECK-NOTF-NEXT: [[TMP2:%.*]] = add i32 [[INDEX]], 3 |
| ; CHECK-NOTF-NEXT: [[TMP3:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[INDEX]], i32 0 |
| ; CHECK-NOTF-NEXT: [[TMP4:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[TMP0]], i32 0 |
| ; CHECK-NOTF-NEXT: [[TMP5:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[TMP1]], i32 0 |
| ; CHECK-NOTF-NEXT: [[TMP6:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[TMP2]], i32 0 |
| ; CHECK-NOTF-NEXT: store i32 [[INDEX]], ptr [[TMP3]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP0]], ptr [[TMP4]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP1]], ptr [[TMP5]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP2]], ptr [[TMP6]], align 4 |
| ; CHECK-NOTF-NEXT: [[TMP7:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[INDEX]], i32 1 |
| ; CHECK-NOTF-NEXT: [[TMP8:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[TMP0]], i32 1 |
| ; CHECK-NOTF-NEXT: [[TMP9:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[TMP1]], i32 1 |
| ; CHECK-NOTF-NEXT: [[TMP10:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[TMP2]], i32 1 |
| ; CHECK-NOTF-NEXT: store i32 [[INDEX]], ptr [[TMP7]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP0]], ptr [[TMP8]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP1]], ptr [[TMP9]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP2]], ptr [[TMP10]], align 4 |
| ; CHECK-NOTF-NEXT: [[TMP11:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[INDEX]], i32 2 |
| ; CHECK-NOTF-NEXT: [[TMP12:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[TMP0]], i32 2 |
| ; CHECK-NOTF-NEXT: [[TMP13:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[TMP1]], i32 2 |
| ; CHECK-NOTF-NEXT: [[TMP14:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[TMP2]], i32 2 |
| ; CHECK-NOTF-NEXT: store i32 [[INDEX]], ptr [[TMP11]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP0]], ptr [[TMP12]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP1]], ptr [[TMP13]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP2]], ptr [[TMP14]], align 4 |
| ; CHECK-NOTF-NEXT: [[INDEX_NEXT]] = add nuw i32 [[INDEX]], 4 |
| ; CHECK-NOTF-NEXT: [[TMP15:%.*]] = icmp eq i32 [[INDEX_NEXT]], [[N_VEC]] |
| ; CHECK-NOTF-NEXT: br i1 [[TMP15]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP18:![0-9]+]] |
| ; CHECK-NOTF: [[MIDDLE_BLOCK]]: |
| ; CHECK-NOTF-NEXT: [[CMP_N:%.*]] = icmp eq i32 [[N]], [[N_VEC]] |
| ; CHECK-NOTF-NEXT: br i1 [[CMP_N]], label %[[EXIT:.*]], label %[[SCALAR_PH]] |
| ; CHECK-NOTF: [[SCALAR_PH]]: |
| ; CHECK-NOTF-NEXT: [[BC_RESUME_VAL:%.*]] = phi i32 [ [[N_VEC]], %[[MIDDLE_BLOCK]] ], [ 0, %[[ENTRY]] ] |
| ; CHECK-NOTF-NEXT: br label %[[LOOP:.*]] |
| ; CHECK-NOTF: [[LOOP]]: |
| ; CHECK-NOTF-NEXT: [[IV:%.*]] = phi i32 [ [[BC_RESUME_VAL]], %[[SCALAR_PH]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ] |
| ; CHECK-NOTF-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[IV]], i32 0 |
| ; CHECK-NOTF-NEXT: store i32 [[IV]], ptr [[ARRAYIDX]], align 4 |
| ; CHECK-NOTF-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[IV]], i32 1 |
| ; CHECK-NOTF-NEXT: store i32 [[IV]], ptr [[ARRAYIDX1]], align 4 |
| ; CHECK-NOTF-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[IV]], i32 2 |
| ; CHECK-NOTF-NEXT: store i32 [[IV]], ptr [[ARRAYIDX2]], align 4 |
| ; CHECK-NOTF-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 |
| ; CHECK-NOTF-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i32 [[IV_NEXT]], [[N]] |
| ; CHECK-NOTF-NEXT: br i1 [[EXITCOND_NOT]], label %[[EXIT]], label %[[LOOP]], !llvm.loop [[LOOP19:![0-9]+]] |
| ; CHECK-NOTF: [[EXIT]]: |
| ; CHECK-NOTF-NEXT: ret void |
| ; |
| ; CHECK-TF-LABEL: define void @store_factor_4_with_tail_gap( |
| ; CHECK-TF-SAME: i32 [[N:%.*]], ptr noalias [[A:%.*]]) #[[ATTR2]] { |
| ; CHECK-TF-NEXT: [[ENTRY:.*]]: |
| ; CHECK-TF-NEXT: br label %[[LOOP:.*]] |
| ; CHECK-TF: [[LOOP]]: |
| ; CHECK-TF-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ] |
| ; CHECK-TF-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[IV]], i32 0 |
| ; CHECK-TF-NEXT: store i32 [[IV]], ptr [[ARRAYIDX]], align 4 |
| ; CHECK-TF-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[IV]], i32 1 |
| ; CHECK-TF-NEXT: store i32 [[IV]], ptr [[ARRAYIDX1]], align 4 |
| ; CHECK-TF-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i32 [[IV]], i32 2 |
| ; CHECK-TF-NEXT: store i32 [[IV]], ptr [[ARRAYIDX2]], align 4 |
| ; CHECK-TF-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 |
| ; CHECK-TF-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i32 [[IV_NEXT]], [[N]] |
| ; CHECK-TF-NEXT: br i1 [[EXITCOND_NOT]], label %[[EXIT:.*]], label %[[LOOP]] |
| ; CHECK-TF: [[EXIT]]: |
| ; CHECK-TF-NEXT: ret void |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] |
| %arrayidx = getelementptr inbounds [4 x i32], ptr %a, i32 %iv, i32 0 |
| store i32 %iv, ptr %arrayidx, align 4 |
| %arrayidx1 = getelementptr inbounds [4 x i32], ptr %a, i32 %iv, i32 1 |
| store i32 %iv, ptr %arrayidx1, align 4 |
| %arrayidx2 = getelementptr inbounds [4 x i32], ptr %a, i32 %iv, i32 2 |
| store i32 %iv, ptr %arrayidx2, align 4 |
| %iv.next = add nuw nsw i32 %iv, 1 |
| %exitcond.not = icmp eq i32 %iv.next, %n |
| br i1 %exitcond.not, label %exit, label %loop |
| |
| exit: |
| ret void |
| } |
| |
| |
| ; Interleaved group with gap but without tail gap, reversed |
| ; E.g. |
| ; int (*a)[4]; |
| ; int rdx = 0; |
| ; for (int i = n; i >= 0; i++) { |
| ; rdx += a[i][0]; |
| ; rdx += a[i][1]; |
| ; // No access a[i][2] |
| ; rdx += a[i][3]; |
| ; } |
| ; |
| define i32 @load_factor_4_with_gap_reverse(i64 %n, ptr noalias %a) { |
| ; CHECK-NOTF-LABEL: define i32 @load_factor_4_with_gap_reverse( |
| ; CHECK-NOTF-SAME: i64 [[N:%.*]], ptr noalias [[A:%.*]]) #[[ATTR2]] { |
| ; CHECK-NOTF-NEXT: [[ENTRY:.*]]: |
| ; CHECK-NOTF-NEXT: [[CMP:%.*]] = icmp sgt i64 [[N]], -1 |
| ; CHECK-NOTF-NEXT: br i1 [[CMP]], label %[[LOOP_PREHEADER:.*]], label %[[EXIT:.*]] |
| ; CHECK-NOTF: [[LOOP_PREHEADER]]: |
| ; CHECK-NOTF-NEXT: [[TMP0:%.*]] = add i64 [[N]], 1 |
| ; CHECK-NOTF-NEXT: [[TMP1:%.*]] = call i64 @llvm.vscale.i64() |
| ; CHECK-NOTF-NEXT: [[TMP47:%.*]] = shl nuw i64 [[TMP1]], 2 |
| ; CHECK-NOTF-NEXT: [[MIN_ITERS_CHECK1:%.*]] = icmp ult i64 [[TMP0]], [[TMP47]] |
| ; CHECK-NOTF-NEXT: [[TMP48:%.*]] = call i64 @llvm.vscale.i64() |
| ; CHECK-NOTF-NEXT: [[TMP51:%.*]] = shl nuw i64 [[TMP48]], 2 |
| ; CHECK-NOTF-NEXT: br i1 [[MIN_ITERS_CHECK1]], label %[[VEC_EPILOG_SCALAR_PH:.*]], label %[[VECTOR_MAIN_LOOP_ITER_CHECK:.*]] |
| ; CHECK-NOTF: [[VECTOR_MAIN_LOOP_ITER_CHECK]]: |
| ; CHECK-NOTF-NEXT: [[TMP2:%.*]] = shl nuw i64 [[TMP1]], 4 |
| ; CHECK-NOTF-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[TMP0]], [[TMP2]] |
| ; CHECK-NOTF-NEXT: br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]] |
| ; CHECK-NOTF: [[VECTOR_PH]]: |
| ; CHECK-NOTF-NEXT: [[TMP3:%.*]] = shl nuw i64 [[TMP1]], 2 |
| ; CHECK-NOTF-NEXT: [[TMP4:%.*]] = shl nuw i64 [[TMP3]], 2 |
| ; CHECK-NOTF-NEXT: [[N_MOD_VF:%.*]] = urem i64 [[TMP0]], [[TMP4]] |
| ; CHECK-NOTF-NEXT: [[N_VEC:%.*]] = sub i64 [[TMP0]], [[N_MOD_VF]] |
| ; CHECK-NOTF-NEXT: [[TMP5:%.*]] = sub i64 [[N]], [[N_VEC]] |
| ; CHECK-NOTF-NEXT: br label %[[VECTOR_BODY:.*]] |
| ; CHECK-NOTF: [[VECTOR_BODY]]: |
| ; CHECK-NOTF-NEXT: [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[VEC_PHI:%.*]] = phi <vscale x 4 x i32> [ zeroinitializer, %[[VECTOR_PH]] ], [ [[TMP24:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[VEC_PHI1:%.*]] = phi <vscale x 4 x i32> [ zeroinitializer, %[[VECTOR_PH]] ], [ [[TMP25:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[VEC_PHI3:%.*]] = phi <vscale x 4 x i32> [ zeroinitializer, %[[VECTOR_PH]] ], [ [[TMP42:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[VEC_PHI4:%.*]] = phi <vscale x 4 x i32> [ zeroinitializer, %[[VECTOR_PH]] ], [ [[TMP43:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[TMP6:%.*]] = sub i64 [[N]], [[INDEX]] |
| ; CHECK-NOTF-NEXT: [[TMP7:%.*]] = getelementptr inbounds nuw [16 x i8], ptr [[A]], i64 [[TMP6]] |
| ; CHECK-NOTF-NEXT: [[TMP8:%.*]] = sub nuw nsw i64 [[TMP3]], 1 |
| ; CHECK-NOTF-NEXT: [[TMP9:%.*]] = mul i64 [[TMP8]], -4 |
| ; CHECK-NOTF-NEXT: [[TMP10:%.*]] = getelementptr inbounds i32, ptr [[TMP7]], i64 [[TMP9]] |
| ; CHECK-NOTF-NEXT: [[TMP11:%.*]] = mul i64 -4, [[TMP3]] |
| ; CHECK-NOTF-NEXT: [[TMP12:%.*]] = add i64 [[TMP9]], [[TMP11]] |
| ; CHECK-NOTF-NEXT: [[TMP13:%.*]] = getelementptr inbounds i32, ptr [[TMP7]], i64 [[TMP12]] |
| ; CHECK-NOTF-NEXT: [[TMP32:%.*]] = mul i64 -8, [[TMP3]] |
| ; CHECK-NOTF-NEXT: [[TMP33:%.*]] = add i64 [[TMP9]], [[TMP32]] |
| ; CHECK-NOTF-NEXT: [[TMP36:%.*]] = getelementptr inbounds i32, ptr [[TMP7]], i64 [[TMP33]] |
| ; CHECK-NOTF-NEXT: [[TMP37:%.*]] = mul i64 -12, [[TMP3]] |
| ; CHECK-NOTF-NEXT: [[TMP40:%.*]] = add i64 [[TMP9]], [[TMP37]] |
| ; CHECK-NOTF-NEXT: [[TMP41:%.*]] = getelementptr inbounds i32, ptr [[TMP7]], i64 [[TMP40]] |
| ; CHECK-NOTF-NEXT: [[WIDE_VEC:%.*]] = load <vscale x 16 x i32>, ptr [[TMP10]], align 4 |
| ; CHECK-NOTF-NEXT: [[STRIDED_VEC:%.*]] = call { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } @llvm.vector.deinterleave4.nxv16i32(<vscale x 16 x i32> [[WIDE_VEC]]) |
| ; CHECK-NOTF-NEXT: [[TMP14:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC]], 0 |
| ; CHECK-NOTF-NEXT: [[REVERSE:%.*]] = call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[TMP14]]) |
| ; CHECK-NOTF-NEXT: [[TMP15:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC]], 1 |
| ; CHECK-NOTF-NEXT: [[REVERSE2:%.*]] = call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[TMP15]]) |
| ; CHECK-NOTF-NEXT: [[TMP16:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC]], 3 |
| ; CHECK-NOTF-NEXT: [[REVERSE3:%.*]] = call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[TMP16]]) |
| ; CHECK-NOTF-NEXT: [[WIDE_VEC4:%.*]] = load <vscale x 16 x i32>, ptr [[TMP13]], align 4 |
| ; CHECK-NOTF-NEXT: [[STRIDED_VEC5:%.*]] = call { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } @llvm.vector.deinterleave4.nxv16i32(<vscale x 16 x i32> [[WIDE_VEC4]]) |
| ; CHECK-NOTF-NEXT: [[TMP17:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC5]], 0 |
| ; CHECK-NOTF-NEXT: [[REVERSE6:%.*]] = call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[TMP17]]) |
| ; CHECK-NOTF-NEXT: [[TMP18:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC5]], 1 |
| ; CHECK-NOTF-NEXT: [[REVERSE7:%.*]] = call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[TMP18]]) |
| ; CHECK-NOTF-NEXT: [[TMP19:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC5]], 3 |
| ; CHECK-NOTF-NEXT: [[REVERSE8:%.*]] = call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[TMP19]]) |
| ; CHECK-NOTF-NEXT: [[WIDE_VEC12:%.*]] = load <vscale x 16 x i32>, ptr [[TMP36]], align 4 |
| ; CHECK-NOTF-NEXT: [[STRIDED_VEC13:%.*]] = call { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } @llvm.vector.deinterleave4.nxv16i32(<vscale x 16 x i32> [[WIDE_VEC12]]) |
| ; CHECK-NOTF-NEXT: [[TMP44:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC13]], 0 |
| ; CHECK-NOTF-NEXT: [[REVERSE14:%.*]] = call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[TMP44]]) |
| ; CHECK-NOTF-NEXT: [[TMP27:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC13]], 1 |
| ; CHECK-NOTF-NEXT: [[REVERSE15:%.*]] = call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[TMP27]]) |
| ; CHECK-NOTF-NEXT: [[TMP28:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC13]], 3 |
| ; CHECK-NOTF-NEXT: [[REVERSE16:%.*]] = call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[TMP28]]) |
| ; CHECK-NOTF-NEXT: [[WIDE_VEC17:%.*]] = load <vscale x 16 x i32>, ptr [[TMP41]], align 4 |
| ; CHECK-NOTF-NEXT: [[STRIDED_VEC18:%.*]] = call { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } @llvm.vector.deinterleave4.nxv16i32(<vscale x 16 x i32> [[WIDE_VEC17]]) |
| ; CHECK-NOTF-NEXT: [[TMP29:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC18]], 0 |
| ; CHECK-NOTF-NEXT: [[REVERSE19:%.*]] = call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[TMP29]]) |
| ; CHECK-NOTF-NEXT: [[TMP30:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC18]], 1 |
| ; CHECK-NOTF-NEXT: [[REVERSE20:%.*]] = call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[TMP30]]) |
| ; CHECK-NOTF-NEXT: [[TMP31:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC18]], 3 |
| ; CHECK-NOTF-NEXT: [[REVERSE21:%.*]] = call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[TMP31]]) |
| ; CHECK-NOTF-NEXT: [[TMP20:%.*]] = add <vscale x 4 x i32> [[REVERSE]], [[VEC_PHI]] |
| ; CHECK-NOTF-NEXT: [[TMP21:%.*]] = add <vscale x 4 x i32> [[REVERSE6]], [[VEC_PHI1]] |
| ; CHECK-NOTF-NEXT: [[TMP34:%.*]] = add <vscale x 4 x i32> [[REVERSE14]], [[VEC_PHI3]] |
| ; CHECK-NOTF-NEXT: [[TMP35:%.*]] = add <vscale x 4 x i32> [[REVERSE19]], [[VEC_PHI4]] |
| ; CHECK-NOTF-NEXT: [[TMP22:%.*]] = add <vscale x 4 x i32> [[TMP20]], [[REVERSE2]] |
| ; CHECK-NOTF-NEXT: [[TMP23:%.*]] = add <vscale x 4 x i32> [[TMP21]], [[REVERSE7]] |
| ; CHECK-NOTF-NEXT: [[TMP38:%.*]] = add <vscale x 4 x i32> [[TMP34]], [[REVERSE15]] |
| ; CHECK-NOTF-NEXT: [[TMP39:%.*]] = add <vscale x 4 x i32> [[TMP35]], [[REVERSE20]] |
| ; CHECK-NOTF-NEXT: [[TMP24]] = add <vscale x 4 x i32> [[TMP22]], [[REVERSE3]] |
| ; CHECK-NOTF-NEXT: [[TMP25]] = add <vscale x 4 x i32> [[TMP23]], [[REVERSE8]] |
| ; CHECK-NOTF-NEXT: [[TMP42]] = add <vscale x 4 x i32> [[TMP38]], [[REVERSE16]] |
| ; CHECK-NOTF-NEXT: [[TMP43]] = add <vscale x 4 x i32> [[TMP39]], [[REVERSE21]] |
| ; CHECK-NOTF-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], [[TMP4]] |
| ; CHECK-NOTF-NEXT: [[TMP26:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]] |
| ; CHECK-NOTF-NEXT: br i1 [[TMP26]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP20:![0-9]+]] |
| ; CHECK-NOTF: [[MIDDLE_BLOCK]]: |
| ; CHECK-NOTF-NEXT: [[BIN_RDX:%.*]] = add <vscale x 4 x i32> [[TMP25]], [[TMP24]] |
| ; CHECK-NOTF-NEXT: [[BIN_RDX22:%.*]] = add <vscale x 4 x i32> [[TMP42]], [[BIN_RDX]] |
| ; CHECK-NOTF-NEXT: [[BIN_RDX23:%.*]] = add <vscale x 4 x i32> [[TMP43]], [[BIN_RDX22]] |
| ; CHECK-NOTF-NEXT: [[TMP45:%.*]] = call i32 @llvm.vector.reduce.add.nxv4i32(<vscale x 4 x i32> [[BIN_RDX23]]) |
| ; CHECK-NOTF-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[TMP0]], [[N_VEC]] |
| ; CHECK-NOTF-NEXT: br i1 [[CMP_N]], label %[[EXIT_LOOPEXIT:.*]], label %[[VEC_EPILOG_ITER_CHECK:.*]] |
| ; CHECK-NOTF: [[VEC_EPILOG_ITER_CHECK]]: |
| ; CHECK-NOTF-NEXT: [[MIN_EPILOG_ITERS_CHECK:%.*]] = icmp ult i64 [[N_MOD_VF]], [[TMP51]] |
| ; CHECK-NOTF-NEXT: br i1 [[MIN_EPILOG_ITERS_CHECK]], label %[[VEC_EPILOG_SCALAR_PH]], label %[[SCALAR_PH]], !prof [[PROF10]] |
| ; CHECK-NOTF: [[SCALAR_PH]]: |
| ; CHECK-NOTF-NEXT: [[VEC_EPILOG_RESUME_VAL:%.*]] = phi i64 [ [[N_VEC]], %[[VEC_EPILOG_ITER_CHECK]] ], [ 0, %[[VECTOR_MAIN_LOOP_ITER_CHECK]] ] |
| ; CHECK-NOTF-NEXT: [[BC_MERGE_RDX:%.*]] = phi i32 [ [[TMP45]], %[[VEC_EPILOG_ITER_CHECK]] ], [ 0, %[[VECTOR_MAIN_LOOP_ITER_CHECK]] ] |
| ; CHECK-NOTF-NEXT: [[TMP49:%.*]] = call i64 @llvm.vscale.i64() |
| ; CHECK-NOTF-NEXT: [[TMP50:%.*]] = shl nuw i64 [[TMP49]], 2 |
| ; CHECK-NOTF-NEXT: [[N_MOD_VF24:%.*]] = urem i64 [[TMP0]], [[TMP50]] |
| ; CHECK-NOTF-NEXT: [[N_VEC25:%.*]] = sub i64 [[TMP0]], [[N_MOD_VF24]] |
| ; CHECK-NOTF-NEXT: [[TMP46:%.*]] = sub i64 [[N]], [[N_VEC25]] |
| ; CHECK-NOTF-NEXT: [[TMP52:%.*]] = insertelement <vscale x 4 x i32> zeroinitializer, i32 [[BC_MERGE_RDX]], i32 0 |
| ; CHECK-NOTF-NEXT: br label %[[LOOP:.*]] |
| ; CHECK-NOTF: [[LOOP]]: |
| ; CHECK-NOTF-NEXT: [[INDEX26:%.*]] = phi i64 [ [[VEC_EPILOG_RESUME_VAL]], %[[SCALAR_PH]] ], [ [[INDEX_NEXT35:%.*]], %[[LOOP]] ] |
| ; CHECK-NOTF-NEXT: [[VEC_PHI27:%.*]] = phi <vscale x 4 x i32> [ [[TMP52]], %[[SCALAR_PH]] ], [ [[TMP63:%.*]], %[[LOOP]] ] |
| ; CHECK-NOTF-NEXT: [[IV:%.*]] = sub i64 [[N]], [[INDEX26]] |
| ; CHECK-NOTF-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [16 x i8], ptr [[A]], i64 [[IV]] |
| ; CHECK-NOTF-NEXT: [[TMP55:%.*]] = sub nuw nsw i64 [[TMP50]], 1 |
| ; CHECK-NOTF-NEXT: [[TMP56:%.*]] = mul i64 [[TMP55]], -4 |
| ; CHECK-NOTF-NEXT: [[TMP57:%.*]] = getelementptr inbounds i32, ptr [[ARRAYIDX]], i64 [[TMP56]] |
| ; CHECK-NOTF-NEXT: [[WIDE_VEC28:%.*]] = load <vscale x 16 x i32>, ptr [[TMP57]], align 4 |
| ; CHECK-NOTF-NEXT: [[STRIDED_VEC29:%.*]] = call { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } @llvm.vector.deinterleave4.nxv16i32(<vscale x 16 x i32> [[WIDE_VEC28]]) |
| ; CHECK-NOTF-NEXT: [[TMP58:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC29]], 0 |
| ; CHECK-NOTF-NEXT: [[REVERSE30:%.*]] = call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[TMP58]]) |
| ; CHECK-NOTF-NEXT: [[TMP59:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC29]], 1 |
| ; CHECK-NOTF-NEXT: [[REVERSE31:%.*]] = call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[TMP59]]) |
| ; CHECK-NOTF-NEXT: [[TMP60:%.*]] = extractvalue { <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32> } [[STRIDED_VEC29]], 3 |
| ; CHECK-NOTF-NEXT: [[REVERSE32:%.*]] = call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[TMP60]]) |
| ; CHECK-NOTF-NEXT: [[TMP61:%.*]] = add <vscale x 4 x i32> [[REVERSE30]], [[VEC_PHI27]] |
| ; CHECK-NOTF-NEXT: [[TMP62:%.*]] = add <vscale x 4 x i32> [[TMP61]], [[REVERSE31]] |
| ; CHECK-NOTF-NEXT: [[TMP63]] = add <vscale x 4 x i32> [[TMP62]], [[REVERSE32]] |
| ; CHECK-NOTF-NEXT: [[INDEX_NEXT35]] = add nuw i64 [[INDEX26]], [[TMP50]] |
| ; CHECK-NOTF-NEXT: [[TMP54:%.*]] = icmp eq i64 [[INDEX_NEXT35]], [[N_VEC25]] |
| ; CHECK-NOTF-NEXT: br i1 [[TMP54]], label %[[VEC_EPILOG_MIDDLE_BLOCK:.*]], label %[[LOOP]], !llvm.loop [[LOOP21:![0-9]+]] |
| ; CHECK-NOTF: [[VEC_EPILOG_MIDDLE_BLOCK]]: |
| ; CHECK-NOTF-NEXT: [[TMP65:%.*]] = call i32 @llvm.vector.reduce.add.nxv4i32(<vscale x 4 x i32> [[TMP63]]) |
| ; CHECK-NOTF-NEXT: [[CMP_N36:%.*]] = icmp eq i64 [[TMP0]], [[N_VEC25]] |
| ; CHECK-NOTF-NEXT: br i1 [[CMP_N36]], label %[[EXIT_LOOPEXIT]], label %[[VEC_EPILOG_SCALAR_PH]] |
| ; CHECK-NOTF: [[VEC_EPILOG_SCALAR_PH]]: |
| ; CHECK-NOTF-NEXT: [[BC_RESUME_VAL35:%.*]] = phi i64 [ [[TMP46]], %[[VEC_EPILOG_MIDDLE_BLOCK]] ], [ [[TMP5]], %[[VEC_EPILOG_ITER_CHECK]] ], [ [[N]], %[[LOOP_PREHEADER]] ] |
| ; CHECK-NOTF-NEXT: [[BC_MERGE_RDX36:%.*]] = phi i32 [ [[TMP65]], %[[VEC_EPILOG_MIDDLE_BLOCK]] ], [ [[TMP45]], %[[VEC_EPILOG_ITER_CHECK]] ], [ 0, %[[LOOP_PREHEADER]] ] |
| ; CHECK-NOTF-NEXT: br label %[[LOOP1:.*]] |
| ; CHECK-NOTF: [[LOOP1]]: |
| ; CHECK-NOTF-NEXT: [[IV1:%.*]] = phi i64 [ [[IV_NEXT:%.*]], %[[LOOP1]] ], [ [[BC_RESUME_VAL35]], %[[VEC_EPILOG_SCALAR_PH]] ] |
| ; CHECK-NOTF-NEXT: [[RDX:%.*]] = phi i32 [ [[RDX_NEXT:%.*]], %[[LOOP1]] ], [ [[BC_MERGE_RDX36]], %[[VEC_EPILOG_SCALAR_PH]] ] |
| ; CHECK-NOTF-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds nuw [16 x i8], ptr [[A]], i64 [[IV1]] |
| ; CHECK-NOTF-NEXT: [[LD1:%.*]] = load i32, ptr [[ARRAYIDX1]], align 4 |
| ; CHECK-NOTF-NEXT: [[ADD:%.*]] = add nsw i32 [[LD1]], [[RDX]] |
| ; CHECK-NOTF-NEXT: [[ARRAYIDX4:%.*]] = getelementptr inbounds nuw i8, ptr [[ARRAYIDX1]], i64 4 |
| ; CHECK-NOTF-NEXT: [[LD2:%.*]] = load i32, ptr [[ARRAYIDX4]], align 4 |
| ; CHECK-NOTF-NEXT: [[ADD2:%.*]] = add nsw i32 [[ADD]], [[LD2]] |
| ; CHECK-NOTF-NEXT: [[ARRAYIDX8:%.*]] = getelementptr inbounds nuw i8, ptr [[ARRAYIDX1]], i64 12 |
| ; CHECK-NOTF-NEXT: [[LD3:%.*]] = load i32, ptr [[ARRAYIDX8]], align 4 |
| ; CHECK-NOTF-NEXT: [[RDX_NEXT]] = add nsw i32 [[ADD2]], [[LD3]] |
| ; CHECK-NOTF-NEXT: [[IV_NEXT]] = add nsw i64 [[IV1]], -1 |
| ; CHECK-NOTF-NEXT: [[CMP_NOT:%.*]] = icmp eq i64 [[IV1]], 0 |
| ; CHECK-NOTF-NEXT: br i1 [[CMP_NOT]], label %[[EXIT_LOOPEXIT]], label %[[LOOP1]], !llvm.loop [[LOOP22:![0-9]+]] |
| ; CHECK-NOTF: [[EXIT_LOOPEXIT]]: |
| ; CHECK-NOTF-NEXT: [[RDX_NEXT_LCSSA:%.*]] = phi i32 [ [[RDX_NEXT]], %[[LOOP1]] ], [ [[TMP45]], %[[MIDDLE_BLOCK]] ], [ [[TMP65]], %[[VEC_EPILOG_MIDDLE_BLOCK]] ] |
| ; CHECK-NOTF-NEXT: br label %[[EXIT]] |
| ; CHECK-NOTF: [[EXIT]]: |
| ; CHECK-NOTF-NEXT: [[RDX_FINAL:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[RDX_NEXT_LCSSA]], %[[EXIT_LOOPEXIT]] ] |
| ; CHECK-NOTF-NEXT: ret i32 [[RDX_FINAL]] |
| ; |
| ; CHECK-TF-LABEL: define i32 @load_factor_4_with_gap_reverse( |
| ; CHECK-TF-SAME: i64 [[N:%.*]], ptr noalias [[A:%.*]]) #[[ATTR2]] { |
| ; CHECK-TF-NEXT: [[ENTRY:.*]]: |
| ; CHECK-TF-NEXT: [[CMP:%.*]] = icmp sgt i64 [[N]], -1 |
| ; CHECK-TF-NEXT: br i1 [[CMP]], label %[[LOOP_PREHEADER:.*]], label %[[EXIT:.*]] |
| ; CHECK-TF: [[LOOP_PREHEADER]]: |
| ; CHECK-TF-NEXT: br label %[[LOOP:.*]] |
| ; CHECK-TF: [[LOOP]]: |
| ; CHECK-TF-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], %[[LOOP]] ], [ [[N]], %[[LOOP_PREHEADER]] ] |
| ; CHECK-TF-NEXT: [[RDX:%.*]] = phi i32 [ [[RDX_NEXT:%.*]], %[[LOOP]] ], [ 0, %[[LOOP_PREHEADER]] ] |
| ; CHECK-TF-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [16 x i8], ptr [[A]], i64 [[IV]] |
| ; CHECK-TF-NEXT: [[LD1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4 |
| ; CHECK-TF-NEXT: [[ADD:%.*]] = add nsw i32 [[LD1]], [[RDX]] |
| ; CHECK-TF-NEXT: [[ARRAYIDX4:%.*]] = getelementptr inbounds nuw i8, ptr [[ARRAYIDX]], i64 4 |
| ; CHECK-TF-NEXT: [[LD2:%.*]] = load i32, ptr [[ARRAYIDX4]], align 4 |
| ; CHECK-TF-NEXT: [[ADD2:%.*]] = add nsw i32 [[ADD]], [[LD2]] |
| ; CHECK-TF-NEXT: [[ARRAYIDX8:%.*]] = getelementptr inbounds nuw i8, ptr [[ARRAYIDX]], i64 12 |
| ; CHECK-TF-NEXT: [[LD3:%.*]] = load i32, ptr [[ARRAYIDX8]], align 4 |
| ; CHECK-TF-NEXT: [[RDX_NEXT]] = add nsw i32 [[ADD2]], [[LD3]] |
| ; CHECK-TF-NEXT: [[IV_NEXT]] = add nsw i64 [[IV]], -1 |
| ; CHECK-TF-NEXT: [[CMP_NOT:%.*]] = icmp eq i64 [[IV]], 0 |
| ; CHECK-TF-NEXT: br i1 [[CMP_NOT]], label %[[EXIT_LOOPEXIT:.*]], label %[[LOOP]] |
| ; CHECK-TF: [[EXIT_LOOPEXIT]]: |
| ; CHECK-TF-NEXT: [[RDX_NEXT_LCSSA:%.*]] = phi i32 [ [[RDX_NEXT]], %[[LOOP]] ] |
| ; CHECK-TF-NEXT: br label %[[EXIT]] |
| ; CHECK-TF: [[EXIT]]: |
| ; CHECK-TF-NEXT: [[RDX_FINAL:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[RDX_NEXT_LCSSA]], %[[EXIT_LOOPEXIT]] ] |
| ; CHECK-TF-NEXT: ret i32 [[RDX_FINAL]] |
| ; |
| entry: |
| %cmp = icmp sgt i64 %n, -1 |
| br i1 %cmp, label %loop, label %exit |
| |
| loop: |
| %iv = phi i64 [ %n, %entry ], [ %iv.next, %loop ] |
| %rdx = phi i32 [ 0, %entry ], [ %rdx.next, %loop ] |
| %arrayidx = getelementptr inbounds nuw [16 x i8], ptr %a, i64 %iv |
| %ld1 = load i32, ptr %arrayidx, align 4 |
| %add = add nsw i32 %ld1, %rdx |
| %arrayidx4 = getelementptr inbounds nuw i8, ptr %arrayidx, i64 4 |
| %ld2 = load i32, ptr %arrayidx4, align 4 |
| %add2 = add nsw i32 %add, %ld2 |
| %arrayidx8 = getelementptr inbounds nuw i8, ptr %arrayidx, i64 12 |
| %ld3 = load i32, ptr %arrayidx8, align 4 |
| %rdx.next = add nsw i32 %add2, %ld3 |
| %iv.next = add nsw i64 %iv, -1 |
| %cmp.not = icmp eq i64 %iv, 0 |
| br i1 %cmp.not, label %exit, label %loop |
| |
| exit: |
| %rdx.final = phi i32 [ 0, %entry ], [ %rdx.next, %loop ] |
| ret i32 %rdx.final |
| } |
| |
| ; Interleaved group with gap but without tail gap, reversed |
| ; E.g. |
| ; int (*a)[4]; |
| ; for (int i = n; i >= 0; i--) { |
| ; a[i][0] = i; |
| ; a[i][1] = i; |
| ; // No access a[i][2] |
| ; a[i][3] = i; |
| ; } |
| ; |
| define void @store_factor_4_with_gap_reverse(i64 %n, ptr noalias %a) { |
| ; CHECK-NOTF-LABEL: define void @store_factor_4_with_gap_reverse( |
| ; CHECK-NOTF-SAME: i64 [[N:%.*]], ptr noalias [[A:%.*]]) #[[ATTR2]] { |
| ; CHECK-NOTF-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NOTF-NEXT: [[CMP:%.*]] = icmp sgt i64 [[N]], -1 |
| ; CHECK-NOTF-NEXT: br i1 [[CMP]], label %[[LOOP_PREHEADER:.*]], label %[[EXIT:.*]] |
| ; CHECK-NOTF: [[LOOP_PREHEADER]]: |
| ; CHECK-NOTF-NEXT: [[TMP0:%.*]] = add i64 [[N]], 1 |
| ; CHECK-NOTF-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[TMP0]], 4 |
| ; CHECK-NOTF-NEXT: br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]] |
| ; CHECK-NOTF: [[VECTOR_PH]]: |
| ; CHECK-NOTF-NEXT: [[N_MOD_VF:%.*]] = urem i64 [[TMP0]], 4 |
| ; CHECK-NOTF-NEXT: [[N_VEC:%.*]] = sub i64 [[TMP0]], [[N_MOD_VF]] |
| ; CHECK-NOTF-NEXT: [[TMP1:%.*]] = sub i64 [[N]], [[N_VEC]] |
| ; CHECK-NOTF-NEXT: br label %[[VECTOR_BODY:.*]] |
| ; CHECK-NOTF: [[VECTOR_BODY]]: |
| ; CHECK-NOTF-NEXT: [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[TMP2:%.*]] = sub i64 [[N]], [[INDEX]] |
| ; CHECK-NOTF-NEXT: [[TMP3:%.*]] = add i64 [[TMP2]], -1 |
| ; CHECK-NOTF-NEXT: [[TMP4:%.*]] = add i64 [[TMP2]], -2 |
| ; CHECK-NOTF-NEXT: [[TMP5:%.*]] = add i64 [[TMP2]], -3 |
| ; CHECK-NOTF-NEXT: [[TMP6:%.*]] = trunc i64 [[TMP2]] to i32 |
| ; CHECK-NOTF-NEXT: [[TMP7:%.*]] = trunc i64 [[TMP3]] to i32 |
| ; CHECK-NOTF-NEXT: [[TMP8:%.*]] = trunc i64 [[TMP4]] to i32 |
| ; CHECK-NOTF-NEXT: [[TMP9:%.*]] = trunc i64 [[TMP5]] to i32 |
| ; CHECK-NOTF-NEXT: [[TMP10:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP2]], i32 0 |
| ; CHECK-NOTF-NEXT: [[TMP11:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP3]], i32 0 |
| ; CHECK-NOTF-NEXT: [[TMP12:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP4]], i32 0 |
| ; CHECK-NOTF-NEXT: [[TMP13:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP5]], i32 0 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP6]], ptr [[TMP10]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP7]], ptr [[TMP11]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP8]], ptr [[TMP12]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP9]], ptr [[TMP13]], align 4 |
| ; CHECK-NOTF-NEXT: [[TMP14:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP2]], i32 1 |
| ; CHECK-NOTF-NEXT: [[TMP15:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP3]], i32 1 |
| ; CHECK-NOTF-NEXT: [[TMP16:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP4]], i32 1 |
| ; CHECK-NOTF-NEXT: [[TMP17:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP5]], i32 1 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP6]], ptr [[TMP14]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP7]], ptr [[TMP15]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP8]], ptr [[TMP16]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP9]], ptr [[TMP17]], align 4 |
| ; CHECK-NOTF-NEXT: [[TMP18:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP2]], i32 3 |
| ; CHECK-NOTF-NEXT: [[TMP19:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP3]], i32 3 |
| ; CHECK-NOTF-NEXT: [[TMP20:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP4]], i32 3 |
| ; CHECK-NOTF-NEXT: [[TMP21:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP5]], i32 3 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP6]], ptr [[TMP18]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP7]], ptr [[TMP19]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP8]], ptr [[TMP20]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP9]], ptr [[TMP21]], align 4 |
| ; CHECK-NOTF-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4 |
| ; CHECK-NOTF-NEXT: [[TMP22:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]] |
| ; CHECK-NOTF-NEXT: br i1 [[TMP22]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP23:![0-9]+]] |
| ; CHECK-NOTF: [[MIDDLE_BLOCK]]: |
| ; CHECK-NOTF-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[TMP0]], [[N_VEC]] |
| ; CHECK-NOTF-NEXT: br i1 [[CMP_N]], label %[[EXIT_LOOPEXIT:.*]], label %[[SCALAR_PH]] |
| ; CHECK-NOTF: [[SCALAR_PH]]: |
| ; CHECK-NOTF-NEXT: [[BC_RESUME_VAL:%.*]] = phi i64 [ [[TMP1]], %[[MIDDLE_BLOCK]] ], [ [[N]], %[[LOOP_PREHEADER]] ] |
| ; CHECK-NOTF-NEXT: br label %[[LOOP:.*]] |
| ; CHECK-NOTF: [[LOOP]]: |
| ; CHECK-NOTF-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], %[[LOOP]] ], [ [[BC_RESUME_VAL]], %[[SCALAR_PH]] ] |
| ; CHECK-NOTF-NEXT: [[IV_TRUNC:%.*]] = trunc i64 [[IV]] to i32 |
| ; CHECK-NOTF-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV]], i32 0 |
| ; CHECK-NOTF-NEXT: store i32 [[IV_TRUNC]], ptr [[ARRAYIDX]], align 4 |
| ; CHECK-NOTF-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV]], i32 1 |
| ; CHECK-NOTF-NEXT: store i32 [[IV_TRUNC]], ptr [[ARRAYIDX1]], align 4 |
| ; CHECK-NOTF-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV]], i32 3 |
| ; CHECK-NOTF-NEXT: store i32 [[IV_TRUNC]], ptr [[ARRAYIDX2]], align 4 |
| ; CHECK-NOTF-NEXT: [[IV_NEXT]] = add nsw i64 [[IV]], -1 |
| ; CHECK-NOTF-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i64 [[IV]], 0 |
| ; CHECK-NOTF-NEXT: br i1 [[EXITCOND_NOT]], label %[[EXIT_LOOPEXIT]], label %[[LOOP]], !llvm.loop [[LOOP24:![0-9]+]] |
| ; CHECK-NOTF: [[EXIT_LOOPEXIT]]: |
| ; CHECK-NOTF-NEXT: br label %[[EXIT]] |
| ; CHECK-NOTF: [[EXIT]]: |
| ; CHECK-NOTF-NEXT: ret void |
| ; |
| ; CHECK-TF-LABEL: define void @store_factor_4_with_gap_reverse( |
| ; CHECK-TF-SAME: i64 [[N:%.*]], ptr noalias [[A:%.*]]) #[[ATTR2]] { |
| ; CHECK-TF-NEXT: [[ENTRY:.*:]] |
| ; CHECK-TF-NEXT: [[CMP:%.*]] = icmp sgt i64 [[N]], -1 |
| ; CHECK-TF-NEXT: br i1 [[CMP]], label %[[LOOP_PREHEADER:.*]], label %[[EXIT:.*]] |
| ; CHECK-TF: [[LOOP_PREHEADER]]: |
| ; CHECK-TF-NEXT: br label %[[LOOP:.*]] |
| ; CHECK-TF: [[LOOP]]: |
| ; CHECK-TF-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], %[[LOOP]] ], [ [[N]], %[[LOOP_PREHEADER]] ] |
| ; CHECK-TF-NEXT: [[IV_TRUNC:%.*]] = trunc i64 [[IV]] to i32 |
| ; CHECK-TF-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV]], i32 0 |
| ; CHECK-TF-NEXT: store i32 [[IV_TRUNC]], ptr [[ARRAYIDX]], align 4 |
| ; CHECK-TF-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV]], i32 1 |
| ; CHECK-TF-NEXT: store i32 [[IV_TRUNC]], ptr [[ARRAYIDX1]], align 4 |
| ; CHECK-TF-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV]], i32 3 |
| ; CHECK-TF-NEXT: store i32 [[IV_TRUNC]], ptr [[ARRAYIDX2]], align 4 |
| ; CHECK-TF-NEXT: [[IV_NEXT]] = add nsw i64 [[IV]], -1 |
| ; CHECK-TF-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i64 [[IV]], 0 |
| ; CHECK-TF-NEXT: br i1 [[EXITCOND_NOT]], label %[[EXIT_LOOPEXIT:.*]], label %[[LOOP]] |
| ; CHECK-TF: [[EXIT_LOOPEXIT]]: |
| ; CHECK-TF-NEXT: br label %[[EXIT]] |
| ; CHECK-TF: [[EXIT]]: |
| ; CHECK-TF-NEXT: ret void |
| ; |
| entry: |
| %cmp = icmp sgt i64 %n, -1 |
| br i1 %cmp, label %loop, label %exit |
| |
| loop: |
| %iv = phi i64 [ %n, %entry ], [ %iv.next, %loop ] |
| %iv.trunc = trunc i64 %iv to i32 |
| %arrayidx = getelementptr inbounds [4 x i32], ptr %a, i64 %iv, i32 0 |
| store i32 %iv.trunc, ptr %arrayidx, align 4 |
| %arrayidx1 = getelementptr inbounds [4 x i32], ptr %a, i64 %iv, i32 1 |
| store i32 %iv.trunc, ptr %arrayidx1, align 4 |
| %arrayidx2 = getelementptr inbounds [4 x i32], ptr %a, i64 %iv, i32 3 |
| store i32 %iv.trunc, ptr %arrayidx2, align 4 |
| %iv.next = add nsw i64 %iv, -1 |
| %exitcond.not = icmp eq i64 %iv, 0 |
| br i1 %exitcond.not, label %exit, label %loop |
| |
| exit: |
| ret void |
| } |
| |
| ; Interleaved group with tail gap, reversed |
| ; E.g. |
| ; int (*a)[4]; |
| ; int rdx = 0; |
| ; for (int i = n; i >= 0; i--) { |
| ; rdx += a[i][0]; |
| ; rdx += a[i][1]; |
| ; rdx += a[i][2]; |
| ; // No access a[i][3] |
| ; } |
| ; |
| define i32 @load_factor_4_with_tail_gap_reverse(i64 %n, ptr noalias %a) { |
| ; CHECK-NOTF-LABEL: define i32 @load_factor_4_with_tail_gap_reverse( |
| ; CHECK-NOTF-SAME: i64 [[N:%.*]], ptr noalias [[A:%.*]]) #[[ATTR2]] { |
| ; CHECK-NOTF-NEXT: [[ENTRY:.*]]: |
| ; CHECK-NOTF-NEXT: [[CMP:%.*]] = icmp sgt i64 [[N]], -1 |
| ; CHECK-NOTF-NEXT: br i1 [[CMP]], label %[[LOOP_PREHEADER:.*]], label %[[EXIT:.*]] |
| ; CHECK-NOTF: [[LOOP_PREHEADER]]: |
| ; CHECK-NOTF-NEXT: [[TMP0:%.*]] = add i64 [[N]], 1 |
| ; CHECK-NOTF-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[TMP0]], 4 |
| ; CHECK-NOTF-NEXT: br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]] |
| ; CHECK-NOTF: [[VECTOR_PH]]: |
| ; CHECK-NOTF-NEXT: [[N_MOD_VF:%.*]] = urem i64 [[TMP0]], 4 |
| ; CHECK-NOTF-NEXT: [[N_VEC:%.*]] = sub i64 [[TMP0]], [[N_MOD_VF]] |
| ; CHECK-NOTF-NEXT: [[TMP1:%.*]] = sub i64 [[N]], [[N_VEC]] |
| ; CHECK-NOTF-NEXT: br label %[[VECTOR_BODY:.*]] |
| ; CHECK-NOTF: [[VECTOR_BODY]]: |
| ; CHECK-NOTF-NEXT: [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[VEC_PHI:%.*]] = phi i32 [ 0, %[[VECTOR_PH]] ], [ [[TMP38:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[VEC_PHI1:%.*]] = phi i32 [ 0, %[[VECTOR_PH]] ], [ [[TMP39:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[VEC_PHI2:%.*]] = phi i32 [ 0, %[[VECTOR_PH]] ], [ [[TMP40:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[VEC_PHI3:%.*]] = phi i32 [ 0, %[[VECTOR_PH]] ], [ [[TMP41:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[TMP2:%.*]] = sub i64 [[N]], [[INDEX]] |
| ; CHECK-NOTF-NEXT: [[TMP3:%.*]] = add i64 [[TMP2]], -1 |
| ; CHECK-NOTF-NEXT: [[TMP4:%.*]] = add i64 [[TMP2]], -2 |
| ; CHECK-NOTF-NEXT: [[TMP5:%.*]] = add i64 [[TMP2]], -3 |
| ; CHECK-NOTF-NEXT: [[TMP6:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP2]], i32 0 |
| ; CHECK-NOTF-NEXT: [[TMP7:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP3]], i32 0 |
| ; CHECK-NOTF-NEXT: [[TMP8:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP4]], i32 0 |
| ; CHECK-NOTF-NEXT: [[TMP9:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP5]], i32 0 |
| ; CHECK-NOTF-NEXT: [[TMP10:%.*]] = load i32, ptr [[TMP6]], align 4 |
| ; CHECK-NOTF-NEXT: [[TMP11:%.*]] = load i32, ptr [[TMP7]], align 4 |
| ; CHECK-NOTF-NEXT: [[TMP12:%.*]] = load i32, ptr [[TMP8]], align 4 |
| ; CHECK-NOTF-NEXT: [[TMP13:%.*]] = load i32, ptr [[TMP9]], align 4 |
| ; CHECK-NOTF-NEXT: [[TMP14:%.*]] = add i32 [[VEC_PHI]], [[TMP10]] |
| ; CHECK-NOTF-NEXT: [[TMP15:%.*]] = add i32 [[VEC_PHI1]], [[TMP11]] |
| ; CHECK-NOTF-NEXT: [[TMP16:%.*]] = add i32 [[VEC_PHI2]], [[TMP12]] |
| ; CHECK-NOTF-NEXT: [[TMP17:%.*]] = add i32 [[VEC_PHI3]], [[TMP13]] |
| ; CHECK-NOTF-NEXT: [[TMP18:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP2]], i32 1 |
| ; CHECK-NOTF-NEXT: [[TMP19:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP3]], i32 1 |
| ; CHECK-NOTF-NEXT: [[TMP20:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP4]], i32 1 |
| ; CHECK-NOTF-NEXT: [[TMP21:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP5]], i32 1 |
| ; CHECK-NOTF-NEXT: [[TMP22:%.*]] = load i32, ptr [[TMP18]], align 4 |
| ; CHECK-NOTF-NEXT: [[TMP23:%.*]] = load i32, ptr [[TMP19]], align 4 |
| ; CHECK-NOTF-NEXT: [[TMP24:%.*]] = load i32, ptr [[TMP20]], align 4 |
| ; CHECK-NOTF-NEXT: [[TMP25:%.*]] = load i32, ptr [[TMP21]], align 4 |
| ; CHECK-NOTF-NEXT: [[TMP26:%.*]] = add i32 [[TMP14]], [[TMP22]] |
| ; CHECK-NOTF-NEXT: [[TMP27:%.*]] = add i32 [[TMP15]], [[TMP23]] |
| ; CHECK-NOTF-NEXT: [[TMP28:%.*]] = add i32 [[TMP16]], [[TMP24]] |
| ; CHECK-NOTF-NEXT: [[TMP29:%.*]] = add i32 [[TMP17]], [[TMP25]] |
| ; CHECK-NOTF-NEXT: [[TMP30:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP2]], i32 2 |
| ; CHECK-NOTF-NEXT: [[TMP31:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP3]], i32 2 |
| ; CHECK-NOTF-NEXT: [[TMP32:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP4]], i32 2 |
| ; CHECK-NOTF-NEXT: [[TMP33:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP5]], i32 2 |
| ; CHECK-NOTF-NEXT: [[TMP34:%.*]] = load i32, ptr [[TMP30]], align 4 |
| ; CHECK-NOTF-NEXT: [[TMP35:%.*]] = load i32, ptr [[TMP31]], align 4 |
| ; CHECK-NOTF-NEXT: [[TMP36:%.*]] = load i32, ptr [[TMP32]], align 4 |
| ; CHECK-NOTF-NEXT: [[TMP37:%.*]] = load i32, ptr [[TMP33]], align 4 |
| ; CHECK-NOTF-NEXT: [[TMP38]] = add i32 [[TMP26]], [[TMP34]] |
| ; CHECK-NOTF-NEXT: [[TMP39]] = add i32 [[TMP27]], [[TMP35]] |
| ; CHECK-NOTF-NEXT: [[TMP40]] = add i32 [[TMP28]], [[TMP36]] |
| ; CHECK-NOTF-NEXT: [[TMP41]] = add i32 [[TMP29]], [[TMP37]] |
| ; CHECK-NOTF-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4 |
| ; CHECK-NOTF-NEXT: [[TMP42:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]] |
| ; CHECK-NOTF-NEXT: br i1 [[TMP42]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP25:![0-9]+]] |
| ; CHECK-NOTF: [[MIDDLE_BLOCK]]: |
| ; CHECK-NOTF-NEXT: [[BIN_RDX:%.*]] = add i32 [[TMP39]], [[TMP38]] |
| ; CHECK-NOTF-NEXT: [[BIN_RDX4:%.*]] = add i32 [[TMP40]], [[BIN_RDX]] |
| ; CHECK-NOTF-NEXT: [[BIN_RDX5:%.*]] = add i32 [[TMP41]], [[BIN_RDX4]] |
| ; CHECK-NOTF-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[TMP0]], [[N_VEC]] |
| ; CHECK-NOTF-NEXT: br i1 [[CMP_N]], label %[[EXIT_LOOPEXIT:.*]], label %[[SCALAR_PH]] |
| ; CHECK-NOTF: [[SCALAR_PH]]: |
| ; CHECK-NOTF-NEXT: [[BC_RESUME_VAL:%.*]] = phi i64 [ [[TMP1]], %[[MIDDLE_BLOCK]] ], [ [[N]], %[[LOOP_PREHEADER]] ] |
| ; CHECK-NOTF-NEXT: [[BC_MERGE_RDX:%.*]] = phi i32 [ [[BIN_RDX5]], %[[MIDDLE_BLOCK]] ], [ 0, %[[LOOP_PREHEADER]] ] |
| ; CHECK-NOTF-NEXT: br label %[[LOOP:.*]] |
| ; CHECK-NOTF: [[LOOP]]: |
| ; CHECK-NOTF-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], %[[LOOP]] ], [ [[BC_RESUME_VAL]], %[[SCALAR_PH]] ] |
| ; CHECK-NOTF-NEXT: [[RDX:%.*]] = phi i32 [ [[RDX_NEXT:%.*]], %[[LOOP]] ], [ [[BC_MERGE_RDX]], %[[SCALAR_PH]] ] |
| ; CHECK-NOTF-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV]], i32 0 |
| ; CHECK-NOTF-NEXT: [[LD1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4 |
| ; CHECK-NOTF-NEXT: [[ADD:%.*]] = add nsw i32 [[RDX]], [[LD1]] |
| ; CHECK-NOTF-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV]], i32 1 |
| ; CHECK-NOTF-NEXT: [[LD2:%.*]] = load i32, ptr [[ARRAYIDX1]], align 4 |
| ; CHECK-NOTF-NEXT: [[ADD1:%.*]] = add nsw i32 [[ADD]], [[LD2]] |
| ; CHECK-NOTF-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV]], i32 2 |
| ; CHECK-NOTF-NEXT: [[LD3:%.*]] = load i32, ptr [[ARRAYIDX2]], align 4 |
| ; CHECK-NOTF-NEXT: [[RDX_NEXT]] = add nsw i32 [[ADD1]], [[LD3]] |
| ; CHECK-NOTF-NEXT: [[IV_NEXT]] = add nsw i64 [[IV]], -1 |
| ; CHECK-NOTF-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i64 [[IV]], 0 |
| ; CHECK-NOTF-NEXT: br i1 [[EXITCOND_NOT]], label %[[EXIT_LOOPEXIT]], label %[[LOOP]], !llvm.loop [[LOOP26:![0-9]+]] |
| ; CHECK-NOTF: [[EXIT_LOOPEXIT]]: |
| ; CHECK-NOTF-NEXT: [[RDX_NEXT_LCSSA:%.*]] = phi i32 [ [[RDX_NEXT]], %[[LOOP]] ], [ [[BIN_RDX5]], %[[MIDDLE_BLOCK]] ] |
| ; CHECK-NOTF-NEXT: br label %[[EXIT]] |
| ; CHECK-NOTF: [[EXIT]]: |
| ; CHECK-NOTF-NEXT: [[RDX_FINAL:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[RDX_NEXT_LCSSA]], %[[EXIT_LOOPEXIT]] ] |
| ; CHECK-NOTF-NEXT: ret i32 [[RDX_FINAL]] |
| ; |
| ; CHECK-TF-LABEL: define i32 @load_factor_4_with_tail_gap_reverse( |
| ; CHECK-TF-SAME: i64 [[N:%.*]], ptr noalias [[A:%.*]]) #[[ATTR2]] { |
| ; CHECK-TF-NEXT: [[ENTRY:.*]]: |
| ; CHECK-TF-NEXT: [[CMP:%.*]] = icmp sgt i64 [[N]], -1 |
| ; CHECK-TF-NEXT: br i1 [[CMP]], label %[[LOOP_PREHEADER:.*]], label %[[EXIT:.*]] |
| ; CHECK-TF: [[LOOP_PREHEADER]]: |
| ; CHECK-TF-NEXT: br label %[[LOOP:.*]] |
| ; CHECK-TF: [[LOOP]]: |
| ; CHECK-TF-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], %[[LOOP]] ], [ [[N]], %[[LOOP_PREHEADER]] ] |
| ; CHECK-TF-NEXT: [[RDX:%.*]] = phi i32 [ [[RDX_NEXT:%.*]], %[[LOOP]] ], [ 0, %[[LOOP_PREHEADER]] ] |
| ; CHECK-TF-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV]], i32 0 |
| ; CHECK-TF-NEXT: [[LD1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4 |
| ; CHECK-TF-NEXT: [[ADD:%.*]] = add nsw i32 [[RDX]], [[LD1]] |
| ; CHECK-TF-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV]], i32 1 |
| ; CHECK-TF-NEXT: [[LD2:%.*]] = load i32, ptr [[ARRAYIDX1]], align 4 |
| ; CHECK-TF-NEXT: [[ADD1:%.*]] = add nsw i32 [[ADD]], [[LD2]] |
| ; CHECK-TF-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV]], i32 2 |
| ; CHECK-TF-NEXT: [[LD3:%.*]] = load i32, ptr [[ARRAYIDX2]], align 4 |
| ; CHECK-TF-NEXT: [[RDX_NEXT]] = add nsw i32 [[ADD1]], [[LD3]] |
| ; CHECK-TF-NEXT: [[IV_NEXT]] = add nsw i64 [[IV]], -1 |
| ; CHECK-TF-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i64 [[IV]], 0 |
| ; CHECK-TF-NEXT: br i1 [[EXITCOND_NOT]], label %[[EXIT_LOOPEXIT:.*]], label %[[LOOP]] |
| ; CHECK-TF: [[EXIT_LOOPEXIT]]: |
| ; CHECK-TF-NEXT: [[RDX_NEXT_LCSSA:%.*]] = phi i32 [ [[RDX_NEXT]], %[[LOOP]] ] |
| ; CHECK-TF-NEXT: br label %[[EXIT]] |
| ; CHECK-TF: [[EXIT]]: |
| ; CHECK-TF-NEXT: [[RDX_FINAL:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[RDX_NEXT_LCSSA]], %[[EXIT_LOOPEXIT]] ] |
| ; CHECK-TF-NEXT: ret i32 [[RDX_FINAL]] |
| ; |
| entry: |
| %cmp = icmp sgt i64 %n, -1 |
| br i1 %cmp, label %loop, label %exit |
| |
| loop: |
| %iv = phi i64 [ %n, %entry ], [ %iv.next, %loop ] |
| %rdx = phi i32 [ 0, %entry ], [ %rdx.next, %loop ] |
| %arrayidx = getelementptr inbounds [4 x i32], ptr %a, i64 %iv, i32 0 |
| %ld1 = load i32, ptr %arrayidx, align 4 |
| %add = add nsw i32 %rdx, %ld1 |
| %arrayidx1 = getelementptr inbounds [4 x i32], ptr %a, i64 %iv, i32 1 |
| %ld2 = load i32, ptr %arrayidx1, align 4 |
| %add1 = add nsw i32 %add, %ld2 |
| %arrayidx2 = getelementptr inbounds [4 x i32], ptr %a, i64 %iv, i32 2 |
| %ld3 = load i32, ptr %arrayidx2, align 4 |
| %rdx.next = add nsw i32 %add1, %ld3 |
| %iv.next = add nsw i64 %iv, -1 |
| %exitcond.not = icmp eq i64 %iv, 0 |
| br i1 %exitcond.not, label %exit, label %loop |
| |
| exit: |
| %rdx.final = phi i32 [ 0, %entry ], [ %rdx.next, %loop ] |
| ret i32 %rdx.final |
| } |
| |
| ; Interleaved group with tail gap, reversed |
| ; E.g. |
| ; int (*a)[4]; |
| ; int rdx = 0; |
| ; for (int i = n; i >= 0; i--) { |
| ; a[i][0] = i; |
| ; a[i][1] = i; |
| ; a[i][2] = i; |
| ; // No access a[i][3] |
| ; } |
| ; |
| define void @store_factor_4_with_tail_gap_reverse(i64 %n, ptr noalias %a) { |
| ; CHECK-NOTF-LABEL: define void @store_factor_4_with_tail_gap_reverse( |
| ; CHECK-NOTF-SAME: i64 [[N:%.*]], ptr noalias [[A:%.*]]) #[[ATTR2]] { |
| ; CHECK-NOTF-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NOTF-NEXT: [[CMP:%.*]] = icmp sgt i64 [[N]], -1 |
| ; CHECK-NOTF-NEXT: br i1 [[CMP]], label %[[LOOP_PREHEADER:.*]], label %[[EXIT:.*]] |
| ; CHECK-NOTF: [[LOOP_PREHEADER]]: |
| ; CHECK-NOTF-NEXT: [[TMP0:%.*]] = add i64 [[N]], 1 |
| ; CHECK-NOTF-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[TMP0]], 4 |
| ; CHECK-NOTF-NEXT: br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]] |
| ; CHECK-NOTF: [[VECTOR_PH]]: |
| ; CHECK-NOTF-NEXT: [[N_MOD_VF:%.*]] = urem i64 [[TMP0]], 4 |
| ; CHECK-NOTF-NEXT: [[N_VEC:%.*]] = sub i64 [[TMP0]], [[N_MOD_VF]] |
| ; CHECK-NOTF-NEXT: [[TMP1:%.*]] = sub i64 [[N]], [[N_VEC]] |
| ; CHECK-NOTF-NEXT: br label %[[VECTOR_BODY:.*]] |
| ; CHECK-NOTF: [[VECTOR_BODY]]: |
| ; CHECK-NOTF-NEXT: [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ] |
| ; CHECK-NOTF-NEXT: [[TMP2:%.*]] = sub i64 [[N]], [[INDEX]] |
| ; CHECK-NOTF-NEXT: [[TMP3:%.*]] = add i64 [[TMP2]], -1 |
| ; CHECK-NOTF-NEXT: [[TMP4:%.*]] = add i64 [[TMP2]], -2 |
| ; CHECK-NOTF-NEXT: [[TMP5:%.*]] = add i64 [[TMP2]], -3 |
| ; CHECK-NOTF-NEXT: [[TMP6:%.*]] = trunc i64 [[TMP2]] to i32 |
| ; CHECK-NOTF-NEXT: [[TMP7:%.*]] = trunc i64 [[TMP3]] to i32 |
| ; CHECK-NOTF-NEXT: [[TMP8:%.*]] = trunc i64 [[TMP4]] to i32 |
| ; CHECK-NOTF-NEXT: [[TMP9:%.*]] = trunc i64 [[TMP5]] to i32 |
| ; CHECK-NOTF-NEXT: [[TMP10:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP2]], i32 0 |
| ; CHECK-NOTF-NEXT: [[TMP11:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP3]], i32 0 |
| ; CHECK-NOTF-NEXT: [[TMP12:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP4]], i32 0 |
| ; CHECK-NOTF-NEXT: [[TMP13:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP5]], i32 0 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP6]], ptr [[TMP10]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP7]], ptr [[TMP11]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP8]], ptr [[TMP12]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP9]], ptr [[TMP13]], align 4 |
| ; CHECK-NOTF-NEXT: [[TMP14:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP2]], i32 1 |
| ; CHECK-NOTF-NEXT: [[TMP15:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP3]], i32 1 |
| ; CHECK-NOTF-NEXT: [[TMP16:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP4]], i32 1 |
| ; CHECK-NOTF-NEXT: [[TMP17:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP5]], i32 1 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP6]], ptr [[TMP14]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP7]], ptr [[TMP15]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP8]], ptr [[TMP16]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP9]], ptr [[TMP17]], align 4 |
| ; CHECK-NOTF-NEXT: [[TMP18:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP2]], i32 2 |
| ; CHECK-NOTF-NEXT: [[TMP19:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP3]], i32 2 |
| ; CHECK-NOTF-NEXT: [[TMP20:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP4]], i32 2 |
| ; CHECK-NOTF-NEXT: [[TMP21:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[TMP5]], i32 2 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP6]], ptr [[TMP18]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP7]], ptr [[TMP19]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP8]], ptr [[TMP20]], align 4 |
| ; CHECK-NOTF-NEXT: store i32 [[TMP9]], ptr [[TMP21]], align 4 |
| ; CHECK-NOTF-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4 |
| ; CHECK-NOTF-NEXT: [[TMP22:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]] |
| ; CHECK-NOTF-NEXT: br i1 [[TMP22]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP27:![0-9]+]] |
| ; CHECK-NOTF: [[MIDDLE_BLOCK]]: |
| ; CHECK-NOTF-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[TMP0]], [[N_VEC]] |
| ; CHECK-NOTF-NEXT: br i1 [[CMP_N]], label %[[EXIT_LOOPEXIT:.*]], label %[[SCALAR_PH]] |
| ; CHECK-NOTF: [[SCALAR_PH]]: |
| ; CHECK-NOTF-NEXT: [[BC_RESUME_VAL:%.*]] = phi i64 [ [[TMP1]], %[[MIDDLE_BLOCK]] ], [ [[N]], %[[LOOP_PREHEADER]] ] |
| ; CHECK-NOTF-NEXT: br label %[[LOOP:.*]] |
| ; CHECK-NOTF: [[LOOP]]: |
| ; CHECK-NOTF-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], %[[LOOP]] ], [ [[BC_RESUME_VAL]], %[[SCALAR_PH]] ] |
| ; CHECK-NOTF-NEXT: [[IV_TRUNC:%.*]] = trunc i64 [[IV]] to i32 |
| ; CHECK-NOTF-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV]], i32 0 |
| ; CHECK-NOTF-NEXT: store i32 [[IV_TRUNC]], ptr [[ARRAYIDX]], align 4 |
| ; CHECK-NOTF-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV]], i32 1 |
| ; CHECK-NOTF-NEXT: store i32 [[IV_TRUNC]], ptr [[ARRAYIDX1]], align 4 |
| ; CHECK-NOTF-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV]], i32 2 |
| ; CHECK-NOTF-NEXT: store i32 [[IV_TRUNC]], ptr [[ARRAYIDX2]], align 4 |
| ; CHECK-NOTF-NEXT: [[IV_NEXT]] = add nsw i64 [[IV]], -1 |
| ; CHECK-NOTF-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i64 [[IV]], 0 |
| ; CHECK-NOTF-NEXT: br i1 [[EXITCOND_NOT]], label %[[EXIT_LOOPEXIT]], label %[[LOOP]], !llvm.loop [[LOOP28:![0-9]+]] |
| ; CHECK-NOTF: [[EXIT_LOOPEXIT]]: |
| ; CHECK-NOTF-NEXT: br label %[[EXIT]] |
| ; CHECK-NOTF: [[EXIT]]: |
| ; CHECK-NOTF-NEXT: ret void |
| ; |
| ; CHECK-TF-LABEL: define void @store_factor_4_with_tail_gap_reverse( |
| ; CHECK-TF-SAME: i64 [[N:%.*]], ptr noalias [[A:%.*]]) #[[ATTR2]] { |
| ; CHECK-TF-NEXT: [[ENTRY:.*:]] |
| ; CHECK-TF-NEXT: [[CMP:%.*]] = icmp sgt i64 [[N]], -1 |
| ; CHECK-TF-NEXT: br i1 [[CMP]], label %[[LOOP_PREHEADER:.*]], label %[[EXIT:.*]] |
| ; CHECK-TF: [[LOOP_PREHEADER]]: |
| ; CHECK-TF-NEXT: br label %[[LOOP:.*]] |
| ; CHECK-TF: [[LOOP]]: |
| ; CHECK-TF-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], %[[LOOP]] ], [ [[N]], %[[LOOP_PREHEADER]] ] |
| ; CHECK-TF-NEXT: [[IV_TRUNC:%.*]] = trunc i64 [[IV]] to i32 |
| ; CHECK-TF-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV]], i32 0 |
| ; CHECK-TF-NEXT: store i32 [[IV_TRUNC]], ptr [[ARRAYIDX]], align 4 |
| ; CHECK-TF-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV]], i32 1 |
| ; CHECK-TF-NEXT: store i32 [[IV_TRUNC]], ptr [[ARRAYIDX1]], align 4 |
| ; CHECK-TF-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [4 x i32], ptr [[A]], i64 [[IV]], i32 2 |
| ; CHECK-TF-NEXT: store i32 [[IV_TRUNC]], ptr [[ARRAYIDX2]], align 4 |
| ; CHECK-TF-NEXT: [[IV_NEXT]] = add nsw i64 [[IV]], -1 |
| ; CHECK-TF-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i64 [[IV]], 0 |
| ; CHECK-TF-NEXT: br i1 [[EXITCOND_NOT]], label %[[EXIT_LOOPEXIT:.*]], label %[[LOOP]] |
| ; CHECK-TF: [[EXIT_LOOPEXIT]]: |
| ; CHECK-TF-NEXT: br label %[[EXIT]] |
| ; CHECK-TF: [[EXIT]]: |
| ; CHECK-TF-NEXT: ret void |
| ; |
| entry: |
| %cmp = icmp sgt i64 %n, -1 |
| br i1 %cmp, label %loop, label %exit |
| |
| loop: |
| %iv = phi i64 [ %n, %entry ], [ %iv.next, %loop ] |
| %iv.trunc = trunc i64 %iv to i32 |
| %arrayidx = getelementptr inbounds [4 x i32], ptr %a, i64 %iv, i32 0 |
| store i32 %iv.trunc, ptr %arrayidx, align 4 |
| %arrayidx1 = getelementptr inbounds [4 x i32], ptr %a, i64 %iv, i32 1 |
| store i32 %iv.trunc, ptr %arrayidx1, align 4 |
| %arrayidx2 = getelementptr inbounds [4 x i32], ptr %a, i64 %iv, i32 2 |
| store i32 %iv.trunc, ptr %arrayidx2, align 4 |
| %iv.next = add nsw i64 %iv, -1 |
| %exitcond.not = icmp eq i64 %iv, 0 |
| br i1 %exitcond.not, label %exit, label %loop |
| |
| exit: |
| ret void |
| } |
| |
| |
| |
| attributes #0 = { "target-cpu"="neoverse-512tvb" } |
| attributes #1 = { "target-cpu"="grace" } |
| |
| !0 = distinct !{!0, !1, !2} |
| !1 = !{!"llvm.loop.mustprogress"} |
| !2 = !{!"llvm.loop.vectorize.enable", i1 true} |