[llvm-branch-commits] [llvm] [TTI] Add cost for @llvm.mask.beforefirst (PR #212174)

Luke Lau via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Oct 23 06:48:40 PDT 2026


https://github.com/lukel97 updated https://github.com/llvm/llvm-project/pull/212174

>From 66b3fcf9364c6cb1ccf7452205819a7f0a87f027 Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Mon, 20 Jul 2026 22:31:01 +0800
Subject: [PATCH 1/3] Precommit tests

---
 .../CostModel/AArch64/mask-beforefirst.ll     | 44 +++++++++++++++++++
 .../CostModel/RISCV/mask-beforefirst.ll       | 42 ++++++++++++++++++
 2 files changed, 86 insertions(+)
 create mode 100644 llvm/test/Analysis/CostModel/AArch64/mask-beforefirst.ll
 create mode 100644 llvm/test/Analysis/CostModel/RISCV/mask-beforefirst.ll

diff --git a/llvm/test/Analysis/CostModel/AArch64/mask-beforefirst.ll b/llvm/test/Analysis/CostModel/AArch64/mask-beforefirst.ll
new file mode 100644
index 00000000000000..33b71fea896588
--- /dev/null
+++ b/llvm/test/Analysis/CostModel/AArch64/mask-beforefirst.ll
@@ -0,0 +1,44 @@
+; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -passes="print<cost-model>" 2>&1 -disable-output -mtriple=aarch64 -mattr=+sve | FileCheck %s --check-prefix=SVE
+; RUN: opt < %s -passes="print<cost-model>" 2>&1 -disable-output -mtriple=aarch64 | FileCheck %s --check-prefix=NEON
+
+define void @mask_beforefirst() {
+; SVE-LABEL: 'mask_beforefirst'
+; SVE-NEXT:  Cost Model: Invalid cost for instruction: %1 = call <vscale x 2 x i1> @llvm.mask.beforefirst.nxv2i1(<vscale x 2 x i1> poison)
+; SVE-NEXT:  Cost Model: Invalid cost for instruction: %2 = call <vscale x 4 x i1> @llvm.mask.beforefirst.nxv4i1(<vscale x 4 x i1> poison)
+; SVE-NEXT:  Cost Model: Invalid cost for instruction: %3 = call <vscale x 8 x i1> @llvm.mask.beforefirst.nxv8i1(<vscale x 8 x i1> poison)
+; SVE-NEXT:  Cost Model: Invalid cost for instruction: %4 = call <vscale x 16 x i1> @llvm.mask.beforefirst.nxv16i1(<vscale x 16 x i1> poison)
+; SVE-NEXT:  Cost Model: Invalid cost for instruction: %5 = call <vscale x 32 x i1> @llvm.mask.beforefirst.nxv32i1(<vscale x 32 x i1> poison)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 6 for instruction: %6 = call <2 x i1> @llvm.mask.beforefirst.v2i1(<2 x i1> poison)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 12 for instruction: %7 = call <4 x i1> @llvm.mask.beforefirst.v4i1(<4 x i1> poison)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 24 for instruction: %8 = call <8 x i1> @llvm.mask.beforefirst.v8i1(<8 x i1> poison)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 48 for instruction: %9 = call <16 x i1> @llvm.mask.beforefirst.v16i1(<16 x i1> poison)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 96 for instruction: %10 = call <32 x i1> @llvm.mask.beforefirst.v32i1(<32 x i1> poison)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret void
+;
+; NEON-LABEL: 'mask_beforefirst'
+; NEON-NEXT:  Cost Model: Invalid cost for instruction: %1 = call <vscale x 2 x i1> @llvm.mask.beforefirst.nxv2i1(<vscale x 2 x i1> poison)
+; NEON-NEXT:  Cost Model: Invalid cost for instruction: %2 = call <vscale x 4 x i1> @llvm.mask.beforefirst.nxv4i1(<vscale x 4 x i1> poison)
+; NEON-NEXT:  Cost Model: Invalid cost for instruction: %3 = call <vscale x 8 x i1> @llvm.mask.beforefirst.nxv8i1(<vscale x 8 x i1> poison)
+; NEON-NEXT:  Cost Model: Invalid cost for instruction: %4 = call <vscale x 16 x i1> @llvm.mask.beforefirst.nxv16i1(<vscale x 16 x i1> poison)
+; NEON-NEXT:  Cost Model: Invalid cost for instruction: %5 = call <vscale x 32 x i1> @llvm.mask.beforefirst.nxv32i1(<vscale x 32 x i1> poison)
+; NEON-NEXT:  Cost Model: Found an estimated cost of 6 for instruction: %6 = call <2 x i1> @llvm.mask.beforefirst.v2i1(<2 x i1> poison)
+; NEON-NEXT:  Cost Model: Found an estimated cost of 12 for instruction: %7 = call <4 x i1> @llvm.mask.beforefirst.v4i1(<4 x i1> poison)
+; NEON-NEXT:  Cost Model: Found an estimated cost of 24 for instruction: %8 = call <8 x i1> @llvm.mask.beforefirst.v8i1(<8 x i1> poison)
+; NEON-NEXT:  Cost Model: Found an estimated cost of 48 for instruction: %9 = call <16 x i1> @llvm.mask.beforefirst.v16i1(<16 x i1> poison)
+; NEON-NEXT:  Cost Model: Found an estimated cost of 96 for instruction: %10 = call <32 x i1> @llvm.mask.beforefirst.v32i1(<32 x i1> poison)
+; NEON-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret void
+;
+  call <vscale x 2 x i1> @llvm.mask.beforefirst(<vscale x 2 x i1> poison)
+  call <vscale x 4 x i1> @llvm.mask.beforefirst(<vscale x 4 x i1> poison)
+  call <vscale x 8 x i1> @llvm.mask.beforefirst(<vscale x 8 x i1> poison)
+  call <vscale x 16 x i1> @llvm.mask.beforefirst(<vscale x 16 x i1> poison)
+  call <vscale x 32 x i1> @llvm.mask.beforefirst(<vscale x 32 x i1> poison)
+  call <2 x i1> @llvm.mask.beforefirst(<2 x i1> poison)
+  call <4 x i1> @llvm.mask.beforefirst(<4 x i1> poison)
+  call <8 x i1> @llvm.mask.beforefirst(<8 x i1> poison)
+  call <16 x i1> @llvm.mask.beforefirst(<16 x i1> poison)
+  call <32 x i1> @llvm.mask.beforefirst(<32 x i1> poison)
+
+  ret void
+}
diff --git a/llvm/test/Analysis/CostModel/RISCV/mask-beforefirst.ll b/llvm/test/Analysis/CostModel/RISCV/mask-beforefirst.ll
new file mode 100644
index 00000000000000..5adce6095b16ac
--- /dev/null
+++ b/llvm/test/Analysis/CostModel/RISCV/mask-beforefirst.ll
@@ -0,0 +1,42 @@
+; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -passes='print<cost-model>' 2>&1 -disable-output -mtriple=riscv64 -mattr=+v | FileCheck %s
+
+define void @mask_beforefirst() {
+; CHECK-LABEL: 'mask_beforefirst'
+; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %1 = call <vscale x 1 x i1> @llvm.mask.beforefirst.nxv1i1(<vscale x 1 x i1> poison)
+; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %2 = call <vscale x 2 x i1> @llvm.mask.beforefirst.nxv2i1(<vscale x 2 x i1> poison)
+; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %3 = call <vscale x 4 x i1> @llvm.mask.beforefirst.nxv4i1(<vscale x 4 x i1> poison)
+; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %4 = call <vscale x 8 x i1> @llvm.mask.beforefirst.nxv8i1(<vscale x 8 x i1> poison)
+; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %5 = call <vscale x 16 x i1> @llvm.mask.beforefirst.nxv16i1(<vscale x 16 x i1> poison)
+; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %6 = call <vscale x 32 x i1> @llvm.mask.beforefirst.nxv32i1(<vscale x 32 x i1> poison)
+; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %7 = call <vscale x 64 x i1> @llvm.mask.beforefirst.nxv64i1(<vscale x 64 x i1> poison)
+; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %8 = call <vscale x 128 x i1> @llvm.mask.beforefirst.nxv128i1(<vscale x 128 x i1> poison)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: %9 = call <1 x i1> @llvm.mask.beforefirst.v1i1(<1 x i1> poison)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 6 for instruction: %10 = call <2 x i1> @llvm.mask.beforefirst.v2i1(<2 x i1> poison)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 10 for instruction: %11 = call <4 x i1> @llvm.mask.beforefirst.v4i1(<4 x i1> poison)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 18 for instruction: %12 = call <8 x i1> @llvm.mask.beforefirst.v8i1(<8 x i1> poison)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 34 for instruction: %13 = call <16 x i1> @llvm.mask.beforefirst.v16i1(<16 x i1> poison)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 99 for instruction: %14 = call <32 x i1> @llvm.mask.beforefirst.v32i1(<32 x i1> poison)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 199 for instruction: %15 = call <64 x i1> @llvm.mask.beforefirst.v64i1(<64 x i1> poison)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 399 for instruction: %16 = call <128 x i1> @llvm.mask.beforefirst.v128i1(<128 x i1> poison)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret void
+;
+  call <vscale x 1 x i1> @llvm.mask.beforefirst(<vscale x 1 x i1> poison)
+  call <vscale x 2 x i1> @llvm.mask.beforefirst(<vscale x 2 x i1> poison)
+  call <vscale x 4 x i1> @llvm.mask.beforefirst(<vscale x 4 x i1> poison)
+  call <vscale x 8 x i1> @llvm.mask.beforefirst(<vscale x 8 x i1> poison)
+  call <vscale x 16 x i1> @llvm.mask.beforefirst(<vscale x 16 x i1> poison)
+  call <vscale x 32 x i1> @llvm.mask.beforefirst(<vscale x 32 x i1> poison)
+  call <vscale x 64 x i1> @llvm.mask.beforefirst(<vscale x 64 x i1> poison)
+  call <vscale x 128 x i1> @llvm.mask.beforefirst(<vscale x 128 x i1> poison)
+  call <1 x i1> @llvm.mask.beforefirst(<1 x i1> poison)
+  call <2 x i1> @llvm.mask.beforefirst(<2 x i1> poison)
+  call <4 x i1> @llvm.mask.beforefirst(<4 x i1> poison)
+  call <8 x i1> @llvm.mask.beforefirst(<8 x i1> poison)
+  call <16 x i1> @llvm.mask.beforefirst(<16 x i1> poison)
+  call <32 x i1> @llvm.mask.beforefirst(<32 x i1> poison)
+  call <64 x i1> @llvm.mask.beforefirst(<64 x i1> poison)
+  call <128 x i1> @llvm.mask.beforefirst(<128 x i1> poison)
+
+  ret void
+}

>From c78bd3a92eecec816e90cbd91017a3564b8d34a9 Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Mon, 20 Jul 2026 23:45:57 +0800
Subject: [PATCH 2/3] [TTI] Add cost for llvm.mask.beforefirst

---
 llvm/include/llvm/CodeGen/BasicTTIImpl.h      | 23 +++++++++++++
 .../CostModel/AArch64/mask-beforefirst.ll     | 30 ++++++++---------
 .../CostModel/RISCV/mask-beforefirst.ll       | 32 +++++++++----------
 3 files changed, 54 insertions(+), 31 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/BasicTTIImpl.h b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
index 0cebf7ae5a6b26..54f61e0d55c4da 100644
--- a/llvm/include/llvm/CodeGen/BasicTTIImpl.h
+++ b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
@@ -2187,6 +2187,7 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
       return Cost;
     }
     case Intrinsic::get_active_lane_mask:
+    case Intrinsic::mask_beforefirst:
     case Intrinsic::experimental_vector_match:
     case Intrinsic::experimental_vector_histogram_add:
     case Intrinsic::experimental_vector_histogram_uadd_sat:
@@ -2683,6 +2684,28 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
                                           CmpInst::ICMP_ULT, CostKind);
       return Cost;
     }
+    case Intrinsic::mask_beforefirst: {
+      ISD = ISD::MASK_BEFOREFIRST;
+      std::pair<InstructionCost, MVT> LT = getTypeLegalizationCost(RetTy);
+      if (!getTLI()->isOperationExpand(ISD, LT.second))
+        break;
+
+      // Expansion via (get_active_lane_mask 0, (cttz.elts mask))
+      RetTy = VectorType::get(RetTy->getScalarType(),
+                              LT.second.getVectorElementCount());
+      Type *IdxTy =
+          IntegerType::get(RetTy->getContext(),
+                           getTLI()->getVectorIdxTy(DL).getFixedSizeInBits());
+      IntrinsicCostAttributes CttzEltsAttrs(Intrinsic::experimental_cttz_elts,
+                                            IdxTy, RetTy, FMF);
+      InstructionCost Cost =
+          thisT()->getIntrinsicInstrCost(CttzEltsAttrs, CostKind);
+
+      IntrinsicCostAttributes ActiveLaneMaskAttrs(
+          Intrinsic::get_active_lane_mask, RetTy, {IdxTy, IdxTy}, FMF);
+      Cost += thisT()->getIntrinsicInstrCost(ActiveLaneMaskAttrs, CostKind);
+      return Cost * LT.first;
+    }
     case Intrinsic::experimental_memset_pattern:
       // This cost is set to match the cost of the memset_pattern16 libcall.
       // It should likely be re-evaluated after migration to this intrinsic
diff --git a/llvm/test/Analysis/CostModel/AArch64/mask-beforefirst.ll b/llvm/test/Analysis/CostModel/AArch64/mask-beforefirst.ll
index 33b71fea896588..48a6200141be03 100644
--- a/llvm/test/Analysis/CostModel/AArch64/mask-beforefirst.ll
+++ b/llvm/test/Analysis/CostModel/AArch64/mask-beforefirst.ll
@@ -4,16 +4,16 @@
 
 define void @mask_beforefirst() {
 ; SVE-LABEL: 'mask_beforefirst'
-; SVE-NEXT:  Cost Model: Invalid cost for instruction: %1 = call <vscale x 2 x i1> @llvm.mask.beforefirst.nxv2i1(<vscale x 2 x i1> poison)
-; SVE-NEXT:  Cost Model: Invalid cost for instruction: %2 = call <vscale x 4 x i1> @llvm.mask.beforefirst.nxv4i1(<vscale x 4 x i1> poison)
-; SVE-NEXT:  Cost Model: Invalid cost for instruction: %3 = call <vscale x 8 x i1> @llvm.mask.beforefirst.nxv8i1(<vscale x 8 x i1> poison)
-; SVE-NEXT:  Cost Model: Invalid cost for instruction: %4 = call <vscale x 16 x i1> @llvm.mask.beforefirst.nxv16i1(<vscale x 16 x i1> poison)
-; SVE-NEXT:  Cost Model: Invalid cost for instruction: %5 = call <vscale x 32 x i1> @llvm.mask.beforefirst.nxv32i1(<vscale x 32 x i1> poison)
-; SVE-NEXT:  Cost Model: Found an estimated cost of 6 for instruction: %6 = call <2 x i1> @llvm.mask.beforefirst.v2i1(<2 x i1> poison)
-; SVE-NEXT:  Cost Model: Found an estimated cost of 12 for instruction: %7 = call <4 x i1> @llvm.mask.beforefirst.v4i1(<4 x i1> poison)
-; SVE-NEXT:  Cost Model: Found an estimated cost of 24 for instruction: %8 = call <8 x i1> @llvm.mask.beforefirst.v8i1(<8 x i1> poison)
-; SVE-NEXT:  Cost Model: Found an estimated cost of 48 for instruction: %9 = call <16 x i1> @llvm.mask.beforefirst.v16i1(<16 x i1> poison)
-; SVE-NEXT:  Cost Model: Found an estimated cost of 96 for instruction: %10 = call <32 x i1> @llvm.mask.beforefirst.v32i1(<32 x i1> poison)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: %1 = call <vscale x 2 x i1> @llvm.mask.beforefirst.nxv2i1(<vscale x 2 x i1> poison)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: %2 = call <vscale x 4 x i1> @llvm.mask.beforefirst.nxv4i1(<vscale x 4 x i1> poison)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: %3 = call <vscale x 8 x i1> @llvm.mask.beforefirst.nxv8i1(<vscale x 8 x i1> poison)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: %4 = call <vscale x 16 x i1> @llvm.mask.beforefirst.nxv16i1(<vscale x 16 x i1> poison)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 4 for instruction: %5 = call <vscale x 32 x i1> @llvm.mask.beforefirst.nxv32i1(<vscale x 32 x i1> poison)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %6 = call <2 x i1> @llvm.mask.beforefirst.v2i1(<2 x i1> poison)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %7 = call <4 x i1> @llvm.mask.beforefirst.v4i1(<4 x i1> poison)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %8 = call <8 x i1> @llvm.mask.beforefirst.v8i1(<8 x i1> poison)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %9 = call <16 x i1> @llvm.mask.beforefirst.v16i1(<16 x i1> poison)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 4 for instruction: %10 = call <32 x i1> @llvm.mask.beforefirst.v32i1(<32 x i1> poison)
 ; SVE-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret void
 ;
 ; NEON-LABEL: 'mask_beforefirst'
@@ -22,11 +22,11 @@ define void @mask_beforefirst() {
 ; NEON-NEXT:  Cost Model: Invalid cost for instruction: %3 = call <vscale x 8 x i1> @llvm.mask.beforefirst.nxv8i1(<vscale x 8 x i1> poison)
 ; NEON-NEXT:  Cost Model: Invalid cost for instruction: %4 = call <vscale x 16 x i1> @llvm.mask.beforefirst.nxv16i1(<vscale x 16 x i1> poison)
 ; NEON-NEXT:  Cost Model: Invalid cost for instruction: %5 = call <vscale x 32 x i1> @llvm.mask.beforefirst.nxv32i1(<vscale x 32 x i1> poison)
-; NEON-NEXT:  Cost Model: Found an estimated cost of 6 for instruction: %6 = call <2 x i1> @llvm.mask.beforefirst.v2i1(<2 x i1> poison)
-; NEON-NEXT:  Cost Model: Found an estimated cost of 12 for instruction: %7 = call <4 x i1> @llvm.mask.beforefirst.v4i1(<4 x i1> poison)
-; NEON-NEXT:  Cost Model: Found an estimated cost of 24 for instruction: %8 = call <8 x i1> @llvm.mask.beforefirst.v8i1(<8 x i1> poison)
-; NEON-NEXT:  Cost Model: Found an estimated cost of 48 for instruction: %9 = call <16 x i1> @llvm.mask.beforefirst.v16i1(<16 x i1> poison)
-; NEON-NEXT:  Cost Model: Found an estimated cost of 96 for instruction: %10 = call <32 x i1> @llvm.mask.beforefirst.v32i1(<32 x i1> poison)
+; NEON-NEXT:  Cost Model: Found an estimated cost of 10 for instruction: %6 = call <2 x i1> @llvm.mask.beforefirst.v2i1(<2 x i1> poison)
+; NEON-NEXT:  Cost Model: Found an estimated cost of 20 for instruction: %7 = call <4 x i1> @llvm.mask.beforefirst.v4i1(<4 x i1> poison)
+; NEON-NEXT:  Cost Model: Found an estimated cost of 40 for instruction: %8 = call <8 x i1> @llvm.mask.beforefirst.v8i1(<8 x i1> poison)
+; NEON-NEXT:  Cost Model: Found an estimated cost of 80 for instruction: %9 = call <16 x i1> @llvm.mask.beforefirst.v16i1(<16 x i1> poison)
+; NEON-NEXT:  Cost Model: Found an estimated cost of 160 for instruction: %10 = call <32 x i1> @llvm.mask.beforefirst.v32i1(<32 x i1> poison)
 ; NEON-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret void
 ;
   call <vscale x 2 x i1> @llvm.mask.beforefirst(<vscale x 2 x i1> poison)
diff --git a/llvm/test/Analysis/CostModel/RISCV/mask-beforefirst.ll b/llvm/test/Analysis/CostModel/RISCV/mask-beforefirst.ll
index 5adce6095b16ac..4c71dd6bf5a513 100644
--- a/llvm/test/Analysis/CostModel/RISCV/mask-beforefirst.ll
+++ b/llvm/test/Analysis/CostModel/RISCV/mask-beforefirst.ll
@@ -3,22 +3,22 @@
 
 define void @mask_beforefirst() {
 ; CHECK-LABEL: 'mask_beforefirst'
-; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %1 = call <vscale x 1 x i1> @llvm.mask.beforefirst.nxv1i1(<vscale x 1 x i1> poison)
-; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %2 = call <vscale x 2 x i1> @llvm.mask.beforefirst.nxv2i1(<vscale x 2 x i1> poison)
-; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %3 = call <vscale x 4 x i1> @llvm.mask.beforefirst.nxv4i1(<vscale x 4 x i1> poison)
-; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %4 = call <vscale x 8 x i1> @llvm.mask.beforefirst.nxv8i1(<vscale x 8 x i1> poison)
-; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %5 = call <vscale x 16 x i1> @llvm.mask.beforefirst.nxv16i1(<vscale x 16 x i1> poison)
-; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %6 = call <vscale x 32 x i1> @llvm.mask.beforefirst.nxv32i1(<vscale x 32 x i1> poison)
-; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %7 = call <vscale x 64 x i1> @llvm.mask.beforefirst.nxv64i1(<vscale x 64 x i1> poison)
-; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %8 = call <vscale x 128 x i1> @llvm.mask.beforefirst.nxv128i1(<vscale x 128 x i1> poison)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: %9 = call <1 x i1> @llvm.mask.beforefirst.v1i1(<1 x i1> poison)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 6 for instruction: %10 = call <2 x i1> @llvm.mask.beforefirst.v2i1(<2 x i1> poison)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 10 for instruction: %11 = call <4 x i1> @llvm.mask.beforefirst.v4i1(<4 x i1> poison)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 18 for instruction: %12 = call <8 x i1> @llvm.mask.beforefirst.v8i1(<8 x i1> poison)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 34 for instruction: %13 = call <16 x i1> @llvm.mask.beforefirst.v16i1(<16 x i1> poison)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 99 for instruction: %14 = call <32 x i1> @llvm.mask.beforefirst.v32i1(<32 x i1> poison)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 199 for instruction: %15 = call <64 x i1> @llvm.mask.beforefirst.v64i1(<64 x i1> poison)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 399 for instruction: %16 = call <128 x i1> @llvm.mask.beforefirst.v128i1(<128 x i1> poison)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: %1 = call <vscale x 1 x i1> @llvm.mask.beforefirst.nxv1i1(<vscale x 1 x i1> poison)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: %2 = call <vscale x 2 x i1> @llvm.mask.beforefirst.nxv2i1(<vscale x 2 x i1> poison)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: %3 = call <vscale x 4 x i1> @llvm.mask.beforefirst.nxv4i1(<vscale x 4 x i1> poison)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: %4 = call <vscale x 8 x i1> @llvm.mask.beforefirst.nxv8i1(<vscale x 8 x i1> poison)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: %5 = call <vscale x 16 x i1> @llvm.mask.beforefirst.nxv16i1(<vscale x 16 x i1> poison)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: %6 = call <vscale x 32 x i1> @llvm.mask.beforefirst.nxv32i1(<vscale x 32 x i1> poison)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: %7 = call <vscale x 64 x i1> @llvm.mask.beforefirst.nxv64i1(<vscale x 64 x i1> poison)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 4 for instruction: %8 = call <vscale x 128 x i1> @llvm.mask.beforefirst.nxv128i1(<vscale x 128 x i1> poison)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %9 = call <1 x i1> @llvm.mask.beforefirst.v1i1(<1 x i1> poison)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %10 = call <2 x i1> @llvm.mask.beforefirst.v2i1(<2 x i1> poison)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %11 = call <4 x i1> @llvm.mask.beforefirst.v4i1(<4 x i1> poison)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %12 = call <8 x i1> @llvm.mask.beforefirst.v8i1(<8 x i1> poison)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %13 = call <16 x i1> @llvm.mask.beforefirst.v16i1(<16 x i1> poison)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %14 = call <32 x i1> @llvm.mask.beforefirst.v32i1(<32 x i1> poison)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %15 = call <64 x i1> @llvm.mask.beforefirst.v64i1(<64 x i1> poison)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %16 = call <128 x i1> @llvm.mask.beforefirst.v128i1(<128 x i1> poison)
 ; CHECK-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret void
 ;
   call <vscale x 1 x i1> @llvm.mask.beforefirst(<vscale x 1 x i1> poison)

>From 88680512d22490a98eeb9212147a83236ec213f4 Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Thu, 22 Oct 2026 10:24:50 +0800
Subject: [PATCH 3/3] Handle scalarization

---
 llvm/include/llvm/CodeGen/BasicTTIImpl.h      |  6 +++++
 .../CostModel/AArch64/mask-beforefirst.ll     | 23 +++++++++++--------
 2 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/BasicTTIImpl.h b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
index 54f61e0d55c4da..6311f5437dbbbc 100644
--- a/llvm/include/llvm/CodeGen/BasicTTIImpl.h
+++ b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
@@ -2690,6 +2690,12 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
       if (!getTLI()->isOperationExpand(ISD, LT.second))
         break;
 
+      // Scalar types are lowered as a not.
+      if (!LT.second.isVector())
+        return LT.first *
+               thisT()->getArithmeticInstrCost(
+                   Instruction::Xor, RetTy->getScalarType(), CostKind);
+
       // Expansion via (get_active_lane_mask 0, (cttz.elts mask))
       RetTy = VectorType::get(RetTy->getScalarType(),
                               LT.second.getVectorElementCount());
diff --git a/llvm/test/Analysis/CostModel/AArch64/mask-beforefirst.ll b/llvm/test/Analysis/CostModel/AArch64/mask-beforefirst.ll
index 48a6200141be03..77480dff9ece80 100644
--- a/llvm/test/Analysis/CostModel/AArch64/mask-beforefirst.ll
+++ b/llvm/test/Analysis/CostModel/AArch64/mask-beforefirst.ll
@@ -9,11 +9,12 @@ define void @mask_beforefirst() {
 ; SVE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: %3 = call <vscale x 8 x i1> @llvm.mask.beforefirst.nxv8i1(<vscale x 8 x i1> poison)
 ; SVE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: %4 = call <vscale x 16 x i1> @llvm.mask.beforefirst.nxv16i1(<vscale x 16 x i1> poison)
 ; SVE-NEXT:  Cost Model: Found an estimated cost of 4 for instruction: %5 = call <vscale x 32 x i1> @llvm.mask.beforefirst.nxv32i1(<vscale x 32 x i1> poison)
-; SVE-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %6 = call <2 x i1> @llvm.mask.beforefirst.v2i1(<2 x i1> poison)
-; SVE-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %7 = call <4 x i1> @llvm.mask.beforefirst.v4i1(<4 x i1> poison)
-; SVE-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %8 = call <8 x i1> @llvm.mask.beforefirst.v8i1(<8 x i1> poison)
-; SVE-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %9 = call <16 x i1> @llvm.mask.beforefirst.v16i1(<16 x i1> poison)
-; SVE-NEXT:  Cost Model: Found an estimated cost of 4 for instruction: %10 = call <32 x i1> @llvm.mask.beforefirst.v32i1(<32 x i1> poison)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: %6 = call <1 x i1> @llvm.mask.beforefirst.v1i1(<1 x i1> poison)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %7 = call <2 x i1> @llvm.mask.beforefirst.v2i1(<2 x i1> poison)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %8 = call <4 x i1> @llvm.mask.beforefirst.v4i1(<4 x i1> poison)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %9 = call <8 x i1> @llvm.mask.beforefirst.v8i1(<8 x i1> poison)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %10 = call <16 x i1> @llvm.mask.beforefirst.v16i1(<16 x i1> poison)
+; SVE-NEXT:  Cost Model: Found an estimated cost of 4 for instruction: %11 = call <32 x i1> @llvm.mask.beforefirst.v32i1(<32 x i1> poison)
 ; SVE-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret void
 ;
 ; NEON-LABEL: 'mask_beforefirst'
@@ -22,11 +23,12 @@ define void @mask_beforefirst() {
 ; NEON-NEXT:  Cost Model: Invalid cost for instruction: %3 = call <vscale x 8 x i1> @llvm.mask.beforefirst.nxv8i1(<vscale x 8 x i1> poison)
 ; NEON-NEXT:  Cost Model: Invalid cost for instruction: %4 = call <vscale x 16 x i1> @llvm.mask.beforefirst.nxv16i1(<vscale x 16 x i1> poison)
 ; NEON-NEXT:  Cost Model: Invalid cost for instruction: %5 = call <vscale x 32 x i1> @llvm.mask.beforefirst.nxv32i1(<vscale x 32 x i1> poison)
-; NEON-NEXT:  Cost Model: Found an estimated cost of 10 for instruction: %6 = call <2 x i1> @llvm.mask.beforefirst.v2i1(<2 x i1> poison)
-; NEON-NEXT:  Cost Model: Found an estimated cost of 20 for instruction: %7 = call <4 x i1> @llvm.mask.beforefirst.v4i1(<4 x i1> poison)
-; NEON-NEXT:  Cost Model: Found an estimated cost of 40 for instruction: %8 = call <8 x i1> @llvm.mask.beforefirst.v8i1(<8 x i1> poison)
-; NEON-NEXT:  Cost Model: Found an estimated cost of 80 for instruction: %9 = call <16 x i1> @llvm.mask.beforefirst.v16i1(<16 x i1> poison)
-; NEON-NEXT:  Cost Model: Found an estimated cost of 160 for instruction: %10 = call <32 x i1> @llvm.mask.beforefirst.v32i1(<32 x i1> poison)
+; NEON-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: %6 = call <1 x i1> @llvm.mask.beforefirst.v1i1(<1 x i1> poison)
+; NEON-NEXT:  Cost Model: Found an estimated cost of 10 for instruction: %7 = call <2 x i1> @llvm.mask.beforefirst.v2i1(<2 x i1> poison)
+; NEON-NEXT:  Cost Model: Found an estimated cost of 20 for instruction: %8 = call <4 x i1> @llvm.mask.beforefirst.v4i1(<4 x i1> poison)
+; NEON-NEXT:  Cost Model: Found an estimated cost of 40 for instruction: %9 = call <8 x i1> @llvm.mask.beforefirst.v8i1(<8 x i1> poison)
+; NEON-NEXT:  Cost Model: Found an estimated cost of 80 for instruction: %10 = call <16 x i1> @llvm.mask.beforefirst.v16i1(<16 x i1> poison)
+; NEON-NEXT:  Cost Model: Found an estimated cost of 160 for instruction: %11 = call <32 x i1> @llvm.mask.beforefirst.v32i1(<32 x i1> poison)
 ; NEON-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret void
 ;
   call <vscale x 2 x i1> @llvm.mask.beforefirst(<vscale x 2 x i1> poison)
@@ -34,6 +36,7 @@ define void @mask_beforefirst() {
   call <vscale x 8 x i1> @llvm.mask.beforefirst(<vscale x 8 x i1> poison)
   call <vscale x 16 x i1> @llvm.mask.beforefirst(<vscale x 16 x i1> poison)
   call <vscale x 32 x i1> @llvm.mask.beforefirst(<vscale x 32 x i1> poison)
+  call <1 x i1> @llvm.mask.beforefirst(<1 x i1> poison)
   call <2 x i1> @llvm.mask.beforefirst(<2 x i1> poison)
   call <4 x i1> @llvm.mask.beforefirst(<4 x i1> poison)
   call <8 x i1> @llvm.mask.beforefirst(<8 x i1> poison)



More information about the llvm-branch-commits mailing list