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

Elvis Wang via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 9 22:14:52 PST 2026


================
@@ -1602,6 +1602,90 @@ void VPlanTransforms::simplifyRecipes(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))) {
+      if (!isa<VPWidenStoreRecipe>(&R))
+        continue;
+      // Convert an unmasked or header masked scatter with an uniform address
+      // into extract-last-lane + scalar store.
+      // TODO: Add a profitability check comparing the cost of a scatter vs.
+      // extract + scalar store.
+      auto *WidenStoreR = dyn_cast<VPWidenStoreRecipe>(&R);
+      if (WidenStoreR && vputils::isSingleScalar(WidenStoreR->getAddr()) &&
+          !WidenStoreR->isConsecutive()) {
+        assert(!WidenStoreR->isReverse() &&
+               "Not consecutive memory recipes shouldn't be reversed");
+        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;
+
+        VPInstruction *Extract;
+        if (!Mask) {
+          Extract = new VPInstruction(VPInstruction::ExtractLastLane,
+                                      {WidenStoreR->getOperand(1)});
+        } else {
+          // If the mask is the header mask, this mask contains 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);
+                    // ConvertToScalarCost = LastActiveLane + ExtractElement +
+                    // scalar store.
+                    InstructionCost ScalarCost = 0;
+                    auto *ValTy = Ctx.Types.inferScalarType(
+                        WidenStoreR->getStoredValue());
+
+                    if (!FoldTailWithEVL)
+                      ScalarCost += Ctx.getLastActiveLaneCost(
+                          Type::getInt1Ty(Ctx.LLVMCtx), VF);
+                    ScalarCost += Ctx.getExtractLaneCost(ValTy, VF);
+
+                    // Scalar store cost
+                    Instruction &I = WidenStoreR->getIngredient();
+                    unsigned AS = getLoadStoreAddressSpace(&I);
+                    TTI::OperandValueInfo OpInfo =
+                        TTI::getOperandInfo(I.getOperand(0));
+                    ScalarCost += Ctx.TTI.getMemoryOpCost(
+                        Instruction::Store, ValTy, WidenStoreR->getAlign(), AS,
+                        Ctx.CostKind, OpInfo, &I);
+
+                    return ScalarCost.isValid() && ScalarCost <= ScatterCost;
+                  },
+                  Range))
+            continue;
+
+          VPInstruction *Idx =
+              new VPInstruction(VPInstruction::LastActiveLane, Mask);
+          Idx->insertBefore(WidenStoreR);
+          Extract = new VPInstruction(VPInstruction::ExtractLane,
+                                      {Idx, WidenStoreR->getOperand(1)});
+        }
+        Extract->insertBefore(WidenStoreR);
+
+        // TODO: Sink the scalar store recipe to middle block if possible.
+        auto *ScalarStore = new VPReplicateRecipe(
+            &WidenStoreR->getIngredient(), {Extract, WidenStoreR->getAddr()},
+            true /*IsSingleScalar*/, nullptr /*Mask*/, {},
+            *WidenStoreR /*Metadata*/);
+        ScalarStore->insertBefore(WidenStoreR);
+        WidenStoreR->eraseFromParent();
+      }
+    }
+  }
+}
+
 static void narrowToSingleScalarRecipes(VPlan &Plan) {
----------------
ElvisWang123 wrote:

Oops, removed, thanks!

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


More information about the llvm-commits mailing list