[llvm] [VPlan] Simplify extract-lane from same single-scalar. (PR #226102)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 24 03:08:49 PDT 2026


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

Generalize extract-lane(idx, single-scalar) -> single-scalar to also apply if there are multiple vectors to extract and all values are the same single-scalar.

>From 396a913cda064a738a03c9455c9578a6681b06ef Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Sun, 13 Sep 2026 21:55:51 +0100
Subject: [PATCH] [VPlan] Simplify extract-lane with the same single-scalar
 source per part.

Generalize extract-lane(idx, single-scalar) -> single-scalar to also
apply if there are multiple vectors to extract and all values are the
same single-scalar.
---
 .../Transforms/Vectorize/VPlanTransforms.cpp  | 24 +++++++----------
 .../early-exit-live-out-extract-lane.ll       | 26 ++-----------------
 .../LoopVectorize/narrow-to-single-scalar.ll  | 13 +---------
 3 files changed, 13 insertions(+), 50 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
index f26c031c79180..7f135c97e6392 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -1339,21 +1339,17 @@ static VPValue *simplifyRecipe(VPlan &Plan, VPSingleDefRecipe *Def) {
   if (!Plan.isUnrolled())
     return nullptr;
 
-  // After unrolling, extract-lane may be used to extract values from multiple
-  // scalar sources. Only simplify when extracting from a single scalar source.
-  VPValue *LaneToExtract;
-  if (match(Def, m_ExtractLane(m_VPValue(LaneToExtract), m_VPValue(A)))) {
-    // Simplify extract-lane(%lane_num, %scalar_val) -> %scalar_val.
-    if (vputils::isSingleScalar(A))
-      return A;
+  // Simplify extracts of the same single-scalar.
+  if (match(Def, m_VPInstruction<VPInstruction::ExtractLane>()) &&
+      all_equal(drop_begin(Def->operands())) &&
+      vputils::isSingleScalar(Def->getOperand(1)))
+    return Def->getOperand(1);
 
-    // Replace extract-lane(0, canonical-WIDEN-INDUCTION) with the region's
-    // scalar canonical IV.
-    VPWidenIntOrFpInductionRecipe *WidenIV;
-    if (match(LaneToExtract, m_ZeroInt()) &&
-        match(A, m_CanonicalWidenIV(WidenIV)))
-      return WidenIV->getRegion()->getCanonicalIV();
-  }
+  // Replace extract-lane(0, canonical-WIDEN-INDUCTION) with the region's
+  // scalar canonical IV.
+  VPWidenIntOrFpInductionRecipe *WidenIV;
+  if (match(Def, m_ExtractLane(m_ZeroInt(), m_CanonicalWidenIV(WidenIV))))
+    return WidenIV->getRegion()->getCanonicalIV();
 
   // Simplify unrolled VectorPointer without offset, or with zero offset, to
   // just the pointer operand.
diff --git a/llvm/test/Transforms/LoopVectorize/early-exit-live-out-extract-lane.ll b/llvm/test/Transforms/LoopVectorize/early-exit-live-out-extract-lane.ll
index 80b1cda71aa12..11a394710f1e0 100644
--- a/llvm/test/Transforms/LoopVectorize/early-exit-live-out-extract-lane.ll
+++ b/llvm/test/Transforms/LoopVectorize/early-exit-live-out-extract-lane.ll
@@ -37,18 +37,7 @@ define i64 @early_exit_with_live_in_condition(i1 %cond) {
 ; VF1IC2:       [[MIDDLE_BLOCK]]:
 ; VF1IC2-NEXT:    br label %[[LOOP_END:.*]]
 ; VF1IC2:       [[VECTOR_EARLY_EXIT_CHECK]]:
-; VF1IC2-NEXT:    [[TMP13:%.*]] = icmp eq i1 [[TMP8]], false
-; VF1IC2-NEXT:    [[TMP14:%.*]] = zext i1 [[TMP13]] to i64
-; VF1IC2-NEXT:    [[TMP15:%.*]] = add i64 1, [[TMP14]]
-; VF1IC2-NEXT:    [[TMP16:%.*]] = icmp eq i1 [[TMP7]], false
-; VF1IC2-NEXT:    [[TMP17:%.*]] = zext i1 [[TMP16]] to i64
-; VF1IC2-NEXT:    [[TMP18:%.*]] = add i64 0, [[TMP17]]
-; VF1IC2-NEXT:    [[TMP19:%.*]] = icmp ne i64 [[TMP17]], 1
-; VF1IC2-NEXT:    [[TMP20:%.*]] = select i1 [[TMP19]], i64 [[TMP18]], i64 [[TMP15]]
-; VF1IC2-NEXT:    [[TMP21:%.*]] = sub i64 [[TMP20]], 1
-; VF1IC2-NEXT:    [[TMP22:%.*]] = icmp uge i64 [[TMP20]], 1
-; VF1IC2-NEXT:    [[TMP23:%.*]] = select i1 [[TMP22]], i1 [[COND]], i1 [[COND]]
-; VF1IC2-NEXT:    br i1 [[TMP23]], label %[[VECTOR_EARLY_EXIT_0:.*]], label %[[VECTOR_EARLY_EXIT_1:.*]]
+; VF1IC2-NEXT:    br i1 [[COND]], label %[[VECTOR_EARLY_EXIT_0:.*]], label %[[VECTOR_EARLY_EXIT_1:.*]]
 ; VF1IC2:       [[VECTOR_EARLY_EXIT_1]]:
 ; VF1IC2-NEXT:    br label %[[LOOP_END]]
 ; VF1IC2:       [[VECTOR_EARLY_EXIT_0]]:
@@ -89,18 +78,7 @@ define i64 @early_exit_with_live_in_condition(i1 %cond) {
 ; VF4IC2:       [[MIDDLE_BLOCK]]:
 ; VF4IC2-NEXT:    br label %[[LOOP_END:.*]]
 ; VF4IC2:       [[VECTOR_EARLY_EXIT_CHECK]]:
-; VF4IC2-NEXT:    [[FIRST_ACTIVE_LANE:%.*]] = call i64 @llvm.experimental.cttz.elts.i64.v4i1(<4 x i1> [[TMP5]], i1 false)
-; VF4IC2-NEXT:    [[TMP11:%.*]] = add i64 4, [[FIRST_ACTIVE_LANE]]
-; VF4IC2-NEXT:    [[FIRST_ACTIVE_LANE2:%.*]] = call i64 @llvm.experimental.cttz.elts.i64.v4i1(<4 x i1> [[TMP4]], i1 false)
-; VF4IC2-NEXT:    [[TMP12:%.*]] = add i64 0, [[FIRST_ACTIVE_LANE2]]
-; VF4IC2-NEXT:    [[TMP13:%.*]] = icmp ne i64 [[FIRST_ACTIVE_LANE2]], 4
-; VF4IC2-NEXT:    [[TMP14:%.*]] = select i1 [[TMP13]], i64 [[TMP12]], i64 [[TMP11]]
-; VF4IC2-NEXT:    [[TMP15:%.*]] = extractelement <4 x i1> [[BROADCAST_SPLAT]], i64 [[TMP14]]
-; VF4IC2-NEXT:    [[TMP16:%.*]] = sub i64 [[TMP14]], 4
-; VF4IC2-NEXT:    [[TMP17:%.*]] = extractelement <4 x i1> [[BROADCAST_SPLAT]], i64 [[TMP16]]
-; VF4IC2-NEXT:    [[TMP18:%.*]] = icmp uge i64 [[TMP14]], 4
-; VF4IC2-NEXT:    [[TMP19:%.*]] = select i1 [[TMP18]], i1 [[TMP17]], i1 [[TMP15]]
-; VF4IC2-NEXT:    br i1 [[TMP19]], label %[[VECTOR_EARLY_EXIT_0:.*]], label %[[VECTOR_EARLY_EXIT_1:.*]]
+; VF4IC2-NEXT:    br i1 [[COND]], label %[[VECTOR_EARLY_EXIT_0:.*]], label %[[VECTOR_EARLY_EXIT_1:.*]]
 ; VF4IC2:       [[VECTOR_EARLY_EXIT_1]]:
 ; VF4IC2-NEXT:    br label %[[LOOP_END]]
 ; VF4IC2:       [[VECTOR_EARLY_EXIT_0]]:
diff --git a/llvm/test/Transforms/LoopVectorize/narrow-to-single-scalar.ll b/llvm/test/Transforms/LoopVectorize/narrow-to-single-scalar.ll
index 1685f3e6ace39..9c684e788c74f 100644
--- a/llvm/test/Transforms/LoopVectorize/narrow-to-single-scalar.ll
+++ b/llvm/test/Transforms/LoopVectorize/narrow-to-single-scalar.ll
@@ -425,18 +425,7 @@ define i32 @narrow_select_used_by_extract_lane(ptr noalias %src) {
 ; VF2IC2:       [[VECTOR_BODY]]:
 ; VF2IC2-NEXT:    br label %[[MIDDLE_BLOCK:.*]]
 ; VF2IC2:       [[MIDDLE_BLOCK]]:
-; VF2IC2-NEXT:    [[FIRST_INACTIVE_LANE:%.*]] = call i64 @llvm.experimental.cttz.elts.i64.v2i1(<2 x i1> <i1 false, i1 true>, i1 false)
-; VF2IC2-NEXT:    [[TMP11:%.*]] = add i64 2, [[FIRST_INACTIVE_LANE]]
-; VF2IC2-NEXT:    [[FIRST_INACTIVE_LANE1:%.*]] = call i64 @llvm.experimental.cttz.elts.i64.v2i1(<2 x i1> zeroinitializer, i1 false)
-; VF2IC2-NEXT:    [[TMP4:%.*]] = add i64 0, [[FIRST_INACTIVE_LANE1]]
-; VF2IC2-NEXT:    [[TMP5:%.*]] = icmp ne i64 [[FIRST_INACTIVE_LANE1]], 2
-; VF2IC2-NEXT:    [[TMP6:%.*]] = select i1 [[TMP5]], i64 [[TMP4]], i64 [[TMP11]]
-; VF2IC2-NEXT:    [[LAST_ACTIVE_LANE:%.*]] = sub i64 [[TMP6]], 1
-; VF2IC2-NEXT:    [[TMP7:%.*]] = extractelement <2 x i32> [[TMP2]], i64 [[LAST_ACTIVE_LANE]]
-; VF2IC2-NEXT:    [[TMP8:%.*]] = sub i64 [[LAST_ACTIVE_LANE]], 2
-; VF2IC2-NEXT:    [[TMP9:%.*]] = extractelement <2 x i32> [[TMP2]], i64 [[TMP8]]
-; VF2IC2-NEXT:    [[TMP10:%.*]] = icmp uge i64 [[LAST_ACTIVE_LANE]], 2
-; VF2IC2-NEXT:    [[TMP3:%.*]] = select i1 [[TMP10]], i32 [[TMP9]], i32 [[TMP7]]
+; VF2IC2-NEXT:    [[TMP3:%.*]] = extractelement <2 x i32> [[TMP2]], i64 0
 ; VF2IC2-NEXT:    br label %[[EXIT:.*]]
 ; VF2IC2:       [[EXIT]]:
 ; VF2IC2-NEXT:    ret i32 [[TMP3]]



More information about the llvm-commits mailing list