[llvm] a259ffb - [SLP][NFC]Add tests for copyables in minmax int intrinsics, NFC
via llvm-commits
llvm-commits at lists.llvm.org
Sun Jul 12 06:50:57 PDT 2026
Author: Alexey Bataev
Date: 2026-07-12T09:50:52-04:00
New Revision: a259ffb45c84f930d3ad810dd4ddde50c2667766
URL: https://github.com/llvm/llvm-project/commit/a259ffb45c84f930d3ad810dd4ddde50c2667766
DIFF: https://github.com/llvm/llvm-project/commit/a259ffb45c84f930d3ad810dd4ddde50c2667766.diff
LOG: [SLP][NFC]Add tests for copyables in minmax int intrinsics, NFC
Reviewers:
Pull Request: https://github.com/llvm/llvm-project/pull/209021
Added:
llvm/test/Transforms/SLPVectorizer/X86/minmax-main-opcode-copyables-cost.ll
llvm/test/Transforms/SLPVectorizer/X86/minmax-main-opcode-copyables.ll
Modified:
Removed:
################################################################################
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/minmax-main-opcode-copyables-cost.ll b/llvm/test/Transforms/SLPVectorizer/X86/minmax-main-opcode-copyables-cost.ll
new file mode 100644
index 0000000000000..0cc58fa07dbbb
--- /dev/null
+++ b/llvm/test/Transforms/SLPVectorizer/X86/minmax-main-opcode-copyables-cost.ll
@@ -0,0 +1,32 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes=slp-vectorizer -S -mtriple=x86_64-unknown-linux-gnu -mattr=+avx2 < %s | FileCheck %s
+
+define void @test_umax(ptr %dst, i32 %x0, i32 %x1, i32 %x2, i32 %x3) {
+; CHECK-LABEL: define void @test_umax(
+; CHECK-SAME: ptr [[DST:%.*]], i32 [[X0:%.*]], i32 [[X1:%.*]], i32 [[X2:%.*]], i32 [[X3:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[UMAX0:%.*]] = call i32 @llvm.umax.i32(i32 [[X0]], i32 1)
+; CHECK-NEXT: [[UMAX1:%.*]] = call i32 @llvm.umax.i32(i32 [[X1]], i32 2)
+; CHECK-NEXT: [[UMAX2:%.*]] = call i32 @llvm.umax.i32(i32 [[X2]], i32 3)
+; CHECK-NEXT: store i32 [[UMAX0]], ptr [[DST]], align 4
+; CHECK-NEXT: [[P1:%.*]] = getelementptr i32, ptr [[DST]], i32 1
+; CHECK-NEXT: store i32 [[UMAX1]], ptr [[P1]], align 4
+; CHECK-NEXT: [[P2:%.*]] = getelementptr i32, ptr [[DST]], i32 2
+; CHECK-NEXT: store i32 [[UMAX2]], ptr [[P2]], align 4
+; CHECK-NEXT: [[P3:%.*]] = getelementptr i32, ptr [[DST]], i32 3
+; CHECK-NEXT: store i32 [[X3]], ptr [[P3]], align 4
+; CHECK-NEXT: ret void
+;
+entry:
+ %umax0 = call i32 @llvm.umax.i32(i32 %x0, i32 1)
+ %umax1 = call i32 @llvm.umax.i32(i32 %x1, i32 2)
+ %umax2 = call i32 @llvm.umax.i32(i32 %x2, i32 3)
+ store i32 %umax0, ptr %dst, align 4
+ %p1 = getelementptr i32, ptr %dst, i32 1
+ store i32 %umax1, ptr %p1, align 4
+ %p2 = getelementptr i32, ptr %dst, i32 2
+ store i32 %umax2, ptr %p2, align 4
+ %p3 = getelementptr i32, ptr %dst, i32 3
+ store i32 %x3, ptr %p3, align 4
+ ret void
+}
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/minmax-main-opcode-copyables.ll b/llvm/test/Transforms/SLPVectorizer/X86/minmax-main-opcode-copyables.ll
new file mode 100644
index 0000000000000..43c44cd1df776
--- /dev/null
+++ b/llvm/test/Transforms/SLPVectorizer/X86/minmax-main-opcode-copyables.ll
@@ -0,0 +1,158 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes=slp-vectorizer -slp-threshold=-99999 -S -mtriple=x86_64-unknown-linux-gnu < %s | FileCheck %s
+
+; umax is the main opcode. x2/x3 are copyable and vectorize as umax with 0.
+define void @test_umax(ptr %dst, i32 %x0, i32 %x1, i32 %x2, i32 %x3) {
+; CHECK-LABEL: define void @test_umax(
+; CHECK-SAME: ptr [[DST:%.*]], i32 [[X0:%.*]], i32 [[X1:%.*]], i32 [[X2:%.*]], i32 [[X3:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = insertelement <2 x i32> poison, i32 [[X0]], i64 0
+; CHECK-NEXT: [[TMP1:%.*]] = insertelement <2 x i32> [[TMP0]], i32 [[X1]], i64 1
+; CHECK-NEXT: [[TMP2:%.*]] = call <2 x i32> @llvm.umax.v2i32(<2 x i32> [[TMP1]], <2 x i32> <i32 1, i32 2>)
+; CHECK-NEXT: store <2 x i32> [[TMP2]], ptr [[DST]], align 4
+; CHECK-NEXT: [[P2:%.*]] = getelementptr i32, ptr [[DST]], i32 2
+; CHECK-NEXT: store i32 [[X2]], ptr [[P2]], align 4
+; CHECK-NEXT: [[P3:%.*]] = getelementptr i32, ptr [[DST]], i32 3
+; CHECK-NEXT: store i32 [[X3]], ptr [[P3]], align 4
+; CHECK-NEXT: ret void
+;
+entry:
+ %umax0 = call i32 @llvm.umax.i32(i32 %x0, i32 1)
+ %umax1 = call i32 @llvm.umax.i32(i32 %x1, i32 2)
+ store i32 %umax0, ptr %dst, align 4
+ %p1 = getelementptr i32, ptr %dst, i32 1
+ store i32 %umax1, ptr %p1, align 4
+ %p2 = getelementptr i32, ptr %dst, i32 2
+ store i32 %x2, ptr %p2, align 4
+ %p3 = getelementptr i32, ptr %dst, i32 3
+ store i32 %x3, ptr %p3, align 4
+ ret void
+}
+
+; umin is the main opcode. x2/x3 are copyable and vectorize as umin with -1
+; (all-ones), the identity for umin.
+define void @test_umin(ptr %dst, i32 %x0, i32 %x1, i32 %x2, i32 %x3) {
+; CHECK-LABEL: define void @test_umin(
+; CHECK-SAME: ptr [[DST:%.*]], i32 [[X0:%.*]], i32 [[X1:%.*]], i32 [[X2:%.*]], i32 [[X3:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = insertelement <2 x i32> poison, i32 [[X0]], i64 0
+; CHECK-NEXT: [[TMP1:%.*]] = insertelement <2 x i32> [[TMP0]], i32 [[X1]], i64 1
+; CHECK-NEXT: [[TMP2:%.*]] = call <2 x i32> @llvm.umin.v2i32(<2 x i32> [[TMP1]], <2 x i32> <i32 1, i32 2>)
+; CHECK-NEXT: store <2 x i32> [[TMP2]], ptr [[DST]], align 4
+; CHECK-NEXT: [[P2:%.*]] = getelementptr i32, ptr [[DST]], i32 2
+; CHECK-NEXT: store i32 [[X2]], ptr [[P2]], align 4
+; CHECK-NEXT: [[P3:%.*]] = getelementptr i32, ptr [[DST]], i32 3
+; CHECK-NEXT: store i32 [[X3]], ptr [[P3]], align 4
+; CHECK-NEXT: ret void
+;
+entry:
+ %umin0 = call i32 @llvm.umin.i32(i32 %x0, i32 1)
+ %umin1 = call i32 @llvm.umin.i32(i32 %x1, i32 2)
+ store i32 %umin0, ptr %dst, align 4
+ %p1 = getelementptr i32, ptr %dst, i32 1
+ store i32 %umin1, ptr %p1, align 4
+ %p2 = getelementptr i32, ptr %dst, i32 2
+ store i32 %x2, ptr %p2, align 4
+ %p3 = getelementptr i32, ptr %dst, i32 3
+ store i32 %x3, ptr %p3, align 4
+ ret void
+}
+
+; smax is the main opcode. x2/x3 are copyable and vectorize as smax with
+; -2147483648 (signed min), the identity for smax.
+define void @test_smax(ptr %dst, i32 %x0, i32 %x1, i32 %x2, i32 %x3) {
+; CHECK-LABEL: define void @test_smax(
+; CHECK-SAME: ptr [[DST:%.*]], i32 [[X0:%.*]], i32 [[X1:%.*]], i32 [[X2:%.*]], i32 [[X3:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = insertelement <2 x i32> poison, i32 [[X0]], i64 0
+; CHECK-NEXT: [[TMP1:%.*]] = insertelement <2 x i32> [[TMP0]], i32 [[X1]], i64 1
+; CHECK-NEXT: [[TMP2:%.*]] = call <2 x i32> @llvm.smax.v2i32(<2 x i32> [[TMP1]], <2 x i32> <i32 1, i32 2>)
+; CHECK-NEXT: store <2 x i32> [[TMP2]], ptr [[DST]], align 4
+; CHECK-NEXT: [[P2:%.*]] = getelementptr i32, ptr [[DST]], i32 2
+; CHECK-NEXT: store i32 [[X2]], ptr [[P2]], align 4
+; CHECK-NEXT: [[P3:%.*]] = getelementptr i32, ptr [[DST]], i32 3
+; CHECK-NEXT: store i32 [[X3]], ptr [[P3]], align 4
+; CHECK-NEXT: ret void
+;
+entry:
+ %smax0 = call i32 @llvm.smax.i32(i32 %x0, i32 1)
+ %smax1 = call i32 @llvm.smax.i32(i32 %x1, i32 2)
+ store i32 %smax0, ptr %dst, align 4
+ %p1 = getelementptr i32, ptr %dst, i32 1
+ store i32 %smax1, ptr %p1, align 4
+ %p2 = getelementptr i32, ptr %dst, i32 2
+ store i32 %x2, ptr %p2, align 4
+ %p3 = getelementptr i32, ptr %dst, i32 3
+ store i32 %x3, ptr %p3, align 4
+ ret void
+}
+
+; smin is the main opcode. x2/x3 are copyable and vectorize as smin with
+; 2147483647 (signed max), the identity for smin.
+define void @test_smin(ptr %dst, i32 %x0, i32 %x1, i32 %x2, i32 %x3) {
+; CHECK-LABEL: define void @test_smin(
+; CHECK-SAME: ptr [[DST:%.*]], i32 [[X0:%.*]], i32 [[X1:%.*]], i32 [[X2:%.*]], i32 [[X3:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = insertelement <2 x i32> poison, i32 [[X0]], i64 0
+; CHECK-NEXT: [[TMP1:%.*]] = insertelement <2 x i32> [[TMP0]], i32 [[X1]], i64 1
+; CHECK-NEXT: [[TMP2:%.*]] = call <2 x i32> @llvm.smin.v2i32(<2 x i32> [[TMP1]], <2 x i32> <i32 1, i32 2>)
+; CHECK-NEXT: store <2 x i32> [[TMP2]], ptr [[DST]], align 4
+; CHECK-NEXT: [[P2:%.*]] = getelementptr i32, ptr [[DST]], i32 2
+; CHECK-NEXT: store i32 [[X2]], ptr [[P2]], align 4
+; CHECK-NEXT: [[P3:%.*]] = getelementptr i32, ptr [[DST]], i32 3
+; CHECK-NEXT: store i32 [[X3]], ptr [[P3]], align 4
+; CHECK-NEXT: ret void
+;
+entry:
+ %smin0 = call i32 @llvm.smin.i32(i32 %x0, i32 1)
+ %smin1 = call i32 @llvm.smin.i32(i32 %x1, i32 2)
+ store i32 %smin0, ptr %dst, align 4
+ %p1 = getelementptr i32, ptr %dst, i32 1
+ store i32 %smin1, ptr %p1, align 4
+ %p2 = getelementptr i32, ptr %dst, i32 2
+ store i32 %x2, ptr %p2, align 4
+ %p3 = getelementptr i32, ptr %dst, i32 3
+ store i32 %x3, ptr %p3, align 4
+ ret void
+}
+
+; smax main opcode with copyables and trunc users, to exercise the
+; minbitwidth (collectValuesToDemote) copyable path for min/max intrinsics.
+define void @test_minbitwidth_trunc(ptr %dst, ptr %src) {
+; CHECK-LABEL: define void @test_minbitwidth_trunc(
+; CHECK-SAME: ptr [[DST:%.*]], ptr [[SRC:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[SRC]], align 4
+; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[SRC]], align 4
+; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[SRC]], align 4
+; CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[SRC]], align 4
+; CHECK-NEXT: [[TMP4:%.*]] = insertelement <2 x i32> poison, i32 [[TMP0]], i64 0
+; CHECK-NEXT: [[TMP8:%.*]] = insertelement <2 x i32> [[TMP4]], i32 [[TMP1]], i64 1
+; CHECK-NEXT: [[TMP10:%.*]] = call <2 x i32> @llvm.smax.v2i32(<2 x i32> [[TMP8]], <2 x i32> <i32 100, i32 200>)
+; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <2 x i32> [[TMP10]], <2 x i32> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
+; CHECK-NEXT: [[TMP11:%.*]] = insertelement <4 x i32> [[TMP5]], i32 [[TMP2]], i64 2
+; CHECK-NEXT: [[TMP7:%.*]] = insertelement <4 x i32> [[TMP11]], i32 [[TMP3]], i64 3
+; CHECK-NEXT: [[TMP9:%.*]] = trunc <4 x i32> [[TMP7]] to <4 x i16>
+; CHECK-NEXT: store <4 x i16> [[TMP9]], ptr [[DST]], align 2
+; CHECK-NEXT: ret void
+;
+entry:
+ %0 = load i32, ptr %src, align 4
+ %1 = load i32, ptr %src, align 4
+ %2 = load i32, ptr %src, align 4
+ %3 = load i32, ptr %src, align 4
+ %smax0 = call i32 @llvm.smax.i32(i32 %0, i32 100)
+ %smax1 = call i32 @llvm.smax.i32(i32 %1, i32 200)
+ %trunc0 = trunc i32 %smax0 to i16
+ %trunc1 = trunc i32 %smax1 to i16
+ %trunc2 = trunc i32 %2 to i16
+ %trunc3 = trunc i32 %3 to i16
+ store i16 %trunc0, ptr %dst, align 2
+ %p1 = getelementptr i16, ptr %dst, i32 1
+ store i16 %trunc1, ptr %p1, align 2
+ %p2 = getelementptr i16, ptr %dst, i32 2
+ store i16 %trunc2, ptr %p2, align 2
+ %p3 = getelementptr i16, ptr %dst, i32 3
+ store i16 %trunc3, ptr %p3, align 2
+ ret void
+}
More information about the llvm-commits
mailing list