[llvm] [SLP][NFC]Add tests for and-cut reduction leaves, NFC (PR #216019)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 13 05:04:01 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Alexey Bataev (alexey-bataev)
<details>
<summary>Changes</summary>
---
Full diff: https://github.com/llvm/llvm-project/pull/216019.diff
2 Files Affected:
- (added) llvm/test/Transforms/SLPVectorizer/RISCV/zext-or-nibble-reduction.ll (+193)
- (added) llvm/test/Transforms/SLPVectorizer/X86/zext-or-nibble-reduction.ll (+90)
``````````diff
diff --git a/llvm/test/Transforms/SLPVectorizer/RISCV/zext-or-nibble-reduction.ll b/llvm/test/Transforms/SLPVectorizer/RISCV/zext-or-nibble-reduction.ll
new file mode 100644
index 0000000000000..da87e9f043008
--- /dev/null
+++ b/llvm/test/Transforms/SLPVectorizer/RISCV/zext-or-nibble-reduction.ll
@@ -0,0 +1,193 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -mtriple=riscv64-unknown-linux-gnu -mattr=+v -passes=slp-vectorizer < %s | FileCheck %s
+
+; Reduction leaves are narrow values widened via zext/shl, with the first two
+; masked bytes packed by InstCombine into a single zext(or i8). The reduction
+; should be analyzed in the narrow type and still form a full-width or
+; reduction of consecutive loads.
+
+define i64 @test(ptr %src) {
+; CHECK-LABEL: @test(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[L0:%.*]] = load i8, ptr [[SRC:%.*]], align 1
+; CHECK-NEXT: [[A0:%.*]] = and i8 [[L0]], 15
+; CHECK-NEXT: [[P1:%.*]] = getelementptr inbounds nuw i8, ptr [[SRC]], i64 1
+; CHECK-NEXT: [[L1:%.*]] = load i8, ptr [[P1]], align 1
+; CHECK-NEXT: [[SH1:%.*]] = shl i8 [[L1]], 4
+; CHECK-NEXT: [[OR8:%.*]] = or disjoint i8 [[SH1]], [[A0]]
+; CHECK-NEXT: [[OR0:%.*]] = zext i8 [[OR8]] to i64
+; CHECK-NEXT: [[P2:%.*]] = getelementptr inbounds nuw i8, ptr [[SRC]], i64 2
+; CHECK-NEXT: [[TMP0:%.*]] = load <4 x i8>, ptr [[P2]], align 1
+; CHECK-NEXT: [[TMP1:%.*]] = and <4 x i8> [[TMP0]], splat (i8 15)
+; CHECK-NEXT: [[TMP2:%.*]] = zext <4 x i8> [[TMP1]] to <4 x i64>
+; CHECK-NEXT: [[TMP3:%.*]] = shl nuw nsw <4 x i64> [[TMP2]], <i64 8, i64 12, i64 16, i64 20>
+; CHECK-NEXT: [[P6:%.*]] = getelementptr inbounds nuw i8, ptr [[SRC]], i64 6
+; CHECK-NEXT: [[L6:%.*]] = load i8, ptr [[P6]], align 1
+; CHECK-NEXT: [[A6:%.*]] = and i8 [[L6]], 15
+; CHECK-NEXT: [[Z6:%.*]] = zext nneg i8 [[A6]] to i64
+; CHECK-NEXT: [[SH6:%.*]] = shl nuw nsw i64 [[Z6]], 24
+; CHECK-NEXT: [[P7:%.*]] = getelementptr inbounds nuw i8, ptr [[SRC]], i64 7
+; CHECK-NEXT: [[L7:%.*]] = load i8, ptr [[P7]], align 1
+; CHECK-NEXT: [[A7:%.*]] = and i8 [[L7]], 15
+; CHECK-NEXT: [[Z7:%.*]] = zext nneg i8 [[A7]] to i64
+; CHECK-NEXT: [[SH7:%.*]] = shl nuw nsw i64 [[Z7]], 28
+; CHECK-NEXT: [[TMP4:%.*]] = call i64 @llvm.vector.reduce.or.v4i64(<4 x i64> [[TMP3]])
+; CHECK-NEXT: [[OP_RDX:%.*]] = or i64 [[TMP4]], [[OR0]]
+; CHECK-NEXT: [[OP_RDX1:%.*]] = or i64 [[SH6]], [[SH7]]
+; CHECK-NEXT: [[TMP6:%.*]] = or i64 [[OP_RDX]], [[OP_RDX1]]
+; CHECK-NEXT: ret i64 [[TMP6]]
+;
+entry:
+ %l0 = load i8, ptr %src, align 1
+ %a0 = and i8 %l0, 15
+ %p1 = getelementptr inbounds nuw i8, ptr %src, i64 1
+ %l1 = load i8, ptr %p1, align 1
+ %sh1 = shl i8 %l1, 4
+ %or8 = or disjoint i8 %sh1, %a0
+ %or0 = zext i8 %or8 to i64
+ %p2 = getelementptr inbounds nuw i8, ptr %src, i64 2
+ %l2 = load i8, ptr %p2, align 1
+ %a2 = and i8 %l2, 15
+ %z2 = zext nneg i8 %a2 to i64
+ %sh2 = shl nuw nsw i64 %z2, 8
+ %or2 = or i64 %sh2, %or0
+ %p3 = getelementptr inbounds nuw i8, ptr %src, i64 3
+ %l3 = load i8, ptr %p3, align 1
+ %a3 = and i8 %l3, 15
+ %z3 = zext nneg i8 %a3 to i64
+ %sh3 = shl nuw nsw i64 %z3, 12
+ %or3 = or i64 %sh3, %or2
+ %p4 = getelementptr inbounds nuw i8, ptr %src, i64 4
+ %l4 = load i8, ptr %p4, align 1
+ %a4 = and i8 %l4, 15
+ %z4 = zext nneg i8 %a4 to i64
+ %sh4 = shl nuw nsw i64 %z4, 16
+ %or4 = or i64 %sh4, %or3
+ %p5 = getelementptr inbounds nuw i8, ptr %src, i64 5
+ %l5 = load i8, ptr %p5, align 1
+ %a5 = and i8 %l5, 15
+ %z5 = zext nneg i8 %a5 to i64
+ %sh5 = shl nuw nsw i64 %z5, 20
+ %or5 = or i64 %sh5, %or4
+ %p6 = getelementptr inbounds nuw i8, ptr %src, i64 6
+ %l6 = load i8, ptr %p6, align 1
+ %a6 = and i8 %l6, 15
+ %z6 = zext nneg i8 %a6 to i64
+ %sh6 = shl nuw nsw i64 %z6, 24
+ %or6 = or i64 %sh6, %or5
+ %p7 = getelementptr inbounds nuw i8, ptr %src, i64 7
+ %l7 = load i8, ptr %p7, align 1
+ %a7 = and i8 %l7, 15
+ %z7 = zext nneg i8 %a7 to i64
+ %sh7 = shl nuw nsw i64 %z7, 28
+ %or7 = or i64 %sh7, %or6
+ ret i64 %or7
+}
+
+; Same with the first four masked bytes packed into a zext(or i32) chain.
+
+define i64 @test_i32_pack(ptr %src) {
+; CHECK-LABEL: @test_i32_pack(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[L0:%.*]] = load i8, ptr [[SRC:%.*]], align 1
+; CHECK-NEXT: [[A0:%.*]] = and i8 [[L0]], 15
+; CHECK-NEXT: [[P1:%.*]] = getelementptr inbounds nuw i8, ptr [[SRC]], i64 1
+; CHECK-NEXT: [[L1:%.*]] = load i8, ptr [[P1]], align 1
+; CHECK-NEXT: [[SH1:%.*]] = shl i8 [[L1]], 4
+; CHECK-NEXT: [[OR8:%.*]] = or disjoint i8 [[SH1]], [[A0]]
+; CHECK-NEXT: [[Z01:%.*]] = zext i8 [[OR8]] to i32
+; CHECK-NEXT: [[P2:%.*]] = getelementptr inbounds nuw i8, ptr [[SRC]], i64 2
+; CHECK-NEXT: [[L2:%.*]] = load i8, ptr [[P2]], align 1
+; CHECK-NEXT: [[A2:%.*]] = and i8 [[L2]], 15
+; CHECK-NEXT: [[Z2:%.*]] = zext nneg i8 [[A2]] to i32
+; CHECK-NEXT: [[SH2:%.*]] = shl nuw i32 [[Z2]], 8
+; CHECK-NEXT: [[OR16:%.*]] = or disjoint i32 [[SH2]], [[Z01]]
+; CHECK-NEXT: [[P3:%.*]] = getelementptr inbounds nuw i8, ptr [[SRC]], i64 3
+; CHECK-NEXT: [[L3:%.*]] = load i8, ptr [[P3]], align 1
+; CHECK-NEXT: [[A3:%.*]] = and i8 [[L3]], 15
+; CHECK-NEXT: [[Z3:%.*]] = zext nneg i8 [[A3]] to i32
+; CHECK-NEXT: [[SH3:%.*]] = shl nuw i32 [[Z3]], 12
+; CHECK-NEXT: [[OR32:%.*]] = or disjoint i32 [[SH3]], [[OR16]]
+; CHECK-NEXT: [[OR0:%.*]] = zext i32 [[OR32]] to i64
+; CHECK-NEXT: [[P4:%.*]] = getelementptr inbounds nuw i8, ptr [[SRC]], i64 4
+; CHECK-NEXT: [[TMP0:%.*]] = load <4 x i8>, ptr [[P4]], align 1
+; CHECK-NEXT: [[TMP1:%.*]] = and <4 x i8> [[TMP0]], splat (i8 15)
+; CHECK-NEXT: [[TMP2:%.*]] = zext <4 x i8> [[TMP1]] to <4 x i64>
+; CHECK-NEXT: [[TMP3:%.*]] = shl nuw nsw <4 x i64> [[TMP2]], <i64 16, i64 20, i64 24, i64 28>
+; CHECK-NEXT: [[TMP4:%.*]] = call i64 @llvm.vector.reduce.or.v4i64(<4 x i64> [[TMP3]])
+; CHECK-NEXT: [[TMP6:%.*]] = or i64 [[TMP4]], [[OR0]]
+; CHECK-NEXT: ret i64 [[TMP6]]
+;
+entry:
+ %l0 = load i8, ptr %src, align 1
+ %a0 = and i8 %l0, 15
+ %p1 = getelementptr inbounds nuw i8, ptr %src, i64 1
+ %l1 = load i8, ptr %p1, align 1
+ %sh1 = shl i8 %l1, 4
+ %or8 = or disjoint i8 %sh1, %a0
+ %z01 = zext i8 %or8 to i32
+ %p2 = getelementptr inbounds nuw i8, ptr %src, i64 2
+ %l2 = load i8, ptr %p2, align 1
+ %a2 = and i8 %l2, 15
+ %z2 = zext nneg i8 %a2 to i32
+ %sh2 = shl nuw i32 %z2, 8
+ %or16 = or disjoint i32 %sh2, %z01
+ %p3 = getelementptr inbounds nuw i8, ptr %src, i64 3
+ %l3 = load i8, ptr %p3, align 1
+ %a3 = and i8 %l3, 15
+ %z3 = zext nneg i8 %a3 to i32
+ %sh3 = shl nuw i32 %z3, 12
+ %or32 = or disjoint i32 %sh3, %or16
+ %or0 = zext i32 %or32 to i64
+ %p4 = getelementptr inbounds nuw i8, ptr %src, i64 4
+ %l4 = load i8, ptr %p4, align 1
+ %a4 = and i8 %l4, 15
+ %z4 = zext nneg i8 %a4 to i64
+ %sh4 = shl nuw nsw i64 %z4, 16
+ %or4 = or i64 %sh4, %or0
+ %p5 = getelementptr inbounds nuw i8, ptr %src, i64 5
+ %l5 = load i8, ptr %p5, align 1
+ %a5 = and i8 %l5, 15
+ %z5 = zext nneg i8 %a5 to i64
+ %sh5 = shl nuw nsw i64 %z5, 20
+ %or5 = or i64 %sh5, %or4
+ %p6 = getelementptr inbounds nuw i8, ptr %src, i64 6
+ %l6 = load i8, ptr %p6, align 1
+ %a6 = and i8 %l6, 15
+ %z6 = zext nneg i8 %a6 to i64
+ %sh6 = shl nuw nsw i64 %z6, 24
+ %or6 = or i64 %sh6, %or5
+ %p7 = getelementptr inbounds nuw i8, ptr %src, i64 7
+ %l7 = load i8, ptr %p7, align 1
+ %a7 = and i8 %l7, 15
+ %z7 = zext nneg i8 %a7 to i64
+ %sh7 = shl nuw nsw i64 %z7, 28
+ %or7 = or i64 %sh7, %or6
+ ret i64 %or7
+}
+
+; zext does not distribute over add: the packed zext(add i32) leaf must stay
+; as is.
+
+define i64 @test_add_rdx(ptr %p, i64 %y, i64 %w) {
+; CHECK-LABEL: @test_add_rdx(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[X0:%.*]] = load i32, ptr [[P:%.*]], align 4
+; CHECK-NEXT: [[P1:%.*]] = getelementptr i32, ptr [[P]], i64 1
+; CHECK-NEXT: [[X1:%.*]] = load i32, ptr [[P1]], align 4
+; CHECK-NEXT: [[A:%.*]] = add i32 [[X0]], [[X1]]
+; CHECK-NEXT: [[Z:%.*]] = zext i32 [[A]] to i64
+; CHECK-NEXT: [[R1:%.*]] = add i64 [[Z]], [[Y:%.*]]
+; CHECK-NEXT: [[R2:%.*]] = add i64 [[R1]], [[W:%.*]]
+; CHECK-NEXT: ret i64 [[R2]]
+;
+entry:
+ %x0 = load i32, ptr %p, align 4
+ %p1 = getelementptr i32, ptr %p, i64 1
+ %x1 = load i32, ptr %p1, align 4
+ %a = add i32 %x0, %x1
+ %z = zext i32 %a to i64
+ %r1 = add i64 %z, %y
+ %r2 = add i64 %r1, %w
+ ret i64 %r2
+}
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/zext-or-nibble-reduction.ll b/llvm/test/Transforms/SLPVectorizer/X86/zext-or-nibble-reduction.ll
new file mode 100644
index 0000000000000..85ca961a7970a
--- /dev/null
+++ b/llvm/test/Transforms/SLPVectorizer/X86/zext-or-nibble-reduction.ll
@@ -0,0 +1,90 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -mtriple=x86_64-unknown-linux-gnu -mcpu=skylake-avx512 -passes=slp-vectorizer < %s | FileCheck %s
+
+; Reduction leaves are narrow values widened via zext/shl, with the first two
+; masked bytes packed by InstCombine into a single zext(or i8). The reduction
+; should be analyzed in the narrow type and still form a full-width or
+; reduction of consecutive loads.
+
+define i64 @test(ptr %src) {
+; CHECK-LABEL: @test(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[L0:%.*]] = load i8, ptr [[SRC:%.*]], align 1
+; CHECK-NEXT: [[A0:%.*]] = and i8 [[L0]], 15
+; CHECK-NEXT: [[P1:%.*]] = getelementptr inbounds nuw i8, ptr [[SRC]], i64 1
+; CHECK-NEXT: [[L1:%.*]] = load i8, ptr [[P1]], align 1
+; CHECK-NEXT: [[SH1:%.*]] = shl i8 [[L1]], 4
+; CHECK-NEXT: [[P2:%.*]] = getelementptr inbounds nuw i8, ptr [[SRC]], i64 2
+; CHECK-NEXT: [[P4:%.*]] = getelementptr inbounds nuw i8, ptr [[SRC]], i64 4
+; CHECK-NEXT: [[L4:%.*]] = load i8, ptr [[P4]], align 1
+; CHECK-NEXT: [[OR8:%.*]] = or disjoint i8 [[SH1]], [[A0]]
+; CHECK-NEXT: [[TMP0:%.*]] = load <2 x i8>, ptr [[P2]], align 1
+; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <2 x i8> [[TMP0]], <2 x i8> poison, <4 x i32> <i32 poison, i32 0, i32 1, i32 poison>
+; CHECK-NEXT: [[TMP2:%.*]] = insertelement <4 x i8> [[TMP1]], i8 [[OR8]], i64 0
+; CHECK-NEXT: [[TMP3:%.*]] = insertelement <4 x i8> [[TMP2]], i8 [[L4]], i64 3
+; CHECK-NEXT: [[TMP4:%.*]] = and <4 x i8> [[TMP3]], <i8 -1, i8 15, i8 15, i8 15>
+; CHECK-NEXT: [[TMP5:%.*]] = zext <4 x i8> [[TMP4]] to <4 x i64>
+; CHECK-NEXT: [[TMP16:%.*]] = shl nuw nsw <4 x i64> [[TMP5]], <i64 0, i64 8, i64 12, i64 16>
+; CHECK-NEXT: [[P5:%.*]] = getelementptr inbounds nuw i8, ptr [[SRC]], i64 5
+; CHECK-NEXT: [[L5:%.*]] = load i8, ptr [[P5]], align 1
+; CHECK-NEXT: [[A5:%.*]] = and i8 [[L5]], 15
+; CHECK-NEXT: [[Z5:%.*]] = zext nneg i8 [[A5]] to i64
+; CHECK-NEXT: [[P6:%.*]] = getelementptr inbounds nuw i8, ptr [[SRC]], i64 6
+; CHECK-NEXT: [[TMP7:%.*]] = load <2 x i8>, ptr [[P6]], align 1
+; CHECK-NEXT: [[TMP8:%.*]] = and <2 x i8> [[TMP7]], splat (i8 15)
+; CHECK-NEXT: [[TMP9:%.*]] = zext <2 x i8> [[TMP8]] to <2 x i64>
+; CHECK-NEXT: [[TMP10:%.*]] = call i64 @llvm.vector.reduce.or.v4i64(<4 x i64> [[TMP16]])
+; CHECK-NEXT: [[TMP11:%.*]] = insertelement <4 x i64> poison, i64 [[TMP10]], i64 0
+; CHECK-NEXT: [[TMP12:%.*]] = insertelement <4 x i64> [[TMP11]], i64 [[Z5]], i64 1
+; CHECK-NEXT: [[TMP13:%.*]] = shufflevector <2 x i64> [[TMP9]], <2 x i64> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
+; CHECK-NEXT: [[TMP14:%.*]] = shufflevector <4 x i64> [[TMP12]], <4 x i64> [[TMP13]], <4 x i32> <i32 0, i32 1, i32 4, i32 5>
+; CHECK-NEXT: [[TMP15:%.*]] = shl nuw nsw <4 x i64> [[TMP14]], <i64 0, i64 20, i64 24, i64 28>
+; CHECK-NEXT: [[TMP6:%.*]] = call i64 @llvm.vector.reduce.or.v4i64(<4 x i64> [[TMP15]])
+; CHECK-NEXT: ret i64 [[TMP6]]
+;
+entry:
+ %l0 = load i8, ptr %src, align 1
+ %a0 = and i8 %l0, 15
+ %p1 = getelementptr inbounds nuw i8, ptr %src, i64 1
+ %l1 = load i8, ptr %p1, align 1
+ %sh1 = shl i8 %l1, 4
+ %or8 = or disjoint i8 %sh1, %a0
+ %or0 = zext i8 %or8 to i64
+ %p2 = getelementptr inbounds nuw i8, ptr %src, i64 2
+ %l2 = load i8, ptr %p2, align 1
+ %a2 = and i8 %l2, 15
+ %z2 = zext nneg i8 %a2 to i64
+ %sh2 = shl nuw nsw i64 %z2, 8
+ %or2 = or i64 %sh2, %or0
+ %p3 = getelementptr inbounds nuw i8, ptr %src, i64 3
+ %l3 = load i8, ptr %p3, align 1
+ %a3 = and i8 %l3, 15
+ %z3 = zext nneg i8 %a3 to i64
+ %sh3 = shl nuw nsw i64 %z3, 12
+ %or3 = or i64 %sh3, %or2
+ %p4 = getelementptr inbounds nuw i8, ptr %src, i64 4
+ %l4 = load i8, ptr %p4, align 1
+ %a4 = and i8 %l4, 15
+ %z4 = zext nneg i8 %a4 to i64
+ %sh4 = shl nuw nsw i64 %z4, 16
+ %or4 = or i64 %sh4, %or3
+ %p5 = getelementptr inbounds nuw i8, ptr %src, i64 5
+ %l5 = load i8, ptr %p5, align 1
+ %a5 = and i8 %l5, 15
+ %z5 = zext nneg i8 %a5 to i64
+ %sh5 = shl nuw nsw i64 %z5, 20
+ %or5 = or i64 %sh5, %or4
+ %p6 = getelementptr inbounds nuw i8, ptr %src, i64 6
+ %l6 = load i8, ptr %p6, align 1
+ %a6 = and i8 %l6, 15
+ %z6 = zext nneg i8 %a6 to i64
+ %sh6 = shl nuw nsw i64 %z6, 24
+ %or6 = or i64 %sh6, %or5
+ %p7 = getelementptr inbounds nuw i8, ptr %src, i64 7
+ %l7 = load i8, ptr %p7, align 1
+ %a7 = and i8 %l7, 15
+ %z7 = zext nneg i8 %a7 to i64
+ %sh7 = shl nuw nsw i64 %z7, 28
+ %or7 = or i64 %sh7, %or6
+ ret i64 %or7
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/216019
More information about the llvm-commits
mailing list