[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