[llvm] [AArch64][CostModel] Model sve costs for ctpop (PR #192428)

Yashwant Singh via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 16 03:51:52 PDT 2026


https://github.com/yashssh created https://github.com/llvm/llvm-project/pull/192428

Targets supporting sve prefer sve for ctpop with fixed length vectors.
However, the cost model reports same costs for both neon and sve targets 
https://godbolt.org/z/44hYhWPhx

>From a8df554efcb6691e8515656ab6fa5bb10fbc9b49 Mon Sep 17 00:00:00 2001
From: Yashwant Singh <yashwants at nvidia.com>
Date: Tue, 14 Apr 2026 23:33:37 -0700
Subject: [PATCH 1/3] [NFC]Pre commit test for ctpop sve

---
 .../CostModel/AArch64/ctpop-neon-sve.ll       | 97 +++++++++++++++++++
 1 file changed, 97 insertions(+)
 create mode 100644 llvm/test/Analysis/CostModel/AArch64/ctpop-neon-sve.ll

diff --git a/llvm/test/Analysis/CostModel/AArch64/ctpop-neon-sve.ll b/llvm/test/Analysis/CostModel/AArch64/ctpop-neon-sve.ll
new file mode 100644
index 0000000000000..e309425b10e7a
--- /dev/null
+++ b/llvm/test/Analysis/CostModel/AArch64/ctpop-neon-sve.ll
@@ -0,0 +1,97 @@
+; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py
+; RUN: opt < %s -passes='print<cost-model>' -disable-output 2>&1 | FileCheck %s --check-prefix=NEON
+; RUN: opt < %s -passes='print<cost-model>' -disable-output -mattr=+sve 2>&1 | FileCheck %s --check-prefix=SVE
+
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32"
+target triple = "aarch64-unknown-linux-gnu"
+
+define <2 x i64> @test_ctpop_v2i64(<2 x i64> %a) {
+; NEON-LABEL: 'test_ctpop_v2i64'
+; NEON-NEXT:  Cost Model: Found an estimated cost of 4 for instruction: %ctpop = call <2 x i64> @llvm.ctpop.v2i64(<2 x i64> %a)
+; NEON-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret <2 x i64> %ctpop
+;
+; SVE-LABEL: 'test_ctpop_v2i64'
+; SVE-NEXT:  Cost Model: Found an estimated cost of 4 for instruction: %ctpop = call <2 x i64> @llvm.ctpop.v2i64(<2 x i64> %a)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret <2 x i64> %ctpop
+;
+  %ctpop = call <2 x i64> @llvm.ctpop.v2i64(<2 x i64> %a)
+  ret <2 x i64> %ctpop
+}
+
+define <4 x i32> @test_ctpop_v4i32(<4 x i32> %a) {
+; NEON-LABEL: 'test_ctpop_v4i32'
+; NEON-NEXT:  Cost Model: Found an estimated cost of 3 for instruction: %ctpop = call <4 x i32> @llvm.ctpop.v4i32(<4 x i32> %a)
+; NEON-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret <4 x i32> %ctpop
+;
+; SVE-LABEL: 'test_ctpop_v4i32'
+; SVE-NEXT:  Cost Model: Found an estimated cost of 3 for instruction: %ctpop = call <4 x i32> @llvm.ctpop.v4i32(<4 x i32> %a)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret <4 x i32> %ctpop
+;
+  %ctpop = call <4 x i32> @llvm.ctpop.v4i32(<4 x i32> %a)
+  ret <4 x i32> %ctpop
+}
+
+define <8 x i16> @test_ctpop_v8i16(<8 x i16> %a) {
+; NEON-LABEL: 'test_ctpop_v8i16'
+; NEON-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %ctpop = call <8 x i16> @llvm.ctpop.v8i16(<8 x i16> %a)
+; NEON-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret <8 x i16> %ctpop
+;
+; SVE-LABEL: 'test_ctpop_v8i16'
+; SVE-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %ctpop = call <8 x i16> @llvm.ctpop.v8i16(<8 x i16> %a)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret <8 x i16> %ctpop
+;
+  %ctpop = call <8 x i16> @llvm.ctpop.v8i16(<8 x i16> %a)
+  ret <8 x i16> %ctpop
+}
+
+define <16 x i8> @test_ctpop_v16i8(<16 x i8> %a) {
+; NEON-LABEL: 'test_ctpop_v16i8'
+; NEON-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: %ctpop = call <16 x i8> @llvm.ctpop.v16i8(<16 x i8> %a)
+; NEON-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret <16 x i8> %ctpop
+;
+; SVE-LABEL: 'test_ctpop_v16i8'
+; SVE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: %ctpop = call <16 x i8> @llvm.ctpop.v16i8(<16 x i8> %a)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret <16 x i8> %ctpop
+;
+  %ctpop = call <16 x i8> @llvm.ctpop.v16i8(<16 x i8> %a)
+  ret <16 x i8> %ctpop
+}
+
+define <2 x i32> @test_ctpop_v2i32(<2 x i32> %a) {
+; NEON-LABEL: 'test_ctpop_v2i32'
+; NEON-NEXT:  Cost Model: Found an estimated cost of 3 for instruction: %ctpop = call <2 x i32> @llvm.ctpop.v2i32(<2 x i32> %a)
+; NEON-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret <2 x i32> %ctpop
+;
+; SVE-LABEL: 'test_ctpop_v2i32'
+; SVE-NEXT:  Cost Model: Found an estimated cost of 3 for instruction: %ctpop = call <2 x i32> @llvm.ctpop.v2i32(<2 x i32> %a)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret <2 x i32> %ctpop
+;
+  %ctpop = call <2 x i32> @llvm.ctpop.v2i32(<2 x i32> %a)
+  ret <2 x i32> %ctpop
+}
+
+define <4 x i16> @test_ctpop_v4i16(<4 x i16> %a) {
+; NEON-LABEL: 'test_ctpop_v4i16'
+; NEON-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %ctpop = call <4 x i16> @llvm.ctpop.v4i16(<4 x i16> %a)
+; NEON-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret <4 x i16> %ctpop
+;
+; SVE-LABEL: 'test_ctpop_v4i16'
+; SVE-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %ctpop = call <4 x i16> @llvm.ctpop.v4i16(<4 x i16> %a)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret <4 x i16> %ctpop
+;
+  %ctpop = call <4 x i16> @llvm.ctpop.v4i16(<4 x i16> %a)
+  ret <4 x i16> %ctpop
+}
+
+define <8 x i8> @test_ctpop_v8i8(<8 x i8> %a) {
+; NEON-LABEL: 'test_ctpop_v8i8'
+; NEON-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: %ctpop = call <8 x i8> @llvm.ctpop.v8i8(<8 x i8> %a)
+; NEON-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret <8 x i8> %ctpop
+;
+; SVE-LABEL: 'test_ctpop_v8i8'
+; SVE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: %ctpop = call <8 x i8> @llvm.ctpop.v8i8(<8 x i8> %a)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret <8 x i8> %ctpop
+;
+  %ctpop = call <8 x i8> @llvm.ctpop.v8i8(<8 x i8> %a)
+  ret <8 x i8> %ctpop
+}

>From 1bfccf9f4d4250a756269fa94afdd767c3fac1c4 Mon Sep 17 00:00:00 2001
From: Yashwant Singh <yashwants at nvidia.com>
Date: Tue, 14 Apr 2026 23:33:51 -0700
Subject: [PATCH 2/3] [AArch64][CostModel] Model sve costs for ctpop

Targets supporting sve prefer sve for ctop intrinsics with fixed length vectors.
However, the cost model reports same costs for both neon and sve targets https://godbolt.org/z/44hYhWPhx
---
 .../AArch64/AArch64TargetTransformInfo.cpp    | 23 +++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index 734339e5c7a05..c19717861b40e 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -812,9 +812,32 @@ AArch64TTIImpl::getIntrinsicInstrCost(const IntrinsicCostAttributes &ICA,
         {ISD::CTPOP, MVT::v4i16, 2},
         {ISD::CTPOP, MVT::v8i8,  1},
         {ISD::CTPOP, MVT::i32,   5},
+        // SVE types (For targets that override NEON for fixed length vectors)
+        {ISD::CTPOP, MVT::nxv2i64, 2},
+        {ISD::CTPOP, MVT::nxv4i32, 2},
+        {ISD::CTPOP, MVT::nxv8i16, 1},
+        {ISD::CTPOP, MVT::nxv16i8, 1},
+        {ISD::CTPOP, MVT::nxv2i32, 2},
+        {ISD::CTPOP, MVT::nxv4i16, 2},
+        {ISD::CTPOP, MVT::nxv8i8, 1},
     };
     auto LT = getTypeLegalizationCost(RetTy);
     MVT MTy = LT.second;
+
+    // When SVE is available, fixed-length vector ctpop is lowered using SVE
+    // (useSVEForFixedLengthVectorVT with OverrideNEON=true), so look up the
+    // scalable equivalent type for accurate costing.
+    if (ST->isSVEorStreamingSVEAvailable() && MTy.isFixedLengthVector()) {
+      EVT ScalableVT = MVT::getScalableVectorVT(
+          MTy.getVectorElementType(),
+          MTy.is128BitVector()
+              ? 128 / MTy.getVectorElementType().getSizeInBits()
+              : 64 / MTy.getVectorElementType().getSizeInBits());
+      if (const auto *Entry = CostTableLookup(CtpopCostTbl, ISD::CTPOP,
+                                              ScalableVT.getSimpleVT()))
+        return LT.first * Entry->Cost;
+    }
+
     if (const auto *Entry = CostTableLookup(CtpopCostTbl, ISD::CTPOP, MTy)) {
       // Extra cost of +1 when illegal vector types are legalized by promoting
       // the integer type.

>From 4c74fed163524ed22a6da774525941614137359f Mon Sep 17 00:00:00 2001
From: Yashwant Singh <yashwants at nvidia.com>
Date: Wed, 15 Apr 2026 03:57:46 -0700
Subject: [PATCH 3/3] [NFC] update test

---
 llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp | 6 +++---
 llvm/test/Analysis/CostModel/AArch64/ctpop-neon-sve.ll | 8 ++++----
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index c19717861b40e..0f940191c15b4 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -807,11 +807,11 @@ AArch64TTIImpl::getIntrinsicInstrCost(const IntrinsicCostAttributes &ICA,
         {ISD::CTPOP, MVT::v4i32, 3},
         {ISD::CTPOP, MVT::v8i16, 2},
         {ISD::CTPOP, MVT::v16i8, 1},
-        {ISD::CTPOP, MVT::i64,   4},
+        {ISD::CTPOP, MVT::i64, 4},
         {ISD::CTPOP, MVT::v2i32, 3},
         {ISD::CTPOP, MVT::v4i16, 2},
-        {ISD::CTPOP, MVT::v8i8,  1},
-        {ISD::CTPOP, MVT::i32,   5},
+        {ISD::CTPOP, MVT::v8i8, 1},
+        {ISD::CTPOP, MVT::i32, 5},
         // SVE types (For targets that override NEON for fixed length vectors)
         {ISD::CTPOP, MVT::nxv2i64, 2},
         {ISD::CTPOP, MVT::nxv4i32, 2},
diff --git a/llvm/test/Analysis/CostModel/AArch64/ctpop-neon-sve.ll b/llvm/test/Analysis/CostModel/AArch64/ctpop-neon-sve.ll
index e309425b10e7a..bc62baea96d5f 100644
--- a/llvm/test/Analysis/CostModel/AArch64/ctpop-neon-sve.ll
+++ b/llvm/test/Analysis/CostModel/AArch64/ctpop-neon-sve.ll
@@ -11,7 +11,7 @@ define <2 x i64> @test_ctpop_v2i64(<2 x i64> %a) {
 ; NEON-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret <2 x i64> %ctpop
 ;
 ; SVE-LABEL: 'test_ctpop_v2i64'
-; SVE-NEXT:  Cost Model: Found an estimated cost of 4 for instruction: %ctpop = call <2 x i64> @llvm.ctpop.v2i64(<2 x i64> %a)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %ctpop = call <2 x i64> @llvm.ctpop.v2i64(<2 x i64> %a)
 ; SVE-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret <2 x i64> %ctpop
 ;
   %ctpop = call <2 x i64> @llvm.ctpop.v2i64(<2 x i64> %a)
@@ -24,7 +24,7 @@ define <4 x i32> @test_ctpop_v4i32(<4 x i32> %a) {
 ; NEON-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret <4 x i32> %ctpop
 ;
 ; SVE-LABEL: 'test_ctpop_v4i32'
-; SVE-NEXT:  Cost Model: Found an estimated cost of 3 for instruction: %ctpop = call <4 x i32> @llvm.ctpop.v4i32(<4 x i32> %a)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %ctpop = call <4 x i32> @llvm.ctpop.v4i32(<4 x i32> %a)
 ; SVE-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret <4 x i32> %ctpop
 ;
   %ctpop = call <4 x i32> @llvm.ctpop.v4i32(<4 x i32> %a)
@@ -37,7 +37,7 @@ define <8 x i16> @test_ctpop_v8i16(<8 x i16> %a) {
 ; NEON-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret <8 x i16> %ctpop
 ;
 ; SVE-LABEL: 'test_ctpop_v8i16'
-; SVE-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %ctpop = call <8 x i16> @llvm.ctpop.v8i16(<8 x i16> %a)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: %ctpop = call <8 x i16> @llvm.ctpop.v8i16(<8 x i16> %a)
 ; SVE-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret <8 x i16> %ctpop
 ;
   %ctpop = call <8 x i16> @llvm.ctpop.v8i16(<8 x i16> %a)
@@ -63,7 +63,7 @@ define <2 x i32> @test_ctpop_v2i32(<2 x i32> %a) {
 ; NEON-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret <2 x i32> %ctpop
 ;
 ; SVE-LABEL: 'test_ctpop_v2i32'
-; SVE-NEXT:  Cost Model: Found an estimated cost of 3 for instruction: %ctpop = call <2 x i32> @llvm.ctpop.v2i32(<2 x i32> %a)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %ctpop = call <2 x i32> @llvm.ctpop.v2i32(<2 x i32> %a)
 ; SVE-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret <2 x i32> %ctpop
 ;
   %ctpop = call <2 x i32> @llvm.ctpop.v2i32(<2 x i32> %a)



More information about the llvm-commits mailing list