[llvm] [VectorCombine] Use TCK_CodeSize for size-optimized functions (PR #202207)

via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 12 08:50:05 PDT 2026


https://github.com/Michael-Chen-NJU updated https://github.com/llvm/llvm-project/pull/202207

>From 212bc3541be4fba08841ae8b5beb812d9248526e Mon Sep 17 00:00:00 2001
From: Michael-Chen-NJU <221250121 at smail.nju.edu.cn>
Date: Fri, 5 Jun 2026 11:46:41 +0800
Subject: [PATCH 1/2] [VectorCombine] Use TCK_CodeSize for size-optimized
 functions

Select TCK_CodeSize when the function has optsize or minsize, while retaining TCK_RecipThroughput for the default optimization mode.

This makes VectorCombine's profitability decisions reflect the size optimization requested by -Os and -Oz. Add an X86 regression test where the code-size model avoids a throughput-oriented sign-bit reduction fold and produces smaller code.
---
 .../Transforms/Vectorize/VectorCombine.cpp    |  5 +-
 .../fold-signbit-reduction-cmp-codesize.ll    | 48 +++++++++++++++++++
 2 files changed, 51 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/Transforms/VectorCombine/X86/fold-signbit-reduction-cmp-codesize.ll

diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index fc6a3c26708d3..065072a8aa1e9 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -6350,8 +6350,9 @@ PreservedAnalyses VectorCombinePass::run(Function &F,
   DominatorTree &DT = FAM.getResult<DominatorTreeAnalysis>(F);
   AAResults &AA = FAM.getResult<AAManager>(F);
   const DataLayout *DL = &F.getDataLayout();
-  VectorCombine Combiner(F, TTI, DT, AA, AC, DL, TTI::TCK_RecipThroughput,
-                         TryEarlyFoldsOnly);
+  TTI::TargetCostKind CostKind =
+      F.hasOptSize() ? TTI::TCK_CodeSize : TTI::TCK_RecipThroughput;
+  VectorCombine Combiner(F, TTI, DT, AA, AC, DL, CostKind, TryEarlyFoldsOnly);
   if (!Combiner.run())
     return PreservedAnalyses::all();
   PreservedAnalyses PA;
diff --git a/llvm/test/Transforms/VectorCombine/X86/fold-signbit-reduction-cmp-codesize.ll b/llvm/test/Transforms/VectorCombine/X86/fold-signbit-reduction-cmp-codesize.ll
new file mode 100644
index 0000000000000..62eb9bd8627a9
--- /dev/null
+++ b/llvm/test/Transforms/VectorCombine/X86/fold-signbit-reduction-cmp-codesize.ll
@@ -0,0 +1,48 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
+; RUN: opt < %s -passes=vector-combine -S -mtriple=x86_64-- -mattr=+avx2 | FileCheck %s
+
+; The throughput cost model folds this sign-bit reduction to a umax reduction.
+; The code-size cost model used for optsize and minsize functions preserves the
+; or reduction, which lowers to smaller code on X86.
+
+define i1 @throughput(<4 x i32> %x) {
+; CHECK-LABEL: define i1 @throughput(
+; CHECK-SAME: <4 x i32> [[X:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.vector.reduce.umax.v4i32(<4 x i32> [[X]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[TMP1]], -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = lshr <4 x i32> %x, splat (i32 31)
+  %red = call i32 @llvm.vector.reduce.or.v4i32(<4 x i32> %shr)
+  %cmp = icmp eq i32 %red, 0
+  ret i1 %cmp
+}
+
+define i1 @optsize(<4 x i32> %x) #0 {
+; CHECK-LABEL: define i1 @optsize(
+; CHECK-SAME: <4 x i32> [[X:%.*]]) #[[ATTR1:[0-9]+]] {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.vector.reduce.or.v4i32(<4 x i32> [[X]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[TMP1]], -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = lshr <4 x i32> %x, splat (i32 31)
+  %red = call i32 @llvm.vector.reduce.or.v4i32(<4 x i32> %shr)
+  %cmp = icmp eq i32 %red, 0
+  ret i1 %cmp
+}
+
+define i1 @minsize(<4 x i32> %x) #1 {
+; CHECK-LABEL: define i1 @minsize(
+; CHECK-SAME: <4 x i32> [[X:%.*]]) #[[ATTR2:[0-9]+]] {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.vector.reduce.or.v4i32(<4 x i32> [[X]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[TMP1]], -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = lshr <4 x i32> %x, splat (i32 31)
+  %red = call i32 @llvm.vector.reduce.or.v4i32(<4 x i32> %shr)
+  %cmp = icmp eq i32 %red, 0
+  ret i1 %cmp
+}
+
+attributes #0 = { optsize }
+attributes #1 = { minsize optsize }

>From 3eef7db7a8d3182feb961e2ad10258fd6477f0fd Mon Sep 17 00:00:00 2001
From: Michael-Chen-NJU <2802328816 at qq.com>
Date: Mon, 8 Jun 2026 22:08:36 +0800
Subject: [PATCH 2/2] fixup! [VectorCombine] Use TCK_CodeSize for
 size-optimized functions

---
 .../fold-signbit-reduction-cmp-codesize.ll    | 39 ++++++++++++++++++-
 1 file changed, 37 insertions(+), 2 deletions(-)

diff --git a/llvm/test/Transforms/VectorCombine/X86/fold-signbit-reduction-cmp-codesize.ll b/llvm/test/Transforms/VectorCombine/X86/fold-signbit-reduction-cmp-codesize.ll
index 62eb9bd8627a9..1d3bb36873109 100644
--- a/llvm/test/Transforms/VectorCombine/X86/fold-signbit-reduction-cmp-codesize.ll
+++ b/llvm/test/Transforms/VectorCombine/X86/fold-signbit-reduction-cmp-codesize.ll
@@ -1,9 +1,13 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
-; RUN: opt < %s -passes=vector-combine -S -mtriple=x86_64-- -mattr=+avx2 | FileCheck %s
+; RUN: opt < %s -passes=vector-combine -S -mtriple=x86_64-- -mcpu=x86-64    | FileCheck %s --check-prefixes=CHECK,SSE2
+; RUN: opt < %s -passes=vector-combine -S -mtriple=x86_64-- -mcpu=x86-64-v2 | FileCheck %s --check-prefixes=CHECK,SSE42
+; RUN: opt < %s -passes=vector-combine -S -mtriple=x86_64-- -mcpu=x86-64-v3 | FileCheck %s --check-prefixes=CHECK,AVX2
+; RUN: opt < %s -passes=vector-combine -S -mtriple=x86_64-- -mcpu=x86-64-v4 | FileCheck %s --check-prefixes=CHECK,AVX512
 
 ; The throughput cost model folds this sign-bit reduction to a umax reduction.
 ; The code-size cost model used for optsize and minsize functions preserves the
-; or reduction, which lowers to smaller code on X86.
+; v4i32 or reduction. For v8i16, SSE4.1 makes the umax reduction cheaper, so
+; x86-64-v2 and later fold while baseline x86-64 preserves the or reduction.
 
 define i1 @throughput(<4 x i32> %x) {
 ; CHECK-LABEL: define i1 @throughput(
@@ -44,5 +48,36 @@ define i1 @minsize(<4 x i32> %x) #1 {
   ret i1 %cmp
 }
 
+define i1 @minsize_v8i16(<8 x i16> %x) #1 {
+; SSE2-LABEL: define i1 @minsize_v8i16(
+; SSE2-SAME: <8 x i16> [[X:%.*]]) #[[ATTR2]] {
+; SSE2-NEXT:    [[TMP1:%.*]] = call i16 @llvm.vector.reduce.or.v8i16(<8 x i16> [[X]])
+; SSE2-NEXT:    [[CMP:%.*]] = icmp sgt i16 [[TMP1]], -1
+; SSE2-NEXT:    ret i1 [[CMP]]
+;
+; SSE42-LABEL: define i1 @minsize_v8i16(
+; SSE42-SAME: <8 x i16> [[X:%.*]]) #[[ATTR2]] {
+; SSE42-NEXT:    [[TMP1:%.*]] = call i16 @llvm.vector.reduce.umax.v8i16(<8 x i16> [[X]])
+; SSE42-NEXT:    [[CMP:%.*]] = icmp sgt i16 [[TMP1]], -1
+; SSE42-NEXT:    ret i1 [[CMP]]
+;
+; AVX2-LABEL: define i1 @minsize_v8i16(
+; AVX2-SAME: <8 x i16> [[X:%.*]]) #[[ATTR2]] {
+; AVX2-NEXT:    [[TMP1:%.*]] = call i16 @llvm.vector.reduce.umax.v8i16(<8 x i16> [[X]])
+; AVX2-NEXT:    [[CMP:%.*]] = icmp sgt i16 [[TMP1]], -1
+; AVX2-NEXT:    ret i1 [[CMP]]
+;
+; AVX512-LABEL: define i1 @minsize_v8i16(
+; AVX512-SAME: <8 x i16> [[X:%.*]]) #[[ATTR2]] {
+; AVX512-NEXT:    [[TMP1:%.*]] = call i16 @llvm.vector.reduce.umax.v8i16(<8 x i16> [[X]])
+; AVX512-NEXT:    [[CMP:%.*]] = icmp sgt i16 [[TMP1]], -1
+; AVX512-NEXT:    ret i1 [[CMP]]
+;
+  %shr = lshr <8 x i16> %x, splat (i16 15)
+  %red = call i16 @llvm.vector.reduce.or.v8i16(<8 x i16> %shr)
+  %cmp = icmp eq i16 %red, 0
+  ret i1 %cmp
+}
+
 attributes #0 = { optsize }
 attributes #1 = { minsize optsize }



More information about the llvm-commits mailing list