[llvm] [RISCV][SLP] Precommit strided-load alignment tests (NFC) (PR #222863)

via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 11 00:13:46 PDT 2026


https://github.com/imkiva created https://github.com/llvm/llvm-project/pull/222863

Record SLP's current handling of adjacent load groups with different alignments on RV32 and RV64.

The RV64 strict-alignment case currently forms a widened i64 strided load with align 4 and a 28-byte stride. Mark this as a FIXME for the follow-up legality fix. Naturally aligned strided loads are also covered.

Precommit coverage for #222520.

>From 1a02d4d0721e8bd7ae596ab16223880732a14fec Mon Sep 17 00:00:00 2001
From: imkiva <zengtao at iscas.ac.cn>
Date: Fri, 11 Sep 2026 13:40:35 +0800
Subject: [PATCH] [RISCV][SLP] Precommit strided-load alignment tests (NFC)

Record SLP's current handling of adjacent load groups with different
alignments on RV32 and RV64, including configurations with and without
unaligned vector memory support.

The RV64 strict-alignment case currently forms a widened i64 strided
load with align 4 and a 28-byte stride. Mark this as a FIXME for the
follow-up legality fix. Naturally aligned strided loads are also covered.

Precommit coverage for #222520.
---
 .../RISCV/strided-load-common-alignment.ll    | 102 ++++++++++++++++++
 1 file changed, 102 insertions(+)
 create mode 100644 llvm/test/Transforms/SLPVectorizer/RISCV/strided-load-common-alignment.ll

diff --git a/llvm/test/Transforms/SLPVectorizer/RISCV/strided-load-common-alignment.ll b/llvm/test/Transforms/SLPVectorizer/RISCV/strided-load-common-alignment.ll
new file mode 100644
index 0000000000000..81203dbb5a047
--- /dev/null
+++ b/llvm/test/Transforms/SLPVectorizer/RISCV/strided-load-common-alignment.ll
@@ -0,0 +1,102 @@
+; 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.
+; FIXME: Do not form an i64 strided load in the RV64 strict-alignment case.
+
+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:    [[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)
+; RV64-NEXT:    [[TMP5:%.*]] = bitcast <2 x i64> [[TMP1]] to <4 x i32>
+; 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:    [[Q2:%.*]] = getelementptr inbounds i32, ptr [[OUT]], i64 2
+; RV32-NEXT:    [[TMP1:%.*]] = load <2 x i32>, ptr [[BASE]], align 16
+; RV32-NEXT:    [[TMP3:%.*]] = add <2 x i32> [[TMP1]], splat (i32 3)
+; RV32-NEXT:    [[TMP2:%.*]] = load <2 x i32>, ptr [[P2]], align 4
+; RV32-NEXT:    [[TMP4:%.*]] = add <2 x i32> [[TMP2]], splat (i32 3)
+; RV32-NEXT:    store <2 x i32> [[TMP3]], ptr [[OUT]], align 4
+; RV32-NEXT:    store <2 x i32> [[TMP4]], ptr [[Q2]], 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
+}



More information about the llvm-commits mailing list