[llvm] [VPlan] Factor first-lane-scalar logic in VPI::execute (NFC) (PR #196207)
Ramkumar Ramachandra via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 9 01:34:00 PDT 2026
https://github.com/artagnon updated https://github.com/llvm/llvm-project/pull/196207
>From f7ee0692b8f5a0d665f6e4bf74fe8f1a63376404 Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <artagnon at tenstorrent.com>
Date: Thu, 7 May 2026 00:07:53 +0100
Subject: [PATCH] [VPlan] Factor first-lane-scalar logic in VPI::execute (NFC)
---
llvm/lib/Transforms/Vectorize/VPlan.h | 7 +--
.../lib/Transforms/Vectorize/VPlanRecipes.cpp | 61 ++++++++-----------
2 files changed, 30 insertions(+), 38 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index 83475129cdebf..277f6692238d0 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -1374,10 +1374,9 @@ class LLVM_ABI_FOR_TEST VPInstruction : public VPRecipeWithIRFlags,
/// needed.
bool canGenerateScalarForFirstLane() const;
- /// Utility methods serving execute(): generates a single vector instance of
- /// the modeled instruction. \returns the generated value. . In some cases an
- /// existing value is returned rather than a generated one.
- Value *generate(VPTransformState &State);
+ /// Utility method serving execute: Generates a scalar or vector value. \p
+ /// IsScalar determines whether to generate a scalar value.
+ Value *generate(VPTransformState &State, bool IsScalar);
/// Returns true if the VPInstruction does not need masking.
bool alwaysUnmasked() const {
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index f78651cf8de6c..0a09c730eeb30 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -667,13 +667,12 @@ static Instruction::BinaryOps getSubRecurOpcode(RecurKind Kind) {
llvm_unreachable("RecurKind should be Sub/FSub.");
}
-Value *VPInstruction::generate(VPTransformState &State) {
+Value *VPInstruction::generate(VPTransformState &State, bool IsScalar) {
IRBuilderBase &Builder = State.Builder;
if (Instruction::isBinaryOp(getOpcode())) {
- bool OnlyFirstLaneUsed = vputils::onlyFirstLaneUsed(this);
- Value *A = State.get(getOperand(0), OnlyFirstLaneUsed);
- Value *B = State.get(getOperand(1), OnlyFirstLaneUsed);
+ Value *A = State.get(getOperand(0), IsScalar);
+ Value *B = State.get(getOperand(1), IsScalar);
auto *Res =
Builder.CreateBinOp((Instruction::BinaryOps)getOpcode(), A, B, Name);
if (auto *I = dyn_cast<Instruction>(Res))
@@ -683,8 +682,7 @@ Value *VPInstruction::generate(VPTransformState &State) {
switch (getOpcode()) {
case VPInstruction::Not: {
- bool OnlyFirstLaneUsed = vputils::onlyFirstLaneUsed(this);
- Value *A = State.get(getOperand(0), OnlyFirstLaneUsed);
+ Value *A = State.get(getOperand(0), IsScalar);
return Builder.CreateNot(A, Name);
}
case Instruction::ExtractElement: {
@@ -703,26 +701,23 @@ Value *VPInstruction::generate(VPTransformState &State) {
return Builder.CreateInsertElement(Vec, Elt, Idx, Name);
}
case Instruction::Freeze: {
- Value *Op = State.get(getOperand(0), vputils::onlyFirstLaneUsed(this));
+ Value *Op = State.get(getOperand(0), IsScalar);
return Builder.CreateFreeze(Op, Name);
}
case Instruction::FCmp:
case Instruction::ICmp: {
- bool OnlyFirstLaneUsed = vputils::onlyFirstLaneUsed(this);
- Value *A = State.get(getOperand(0), OnlyFirstLaneUsed);
- Value *B = State.get(getOperand(1), OnlyFirstLaneUsed);
+ Value *A = State.get(getOperand(0), IsScalar);
+ Value *B = State.get(getOperand(1), IsScalar);
return Builder.CreateCmp(getPredicate(), A, B, Name);
}
case Instruction::PHI: {
llvm_unreachable("should be handled by VPPhi::execute");
}
case Instruction::Select: {
- bool OnlyFirstLaneUsed = vputils::onlyFirstLaneUsed(this);
- Value *Cond =
- State.get(getOperand(0),
- OnlyFirstLaneUsed || vputils::isSingleScalar(getOperand(0)));
- Value *Op1 = State.get(getOperand(1), OnlyFirstLaneUsed);
- Value *Op2 = State.get(getOperand(2), OnlyFirstLaneUsed);
+ Value *Cond = State.get(getOperand(0),
+ IsScalar || vputils::isSingleScalar(getOperand(0)));
+ Value *Op1 = State.get(getOperand(1), IsScalar);
+ Value *Op2 = State.get(getOperand(2), IsScalar);
return Builder.CreateSelectFMF(Cond, Op1, Op2, getFastMathFlagsOrNone(),
Name);
}
@@ -933,23 +928,23 @@ Value *VPInstruction::generate(VPTransformState &State) {
return Res;
}
case VPInstruction::LogicalAnd: {
- Value *A = State.get(getOperand(0));
- Value *B = State.get(getOperand(1));
+ Value *A = State.get(getOperand(0), IsScalar);
+ Value *B = State.get(getOperand(1), IsScalar);
return Builder.CreateLogicalAnd(A, B, Name);
}
case VPInstruction::LogicalOr: {
- Value *A = State.get(getOperand(0));
- Value *B = State.get(getOperand(1));
+ Value *A = State.get(getOperand(0), IsScalar);
+ Value *B = State.get(getOperand(1), IsScalar);
return Builder.CreateLogicalOr(A, B, Name);
}
case VPInstruction::PtrAdd: {
- assert((State.VF.isScalar() || vputils::onlyFirstLaneUsed(this)) &&
- "can only generate first lane for PtrAdd");
- Value *Ptr = State.get(getOperand(0), VPLane(0));
- Value *Addend = State.get(getOperand(1), VPLane(0));
+ assert(IsScalar && "can only generate first lane for PtrAdd");
+ Value *Ptr = State.get(getOperand(0), IsScalar);
+ Value *Addend = State.get(getOperand(1), IsScalar);
return Builder.CreatePtrAdd(Ptr, Addend, Name, getGEPNoWrapFlags());
}
case VPInstruction::WidePtrAdd: {
+ assert(!IsScalar && "Cannot generate scalar value for WidePtrAdd");
Value *Ptr =
State.get(getOperand(0), vputils::isSingleScalar(getOperand(0)));
Value *Addend = State.get(getOperand(1));
@@ -1515,20 +1510,18 @@ void VPInstruction::execute(VPTransformState &State) {
"Opcode requires specific flags to be set");
if (hasFastMathFlags())
State.Builder.setFastMathFlags(getFastMathFlagsOrNone());
- Value *GeneratedValue = generate(State);
+ bool GenerateScalar =
+ State.VF.isScalar() || (canGenerateScalarForFirstLane() &&
+ (vputils::onlyFirstLaneUsed(this) ||
+ isVectorToScalar() || isSingleScalar()));
+ Value *GeneratedValue = generate(State, GenerateScalar);
if (!hasResult())
return;
assert(GeneratedValue && "generate must produce a value");
- bool GeneratesPerFirstLaneOnly = canGenerateScalarForFirstLane() &&
- (vputils::onlyFirstLaneUsed(this) ||
- isVectorToScalar() || isSingleScalar());
- assert((((GeneratedValue->getType()->isVectorTy() ||
- GeneratedValue->getType()->isStructTy()) ==
- !GeneratesPerFirstLaneOnly) ||
- State.VF.isScalar()) &&
+ assert(((GeneratedValue->getType()->isVectorTy() ||
+ GeneratedValue->getType()->isStructTy()) == !GenerateScalar) &&
"scalar value but not only first lane defined");
- State.set(this, GeneratedValue,
- /*IsScalar*/ GeneratesPerFirstLaneOnly);
+ State.set(this, GeneratedValue, GenerateScalar);
if (getOpcode() == VPInstruction::ResumeForEpilogue) {
// FIXME: This is a workaround to enable reliable updates of the scalar loop
// resume phis, when vectorizing the epilogue. Must be removed once epilogue
More information about the llvm-commits
mailing list