[llvm] [VPlan] Add doesGenerateSingleScalalar and use where applicable. (NFCI) (PR #222447)

via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 9 14:01:33 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-vectorizers

Author: Florian Hahn (fhahn)

<details>
<summary>Changes</summary>

Similar to #<!-- -->199047, factor out the non-recursive logic from isSingleScalar to doesGenerateSingleScalar to determine single-scalar-ness encoded by the recipe, without recursion.

Use the cheaper, non-recursive variant at sites where the recursive result cannot differ or is not needed:
 - VPCSEDenseMapInfo hash/equality: operands are compared separately, so the recursive classification is fully determined including operands in the hash
 - materializePacksAndUnpacks,  VPWidenGEPRecipe::usesFirstLaneOnly: narrowToSingleScalar already scalarizes all relevant cases explicitly.

Most other users cannot be converted yet without functional changes

---
Full diff: https://github.com/llvm/llvm-project/pull/222447.diff


5 Files Affected:

- (modified) llvm/lib/Transforms/Vectorize/VPlanLowering.cpp (+1-1) 
- (modified) llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp (+1-1) 
- (modified) llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp (+7-5) 
- (modified) llvm/lib/Transforms/Vectorize/VPlanUtils.cpp (+23-12) 
- (modified) llvm/lib/Transforms/Vectorize/VPlanUtils.h (+4) 


``````````diff
diff --git a/llvm/lib/Transforms/Vectorize/VPlanLowering.cpp b/llvm/lib/Transforms/Vectorize/VPlanLowering.cpp
index ddde0cd83a704..ce8f06c561b1b 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanLowering.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanLowering.cpp
@@ -851,7 +851,7 @@ void VPlanTransforms::materializePacksAndUnpacks(VPlan &Plan) {
         // TODO: The Defs skipped here may or may not be vector values.
         // Introduce Unpacks, and remove them later, if they are guaranteed to
         // produce scalar values.
-        if (vputils::isSingleScalar(Def))
+        if (vputils::doesGenerateSingleScalar(Def))
           continue;
 
         // Only introduce an Unpack if some, but not all, users use the first
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index c0beb2e825e52..7de75811944c4 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -3250,7 +3250,7 @@ void VPScalarIVStepsRecipe::printRecipe(raw_ostream &O, const Twine &Indent,
 
 bool VPWidenGEPRecipe::usesFirstLaneOnly(const VPValue *Op) const {
   assert(is_contained(operands(), Op) && "Op must be an operand of the recipe");
-  return vputils::isSingleScalar(Op);
+  return vputils::doesGenerateSingleScalar(Op);
 }
 
 void VPWidenGEPRecipe::execute(VPTransformState &State) {
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
index d12aec83f2856..8fe06568e2ac8 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -2264,10 +2264,11 @@ struct VPCSEDenseMapInfo : public DenseMapInfo<VPSingleDefRecipe *> {
 
   /// Hash the underlying data of \p Def.
   static unsigned getHashValue(const VPSingleDefRecipe *Def) {
-    hash_code Result = hash_combine(
-        Def->getVPRecipeID(), vputils::getOpcodeOrIntrinsicID(Def),
-        getGEPSourceElementType(Def), Def->getScalarType(),
-        vputils::isSingleScalar(Def), hash_combine_range(Def->operands()));
+    hash_code Result =
+        hash_combine(Def->getVPRecipeID(), vputils::getOpcodeOrIntrinsicID(Def),
+                     getGEPSourceElementType(Def), Def->getScalarType(),
+                     vputils::doesGenerateSingleScalar(Def),
+                     hash_combine_range(Def->operands()));
     if (auto *RFlags = dyn_cast<VPRecipeWithIRFlags>(Def))
       if (RFlags->hasPredicate())
         return hash_combine(Result, RFlags->getPredicate());
@@ -2286,7 +2287,8 @@ struct VPCSEDenseMapInfo : public DenseMapInfo<VPSingleDefRecipe *> {
         vputils::getOpcodeOrIntrinsicID(L) !=
             vputils::getOpcodeOrIntrinsicID(R) ||
         getGEPSourceElementType(L) != getGEPSourceElementType(R) ||
-        vputils::isSingleScalar(L) != vputils::isSingleScalar(R) ||
+        vputils::doesGenerateSingleScalar(L) !=
+            vputils::doesGenerateSingleScalar(R) ||
         !equal(L->operands(), R->operands()))
       return false;
     assert(vputils::getOpcodeOrIntrinsicID(L) &&
diff --git a/llvm/lib/Transforms/Vectorize/VPlanUtils.cpp b/llvm/lib/Transforms/Vectorize/VPlanUtils.cpp
index 8327b30c7583e..43c1eb41778ac 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanUtils.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanUtils.cpp
@@ -431,7 +431,7 @@ bool vputils::isElementwise(const VPValue *V) {
   return Instruction::isUnaryOp(Opcode) || Instruction::isBinaryOp(Opcode);
 }
 
-bool vputils::isSingleScalar(const VPValue *VPV) {
+bool vputils::doesGenerateSingleScalar(const VPValue *VPV) {
   // Live-in, symbolic and canonical-IV region values are single-scalar.
   if (auto *RV = dyn_cast<VPRegionValue>(VPV))
     return RV == RV->getDefiningRegion()->getCanonicalIV();
@@ -445,19 +445,10 @@ bool vputils::isSingleScalar(const VPValue *VPV) {
     // lanes.
     if (RegionOfR && RegionOfR->isReplicator())
       return false;
-    return Rep->isSingleScalar() || (preservesUniformity(Rep->getOpcode()) &&
-                                     all_of(Rep->operands(), isSingleScalar));
-  }
-  if (isa<VPWidenGEPRecipe, VPBlendRecipe>(VPV))
-    return all_of(VPV->getDefiningRecipe()->operands(), isSingleScalar);
-  if (auto *WidenR = dyn_cast<VPWidenRecipe>(VPV)) {
-    return preservesUniformity(WidenR->getOpcode()) &&
-           all_of(WidenR->operands(), isSingleScalar);
+    return Rep->isSingleScalar();
   }
   if (auto *VPI = dyn_cast<VPInstruction>(VPV))
-    return VPI->isSingleScalar() || VPI->isVectorToScalar() ||
-           (preservesUniformity(VPI->getOpcode()) &&
-            all_of(VPI->operands(), isSingleScalar));
+    return VPI->isSingleScalar() || VPI->isVectorToScalar();
   if (auto *RR = dyn_cast<VPReductionRecipe>(VPV))
     return !RR->isPartialReduction();
   if (isa<VPVectorPointerRecipe, VPVectorEndPointerRecipe, VPDerivedIVRecipe>(
@@ -470,6 +461,26 @@ bool vputils::isSingleScalar(const VPValue *VPV) {
   return isa<VPExpandSCEVRecipe>(VPV);
 }
 
+bool vputils::isSingleScalar(const VPValue *VPV) {
+  if (doesGenerateSingleScalar(VPV))
+    return true;
+
+  // A uniformity-preserving operation is single-scalar if all its operands are.
+  if (auto *Rep = dyn_cast<VPReplicateRecipe>(VPV)) {
+    const VPRegionBlock *RegionOfR = Rep->getRegion();
+    if (RegionOfR && RegionOfR->isReplicator())
+      return false;
+    return preservesUniformity(Rep->getOpcode()) &&
+           all_of(Rep->operands(), isSingleScalar);
+  }
+  if (isa<VPWidenGEPRecipe, VPBlendRecipe>(VPV))
+    return all_of(VPV->getDefiningRecipe()->operands(), isSingleScalar);
+
+  return isa<VPWidenRecipe, VPInstruction>(VPV) &&
+         preservesUniformity(vputils::getOpcode(VPV)) &&
+         all_of(VPV->getDefiningRecipe()->operands(), isSingleScalar);
+}
+
 bool vputils::isUniformAcrossVFsAndUFs(const VPValue *V) {
   // Live-ins, symbolic and canonical-IV region values are uniform.
   if (auto *RV = dyn_cast<VPRegionValue>(V))
diff --git a/llvm/lib/Transforms/Vectorize/VPlanUtils.h b/llvm/lib/Transforms/Vectorize/VPlanUtils.h
index 738a5bc8b8066..8f1cbb9006209 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanUtils.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanUtils.h
@@ -70,6 +70,10 @@ bool isElementwise(const VPValue *V);
 /// Returns true if \p R produces scalar values for all VF lanes.
 bool doesGeneratePerAllLanes(const VPRecipeBase *R);
 
+/// Returns true if \p VPV is defined by a recipe producing a single-scalar
+/// value or a live-in/symbolic value/single-scalar region value.
+bool doesGenerateSingleScalar(const VPValue *VPV);
+
 /// Returns the header block of the first, top-level loop, or null if none
 /// exist.
 VPBasicBlock *getFirstLoopHeader(VPlan &Plan, VPDominatorTree &VPDT);

``````````

</details>


https://github.com/llvm/llvm-project/pull/222447


More information about the llvm-commits mailing list