[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-backend-hexagon
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