[llvm] [VPlan] Add visited set for onlyFirstLaneUsed() (PR #228438)
Nikita Popov via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 2 06:33:42 PDT 2026
https://github.com/nikic created https://github.com/llvm/llvm-project/pull/228438
This avoids exponential recursive fan-out, and addresses the original slow compile case from #228403 (but not the reduced case).
This ends up having to thread the Visited parameter through lots of places, not sure if there is some better solution here.
AI assisted.
>From 0d40ab9cbedbbad60c746fece50c8348f30dd66c Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Fri, 2 Oct 2026 15:24:14 +0200
Subject: [PATCH] [VPlan] Add visited set for onlyFirstLaneUsed()
This avoids exponential recursive fan-out, and addresses the
original slow compile case from #228403.
---
llvm/lib/Transforms/Vectorize/VPlan.h | 102 +++++++++++++-----
.../lib/Transforms/Vectorize/VPlanRecipes.cpp | 27 +++--
llvm/lib/Transforms/Vectorize/VPlanUtils.cpp | 13 ++-
llvm/lib/Transforms/Vectorize/VPlanUtils.h | 5 +
llvm/lib/Transforms/Vectorize/VPlanValue.h | 11 +-
5 files changed, 118 insertions(+), 40 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index 55741c2ac0e42d..74156e26389cb4 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -1565,11 +1565,13 @@ class LLVM_ABI_FOR_TEST VPInstruction : public VPRecipeWithIRFlags,
bool opcodeMayReadOrWriteFromMemory() const;
/// Returns true if the recipe only uses the first lane of operand \p Op.
- bool usesFirstLaneOnly(const VPValue *Op) const override;
+ bool
+ usesFirstLaneOnly(const VPValue *Op,
+ SmallPtrSetImpl<const VPValue *> &Visited) const override;
/// Returns true if the recipe only uses scalars of operand \p Op.
bool usesScalars(const VPValue *Op) const override {
- return isSingleScalar() || usesFirstLaneOnly(Op);
+ return isSingleScalar() || VPUser::usesFirstLaneOnly(Op);
}
/// Returns true if the recipe only uses the first part of operand \p Op.
@@ -1758,7 +1760,9 @@ class VPIRInstruction : public VPRecipeBase {
return true;
}
- bool usesFirstLaneOnly(const VPValue *Op) const override {
+ bool
+ usesFirstLaneOnly(const VPValue *Op,
+ SmallPtrSetImpl<const VPValue *> &Visited) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
return true;
@@ -1864,7 +1868,9 @@ class LLVM_ABI_FOR_TEST VPWidenRecipe : public VPRecipeWithIRFlags,
#endif
/// Returns true if the recipe only uses the first lane of operand \p Op.
- bool usesFirstLaneOnly(const VPValue *Op) const override {
+ bool
+ usesFirstLaneOnly(const VPValue *Op,
+ SmallPtrSetImpl<const VPValue *> &Visited) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
return Opcode == Instruction::Select && Op == getOperand(0) &&
@@ -2041,7 +2047,9 @@ class LLVM_ABI_FOR_TEST VPWidenIntrinsicRecipe : public VPRecipeWithIRFlags,
/// Returns true if the intrinsic may have side-effects.
bool mayHaveSideEffects() const { return MayHaveSideEffects; }
- bool usesFirstLaneOnly(const VPValue *Op) const override;
+ bool
+ usesFirstLaneOnly(const VPValue *Op,
+ SmallPtrSetImpl<const VPValue *> &Visited) const override;
protected:
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
@@ -2146,7 +2154,9 @@ class LLVM_ABI_FOR_TEST VPWidenCallRecipe : public VPRecipeWithIRFlags,
const_operand_range args() const { return drop_end(operands()); }
/// Returns true if the recipe only uses the first lane of operand \p Op.
- bool usesFirstLaneOnly(const VPValue *Op) const override;
+ bool
+ usesFirstLaneOnly(const VPValue *Op,
+ SmallPtrSetImpl<const VPValue *> &Visited) const override;
protected:
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
@@ -2194,7 +2204,9 @@ class VPHistogramRecipe : public VPRecipeBase, public VPIRMetadata {
}
/// Returns true if the recipe only uses the first lane of operand \p Op.
- bool usesFirstLaneOnly(const VPValue *Op) const override {
+ bool
+ usesFirstLaneOnly(const VPValue *Op,
+ SmallPtrSetImpl<const VPValue *> &Visited) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
return Op == getOperand(1);
@@ -2254,7 +2266,9 @@ class LLVM_ABI_FOR_TEST VPWidenGEPRecipe : public VPRecipeWithIRFlags {
}
/// Returns true if the recipe only uses the first lane of operand \p Op.
- bool usesFirstLaneOnly(const VPValue *Op) const override;
+ bool
+ usesFirstLaneOnly(const VPValue *Op,
+ SmallPtrSetImpl<const VPValue *> &Visited) const override;
protected:
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
@@ -2309,7 +2323,9 @@ class VPVectorEndPointerRecipe : public VPRecipeWithIRFlags {
void execute(VPTransformState &State) override;
- bool usesFirstLaneOnly(const VPValue *Op) const override {
+ bool
+ usesFirstLaneOnly(const VPValue *Op,
+ SmallPtrSetImpl<const VPValue *> &Visited) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
return true;
@@ -2381,7 +2397,9 @@ class VPVectorPointerRecipe : public VPRecipeWithIRFlags {
Type *getSourceElementType() const { return SourceElementTy; }
- bool usesFirstLaneOnly(const VPValue *Op) const override {
+ bool
+ usesFirstLaneOnly(const VPValue *Op,
+ SmallPtrSetImpl<const VPValue *> &Visited) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
return true;
@@ -2591,7 +2609,9 @@ class VPWidenInductionRecipe : public VPHeaderPHIRecipe {
}
/// Returns true if the recipe only uses the first lane of operand \p Op.
- bool usesFirstLaneOnly(const VPValue *Op) const override {
+ bool
+ usesFirstLaneOnly(const VPValue *Op,
+ SmallPtrSetImpl<const VPValue *> &Visited) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
// The recipe creates its own wide start value, so it only requests the
@@ -2814,7 +2834,9 @@ struct VPFirstOrderRecurrencePHIRecipe : public VPHeaderPHIRecipe {
VPCostContext &Ctx) const override;
/// Returns true if the recipe only uses the first lane of operand \p Op.
- bool usesFirstLaneOnly(const VPValue *Op) const override {
+ bool
+ usesFirstLaneOnly(const VPValue *Op,
+ SmallPtrSetImpl<const VPValue *> &Visited) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
return Op == getStartValue();
@@ -2928,7 +2950,9 @@ class VPReductionPHIRecipe : public VPHeaderPHIRecipe, public VPIRFlags {
}
/// Returns true if the recipe only uses the first lane of operand \p Op.
- bool usesFirstLaneOnly(const VPValue *Op) const override {
+ bool
+ usesFirstLaneOnly(const VPValue *Op,
+ SmallPtrSetImpl<const VPValue *> &Visited) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
return isOrdered() || isInLoop();
@@ -3017,7 +3041,9 @@ class LLVM_ABI_FOR_TEST VPBlendRecipe : public VPRecipeWithIRFlags {
VPCostContext &Ctx) const override;
/// Returns true if the recipe only uses the first lane of operand \p Op.
- bool usesFirstLaneOnly(const VPValue *Op) const override;
+ bool
+ usesFirstLaneOnly(const VPValue *Op,
+ SmallPtrSetImpl<const VPValue *> &Visited) const override;
protected:
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
@@ -3110,7 +3136,9 @@ class LLVM_ABI_FOR_TEST VPInterleaveBase : public VPRecipeBase,
VPCostContext &Ctx) const override;
/// Returns true if the recipe only uses the first lane of operand \p Op.
- bool usesFirstLaneOnly(const VPValue *Op) const override = 0;
+ bool usesFirstLaneOnly(
+ const VPValue *Op,
+ SmallPtrSetImpl<const VPValue *> &Visited) const override = 0;
/// Returns the number of stored operands of this interleave group. Returns 0
/// for load interleave groups.
@@ -3149,7 +3177,9 @@ class LLVM_ABI_FOR_TEST VPInterleaveRecipe final : public VPInterleaveBase {
/// Generate the wide load or store, and shuffles.
void execute(VPTransformState &State) override;
- bool usesFirstLaneOnly(const VPValue *Op) const override {
+ bool
+ usesFirstLaneOnly(const VPValue *Op,
+ SmallPtrSetImpl<const VPValue *> &Visited) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
return Op == getAddr() && !llvm::is_contained(getStoredValues(), Op);
@@ -3198,7 +3228,9 @@ class LLVM_ABI_FOR_TEST VPInterleaveEVLRecipe final : public VPInterleaveBase {
void execute(VPTransformState &State) override;
/// The recipe only uses the first lane of the address, and EVL operand.
- bool usesFirstLaneOnly(const VPValue *Op) const override {
+ bool
+ usesFirstLaneOnly(const VPValue *Op,
+ SmallPtrSetImpl<const VPValue *> &Visited) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
return (Op == getAddr() && !llvm::is_contained(getStoredValues(), Op)) ||
@@ -3369,7 +3401,9 @@ class LLVM_ABI_FOR_TEST VPReductionEVLRecipe : public VPReductionRecipe {
VPValue *getEVL() const { return getOperand(2); }
/// Returns true if the recipe only uses the first lane of operand \p Op.
- bool usesFirstLaneOnly(const VPValue *Op) const override {
+ bool
+ usesFirstLaneOnly(const VPValue *Op,
+ SmallPtrSetImpl<const VPValue *> &Visited) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
return Op == getEVL();
@@ -3455,7 +3489,9 @@ class LLVM_ABI_FOR_TEST VPReplicateRecipe : public VPRecipeWithIRFlags,
bool isPredicated() const { return IsPredicated; }
/// Returns true if the recipe only uses the first lane of operand \p Op.
- bool usesFirstLaneOnly(const VPValue *Op) const override {
+ bool
+ usesFirstLaneOnly(const VPValue *Op,
+ SmallPtrSetImpl<const VPValue *> &Visited) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
return isSingleScalar();
@@ -3834,7 +3870,9 @@ struct LLVM_ABI_FOR_TEST VPWidenLoadRecipe final : public VPSingleDefRecipe,
}
/// Returns true if the recipe only uses the first lane of operand \p Op.
- bool usesFirstLaneOnly(const VPValue *Op) const override {
+ bool
+ usesFirstLaneOnly(const VPValue *Op,
+ SmallPtrSetImpl<const VPValue *> &Visited) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
// Widened, consecutive loads operations only demand the first lane of
@@ -3888,7 +3926,9 @@ struct LLVM_ABI_FOR_TEST VPWidenLoadEVLRecipe final
VPCostContext &Ctx) const override;
/// Returns true if the recipe only uses the first lane of operand \p Op.
- bool usesFirstLaneOnly(const VPValue *Op) const override {
+ bool
+ usesFirstLaneOnly(const VPValue *Op,
+ SmallPtrSetImpl<const VPValue *> &Visited) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
// Widened loads only demand the first lane of EVL and consecutive loads
@@ -3940,7 +3980,9 @@ struct LLVM_ABI_FOR_TEST VPWidenStoreRecipe final : public VPRecipeBase,
}
/// Returns true if the recipe only uses the first lane of operand \p Op.
- bool usesFirstLaneOnly(const VPValue *Op) const override {
+ bool
+ usesFirstLaneOnly(const VPValue *Op,
+ SmallPtrSetImpl<const VPValue *> &Visited) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
// Widened, consecutive stores only demand the first lane of their address,
@@ -3993,7 +4035,9 @@ struct LLVM_ABI_FOR_TEST VPWidenStoreEVLRecipe final
VPCostContext &Ctx) const override;
/// Returns true if the recipe only uses the first lane of operand \p Op.
- bool usesFirstLaneOnly(const VPValue *Op) const override {
+ bool
+ usesFirstLaneOnly(const VPValue *Op,
+ SmallPtrSetImpl<const VPValue *> &Visited) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
if (Op == getEVL()) {
@@ -4112,7 +4156,9 @@ class VPCurrentIterationPHIRecipe : public VPHeaderPHIRecipe {
}
/// Returns true if the recipe only uses the first lane of operand \p Op.
- bool usesFirstLaneOnly(const VPValue *Op) const override {
+ bool
+ usesFirstLaneOnly(const VPValue *Op,
+ SmallPtrSetImpl<const VPValue *> &Visited) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
return true;
@@ -4226,7 +4272,9 @@ class LLVM_ABI_FOR_TEST VPDerivedIVRecipe : public VPRecipeWithIRFlags {
InductionDescriptor::InductionKind getInductionKind() const { return Kind; }
/// Returns true if the recipe only uses the first lane of operand \p Op.
- bool usesFirstLaneOnly(const VPValue *Op) const override {
+ bool
+ usesFirstLaneOnly(const VPValue *Op,
+ SmallPtrSetImpl<const VPValue *> &Visited) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
return true;
@@ -4302,7 +4350,9 @@ class LLVM_ABI_FOR_TEST VPScalarIVStepsRecipe : public VPRecipeWithIRFlags {
bool doesGeneratePerAllLanes() const;
/// Returns true if the recipe only uses the first lane of operand \p Op.
- bool usesFirstLaneOnly(const VPValue *Op) const override {
+ bool
+ usesFirstLaneOnly(const VPValue *Op,
+ SmallPtrSetImpl<const VPValue *> &Visited) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
return true;
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index ae9001dc8c67fa..350ef7a938a073 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -1758,10 +1758,11 @@ bool VPInstruction::opcodeMayReadOrWriteFromMemory() const {
}
}
-bool VPInstruction::usesFirstLaneOnly(const VPValue *Op) const {
+bool VPInstruction::usesFirstLaneOnly(
+ const VPValue *Op, SmallPtrSetImpl<const VPValue *> &Visited) const {
assert(is_contained(operands(), Op) && "Op must be an operand of the recipe");
if (Instruction::isBinaryOp(getOpcode()) || Instruction::isCast(getOpcode()))
- return vputils::onlyFirstLaneUsed(this);
+ return vputils::onlyFirstLaneUsed(this, Visited);
switch (getOpcode()) {
default:
@@ -1781,7 +1782,7 @@ bool VPInstruction::usesFirstLaneOnly(const VPValue *Op) const {
case Instruction::Freeze:
case VPInstruction::Not:
// TODO: Cover additional opcodes.
- return vputils::onlyFirstLaneUsed(this);
+ return vputils::onlyFirstLaneUsed(this, Visited);
case Instruction::Load:
case VPInstruction::ActiveLaneMask:
case VPInstruction::WideActiveLaneMask:
@@ -1802,7 +1803,7 @@ bool VPInstruction::usesFirstLaneOnly(const VPValue *Op) const {
// Before replicating, it will have only a single operand.
return getNumOperands() > 1;
case VPInstruction::PtrAdd:
- return Op == getOperand(0) || vputils::onlyFirstLaneUsed(this);
+ return Op == getOperand(0) || vputils::onlyFirstLaneUsed(this, Visited);
case VPInstruction::WidePtrAdd:
// WidePtrAdd supports scalar and vector base addresses.
return false;
@@ -2244,7 +2245,7 @@ void VPWidenCallRecipe::execute(VPTransformState &State) {
if (!VFTy->getParamType(I.index())->isVectorTy())
Arg = State.get(I.value(), VPLane(0));
else
- Arg = State.get(I.value(), usesFirstLaneOnly(I.value()));
+ Arg = State.get(I.value(), VPUser::usesFirstLaneOnly(I.value()));
Args.push_back(Arg);
}
@@ -2276,7 +2277,8 @@ InstructionCost VPWidenCallRecipe::computeCallCost(Function *Variant,
Ctx.CostKind);
}
-bool VPWidenCallRecipe::usesFirstLaneOnly(const VPValue *Op) const {
+bool VPWidenCallRecipe::usesFirstLaneOnly(
+ const VPValue *Op, SmallPtrSetImpl<const VPValue *> &Visited) const {
assert(is_contained(operands(), Op) && "Op must be an operand of the recipe");
assert(Variant && "Variant not set");
FunctionType *VFTy = Variant->getFunctionType();
@@ -2340,7 +2342,7 @@ CallInst *VPWidenIntrinsicRecipe::createVectorCall(VPTransformState &State) {
State.TTI))
Arg = State.get(I.value(), VPLane(0));
else
- Arg = State.get(I.value(), usesFirstLaneOnly(I.value()));
+ Arg = State.get(I.value(), VPUser::usesFirstLaneOnly(I.value()));
if (isVectorIntrinsicWithOverloadTypeAtArg(VectorIntrinsicID, I.index(),
State.TTI))
TysForDecl.push_back(Arg->getType());
@@ -2433,7 +2435,8 @@ StringRef VPWidenIntrinsicRecipe::getIntrinsicName() const {
return Intrinsic::getBaseName(VectorIntrinsicID);
}
-bool VPWidenIntrinsicRecipe::usesFirstLaneOnly(const VPValue *Op) const {
+bool VPWidenIntrinsicRecipe::usesFirstLaneOnly(
+ const VPValue *Op, SmallPtrSetImpl<const VPValue *> &Visited) const {
assert(is_contained(operands(), Op) && "Op must be an operand of the recipe");
return all_of(enumerate(operands()), [this, &Op](const auto &X) {
auto [Idx, V] = X;
@@ -3327,7 +3330,8 @@ void VPScalarIVStepsRecipe::printRecipe(raw_ostream &O, const Twine &Indent,
}
#endif
-bool VPWidenGEPRecipe::usesFirstLaneOnly(const VPValue *Op) const {
+bool VPWidenGEPRecipe::usesFirstLaneOnly(
+ const VPValue *Op, SmallPtrSetImpl<const VPValue *> &Visited) const {
assert(is_contained(operands(), Op) && "Op must be an operand of the recipe");
return vputils::isSingleScalar(Op);
}
@@ -5158,9 +5162,10 @@ void VPReductionPHIRecipe::printRecipe(raw_ostream &O, const Twine &Indent,
}
#endif
-bool VPBlendRecipe::usesFirstLaneOnly(const VPValue *Op) const {
+bool VPBlendRecipe::usesFirstLaneOnly(
+ const VPValue *Op, SmallPtrSetImpl<const VPValue *> &Visited) const {
assert(is_contained(operands(), Op) && "Op must be an operand of the recipe");
- return vputils::onlyFirstLaneUsed(this);
+ return vputils::onlyFirstLaneUsed(this, Visited);
}
void VPWidenPHIRecipe::execute(VPTransformState &State) {
diff --git a/llvm/lib/Transforms/Vectorize/VPlanUtils.cpp b/llvm/lib/Transforms/Vectorize/VPlanUtils.cpp
index b68040911c1429..e905f297b33af3 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanUtils.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanUtils.cpp
@@ -33,8 +33,17 @@ using namespace llvm::VPlanPatternMatch;
using namespace llvm::SCEVPatternMatch;
bool vputils::onlyFirstLaneUsed(const VPValue *Def) {
- return all_of(Def->users(),
- [Def](const VPUser *U) { return U->usesFirstLaneOnly(Def); });
+ SmallPtrSet<const VPValue *, 8> Visited;
+ return onlyFirstLaneUsed(Def, Visited);
+}
+
+bool vputils::onlyFirstLaneUsed(const VPValue *Def,
+ SmallPtrSetImpl<const VPValue *> &Visited) {
+ if (!Visited.insert(Def).second)
+ return true;
+ return all_of(Def->users(), [Def, &Visited](const VPUser *U) {
+ return U->usesFirstLaneOnly(Def, Visited);
+ });
}
bool vputils::onlyFirstPartUsed(const VPValue *Def) {
diff --git a/llvm/lib/Transforms/Vectorize/VPlanUtils.h b/llvm/lib/Transforms/Vectorize/VPlanUtils.h
index c046239e2f9830..7e01e00f51ed5d 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanUtils.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanUtils.h
@@ -28,6 +28,11 @@ namespace vputils {
/// Returns true if only the first lane of \p Def is used.
bool onlyFirstLaneUsed(const VPValue *Def);
+/// Returns true if only the first lane of \p Def is used. Accepts a \p Visited
+/// set for recursive calls inside usesFirstLaneOnly().
+bool onlyFirstLaneUsed(const VPValue *Def,
+ SmallPtrSetImpl<const VPValue *> &Visited);
+
/// Returns true if only the first part of \p Def is used.
bool onlyFirstPartUsed(const VPValue *Def);
diff --git a/llvm/lib/Transforms/Vectorize/VPlanValue.h b/llvm/lib/Transforms/Vectorize/VPlanValue.h
index 7256c3b4e1f5d3..1803ab2202d199 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanValue.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanValue.h
@@ -21,6 +21,7 @@
#define LLVM_TRANSFORMS_VECTORIZE_VPLAN_VALUE_H
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/ADT/iterator_range.h"
@@ -484,12 +485,20 @@ class LLVM_ABI_FOR_TEST VPUser {
/// Returns true if the VPUser only uses the first lane of operand \p Op.
/// Conservatively returns false.
- virtual bool usesFirstLaneOnly(const VPValue *Op) const {
+ virtual bool
+ usesFirstLaneOnly(const VPValue *Op,
+ SmallPtrSetImpl<const VPValue *> &Visited) const {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
return false;
}
+ /// Convenience wrapper that creates a fresh Visited set.
+ bool usesFirstLaneOnly(const VPValue *Op) const {
+ SmallPtrSet<const VPValue *, 8> Visited;
+ return usesFirstLaneOnly(Op, Visited);
+ }
+
/// Returns true if the VPUser only uses the first part of operand \p Op.
/// Conservatively returns false.
virtual bool usesFirstPartOnly(const VPValue *Op) const {
More information about the llvm-commits
mailing list