[llvm] [VPlan] Reject partial reductions with invalid costs in getScaledReds. (PR #180438)
Sander de Smalen via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 9 02:24:21 PST 2026
================
@@ -5542,137 +5542,120 @@ struct VPPartialReductionChain {
unsigned ScaleFactor;
};
-// Helper to transform a partial reduction chain into a partial reduction
-// recipe. Returns true if transformation succeeded. Checks profitability and
-// clamps VF range.
-static bool transformToPartialReduction(const VPPartialReductionChain &Chain,
- VFRange &Range, VPCostContext &CostCtx,
- VPlan &Plan) {
+// Transform a partial reduction chain into a partial reduction recipe.
+// Assumes profitability has been checked. Performs RAUW so chained reductions'
+// accumulators are automatically updated. Updates the PHI's scale factor when
+// the accumulator is the reduction PHI.
+static void transformToPartialReduction(const VPPartialReductionChain &Chain,
+ VPTypeAnalysis &TypeInfo, VPlan &Plan) {
VPWidenRecipe *WidenRecipe = Chain.ReductionBinOp;
- unsigned ScaleFactor = Chain.ScaleFactor;
- assert(WidenRecipe->getNumOperands() == 2 && "Expected binary operation");
VPValue *BinOp = WidenRecipe->getOperand(0);
VPValue *Accumulator = WidenRecipe->getOperand(1);
-
- // Swap if needed to ensure Accumulator is the PHI or partial reduction.
- if (isa_and_present<VPReductionPHIRecipe, VPReductionRecipe>(BinOp))
+ if (isa_and_present<VPReductionPHIRecipe, VPReductionRecipe>(
+ BinOp->getDefiningRecipe()))
std::swap(BinOp, Accumulator);
- // For chained reductions, only transform if accumulator is already a PHI or
- // partial reduction. Otherwise, it needs to be transformed first.
- auto *AccumRecipe = Accumulator->getDefiningRecipe();
- if (!isa_and_present<VPReductionPHIRecipe, VPReductionRecipe>(AccumRecipe))
- return false;
+ Type *PhiType = TypeInfo.inferScalarType(Accumulator);
- // Check if the partial reduction is profitable for the VF range.
- Type *PhiType = CostCtx.Types.inferScalarType(Accumulator);
+ // Update PHI and start vector scale factors when accumulator is the PHI.
+ if (auto *RdxPhi =
+ dyn_cast<VPReductionPHIRecipe>(Accumulator->getDefiningRecipe())) {
+ assert(RdxPhi->getVFScaleFactor() == 1 && "scale factor must not be set");
+ RdxPhi->setVFScaleFactor(Chain.ScaleFactor);
+ auto *StartInst = cast<VPInstruction>(RdxPhi->getOperand(0));
+ assert(StartInst->getOpcode() == VPInstruction::ReductionStartVector &&
+ "start value must be ReductionStartVector");
+ StartInst->setOperand(2, Plan.getConstantInt(32, Chain.ScaleFactor));
+ }
- // Derive extend info from the stored extends.
+ // Handle SUB by negating the operand.
+ if (WidenRecipe->getOpcode() == Instruction::Sub) {
+ VPBuilder Builder(WidenRecipe);
+ auto *Zero = Plan.getConstantInt(TypeInfo.inferScalarType(BinOp), 0);
+ VPIRFlags Flags = WidenRecipe->getUnderlyingInstr()
+ ? VPIRFlags(*WidenRecipe->getUnderlyingInstr())
+ : VPIRFlags();
+ auto *NegRecipe = new VPWidenRecipe(Instruction::Sub, {Zero, BinOp}, Flags,
+ VPIRMetadata(), DebugLoc::getUnknown());
+ Builder.insert(NegRecipe);
+ BinOp = NegRecipe;
+ }
+
+ // Look for predicated reduction's condition and replace select if found.
+ VPValue *Cond = nullptr;
+ VPReductionPHIRecipe *RdxPhi;
+ auto *Sel = cast_or_null<VPInstruction>(vputils::findUserOf(
+ WidenRecipe, m_Select(m_VPValue(Cond), m_Specific(WidenRecipe),
+ m_ReductionPhi(RdxPhi))));
+
+ RecurKind RdxKind =
+ PhiType->isFloatingPointTy() ? RecurKind::FAdd : RecurKind::Add;
+ auto *PartialRed = new VPReductionRecipe(
+ RdxKind,
+ RdxKind == RecurKind::FAdd ? WidenRecipe->getFastMathFlags()
+ : FastMathFlags(),
+ WidenRecipe->getUnderlyingInstr(), Accumulator, BinOp, Cond,
+ RdxUnordered{/*VFScaleFactor=*/Chain.ScaleFactor});
+ PartialRed->insertBefore(WidenRecipe);
+
+ if (Sel)
+ Sel->replaceAllUsesWith(PartialRed);
+ WidenRecipe->replaceAllUsesWith(PartialRed);
+}
+
+/// Check if a partial reduction chain is is supported by the target (i.e. does
+/// not have an invalid cost) for the given VF range. Clamps the range and
+/// returns true if profitable for any VF.
+static bool isValidPartialReduction(const VPPartialReductionChain &Chain,
+ Type *PhiType, VPCostContext &CostCtx,
+ VFRange &Range) {
auto GetExtInfo = [&CostCtx](VPWidenCastRecipe *Ext)
-> std::pair<Type *, TargetTransformInfo::PartialReductionExtendKind> {
if (!Ext)
return {nullptr, TargetTransformInfo::PR_None};
Type *ExtOpType = CostCtx.Types.inferScalarType(Ext->getOperand(0));
- auto ExtKind = TargetTransformInfo::getPartialReductionExtendKind(
- static_cast<Instruction::CastOps>(Ext->getOpcode()));
- return {ExtOpType, ExtKind};
+ return {ExtOpType,
+ TargetTransformInfo::getPartialReductionExtendKind(
+ static_cast<Instruction::CastOps>(Ext->getOpcode()))};
};
auto ExtInfoA = GetExtInfo(Chain.ExtendA);
auto ExtInfoB = GetExtInfo(Chain.ExtendB);
Type *ExtOpTypeA = ExtInfoA.first;
Type *ExtOpTypeB = ExtInfoB.first;
auto ExtKindA = ExtInfoA.second;
auto ExtKindB = ExtInfoB.second;
+
// If ExtendB is nullptr but there's a separate BinOp, the second operand
// was a constant that can use the same extend kind as the first.
if (!Chain.ExtendB && Chain.BinOp && Chain.BinOp != Chain.ReductionBinOp) {
- // Validate that the constant can be extended to the narrow type.
const APInt *Const = nullptr;
- for (VPValue *Op : Chain.BinOp->operands()) {
+ for (VPValue *Op : Chain.BinOp->operands())
----------------
sdesmalen-arm wrote:
unnecessary change
https://github.com/llvm/llvm-project/pull/180438
More information about the llvm-commits
mailing list