// Reductions do not have to start at zero. They can start with
// any loop invariant values.
- BasicBlock *OrigLatch = OrigLoop->getLoopLatch();
- Value *OrigLoopVal = OrigPhi->getIncomingValueForBlock(OrigLatch);
BasicBlock *VectorLoopLatch = LI->getLoopFor(LoopVectorBody)->getLoopLatch();
bool IsOrdered = State.VF.isVector() && IsInLoopReductionPhi &&
if (IsOrdered && Part > 0)
break;
Value *VecRdxPhi = State.get(PhiR->getVPSingleValue(), Part);
- Value *Val = State.get(State.Plan->getVPValue(OrigLoopVal), Part);
+ Value *Val = State.get(PhiR->getBackedgeValue(), Part);
if (IsOrdered)
- Val = State.get(State.Plan->getVPValue(OrigLoopVal), UF - 1);
+ Val = State.get(PhiR->getBackedgeValue(), UF - 1);
+
cast<PHINode>(VecRdxPhi)->addIncoming(Val, VectorLoopLatch);
}
return new VPWidenRecipe(*I, make_range(Operands.begin(), Operands.end()));
}
+void VPRecipeBuilder::fixHeaderPhis() {
+ BasicBlock *OrigLatch = OrigLoop->getLoopLatch();
+ for (VPWidenPHIRecipe *R : PhisToFix) {
+ auto *PN = cast<PHINode>(R->getUnderlyingValue());
+ VPRecipeBase *IncR =
+ getRecipe(cast<Instruction>(PN->getIncomingValueForBlock(OrigLatch)));
+ R->addOperand(IncR->getVPSingleValue());
+ }
+}
+
VPBasicBlock *VPRecipeBuilder::handleReplication(
Instruction *I, VFRange &Range, VPBasicBlock *VPBB,
VPlanPtr &Plan) {
assert(RdxDesc.getRecurrenceStartValue() ==
Phi->getIncomingValueForBlock(OrigLoop->getLoopPreheader()));
VPValue *StartV = Operands[0];
- return toVPRecipeResult(new VPWidenPHIRecipe(Phi, RdxDesc, *StartV));
+
+ // Record the PHI and the incoming value from the backedge, so we can add
+ // the incoming value from the backedge after all recipes have been
+ // created.
+ auto *PhiRecipe = new VPWidenPHIRecipe(Phi, RdxDesc, *StartV);
+ PhisToFix.push_back(PhiRecipe);
+ recordRecipeOf(cast<Instruction>(
+ Phi->getIncomingValueForBlock(OrigLoop->getLoopLatch())));
+ return toVPRecipeResult(PhiRecipe);
}
return toVPRecipeResult(new VPWidenPHIRecipe(Phi));
}
}
+ RecipeBuilder.fixHeaderPhis();
+
// Discard empty dummy pre-entry VPBasicBlock. Note that other VPBasicBlocks
// may also be empty, such as the last one VPBB, reflecting original
// basic-blocks with no recipes.
// marked by having a nullptr entry in this map.
DenseMap<Instruction *, VPRecipeBase *> Ingredient2Recipe;
+ /// Cross-iteration reduction phis for which we need to add the incoming value
+ /// from the backedge after all recipes have been created.
+ SmallVector<VPWidenPHIRecipe *, 4> PhisToFix;
+
/// Check if \p I can be widened at the start of \p Range and possibly
/// decrease the range such that the returned value holds for the entire \p
/// Range. The function should not be called for memory instructions or calls.
VPBasicBlock *handleReplication(
Instruction *I, VFRange &Range, VPBasicBlock *VPBB,
VPlanPtr &Plan);
+
+ /// Add the incoming values from the backedge to reduction cross-iteration
+ /// phis.
+ void fixHeaderPhis();
};
} // end namespace llvm
/// A recipe for handling all phi nodes except for integer and FP inductions.
/// For reduction PHIs, RdxDesc must point to the corresponding recurrence
-/// descriptor and the start value is the first operand of the recipe.
-/// In the VPlan native path, all incoming VPValues & VPBasicBlock pairs are
-/// managed in the recipe directly.
+/// descriptor, the start value is the first operand of the recipe and the
+/// incoming value from the backedge is the second operand. In the VPlan native
+/// path, all incoming VPValues & VPBasicBlock pairs are managed in the recipe
+/// directly.
class VPWidenPHIRecipe : public VPRecipeBase, public VPValue {
/// Descriptor for a reduction PHI.
RecurrenceDescriptor *RdxDesc = nullptr;
return getNumOperands() == 0 ? nullptr : getOperand(0);
}
+ /// Returns the incoming value from the loop backedge, if it is a reduction.
+ VPValue *getBackedgeValue() {
+ assert(RdxDesc && "second incoming value is only guaranteed to be backedge "
+ "value for reductions");
+ return getOperand(1);
+ }
+
/// Adds a pair (\p IncomingV, \p IncomingBlock) to the phi.
void addIncoming(VPValue *IncomingV, VPBasicBlock *IncomingBlock) {
addOperand(IncomingV);