xref: /llvm-project/llvm/lib/Transforms/Vectorize/VPlanUtils.cpp (revision 6c8f41d3367476d35ac730abf9f980291737193b)
171ede8d8SRamkumar Ramachandra //===- VPlanUtils.cpp - VPlan-related utilities ---------------------------===//
271ede8d8SRamkumar Ramachandra //
371ede8d8SRamkumar Ramachandra // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
471ede8d8SRamkumar Ramachandra // See https://llvm.org/LICENSE.txt for license information.
571ede8d8SRamkumar Ramachandra // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
671ede8d8SRamkumar Ramachandra //
771ede8d8SRamkumar Ramachandra //===----------------------------------------------------------------------===//
871ede8d8SRamkumar Ramachandra 
971ede8d8SRamkumar Ramachandra #include "VPlanUtils.h"
1071ede8d8SRamkumar Ramachandra #include "VPlanPatternMatch.h"
110d736e29SFlorian Hahn #include "llvm/ADT/TypeSwitch.h"
1271ede8d8SRamkumar Ramachandra #include "llvm/Analysis/ScalarEvolutionExpressions.h"
1371ede8d8SRamkumar Ramachandra 
1471ede8d8SRamkumar Ramachandra using namespace llvm;
1571ede8d8SRamkumar Ramachandra 
1671ede8d8SRamkumar Ramachandra bool vputils::onlyFirstLaneUsed(const VPValue *Def) {
1771ede8d8SRamkumar Ramachandra   return all_of(Def->users(),
1871ede8d8SRamkumar Ramachandra                 [Def](const VPUser *U) { return U->onlyFirstLaneUsed(Def); });
1971ede8d8SRamkumar Ramachandra }
2071ede8d8SRamkumar Ramachandra 
2171ede8d8SRamkumar Ramachandra bool vputils::onlyFirstPartUsed(const VPValue *Def) {
2271ede8d8SRamkumar Ramachandra   return all_of(Def->users(),
2371ede8d8SRamkumar Ramachandra                 [Def](const VPUser *U) { return U->onlyFirstPartUsed(Def); });
2471ede8d8SRamkumar Ramachandra }
2571ede8d8SRamkumar Ramachandra 
2671ede8d8SRamkumar Ramachandra VPValue *vputils::getOrCreateVPValueForSCEVExpr(VPlan &Plan, const SCEV *Expr,
2771ede8d8SRamkumar Ramachandra                                                 ScalarEvolution &SE) {
2871ede8d8SRamkumar Ramachandra   if (auto *Expanded = Plan.getSCEVExpansion(Expr))
2971ede8d8SRamkumar Ramachandra     return Expanded;
3071ede8d8SRamkumar Ramachandra   VPValue *Expanded = nullptr;
3171ede8d8SRamkumar Ramachandra   if (auto *E = dyn_cast<SCEVConstant>(Expr))
3271ede8d8SRamkumar Ramachandra     Expanded = Plan.getOrAddLiveIn(E->getValue());
3371ede8d8SRamkumar Ramachandra   else if (auto *E = dyn_cast<SCEVUnknown>(Expr))
3471ede8d8SRamkumar Ramachandra     Expanded = Plan.getOrAddLiveIn(E->getValue());
3571ede8d8SRamkumar Ramachandra   else {
3671ede8d8SRamkumar Ramachandra     Expanded = new VPExpandSCEVRecipe(Expr, SE);
37*6c8f41d3SFlorian Hahn     Plan.getEntry()->appendRecipe(Expanded->getDefiningRecipe());
3871ede8d8SRamkumar Ramachandra   }
3971ede8d8SRamkumar Ramachandra   Plan.addSCEVExpansion(Expr, Expanded);
4071ede8d8SRamkumar Ramachandra   return Expanded;
4171ede8d8SRamkumar Ramachandra }
4271ede8d8SRamkumar Ramachandra 
4371ede8d8SRamkumar Ramachandra bool vputils::isHeaderMask(const VPValue *V, VPlan &Plan) {
4471ede8d8SRamkumar Ramachandra   if (isa<VPActiveLaneMaskPHIRecipe>(V))
4571ede8d8SRamkumar Ramachandra     return true;
4671ede8d8SRamkumar Ramachandra 
4771ede8d8SRamkumar Ramachandra   auto IsWideCanonicalIV = [](VPValue *A) {
4871ede8d8SRamkumar Ramachandra     return isa<VPWidenCanonicalIVRecipe>(A) ||
4971ede8d8SRamkumar Ramachandra            (isa<VPWidenIntOrFpInductionRecipe>(A) &&
5071ede8d8SRamkumar Ramachandra             cast<VPWidenIntOrFpInductionRecipe>(A)->isCanonical());
5171ede8d8SRamkumar Ramachandra   };
5271ede8d8SRamkumar Ramachandra 
5371ede8d8SRamkumar Ramachandra   VPValue *A, *B;
5471ede8d8SRamkumar Ramachandra   using namespace VPlanPatternMatch;
5571ede8d8SRamkumar Ramachandra 
5671ede8d8SRamkumar Ramachandra   if (match(V, m_ActiveLaneMask(m_VPValue(A), m_VPValue(B))))
5771ede8d8SRamkumar Ramachandra     return B == Plan.getTripCount() &&
5871ede8d8SRamkumar Ramachandra            (match(A, m_ScalarIVSteps(m_CanonicalIV(), m_SpecificInt(1))) ||
5971ede8d8SRamkumar Ramachandra             IsWideCanonicalIV(A));
6071ede8d8SRamkumar Ramachandra 
6171ede8d8SRamkumar Ramachandra   return match(V, m_Binary<Instruction::ICmp>(m_VPValue(A), m_VPValue(B))) &&
6271ede8d8SRamkumar Ramachandra          IsWideCanonicalIV(A) && B == Plan.getOrCreateBackedgeTakenCount();
6371ede8d8SRamkumar Ramachandra }
640d736e29SFlorian Hahn 
650d736e29SFlorian Hahn const SCEV *vputils::getSCEVExprForVPValue(VPValue *V, ScalarEvolution &SE) {
660d736e29SFlorian Hahn   if (V->isLiveIn())
670d736e29SFlorian Hahn     return SE.getSCEV(V->getLiveInIRValue());
680d736e29SFlorian Hahn 
690d736e29SFlorian Hahn   // TODO: Support constructing SCEVs for more recipes as needed.
700d736e29SFlorian Hahn   return TypeSwitch<const VPRecipeBase *, const SCEV *>(V->getDefiningRecipe())
710d736e29SFlorian Hahn       .Case<VPExpandSCEVRecipe>(
720d736e29SFlorian Hahn           [](const VPExpandSCEVRecipe *R) { return R->getSCEV(); })
730d736e29SFlorian Hahn       .Default([&SE](const VPRecipeBase *) { return SE.getCouldNotCompute(); });
740d736e29SFlorian Hahn }
758ec40675SFlorian Hahn 
768ec40675SFlorian Hahn bool vputils::isUniformAcrossVFsAndUFs(VPValue *V) {
778ec40675SFlorian Hahn   using namespace VPlanPatternMatch;
788ec40675SFlorian Hahn   // Live-ins are uniform.
798ec40675SFlorian Hahn   if (V->isLiveIn())
808ec40675SFlorian Hahn     return true;
818ec40675SFlorian Hahn 
828ec40675SFlorian Hahn   VPRecipeBase *R = V->getDefiningRecipe();
838ec40675SFlorian Hahn   if (R && V->isDefinedOutsideLoopRegions()) {
848ec40675SFlorian Hahn     if (match(V->getDefiningRecipe(),
858ec40675SFlorian Hahn               m_VPInstruction<VPInstruction::CanonicalIVIncrementForPart>(
868ec40675SFlorian Hahn                   m_VPValue())))
878ec40675SFlorian Hahn       return false;
888ec40675SFlorian Hahn     return all_of(R->operands(),
898ec40675SFlorian Hahn                   [](VPValue *Op) { return isUniformAcrossVFsAndUFs(Op); });
908ec40675SFlorian Hahn   }
918ec40675SFlorian Hahn 
928ec40675SFlorian Hahn   auto *CanonicalIV = R->getParent()->getPlan()->getCanonicalIV();
938ec40675SFlorian Hahn   // Canonical IV chain is uniform.
948ec40675SFlorian Hahn   if (V == CanonicalIV || V == CanonicalIV->getBackedgeValue())
958ec40675SFlorian Hahn     return true;
968ec40675SFlorian Hahn 
978ec40675SFlorian Hahn   return TypeSwitch<const VPRecipeBase *, bool>(R)
988ec40675SFlorian Hahn       .Case<VPDerivedIVRecipe>([](const auto *R) { return true; })
998ec40675SFlorian Hahn       .Case<VPReplicateRecipe>([](const auto *R) {
1008ec40675SFlorian Hahn         // Loads and stores that are uniform across VF lanes are handled by
1018ec40675SFlorian Hahn         // VPReplicateRecipe.IsUniform. They are also uniform across UF parts if
1028ec40675SFlorian Hahn         // all their operands are invariant.
1038ec40675SFlorian Hahn         // TODO: Further relax the restrictions.
1048ec40675SFlorian Hahn         return R->isUniform() &&
1058ec40675SFlorian Hahn                (isa<LoadInst, StoreInst>(R->getUnderlyingValue())) &&
1068ec40675SFlorian Hahn                all_of(R->operands(),
1078ec40675SFlorian Hahn                       [](VPValue *Op) { return isUniformAcrossVFsAndUFs(Op); });
1088ec40675SFlorian Hahn       })
1098ec40675SFlorian Hahn       .Case<VPScalarCastRecipe, VPWidenCastRecipe>([](const auto *R) {
1108ec40675SFlorian Hahn         // A cast is uniform according to its operand.
1118ec40675SFlorian Hahn         return isUniformAcrossVFsAndUFs(R->getOperand(0));
1128ec40675SFlorian Hahn       })
1138ec40675SFlorian Hahn       .Default([](const VPRecipeBase *) { // A value is considered non-uniform
1148ec40675SFlorian Hahn                                           // unless proven otherwise.
1158ec40675SFlorian Hahn         return false;
1168ec40675SFlorian Hahn       });
1178ec40675SFlorian Hahn }
118