================
@@ -7309,6 +7331,231 @@ void VPlanTransforms::makeMemOpWideningDecisions(VPlan 
&Plan, VFRange &Range,
                            });
 }
 
+void VPlanTransforms::multiversionForUnitStridedMemOps(
+    VPlan &Plan, VPCostContext &CostCtx, VPRecipeBuilder &RecipeBuilder,
+    VFRange &Range, SmallVectorImpl<VPInstruction *> &MemOps) {
+  if (CostCtx.L->getHeader()->getParent()->hasOptSize())
+    return;
+  SmallVector<VPInstruction *> RemainingOps;
+
+  ScalarEvolution *SE = CostCtx.PSE.getSE();
+
+  PredicatedScalarEvolution StrideMVPSE(*SE, const_cast<Loop &>(*CostCtx.L));
+
+  SCEVUnionPredicate StridePredicates({}, *SE);
+
+  // Use `for_each` so that we could do `return Skip();`.
+  for_each(MemOps, [&](VPInstruction *VPI) {
+    auto Skip = [&]() { RemainingOps.push_back(VPI); };
+    if (RecipeBuilder.isConsecutiveWithoutVPlanBasedStrideSpeculation(VPI))
+      return Skip();
+    auto *PtrOp = VPI->getOpcode() == Instruction::Load ? VPI->getOperand(0)
+                                                        : VPI->getOperand(1);
+
+    const SCEV *PtrSCEV =
+        vputils::getSCEVExprForVPValue(PtrOp, CostCtx.PSE, CostCtx.L);
+    const SCEV *Start = nullptr;
+    const SCEV *Stride = nullptr;
+
+    if (!match(PtrSCEV, m_scev_AffineAddRec(m_SCEV(Start), m_SCEV(Stride),
+                                            m_SpecificLoop(CostCtx.L)))) {
+      return Skip();
+    }
+
+    Type *ScalarTy = VPI->getOpcode() == Instruction::Load
+                         ? VPI->getScalarType()
+                         : VPI->getOperand(0)->getScalarType();
+
+    if (VPI->getMask()) {
+      auto &TTI = CostCtx.TTI;
+      Instruction *I = VPI->getUnderlyingInstr();
+      unsigned AS = getLoadStoreAddressSpace(I);
+      const Align Alignment = getLoadStoreAlignment(I);
+      if (!LoopVectorizationPlanner::getDecisionAndClampRange(
+              [&](ElementCount VF) -> bool {
+                Type *VTy = VectorType::get(ScalarTy, VF);
+                return VPI->getOpcode() == Instruction::Load
+                           ? (TTI.isLegalMaskedLoad(VTy, Alignment, AS) ||
+                              TTI.isLegalMaskedGather(VTy, Alignment))
+                           : (TTI.isLegalMaskedStore(VTy, Alignment, AS) ||
+                              TTI.isLegalMaskedScatter(VTy, Alignment));
+              },
+              Range))
+        return Skip();
+    }
+
+    const auto *TypeSize = cast<SCEVConstant>(SE->getSizeOfExpr(
+        Stride->getType(), SE->getDataLayout().getTypeStoreSize(ScalarTy)));
+
+    auto ReplaceWithUnitStrided = [&]() {
+      VPBuilder Builder(VPI);
+      VPValue *StrideInBytes = Plan.getOrAddLiveIn(TypeSize->getValue());
+      auto *VecPtr =
+          new VPVectorPointerRecipe(PtrOp, ScalarTy, StrideInBytes,
+                                    GEPNoWrapFlags::none(), 
VPI->getDebugLoc());
+      Builder.insert(VecPtr);
+      if (VPI->getOpcode() == Instruction::Load) {
+        auto *WideLoad = new VPWidenLoadRecipe(
+            cast<LoadInst>(*VPI->getUnderlyingInstr()), VecPtr, VPI->getMask(),
+            true, *VPI, VPI->getDebugLoc());
+        Builder.insert(WideLoad);
+        VPI->replaceAllUsesWith(WideLoad);
+      } else {
+        auto *WideStore = new VPWidenStoreRecipe(
+            cast<StoreInst>(*VPI->getUnderlyingInstr()), VecPtr,
+            VPI->getOperand(0), VPI->getMask(), true, *VPI, 
VPI->getDebugLoc());
+        Builder.insert(WideStore);
+      }
+      VPI->eraseFromParent();
+    };
+
+    if (isa<SCEVConstant>(Stride)) {
+      if (Stride != TypeSize)
+        return Skip();
+
+      // Earlier MV helped with this memory operation too.
+      ReplaceWithUnitStrided();
+      return;
+    }
+
+    const SCEVConstant *StrideConstantMultiplier;
+    const SCEV *StrideNonConstantMultiplier;
+
+    const SCEV *ToMultiVersion = Stride;
+    const SCEV *MVConst = TypeSize;
+    if (match(Stride, m_scev_c_Mul(m_SCEVConstant(StrideConstantMultiplier),
+                                   m_SCEV(StrideNonConstantMultiplier)))) {
+      if (TypeSize != StrideConstantMultiplier) {
+        // TODO: Support `TypeSize = N * StrideCosntantMultiplier`,
+        // including negative `N`. For now, only process when they're equal,
+        // which matches the usefull part of the legacy behavior that
+        // multiversiones GEP index for stride one.
+        return Skip();
+      }
+      ToMultiVersion = StrideNonConstantMultiplier;
+      MVConst = SE->getOne(ToMultiVersion->getType());
+    } else if (!TypeSize->isOne()) {
+      // Likewise - try to match legacy behavior.
+      return Skip();
+    }
+
+    while (auto *C = dyn_cast<SCEVIntegralCastExpr>(ToMultiVersion)) {
+      ToMultiVersion = C->getOperand();
+      MVConst = SE->getTruncateOrSignExtend(MVConst, 
ToMultiVersion->getType());
+    }
+
+    if (!isa<SCEVUnknown>(ToMultiVersion)) {
+      // Match legacy behavior.
+      // If/when changed, make sure that explicit poison/undef in the defining
+      // expression doesn't cause any issues.
+      return Skip();
+    }
+
+    Value *StrideVal = cast<SCEVUnknown>(ToMultiVersion)->getValue();
+
+    if (isa<UndefValue>(StrideVal))
+      return Skip();
+
+    const SCEVPredicate *NewPred =
+        SE->getComparePredicate(CmpInst::ICMP_EQ, ToMultiVersion, MVConst);
+
+    // Check if new predicate implies that backedge is never taken. If so, 
there
+    // is no reason to multiversion for it.
+    SmallVector<const SCEVPredicate *> Preds{&CostCtx.PSE.getPredicate(),
+                                             &StridePredicates, NewPred};
+    auto *PredicatedMaxBTC = SE->rewriteUsingPredicate(
+        SE->getSymbolicMaxBackedgeTakenCount(CostCtx.L), CostCtx.L,
+        StridePredicates.getUnionWith(NewPred, *SE)
+            .getUnionWith(&CostCtx.PSE.getPredicate(), *SE));
+
+    if (LoopVectorizationPlanner::getDecisionAndClampRange(
+            [&](ElementCount VF) {
+              return SE->isKnownPositive(SE->getMinusSCEV(
+                  SE->getConstant(PredicatedMaxBTC->getType(),
+                                  VF.isScalable() ? 1 : VF.getFixedValue() - 
1),
+                  PredicatedMaxBTC));
+            },
+            Range))
+      return Skip();
+
+    StridePredicates = StridePredicates.getUnionWith(NewPred, *SE);
+
+    auto ReplaceMVUses = [&](Value *V) {
+      VPValue *From = Plan.getLiveIn(V);
+      if (!From)
+        return;
+      VPValue *To = Plan.getConstantInt(
+          From->getScalarType(),
+          cast<SCEVConstant>(MVConst)->getAPInt().getLimitedValue());
----------------
eas wrote:

I'm not matching it, `MVConst` is created as a constant in the code above 
(except `SE::getOne` hides that return type behind just `const SCEV *`)

https://github.com/llvm/llvm-project/pull/182595
_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to