[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