[llvm] [LV] Convert scatter w/uniform addr and mask being header mask to scalar store. (PR #172799)

Ramkumar Ramachandra via llvm-commits llvm-commits at lists.llvm.org
Thu May 7 07:06:19 PDT 2026


================
@@ -1845,12 +1845,107 @@ static void reassociateHeaderMask(VPlan &Plan) {
   }
 }
 
+void VPlanTransforms::narrowScatters(VPlan &Plan, VPCostContext &Ctx,
+                                     VFRange &Range,
+                                     const bool &FoldTailWithEVL) {
+  if (Plan.hasScalarVFOnly())
+    return;
+
+  for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(
+           vp_depth_first_shallow(Plan.getVectorLoopRegion()->getEntry()))) {
+    for (VPRecipeBase &R : make_early_inc_range(reverse(*VPBB))) {
+      // Convert an unmasked or header masked scatter with a uniform address
+      // into extract-last-lane + scalar store.
+      auto *WidenStoreR = dyn_cast<VPWidenStoreRecipe>(&R);
+      if (!WidenStoreR ||
+          !vputils::isUniformAcrossVFsAndUFs(WidenStoreR->getAddr()) ||
+          WidenStoreR->isConsecutive())
+        continue;
+      VPValue *Mask = WidenStoreR->getMask();
+
+      // Convert the scatter to a scalar store if it is unmasked or header
+      // masked.
+      if (Mask && !vputils::isHeaderMask(Mask, Plan))
+        continue;
+
+      if (!Mask) {
+        VPInstruction *Extract = new VPInstruction(
+            VPInstruction::ExtractLastLane, {WidenStoreR->getOperand(1)});
+        // TODO: Sink the scalar store recipe to middle block if possible.
+        auto *ScalarStore = new VPReplicateRecipe(
+            &WidenStoreR->getIngredient(), {Extract, WidenStoreR->getAddr()},
+            /*IsSingleScalar*/ true, /*Mask*/ nullptr, {},
+            /*Metadata*/ *WidenStoreR);
+        Extract->insertBefore(WidenStoreR);
+        ScalarStore->insertBefore(WidenStoreR);
+        WidenStoreR->eraseFromParent();
+      } else {
+        // If the body is header-masked, it guarantees each iteration has at
+        // least one active lane. So it is safe to convert the scatter to a
+        // scalar store.
+        if (!LoopVectorizationPlanner::getDecisionAndClampRange(
+                [&](ElementCount VF) {
+                  InstructionCost ScatterCost =
+                      WidenStoreR->computeCost(VF, Ctx);
+                  auto *ValTy =
+                      Ctx.Types.inferScalarType(WidenStoreR->getStoredValue());
+
+                  // ScalarCost = LastActiveLaneCost + ExtractLaneCost +
+                  // ScalarStoreCost.
+                  InstructionCost ScalarCost = 0;
+
+                  // LastActiveLane can lower to EVL - 1 when folding tail with
+                  // EVL.
+                  if (FoldTailWithEVL)
+                    ScalarCost +=
+                        VPRecipeWithIRFlags::getCostForRecipeWithOpcodeAndTypes(
+                            Instruction::Sub, Type::getInt32Ty(Ctx.LLVMCtx),
+                            nullptr, ElementCount::getFixed(1), Ctx);
+                  else
+                    ScalarCost +=
+                        VPRecipeWithIRFlags::getCostForRecipeWithOpcodeAndTypes(
+                            VPInstruction::LastActiveLane,
+                            Type::getInt1Ty(Ctx.LLVMCtx), nullptr, VF, Ctx);
+                  ScalarCost +=
+                      VPRecipeWithIRFlags::getCostForRecipeWithOpcodeAndTypes(
+                          VPInstruction::ExtractLane, ValTy, nullptr, VF, Ctx);
+                  ScalarCost +=
+                      VPRecipeWithIRFlags::getCostForRecipeWithOpcodeAndTypes(
+                          Instruction::Store, ValTy,
+                          &WidenStoreR->getIngredient(), VF, Ctx);
+
+                  return ScalarCost.isValid() && ScalarCost <= ScatterCost;
+                },
+                Range)) {
+          continue;
+        }
+        VPBuilder Builder(WidenStoreR);
+        VPInstruction *LastActiveLane =
+            Builder.createNaryOp(VPInstruction::LastActiveLane, {Mask});
+        VPInstruction *Extract = Builder.createNaryOp(
+            VPInstruction::ExtractLane,
+            {LastActiveLane, WidenStoreR->getStoredValue()});
+        auto *ScalarStore = new VPReplicateRecipe(
+            &WidenStoreR->getIngredient(), {Extract, WidenStoreR->getAddr()},
+            /*IsSingleScalar*/ true, /*Mask*/ nullptr, {},
+            /*Metadata*/ *WidenStoreR);
+        ScalarStore->insertBefore(WidenStoreR);
+        WidenStoreR->eraseFromParent();
----------------
artagnon wrote:

Could unify this with the other ScalarStore insertion?

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


More information about the llvm-commits mailing list