[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