blob: 0e34894be821c8b9786f6fc75ba97d107df7bedc [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt -S -passes=slp-vectorizer -mtriple=riscv64 -mattr=+v,-unaligned-vector-mem < %s | FileCheck %s --check-prefix=RV64
; RUN: opt -S -passes=slp-vectorizer -mtriple=riscv32 -mattr=+v,-unaligned-vector-mem < %s | FileCheck %s --check-prefix=RV32
; RUN: opt -S -passes=slp-vectorizer -mtriple=riscv64 -mattr=+v,+unaligned-vector-mem < %s | FileCheck %s --check-prefix=UNALIGNED
;
; The first load's alignment does not describe every group. Widening each
; adjacent pair to i64 would leave the group at byte offset 28 misaligned.
define void @gather_fields(ptr %base, ptr %out) {
; RV64-LABEL: define void @gather_fields(
; RV64-SAME: ptr [[BASE:%.*]], ptr [[OUT:%.*]]) #[[ATTR0:[0-9]+]] {
; RV64-NEXT: [[P2:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i64 7
; RV64-NEXT: [[TMP1:%.*]] = load <2 x i32>, ptr [[BASE]], align 16
; RV64-NEXT: [[TMP2:%.*]] = load <2 x i32>, ptr [[P2]], align 4
; RV64-NEXT: [[TMP3:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
; RV64-NEXT: [[TMP4:%.*]] = shufflevector <2 x i32> [[TMP2]], <2 x i32> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
; RV64-NEXT: [[TMP5:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> [[TMP2]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
; RV64-NEXT: [[TMP6:%.*]] = add <4 x i32> [[TMP5]], splat (i32 3)
; RV64-NEXT: store <4 x i32> [[TMP6]], ptr [[OUT]], align 4
; RV64-NEXT: ret void
;
; RV32-LABEL: define void @gather_fields(
; RV32-SAME: ptr [[BASE:%.*]], ptr [[OUT:%.*]]) #[[ATTR0:[0-9]+]] {
; RV32-NEXT: [[P2:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i64 7
; RV32-NEXT: [[TMP1:%.*]] = load <2 x i32>, ptr [[BASE]], align 16
; RV32-NEXT: [[TMP2:%.*]] = load <2 x i32>, ptr [[P2]], align 4
; RV32-NEXT: [[TMP3:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
; RV32-NEXT: [[TMP4:%.*]] = shufflevector <2 x i32> [[TMP2]], <2 x i32> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
; RV32-NEXT: [[TMP5:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> [[TMP2]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
; RV32-NEXT: [[TMP6:%.*]] = add <4 x i32> [[TMP5]], splat (i32 3)
; RV32-NEXT: store <4 x i32> [[TMP6]], ptr [[OUT]], align 4
; RV32-NEXT: ret void
;
; UNALIGNED-LABEL: define void @gather_fields(
; UNALIGNED-SAME: ptr [[BASE:%.*]], ptr [[OUT:%.*]]) #[[ATTR0:[0-9]+]] {
; UNALIGNED-NEXT: [[TMP1:%.*]] = call <2 x i64> @llvm.experimental.vp.strided.load.v2i64.p0.i64(ptr align 4 [[BASE]], i64 28, <2 x i1> splat (i1 true), i32 2)
; UNALIGNED-NEXT: [[TMP2:%.*]] = bitcast <2 x i64> [[TMP1]] to <4 x i32>
; UNALIGNED-NEXT: [[TMP3:%.*]] = add <4 x i32> [[TMP2]], splat (i32 3)
; UNALIGNED-NEXT: store <4 x i32> [[TMP3]], ptr [[OUT]], align 4
; UNALIGNED-NEXT: ret void
;
%p1 = getelementptr inbounds i32, ptr %base, i64 1
%p2 = getelementptr inbounds i32, ptr %base, i64 7
%p3 = getelementptr inbounds i32, ptr %base, i64 8
%a = load i32, ptr %base, align 16
%b = load i32, ptr %p1, align 4
%c = load i32, ptr %p2, align 4
%d = load i32, ptr %p3, align 16
%v0 = add i32 %a, 3
%v1 = add i32 %b, 3
%v2 = add i32 %c, 3
%v3 = add i32 %d, 3
%q1 = getelementptr inbounds i32, ptr %out, i64 1
%q2 = getelementptr inbounds i32, ptr %out, i64 2
%q3 = getelementptr inbounds i32, ptr %out, i64 3
store i32 %v0, ptr %out, align 4
store i32 %v1, ptr %q1, align 4
store i32 %v2, ptr %q2, align 4
store i32 %v3, ptr %q3, align 4
ret void
}
; Naturally aligned strided loads remain legal.
define void @aligned_values(ptr %base, ptr %out) {
; RV64-LABEL: define void @aligned_values(
; RV64-SAME: ptr [[BASE:%.*]], ptr [[OUT:%.*]]) #[[ATTR0]] {
; RV64-NEXT: [[TMP1:%.*]] = call <4 x i64> @llvm.experimental.vp.strided.load.v4i64.p0.i64(ptr align 8 [[BASE]], i64 64, <4 x i1> splat (i1 true), i32 4)
; RV64-NEXT: [[TMP2:%.*]] = add <4 x i64> [[TMP1]], splat (i64 3)
; RV64-NEXT: store <4 x i64> [[TMP2]], ptr [[OUT]], align 8
; RV64-NEXT: ret void
;
; RV32-LABEL: define void @aligned_values(
; RV32-SAME: ptr [[BASE:%.*]], ptr [[OUT:%.*]]) #[[ATTR0]] {
; RV32-NEXT: [[TMP1:%.*]] = call <4 x i64> @llvm.experimental.vp.strided.load.v4i64.p0.i32(ptr align 8 [[BASE]], i32 64, <4 x i1> splat (i1 true), i32 4)
; RV32-NEXT: [[TMP2:%.*]] = add <4 x i64> [[TMP1]], splat (i64 3)
; RV32-NEXT: store <4 x i64> [[TMP2]], ptr [[OUT]], align 8
; RV32-NEXT: ret void
;
; UNALIGNED-LABEL: define void @aligned_values(
; UNALIGNED-SAME: ptr [[BASE:%.*]], ptr [[OUT:%.*]]) #[[ATTR0]] {
; UNALIGNED-NEXT: [[TMP1:%.*]] = call <4 x i64> @llvm.experimental.vp.strided.load.v4i64.p0.i64(ptr align 8 [[BASE]], i64 64, <4 x i1> splat (i1 true), i32 4)
; UNALIGNED-NEXT: [[TMP2:%.*]] = add <4 x i64> [[TMP1]], splat (i64 3)
; UNALIGNED-NEXT: store <4 x i64> [[TMP2]], ptr [[OUT]], align 8
; UNALIGNED-NEXT: ret void
;
%p1 = getelementptr inbounds i64, ptr %base, i64 8
%p2 = getelementptr inbounds i64, ptr %base, i64 16
%p3 = getelementptr inbounds i64, ptr %base, i64 24
%a = load i64, ptr %base, align 16
%b = load i64, ptr %p1, align 8
%c = load i64, ptr %p2, align 8
%d = load i64, ptr %p3, align 8
%v0 = add i64 %a, 3
%v1 = add i64 %b, 3
%v2 = add i64 %c, 3
%v3 = add i64 %d, 3
%q1 = getelementptr inbounds i64, ptr %out, i64 1
%q2 = getelementptr inbounds i64, ptr %out, i64 2
%q3 = getelementptr inbounds i64, ptr %out, i64 3
store i64 %v0, ptr %out, align 8
store i64 %v1, ptr %q1, align 8
store i64 %v2, ptr %q2, align 8
store i64 %v3, ptr %q3, align 8
ret void
}