[llvm] [CodeGen] Add widening support for ISD::CTTZ_ELTS (PR #205841)

via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 25 08:01:05 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-selectiondag

Author: Chandana Mudda (chandmudda)

<details>
<summary>Changes</summary>

WidenVectorOperand had no handler forCTTZ_ELTS/
CTTZ_ELTS_ZERO_POISON, causing a fatal error when the input vector type needed widening.

Add WidenVecOp_CttzElements which widens the input vector and pads the extra lanes with all-ones, ensuring they do not contribute spurious trailing zeros to the count. This follows the same pattern as the existing
WidenVecOp_VP_CttzElements.

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


3 Files Affected:

- (modified) llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h (+1) 
- (modified) llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp (+19) 
- (added) llvm/test/CodeGen/Hexagon/cttz-elts-widen.ll (+56) 


``````````diff
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
index 71d3e1c66be86..d4d56a9563f71 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
@@ -1132,6 +1132,7 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer {
   SDValue WidenVecOp_VECREDUCE_SEQ(SDNode *N);
   SDValue WidenVecOp_VP_REDUCE(SDNode *N);
   SDValue WidenVecOp_ExpOp(SDNode *N);
+  SDValue WidenVecOp_CttzElements(SDNode *N);
   SDValue WidenVecOp_VP_CttzElements(SDNode *N);
   SDValue WidenVecOp_VECTOR_FIND_LAST_ACTIVE(SDNode *N);
 
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
index 97aa765642ea7..78b99c49e07d0 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
@@ -7741,6 +7741,10 @@ bool DAGTypeLegalizer::WidenVectorOperand(SDNode *N, unsigned OpNo) {
   case ISD::VP_REDUCE_FMINIMUM:
     Res = WidenVecOp_VP_REDUCE(N);
     break;
+  case ISD::CTTZ_ELTS:
+  case ISD::CTTZ_ELTS_ZERO_POISON:
+    Res = WidenVecOp_CttzElements(N);
+    break;
   case ISD::VP_CTTZ_ELTS:
   case ISD::VP_CTTZ_ELTS_ZERO_POISON:
     Res = WidenVecOp_VP_CttzElements(N);
@@ -8723,6 +8727,21 @@ SDValue DAGTypeLegalizer::WidenVecOp_VSELECT(SDNode *N) {
   return DAG.getExtractSubvector(DL, VT, Select, 0);
 }
 
+SDValue DAGTypeLegalizer::WidenVecOp_CttzElements(SDNode *N) {
+  SDLoc DL(N);
+  SDValue Source = N->getOperand(0);
+  EVT WideVT = GetWidenedVector(Source).getValueType();
+
+  // Pad the widened portion with all-ones so the extra lanes appear as
+  // active (non-zero) elements and do not contribute trailing zeros.
+  SDValue AllOnes = DAG.getAllOnesConstant(DL, WideVT);
+  SDValue WideSource = DAG.getNode(ISD::INSERT_SUBVECTOR, DL, WideVT, AllOnes,
+                                   Source, DAG.getVectorIdxConstant(0, DL));
+
+  return DAG.getNode(N->getOpcode(), DL, N->getValueType(0), WideSource,
+                     N->getFlags());
+}
+
 SDValue DAGTypeLegalizer::WidenVecOp_VP_CttzElements(SDNode *N) {
   SDLoc DL(N);
   SDValue Source = GetWidenedVector(N->getOperand(0));
diff --git a/llvm/test/CodeGen/Hexagon/cttz-elts-widen.ll b/llvm/test/CodeGen/Hexagon/cttz-elts-widen.ll
new file mode 100644
index 0000000000000..ac262ad431ae5
--- /dev/null
+++ b/llvm/test/CodeGen/Hexagon/cttz-elts-widen.ll
@@ -0,0 +1,56 @@
+; RUN: llc -march=hexagon < %s | FileCheck %s
+
+; Widening of ISD::CTTZ_ELTS / CTTZ_ELTS_ZERO_POISON when the operand
+; vector type is illegal (<3 x i32> widens to <4 x i32>). Padded lanes
+; must be all-ones so the count never falls into the synthetic lane.
+
+; All-zero input must return OrigElts (3), never WideElts (4).
+; CHECK-LABEL: cttz_elts_zero_v3i32:
+; CHECK:        r0 = #3
+; CHECK-NEXT:   jumpr r31
+; CHECK-NOT:    r0 = #4
+define i32 @cttz_elts_zero_v3i32() {
+  %res = call i32 @llvm.experimental.cttz.elts.i32.v3i32(<3 x i32> zeroinitializer, i1 false)
+  ret i32 %res
+}
+
+; First non-zero element at the highest *original* lane (lane 2 of
+; <3 x i32>). The padded lane 3 must not steal the result: answer is 2.
+; CHECK-LABEL: cttz_elts_high_lane_v3i32:
+; CHECK:        r0 = #2
+; CHECK-NEXT:   jumpr r31
+; CHECK-NOT:    r0 = #3
+define i32 @cttz_elts_high_lane_v3i32() {
+  %res = call i32 @llvm.experimental.cttz.elts.i32.v3i32(<3 x i32> <i32 0, i32 0, i32 9>, i1 false)
+  ret i32 %res
+}
+
+; Symbolic input: confirm the operand is actually widened to <4 x i32>.
+; Two vcmpw.eq compares against the zero pair cover both halves of the
+; widened vector, and the final sub(#4, ...) reflects the widened lane
+; count. A regression that fails to widen, or widens without all-ones
+; padding, would change these.
+; CHECK-LABEL: cttz_elts_v3i32:
+; CHECK:        r{{[0-9]+}}:{{[0-9]+}} = combine(#0,#0)
+; CHECK:        vcmpw.eq(r{{[0-9]+}}:{{[0-9]+}},r{{[0-9]+}}:{{[0-9]+}})
+; CHECK:        vcmpw.eq(r{{[0-9]+}}:{{[0-9]+}},r{{[0-9]+}}:{{[0-9]+}})
+; CHECK:        r0 = sub(#4,r{{[0-9]+}})
+; CHECK-NEXT:   jumpr r31
+define i32 @cttz_elts_v3i32(<3 x i32> %v) {
+  %res = call i32 @llvm.experimental.cttz.elts.i32.v3i32(<3 x i32> %v, i1 false)
+  ret i32 %res
+}
+
+; Same shape for the zero-poison variant; padding must still be emitted.
+; CHECK-LABEL: cttz_elts_zero_poison_v3i32:
+; CHECK:        r{{[0-9]+}}:{{[0-9]+}} = combine(#0,#0)
+; CHECK:        vcmpw.eq(r{{[0-9]+}}:{{[0-9]+}},r{{[0-9]+}}:{{[0-9]+}})
+; CHECK:        vcmpw.eq(r{{[0-9]+}}:{{[0-9]+}},r{{[0-9]+}}:{{[0-9]+}})
+; CHECK:        r0 = sub(#4,r{{[0-9]+}})
+; CHECK-NEXT:   jumpr r31
+define i32 @cttz_elts_zero_poison_v3i32(<3 x i32> %v) {
+  %res = call i32 @llvm.experimental.cttz.elts.i32.v3i32(<3 x i32> %v, i1 true)
+  ret i32 %res
+}
+
+declare i32 @llvm.experimental.cttz.elts.i32.v3i32(<3 x i32>, i1)

``````````

</details>


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


More information about the llvm-commits mailing list