[llvm] [ISel] Handle TypeWidenVector in expandVectorFindLastActive. (PR #174384)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jan 5 03:06:17 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-selectiondag
Author: Florian Hahn (fhahn)
<details>
<summary>Changes</summary>
When widening extract.last.active, the element count changes. Create a step vector with only the original elements valid and zeros for padding. Also widen the mask accordingly. This fixes a hang when lowering on X86, where widening is required in some cases.
Fixes https://github.com/llvm/llvm-project/issues/171831.
---
Full diff: https://github.com/llvm/llvm-project/pull/174384.diff
2 Files Affected:
- (modified) llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp (+31-7)
- (added) llvm/test/CodeGen/X86/vector-extract-last-active.ll (+76)
``````````diff
diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index 69c3455573918..b37a5e4144aea 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -9668,20 +9668,44 @@ SDValue TargetLowering::expandVectorFindLastActive(SDNode *N,
EVT StepVT = MVT::getIntegerVT(EltWidth);
EVT StepVecVT = MaskVT.changeVectorElementType(*DAG.getContext(), StepVT);
- // If promotion is required to make the type legal, do it here; promotion
- // of integers within LegalizeVectorOps is looking for types of the same
- // size but with a smaller number of larger elements, not the usual larger
- // size with the same number of larger elements.
- if (TLI.getTypeAction(StepVecVT.getSimpleVT()) ==
- TargetLowering::TypePromoteInteger) {
+ // If promotion or widening is required to make the type legal, do it here.
+ // Promotion of integers within LegalizeVectorOps is looking for types of
+ // the same size but with a smaller number of larger elements, not the usual
+ // larger size with the same number of larger elements.
+ TargetLowering::LegalizeTypeAction TypeAction =
+ TLI.getTypeAction(StepVecVT.getSimpleVT());
+ SDValue StepVec;
+ if (TypeAction == TargetLowering::TypePromoteInteger) {
StepVecVT = TLI.getTypeToTransformTo(*DAG.getContext(), StepVecVT);
StepVT = StepVecVT.getVectorElementType();
+ StepVec = DAG.getStepVector(DL, StepVecVT);
+ } else if (TypeAction == TargetLowering::TypeWidenVector) {
+ // For widening, the element count changes. Create a step vector with only
+ // the original elements valid and zeros for padding. Also widen the mask.
+ EVT WideVecVT = TLI.getTypeToTransformTo(*DAG.getContext(), StepVecVT);
+ unsigned WideNumElts = WideVecVT.getVectorNumElements();
+
+ // Build widened step vector: <0, 1, ..., OrigNumElts-1, 0, 0, ...>
+ SDValue OrigStepVec = DAG.getStepVector(DL, StepVecVT);
+ StepVec = DAG.getNode(ISD::INSERT_SUBVECTOR, DL, WideVecVT,
+ DAG.getConstant(0, DL, WideVecVT), OrigStepVec,
+ DAG.getIntPtrConstant(0, DL));
+
+ // Widen mask: pad with zeros.
+ EVT WideMaskVT = EVT::getVectorVT(*DAG.getContext(), BoolVT, WideNumElts);
+ SDValue ZeroMask = DAG.getConstant(0, DL, WideMaskVT);
+ Mask = DAG.getNode(ISD::INSERT_SUBVECTOR, DL, WideMaskVT, ZeroMask, Mask,
+ DAG.getIntPtrConstant(0, DL));
+
+ StepVecVT = WideVecVT;
+ StepVT = WideVecVT.getVectorElementType();
+ } else {
+ StepVec = DAG.getStepVector(DL, StepVecVT);
}
// Zero out lanes with inactive elements, then find the highest remaining
// value from the stepvector.
SDValue Zeroes = DAG.getConstant(0, DL, StepVecVT);
- SDValue StepVec = DAG.getStepVector(DL, StepVecVT);
SDValue ActiveElts = DAG.getSelect(DL, StepVecVT, Mask, StepVec, Zeroes);
SDValue HighestIdx = DAG.getNode(ISD::VECREDUCE_UMAX, DL, StepVT, ActiveElts);
return DAG.getZExtOrTrunc(HighestIdx, DL, N->getValueType(0));
diff --git a/llvm/test/CodeGen/X86/vector-extract-last-active.ll b/llvm/test/CodeGen/X86/vector-extract-last-active.ll
new file mode 100644
index 0000000000000..436eac4852149
--- /dev/null
+++ b/llvm/test/CodeGen/X86/vector-extract-last-active.ll
@@ -0,0 +1,76 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -mtriple=x86_64-unknown-linux | FileCheck %s
+
+; This test verifies that the experimental.vector.extract.last.active intrinsic
+; doesn't cause an infinite loop during legalization when the step vector type
+; needs widening (e.g., v4i8 -> v16i8 on X86).
+
+define i32 @extract_last_active_v4i32(<4 x i32> %a, <4 x i1> %c) {
+; CHECK-LABEL: extract_last_active_v4i32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movd %xmm1, %eax
+; CHECK-NEXT: pshufd {{.*#+}} xmm2 = xmm1[2,3,2,3]
+; CHECK-NEXT: movd %xmm2, %ecx
+; CHECK-NEXT: pshufd {{.*#+}} xmm2 = xmm1[1,1,1,1]
+; CHECK-NEXT: movd %xmm2, %edx
+; CHECK-NEXT: pshufd {{.*#+}} xmm1 = xmm1[3,3,3,3]
+; CHECK-NEXT: movd %xmm1, %esi
+; CHECK-NEXT: movaps %xmm0, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT: xorl %edi, %edi
+; CHECK-NEXT: testl %esi, %esi
+; CHECK-NEXT: setne %dil
+; CHECK-NEXT: leal (%rdi,%rdi,2), %r8d
+; CHECK-NEXT: xorl %r9d, %r9d
+; CHECK-NEXT: testl %edx, %edx
+; CHECK-NEXT: setne %r9b
+; CHECK-NEXT: xorl %edi, %edi
+; CHECK-NEXT: testl %ecx, %ecx
+; CHECK-NEXT: setne %dil
+; CHECK-NEXT: addl %edi, %edi
+; CHECK-NEXT: cmpb %dil, %r9b
+; CHECK-NEXT: cmoval %r9d, %edi
+; CHECK-NEXT: cmpb %r8b, %dil
+; CHECK-NEXT: cmovbel %r8d, %edi
+; CHECK-NEXT: orl %edx, %eax
+; CHECK-NEXT: orl %esi, %ecx
+; CHECK-NEXT: orl %eax, %ecx
+; CHECK-NEXT: andb $1, %cl
+; CHECK-NEXT: xorl %eax, %eax
+; CHECK-NEXT: cmpb $1, %cl
+; CHECK-NEXT: sbbl %eax, %eax
+; CHECK-NEXT: orl -24(%rsp,%rdi,4), %eax
+; CHECK-NEXT: retq
+ %res = call i32 @llvm.experimental.vector.extract.last.active.v4i32(<4 x i32> %a, <4 x i1> %c, i32 -1)
+ ret i32 %res
+}
+
+define i32 @extract_last_active_v4i32_no_default(<4 x i32> %a, <4 x i1> %c) {
+; CHECK-LABEL: extract_last_active_v4i32_no_default:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movaps %xmm0, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT: pshufd {{.*#+}} xmm0 = xmm1[3,3,3,3]
+; CHECK-NEXT: movd %xmm0, %eax
+; CHECK-NEXT: xorl %ecx, %ecx
+; CHECK-NEXT: testl %eax, %eax
+; CHECK-NEXT: setne %cl
+; CHECK-NEXT: leal (%rcx,%rcx,2), %eax
+; CHECK-NEXT: pshufd {{.*#+}} xmm0 = xmm1[1,1,1,1]
+; CHECK-NEXT: movd %xmm0, %ecx
+; CHECK-NEXT: xorl %edx, %edx
+; CHECK-NEXT: testl %ecx, %ecx
+; CHECK-NEXT: setne %dl
+; CHECK-NEXT: pshufd {{.*#+}} xmm0 = xmm1[2,3,2,3]
+; CHECK-NEXT: movd %xmm0, %ecx
+; CHECK-NEXT: xorl %esi, %esi
+; CHECK-NEXT: testl %ecx, %ecx
+; CHECK-NEXT: setne %sil
+; CHECK-NEXT: addl %esi, %esi
+; CHECK-NEXT: cmpb %sil, %dl
+; CHECK-NEXT: cmoval %edx, %esi
+; CHECK-NEXT: cmpb %al, %sil
+; CHECK-NEXT: cmovbel %eax, %esi
+; CHECK-NEXT: movl -24(%rsp,%rsi,4), %eax
+; CHECK-NEXT: retq
+ %res = call i32 @llvm.experimental.vector.extract.last.active.v4i32(<4 x i32> %a, <4 x i1> %c, i32 undef)
+ ret i32 %res
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/174384
More information about the llvm-commits
mailing list