[llvm] [RISCV] Fix crash costing cttz.elts without fixed-length RVV. (PR #226181)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 24 07:24:15 PDT 2026


https://github.com/fhahn created https://github.com/llvm/llvm-project/pull/226181

With +zve32x fixed-length vectors are not legalized to RVV types and getTypeLegalizationCost returns a scalar MVT. Skip non-vector types and return Invalid instead of asserting in the getVectorElementType call below.

We may be able to give more accurate costs, but I am not familiar enough with the details.

Hit this while fuzzing some LoopVectorize changes.

Aided by Claude Opus.

>From 413af7f0c574b8d253ee2bf1e14065fef11abb3f Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Thu, 24 Sep 2026 10:23:57 +0100
Subject: [PATCH] [RISCV] Fix crash when costing cttz.elts without fixed-length
 RVV

With +zve32x fixed-length vectors are not legalized to RVV types and
getTypeLegalizationCost returns a scalar MVT. Skip non-vector types and
return Invalid instead of asserting in the getVectorElementType call below.

We may be able to give more accurate costs, but I am not familiar
enough with the details.

Hit this while fuzzing some LoopVectorize changes.

Aided by Claude Opus.

This now returns invalid costs, instead of crashing
---
 .../Target/RISCV/RISCVTargetTransformInfo.cpp |  2 +
 .../Analysis/CostModel/RISCV/cttz_elts.ll     | 55 +++++++++++++------
 2 files changed, 39 insertions(+), 18 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
index 7f65e3dd4456a2..bd87a7cd905e21 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
@@ -1783,6 +1783,8 @@ RISCVTTIImpl::getIntrinsicInstrCost(const IntrinsicCostAttributes &ICA,
     InstructionCost Cost = 0;
     Type *ArgTy = ICA.getArgTypes()[0];
     auto LT = getTypeLegalizationCost(ArgTy);
+    if (!LT.second.isVector())
+      break;
 
     // If the element type is not i1, do a comparison with all-zeros.
     if (LT.second.getVectorElementType() != MVT::i1)
diff --git a/llvm/test/Analysis/CostModel/RISCV/cttz_elts.ll b/llvm/test/Analysis/CostModel/RISCV/cttz_elts.ll
index 07cf67881289d6..35c6085abfe57a 100644
--- a/llvm/test/Analysis/CostModel/RISCV/cttz_elts.ll
+++ b/llvm/test/Analysis/CostModel/RISCV/cttz_elts.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 4
-; RUN: opt < %s -passes="print<cost-model>" 2>&1 -disable-output -mtriple=riscv64 -mattr=+v | FileCheck %s
+; RUN: opt < %s -passes="print<cost-model>" 2>&1 -disable-output -mtriple=riscv64 -mattr=+v | FileCheck %s --check-prefixes=CHECK,V
+; RUN: opt < %s -passes="print<cost-model>" 2>&1 -disable-output -mtriple=riscv64 -mattr=+zve32x | FileCheck %s --check-prefixes=CHECK,ZVE32X
 
 define void @foo_no_vscale_range() {
 ; CHECK-LABEL: 'foo_no_vscale_range'
@@ -134,23 +135,41 @@ define void @foo_vscale_range_2_16() vscale_range(2,16) {
 
 
 define void @foo_fixed_len_vectors() {
-; CHECK-LABEL: 'foo_fixed_len_vectors'
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 3 for instruction: %res.i32.v2i1.false = call i32 @llvm.experimental.cttz.elts.i32.v2i1(<2 x i1> poison, i1 false)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 3 for instruction: %res.i32.v4i1.false = call i32 @llvm.experimental.cttz.elts.i32.v4i1(<4 x i1> poison, i1 false)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 3 for instruction: %res.i32.v8i1.false = call i32 @llvm.experimental.cttz.elts.i32.v8i1(<8 x i1> poison, i1 false)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 3 for instruction: %res.i32.v64i1.false = call i32 @llvm.experimental.cttz.elts.i32.v64i1(<64 x i1> poison, i1 false)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 3 for instruction: %res.i32.v128i1.false = call i32 @llvm.experimental.cttz.elts.i32.v128i1(<128 x i1> poison, i1 false)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 24 for instruction: %res.i32.v1024i1.false = call i32 @llvm.experimental.cttz.elts.i32.v1024i1(<1024 x i1> poison, i1 false)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 48 for instruction: %res.i32.v2048i1.false = call i32 @llvm.experimental.cttz.elts.i32.v2048i1(<2048 x i1> poison, i1 false)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: %res.i32.v2i1.true = call i32 @llvm.experimental.cttz.elts.i32.v2i1(<2 x i1> poison, i1 true)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 16 for instruction: %res.i32.v2048i1.true = call i32 @llvm.experimental.cttz.elts.i32.v2048i1(<2048 x i1> poison, i1 true)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 4 for instruction: %res.i32.v2i32 = call i32 @llvm.experimental.cttz.elts.i32.v2i32(<2 x i32> poison, i1 false)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 4 for instruction: %res.i32.v4i32 = call i32 @llvm.experimental.cttz.elts.i32.v4i32(<4 x i32> poison, i1 false)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 11 for instruction: %res.i32.v32i32 = call i32 @llvm.experimental.cttz.elts.i32.v32i32(<32 x i32> poison, i1 false)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 4 for instruction: %res.i32.v2i33 = call i32 @llvm.experimental.cttz.elts.i32.v2i33(<2 x i33> poison, i1 false)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 5 for instruction: %res.i32.v4i33 = call i32 @llvm.experimental.cttz.elts.i32.v4i33(<4 x i33> poison, i1 false)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 22 for instruction: %res.i32.v32i33 = call i32 @llvm.experimental.cttz.elts.i32.v32i33(<32 x i33> poison, i1 false)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret void
+; V-LABEL: 'foo_fixed_len_vectors'
+; V-NEXT:  Cost Model: Found an estimated cost of 3 for instruction: %res.i32.v2i1.false = call i32 @llvm.experimental.cttz.elts.i32.v2i1(<2 x i1> poison, i1 false)
+; V-NEXT:  Cost Model: Found an estimated cost of 3 for instruction: %res.i32.v4i1.false = call i32 @llvm.experimental.cttz.elts.i32.v4i1(<4 x i1> poison, i1 false)
+; V-NEXT:  Cost Model: Found an estimated cost of 3 for instruction: %res.i32.v8i1.false = call i32 @llvm.experimental.cttz.elts.i32.v8i1(<8 x i1> poison, i1 false)
+; V-NEXT:  Cost Model: Found an estimated cost of 3 for instruction: %res.i32.v64i1.false = call i32 @llvm.experimental.cttz.elts.i32.v64i1(<64 x i1> poison, i1 false)
+; V-NEXT:  Cost Model: Found an estimated cost of 3 for instruction: %res.i32.v128i1.false = call i32 @llvm.experimental.cttz.elts.i32.v128i1(<128 x i1> poison, i1 false)
+; V-NEXT:  Cost Model: Found an estimated cost of 24 for instruction: %res.i32.v1024i1.false = call i32 @llvm.experimental.cttz.elts.i32.v1024i1(<1024 x i1> poison, i1 false)
+; V-NEXT:  Cost Model: Found an estimated cost of 48 for instruction: %res.i32.v2048i1.false = call i32 @llvm.experimental.cttz.elts.i32.v2048i1(<2048 x i1> poison, i1 false)
+; V-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: %res.i32.v2i1.true = call i32 @llvm.experimental.cttz.elts.i32.v2i1(<2 x i1> poison, i1 true)
+; V-NEXT:  Cost Model: Found an estimated cost of 16 for instruction: %res.i32.v2048i1.true = call i32 @llvm.experimental.cttz.elts.i32.v2048i1(<2048 x i1> poison, i1 true)
+; V-NEXT:  Cost Model: Found an estimated cost of 4 for instruction: %res.i32.v2i32 = call i32 @llvm.experimental.cttz.elts.i32.v2i32(<2 x i32> poison, i1 false)
+; V-NEXT:  Cost Model: Found an estimated cost of 4 for instruction: %res.i32.v4i32 = call i32 @llvm.experimental.cttz.elts.i32.v4i32(<4 x i32> poison, i1 false)
+; V-NEXT:  Cost Model: Found an estimated cost of 11 for instruction: %res.i32.v32i32 = call i32 @llvm.experimental.cttz.elts.i32.v32i32(<32 x i32> poison, i1 false)
+; V-NEXT:  Cost Model: Found an estimated cost of 4 for instruction: %res.i32.v2i33 = call i32 @llvm.experimental.cttz.elts.i32.v2i33(<2 x i33> poison, i1 false)
+; V-NEXT:  Cost Model: Found an estimated cost of 5 for instruction: %res.i32.v4i33 = call i32 @llvm.experimental.cttz.elts.i32.v4i33(<4 x i33> poison, i1 false)
+; V-NEXT:  Cost Model: Found an estimated cost of 22 for instruction: %res.i32.v32i33 = call i32 @llvm.experimental.cttz.elts.i32.v32i33(<32 x i33> poison, i1 false)
+; V-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret void
+;
+; ZVE32X-LABEL: 'foo_fixed_len_vectors'
+; ZVE32X-NEXT:  Cost Model: Invalid cost for instruction: %res.i32.v2i1.false = call i32 @llvm.experimental.cttz.elts.i32.v2i1(<2 x i1> poison, i1 false)
+; ZVE32X-NEXT:  Cost Model: Invalid cost for instruction: %res.i32.v4i1.false = call i32 @llvm.experimental.cttz.elts.i32.v4i1(<4 x i1> poison, i1 false)
+; ZVE32X-NEXT:  Cost Model: Invalid cost for instruction: %res.i32.v8i1.false = call i32 @llvm.experimental.cttz.elts.i32.v8i1(<8 x i1> poison, i1 false)
+; ZVE32X-NEXT:  Cost Model: Invalid cost for instruction: %res.i32.v64i1.false = call i32 @llvm.experimental.cttz.elts.i32.v64i1(<64 x i1> poison, i1 false)
+; ZVE32X-NEXT:  Cost Model: Invalid cost for instruction: %res.i32.v128i1.false = call i32 @llvm.experimental.cttz.elts.i32.v128i1(<128 x i1> poison, i1 false)
+; ZVE32X-NEXT:  Cost Model: Invalid cost for instruction: %res.i32.v1024i1.false = call i32 @llvm.experimental.cttz.elts.i32.v1024i1(<1024 x i1> poison, i1 false)
+; ZVE32X-NEXT:  Cost Model: Invalid cost for instruction: %res.i32.v2048i1.false = call i32 @llvm.experimental.cttz.elts.i32.v2048i1(<2048 x i1> poison, i1 false)
+; ZVE32X-NEXT:  Cost Model: Invalid cost for instruction: %res.i32.v2i1.true = call i32 @llvm.experimental.cttz.elts.i32.v2i1(<2 x i1> poison, i1 true)
+; ZVE32X-NEXT:  Cost Model: Invalid cost for instruction: %res.i32.v2048i1.true = call i32 @llvm.experimental.cttz.elts.i32.v2048i1(<2048 x i1> poison, i1 true)
+; ZVE32X-NEXT:  Cost Model: Invalid cost for instruction: %res.i32.v2i32 = call i32 @llvm.experimental.cttz.elts.i32.v2i32(<2 x i32> poison, i1 false)
+; ZVE32X-NEXT:  Cost Model: Invalid cost for instruction: %res.i32.v4i32 = call i32 @llvm.experimental.cttz.elts.i32.v4i32(<4 x i32> poison, i1 false)
+; ZVE32X-NEXT:  Cost Model: Invalid cost for instruction: %res.i32.v32i32 = call i32 @llvm.experimental.cttz.elts.i32.v32i32(<32 x i32> poison, i1 false)
+; ZVE32X-NEXT:  Cost Model: Invalid cost for instruction: %res.i32.v2i33 = call i32 @llvm.experimental.cttz.elts.i32.v2i33(<2 x i33> poison, i1 false)
+; ZVE32X-NEXT:  Cost Model: Invalid cost for instruction: %res.i32.v4i33 = call i32 @llvm.experimental.cttz.elts.i32.v4i33(<4 x i33> poison, i1 false)
+; ZVE32X-NEXT:  Cost Model: Invalid cost for instruction: %res.i32.v32i33 = call i32 @llvm.experimental.cttz.elts.i32.v32i33(<32 x i33> poison, i1 false)
+; ZVE32X-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret void
 ;
   %res.i32.v2i1.false = call i32 @llvm.experimental.cttz.elts.i32.v2i1(<2 x i1> poison, i1 false)
   %res.i32.v4i1.false = call i32 @llvm.experimental.cttz.elts.i32.v4i1(<4 x i1> poison, i1 false)



More information about the llvm-commits mailing list