[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