[llvm] [AArch64] Update cttz cost (PR #214003)

via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 4 09:51:27 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-aarch64

Author: David Green (davemgreen)

<details>
<summary>Changes</summary>

The previous scalar cttz cost was 1, even though we generate a rbit + clz (without cssc which adds a ctz instruction). Add some costs for scalar instructions whilst trying to keep the vector costs mostly the same.

---
Full diff: https://github.com/llvm/llvm-project/pull/214003.diff


2 Files Affected:

- (modified) llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp (+25-6) 
- (modified) llvm/test/Analysis/CostModel/AArch64/cttz.ll (+21-16) 


``````````diff
diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index 7b1c603d4134c..e08ed336ccfe2 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -1163,12 +1163,31 @@ AArch64TTIImpl::getIntrinsicInstrCost(const IntrinsicCostAttributes &ICA,
     break;
   }
   case Intrinsic::cttz: {
-    auto LT = getTypeLegalizationCost(ICA.getArgTypes()[0]);
-    if (LT.second == MVT::v8i8 || LT.second == MVT::v16i8)
-      return LT.first * 2;
-    if (LT.second == MVT::v4i16 || LT.second == MVT::v8i16 ||
-        LT.second == MVT::v2i32 || LT.second == MVT::v4i32)
-      return LT.first * 3;
+    auto LT = getTypeLegalizationCost(RetTy);
+    if (LT.second == MVT::i32 || LT.second == MVT::i64) {
+      // Extra cost for and mask of smaller types
+      InstructionCost ExtraCost =
+          LT.second.getSizeInBits() > RetTy->getScalarSizeInBits() ? 1 : 0;
+      // And combine larger sizes to i64 with cmp+add+csel
+      if (LT.second.getSizeInBits() < RetTy->getScalarSizeInBits())
+        ExtraCost += (LT.first - 1) * 3;
+      // Basic cost is rbit+clz or ctz.
+      return LT.first * (ST->hasCSSC() ? 1 : 2) + ExtraCost;
+    }
+
+    static const CostTblEntry BaseCostTbl[] = {
+        {Intrinsic::cttz, MVT::v8i8, 2}, // rbit+clz
+        {Intrinsic::cttz, MVT::v16i8, 2},
+        {Intrinsic::cttz, MVT::v4i16, 3}, // rev16+rbit+clz
+        {Intrinsic::cttz, MVT::v8i16, 3},
+        {Intrinsic::cttz, MVT::v2i32, 3},
+        {Intrinsic::cttz, MVT::v4i32, 3},
+        {Intrinsic::cttz, MVT::v1i64, 6}, // add+bic+cnt+reduce
+        {Intrinsic::cttz, MVT::v2i64, 6}};
+    const auto *Entry =
+        CostTableLookup(BaseCostTbl, Intrinsic::cttz, LT.second);
+    if (Entry)
+      return LT.first * Entry->Cost;
     break;
   }
   case Intrinsic::experimental_cttz_elts: {
diff --git a/llvm/test/Analysis/CostModel/AArch64/cttz.ll b/llvm/test/Analysis/CostModel/AArch64/cttz.ll
index 68b69855cd247..a7e7233313d90 100644
--- a/llvm/test/Analysis/CostModel/AArch64/cttz.ll
+++ b/llvm/test/Analysis/CostModel/AArch64/cttz.ll
@@ -5,19 +5,30 @@
 target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
 
 define void @scalar() {
-; CHECK-LABEL: 'scalar'
-; CHECK-NEXT:  Cost Model: Found costs of 1 for: %I8 = call i8 @llvm.cttz.i8(i8 undef, i1 false)
-; CHECK-NEXT:  Cost Model: Found costs of 1 for: %I16 = call i16 @llvm.cttz.i16(i16 undef, i1 false)
-; CHECK-NEXT:  Cost Model: Found costs of 1 for: %I32 = call i32 @llvm.cttz.i32(i32 undef, i1 false)
-; CHECK-NEXT:  Cost Model: Found costs of 1 for: %I64 = call i64 @llvm.cttz.i64(i64 undef, i1 false)
-; CHECK-NEXT:  Cost Model: Found costs of 1 for: %I128 = call i128 @llvm.cttz.i128(i128 undef, i1 false)
-; CHECK-NEXT:  Cost Model: Found costs of RThru:0 CodeSize:1 Lat:1 SizeLat:1 for: ret void
+; CHECK-BASE-LABEL: 'scalar'
+; CHECK-BASE-NEXT:  Cost Model: Found costs of 3 for: %I8 = call i8 @llvm.cttz.i8(i8 undef, i1 false)
+; CHECK-BASE-NEXT:  Cost Model: Found costs of 3 for: %I16 = call i16 @llvm.cttz.i16(i16 undef, i1 false)
+; CHECK-BASE-NEXT:  Cost Model: Found costs of 2 for: %I32 = call i32 @llvm.cttz.i32(i32 undef, i1 false)
+; CHECK-BASE-NEXT:  Cost Model: Found costs of 2 for: %I64 = call i64 @llvm.cttz.i64(i64 undef, i1 false)
+; CHECK-BASE-NEXT:  Cost Model: Found costs of 7 for: %I128 = call i128 @llvm.cttz.i128(i128 undef, i1 false)
+; CHECK-BASE-NEXT:  Cost Model: Found costs of 17 for: %V2I128 = call <2 x i128> @llvm.cttz.v2i128(<2 x i128> undef, i1 false)
+; CHECK-BASE-NEXT:  Cost Model: Found costs of RThru:0 CodeSize:1 Lat:1 SizeLat:1 for: ret void
+;
+; CHECK-CSSC-LABEL: 'scalar'
+; CHECK-CSSC-NEXT:  Cost Model: Found costs of 2 for: %I8 = call i8 @llvm.cttz.i8(i8 undef, i1 false)
+; CHECK-CSSC-NEXT:  Cost Model: Found costs of 2 for: %I16 = call i16 @llvm.cttz.i16(i16 undef, i1 false)
+; CHECK-CSSC-NEXT:  Cost Model: Found costs of 1 for: %I32 = call i32 @llvm.cttz.i32(i32 undef, i1 false)
+; CHECK-CSSC-NEXT:  Cost Model: Found costs of 1 for: %I64 = call i64 @llvm.cttz.i64(i64 undef, i1 false)
+; CHECK-CSSC-NEXT:  Cost Model: Found costs of 5 for: %I128 = call i128 @llvm.cttz.i128(i128 undef, i1 false)
+; CHECK-CSSC-NEXT:  Cost Model: Found costs of 13 for: %V2I128 = call <2 x i128> @llvm.cttz.v2i128(<2 x i128> undef, i1 false)
+; CHECK-CSSC-NEXT:  Cost Model: Found costs of RThru:0 CodeSize:1 Lat:1 SizeLat:1 for: ret void
 ;
   %I8 = call i8 @llvm.cttz.i8(i8 undef, i1 false)
   %I16 = call i16 @llvm.cttz.i16(i16 undef, i1 false)
   %I32 = call i32 @llvm.cttz.i32(i32 undef, i1 false)
   %I64 = call i64 @llvm.cttz.i64(i64 undef, i1 false)
   %I128 = call i128 @llvm.cttz.i128(i128 undef, i1 false)
+  %V2I128 = call <2 x i128> @llvm.cttz.v2i128(<2 x i128> undef, i1 false)
   ret void
 }
 
@@ -38,10 +49,9 @@ define void @vec() {
 ; CHECK-NEXT:  Cost Model: Found costs of 3 for: %V4I32 = call <4 x i32> @llvm.cttz.v4i32(<4 x i32> undef, i1 false)
 ; CHECK-NEXT:  Cost Model: Found costs of 6 for: %V8I32 = call <8 x i32> @llvm.cttz.v8i32(<8 x i32> undef, i1 false)
 ; CHECK-NEXT:  Cost Model: Found costs of 12 for: %V16I32 = call <16 x i32> @llvm.cttz.v16i32(<16 x i32> undef, i1 false)
-; CHECK-NEXT:  Cost Model: Found costs of RThru:6 CodeSize:4 Lat:6 SizeLat:6 for: %V2I64 = call <2 x i64> @llvm.cttz.v2i64(<2 x i64> undef, i1 false)
-; CHECK-NEXT:  Cost Model: Found costs of RThru:12 CodeSize:8 Lat:12 SizeLat:12 for: %V4I64 = call <4 x i64> @llvm.cttz.v4i64(<4 x i64> undef, i1 false)
-; CHECK-NEXT:  Cost Model: Found costs of RThru:24 CodeSize:16 Lat:24 SizeLat:24 for: %V8I64 = call <8 x i64> @llvm.cttz.v8i64(<8 x i64> undef, i1 false)
-; CHECK-NEXT:  Cost Model: Found costs of 8 for: %V2I128 = call <2 x i128> @llvm.cttz.v2i128(<2 x i128> undef, i1 false)
+; CHECK-NEXT:  Cost Model: Found costs of 6 for: %V2I64 = call <2 x i64> @llvm.cttz.v2i64(<2 x i64> undef, i1 false)
+; CHECK-NEXT:  Cost Model: Found costs of 12 for: %V4I64 = call <4 x i64> @llvm.cttz.v4i64(<4 x i64> undef, i1 false)
+; CHECK-NEXT:  Cost Model: Found costs of 24 for: %V8I64 = call <8 x i64> @llvm.cttz.v8i64(<8 x i64> undef, i1 false)
 ; CHECK-NEXT:  Cost Model: Found costs of RThru:0 CodeSize:1 Lat:1 SizeLat:1 for: ret void
 ;
   %V2I8  = call <2 x i8> @llvm.cttz.v2i8(<2 x i8> undef, i1 false)
@@ -66,10 +76,5 @@ define void @vec() {
   %V4I64 = call <4 x i64> @llvm.cttz.v4i64(<4 x i64> undef, i1 false)
   %V8I64 = call <8 x i64> @llvm.cttz.v8i64(<8 x i64> undef, i1 false)
 
-  %V2I128 = call <2 x i128> @llvm.cttz.v2i128(<2 x i128> undef, i1 false)
-
   ret void
 }
-;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
-; CHECK-BASE: {{.*}}
-; CHECK-CSSC: {{.*}}

``````````

</details>


https://github.com/llvm/llvm-project/pull/214003


More information about the llvm-commits mailing list