-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[VPlan] Handle early exit before forming regions. (NFC) #138393
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
d0d2c2e
76c470a
80a629c
56d576a
ce06761
2289a5e
4747678
b74e363
dd38677
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9384,7 +9384,8 @@ LoopVectorizationPlanner::tryToBuildVPlanWithVPRecipes(VFRange &Range) { | |
VPlanTransforms::prepareForVectorization( | ||
*Plan, Legal->getWidestInductionType(), PSE, RequiresScalarEpilogueCheck, | ||
CM.foldTailByMasking(), OrigLoop, | ||
getDebugLocFromInstOrOperands(Legal->getPrimaryInduction())); | ||
getDebugLocFromInstOrOperands(Legal->getPrimaryInduction()), | ||
Legal->hasUncountableEarlyExit(), Range); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does passing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
If it is false, it means there are no uncountable early exits and we require a scalar epilogue There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, thanks for clarifying! |
||
VPlanTransforms::createLoopRegions(*Plan); | ||
|
||
// Don't use getDecisionAndClampRange here, because we don't know the UF | ||
|
@@ -9582,12 +9583,6 @@ LoopVectorizationPlanner::tryToBuildVPlanWithVPRecipes(VFRange &Range) { | |
R->setOperand(1, WideIV->getStepValue()); | ||
} | ||
|
||
if (auto *UncountableExitingBlock = | ||
Legal->getUncountableEarlyExitingBlock()) { | ||
VPlanTransforms::runPass(VPlanTransforms::handleUncountableEarlyExit, *Plan, | ||
OrigLoop, UncountableExitingBlock, RecipeBuilder, | ||
Range); | ||
} | ||
DenseMap<VPValue *, VPValue *> IVEndValues; | ||
addScalarResumePhis(RecipeBuilder, *Plan, IVEndValues); | ||
SetVector<VPIRInstruction *> ExitUsersToFix = | ||
|
@@ -9685,7 +9680,8 @@ VPlanPtr LoopVectorizationPlanner::tryToBuildVPlan(VFRange &Range) { | |
auto Plan = VPlanTransforms::buildPlainCFG(OrigLoop, *LI, VPB2IRBB); | ||
VPlanTransforms::prepareForVectorization( | ||
*Plan, Legal->getWidestInductionType(), PSE, true, false, OrigLoop, | ||
getDebugLocFromInstOrOperands(Legal->getPrimaryInduction())); | ||
getDebugLocFromInstOrOperands(Legal->getPrimaryInduction()), false, | ||
Range); | ||
VPlanTransforms::createLoopRegions(*Plan); | ||
|
||
for (ElementCount VF : Range) | ||
|
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -460,11 +460,10 @@ static void addCanonicalIVRecipes(VPlan &Plan, VPBasicBlock *HeaderVPBB, | |||||||||
{CanonicalIVIncrement, &Plan.getVectorTripCount()}, DL); | ||||||||||
} | ||||||||||
|
||||||||||
void VPlanTransforms::prepareForVectorization(VPlan &Plan, Type *InductionTy, | ||||||||||
PredicatedScalarEvolution &PSE, | ||||||||||
bool RequiresScalarEpilogueCheck, | ||||||||||
bool TailFolded, Loop *TheLoop, | ||||||||||
DebugLoc IVDL) { | ||||||||||
void VPlanTransforms::prepareForVectorization( | ||||||||||
VPlan &Plan, Type *InductionTy, PredicatedScalarEvolution &PSE, | ||||||||||
bool RequiresScalarEpilogueCheck, bool TailFolded, Loop *TheLoop, | ||||||||||
DebugLoc IVDL, bool HasUncountableEarlyExit, VFRange &Range) { | ||||||||||
VPDominatorTree VPDT; | ||||||||||
VPDT.recalculate(Plan); | ||||||||||
|
||||||||||
|
@@ -491,19 +490,35 @@ void VPlanTransforms::prepareForVectorization(VPlan &Plan, Type *InductionTy, | |||||||||
addCanonicalIVRecipes(Plan, cast<VPBasicBlock>(HeaderVPB), | ||||||||||
cast<VPBasicBlock>(LatchVPB), InductionTy, IVDL); | ||||||||||
|
||||||||||
// Disconnect all edges to exit blocks other than from the middle block. | ||||||||||
// TODO: VPlans with early exits should be explicitly converted to a form | ||||||||||
// exiting only via the latch here, including adjusting the exit condition, | ||||||||||
// instead of simply disconnecting the edges and adjusting the VPlan later. | ||||||||||
for (VPBlockBase *EB : Plan.getExitBlocks()) { | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps worth replacing the old comment with a new one explaining what the loop is doing at a high level? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done thanks |
||||||||||
[[maybe_unused]] bool HandledUncountableEarlyExit = false; | ||||||||||
for (VPIRBasicBlock *EB : Plan.getExitBlocks()) { | ||||||||||
for (VPBlockBase *Pred : to_vector(EB->getPredecessors())) { | ||||||||||
if (Pred == MiddleVPBB) | ||||||||||
continue; | ||||||||||
|
||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. dropped, thanks |
||||||||||
if (HasUncountableEarlyExit) { | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Independent note: this condition disregards the actual Pred->EB edge itself. |
||||||||||
assert(!HandledUncountableEarlyExit && | ||||||||||
"can handle exactly one uncountable early exit"); | ||||||||||
// Convert VPlans with early exits to a form exiting only via the latch | ||||||||||
// here, including adjusting the exit condition of the latch. | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Explained above, plus can document the function itself. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, removed |
||||||||||
handleUncountableEarlyExit(cast<VPBasicBlock>(Pred), EB, Plan, | ||||||||||
cast<VPBasicBlock>(HeaderVPB), | ||||||||||
cast<VPBasicBlock>(LatchVPB), Range); | ||||||||||
HandledUncountableEarlyExit = true; | ||||||||||
continue; | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
All early exits are disconnected. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could fall exit the loop here, but then the verification would be more work. For all supported loops, we should leave the loop after the continue. |
||||||||||
} | ||||||||||
|
||||||||||
// Otherwise all early exits must be countable and we require at least one | ||||||||||
// iteration in the scalar epilogue. Disconnect all edges to exit blocks | ||||||||||
// other than from the middle block. | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Explanation above suffices? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed, thanks |
||||||||||
cast<VPBasicBlock>(Pred)->getTerminator()->eraseFromParent(); | ||||||||||
VPBlockUtils::disconnectBlocks(Pred, EB); | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
assert((!HasUncountableEarlyExit || HandledUncountableEarlyExit) && | ||||||||||
"did not handle uncountable early exit"); | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that this essentially checks if any early exit was found. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tried to make this clearer in the message: |
||||||||||
|
||||||||||
// Create SCEV and VPValue for the trip count. | ||||||||||
// We use the symbolic max backedge-taken-count, which works also when | ||||||||||
// vectorizing loops with uncountable early exits. | ||||||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -2458,64 +2458,60 @@ void VPlanTransforms::convertToConcreteRecipes(VPlan &Plan, | |||||
R->eraseFromParent(); | ||||||
} | ||||||
|
||||||
void VPlanTransforms::handleUncountableEarlyExit( | ||||||
VPlan &Plan, Loop *OrigLoop, BasicBlock *UncountableExitingBlock, | ||||||
VPRecipeBuilder &RecipeBuilder, VFRange &Range) { | ||||||
VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion(); | ||||||
auto *LatchVPBB = cast<VPBasicBlock>(LoopRegion->getExiting()); | ||||||
VPBuilder Builder(LatchVPBB->getTerminator()); | ||||||
auto *MiddleVPBB = Plan.getMiddleBlock(); | ||||||
VPValue *IsEarlyExitTaken = nullptr; | ||||||
|
||||||
// Process the uncountable exiting block. Update IsEarlyExitTaken, which | ||||||
// tracks if the uncountable early exit has been taken. Also split the middle | ||||||
// block and have it conditionally branch to the early exit block if | ||||||
// EarlyExitTaken. | ||||||
auto *EarlyExitingBranch = | ||||||
cast<BranchInst>(UncountableExitingBlock->getTerminator()); | ||||||
BasicBlock *TrueSucc = EarlyExitingBranch->getSuccessor(0); | ||||||
BasicBlock *FalseSucc = EarlyExitingBranch->getSuccessor(1); | ||||||
BasicBlock *EarlyExitIRBB = | ||||||
!OrigLoop->contains(TrueSucc) ? TrueSucc : FalseSucc; | ||||||
VPIRBasicBlock *VPEarlyExitBlock = Plan.getExitBlock(EarlyExitIRBB); | ||||||
|
||||||
VPValue *EarlyExitNotTakenCond = RecipeBuilder.getBlockInMask( | ||||||
OrigLoop->contains(TrueSucc) ? TrueSucc : FalseSucc); | ||||||
auto *EarlyExitTakenCond = Builder.createNot(EarlyExitNotTakenCond); | ||||||
IsEarlyExitTaken = | ||||||
Builder.createNaryOp(VPInstruction::AnyOf, {EarlyExitTakenCond}); | ||||||
void VPlanTransforms::handleUncountableEarlyExit(VPBasicBlock *EarlyExitingVPBB, | ||||||
VPBasicBlock *EarlyExitVPBB, | ||||||
|
||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. removed thanks |
||||||
VPlan &Plan, | ||||||
VPBasicBlock *HeaderVPBB, | ||||||
VPBasicBlock *LatchVPBB, | ||||||
VFRange &Range) { | ||||||
using namespace llvm::VPlanPatternMatch; | ||||||
|
||||||
VPBlockBase *MiddleVPBB = LatchVPBB->getSuccessors()[0]; | ||||||
if (!EarlyExitVPBB->getSinglePredecessor() && | ||||||
EarlyExitVPBB->getPredecessors()[0] != MiddleVPBB) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Clearer and more consistent with explanation below? Or
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated thanks |
||||||
// Early exit operand should always be last phi operand. If EarlyExitVPBB | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it worth adding an assert that MiddleVPBB is actually the second predecessor? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done, thanks |
||||||
// has two predecessors and MiddleVPBB isn't the first, swap the operands of | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated thanks |
||||||
// the phis. | ||||||
for (VPRecipeBase &R : EarlyExitVPBB->phis()) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is making sure the operand corresponding to the middle block is always first, right? I guess in future if we do want to support multiple early exits this will get a bit more complicated, but swapping operands works for now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep |
||||||
cast<VPIRPhi>(&R)->swapOperands(); | ||||||
} | ||||||
|
||||||
VPBuilder Builder(LatchVPBB->getTerminator()); | ||||||
VPBlockBase *TrueSucc = EarlyExitingVPBB->getSuccessors()[0]; | ||||||
assert( | ||||||
match(EarlyExitingVPBB->getTerminator(), m_BranchOnCond(m_VPValue())) && | ||||||
"Terminator must be be BranchOnCond"); | ||||||
VPValue *CondOfEarlyExitingVPBB = | ||||||
EarlyExitingVPBB->getTerminator()->getOperand(0); | ||||||
auto *CondToEarlyExit = TrueSucc == EarlyExitVPBB | ||||||
? CondOfEarlyExitingVPBB | ||||||
: Builder.createNot(CondOfEarlyExitingVPBB); | ||||||
EarlyExitingVPBB->getTerminator()->eraseFromParent(); | ||||||
VPBlockUtils::disconnectBlocks(EarlyExitingVPBB, EarlyExitVPBB); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could be left to the caller, as it is common to dealing with early exits via scalar epilog? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done thanks There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Waiting for a commit? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah yes, should be included in the latest update |
||||||
|
||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Have the caller take care of this, for all early exits consistently? |
||||||
// Split the middle block and have it conditionally branch to the early exit | ||||||
// block if EarlyExitTaken. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated, thanks |
||||||
VPValue *IsEarlyExitTaken = | ||||||
Builder.createNaryOp(VPInstruction::AnyOf, {CondToEarlyExit}); | ||||||
VPBasicBlock *NewMiddle = Plan.createVPBasicBlock("middle.split"); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Independent:
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can do separately, thanks |
||||||
VPBasicBlock *VectorEarlyExitVPBB = | ||||||
Plan.createVPBasicBlock("vector.early.exit"); | ||||||
VPBlockUtils::insertOnEdge(LoopRegion, MiddleVPBB, NewMiddle); | ||||||
VPBlockUtils::insertOnEdge(LatchVPBB, MiddleVPBB, NewMiddle); | ||||||
VPBlockUtils::connectBlocks(NewMiddle, VectorEarlyExitVPBB); | ||||||
NewMiddle->swapSuccessors(); | ||||||
|
||||||
VPBlockUtils::connectBlocks(VectorEarlyExitVPBB, VPEarlyExitBlock); | ||||||
VPBlockUtils::connectBlocks(VectorEarlyExitVPBB, EarlyExitVPBB); | ||||||
|
||||||
// Update the exit phis in the early exit block. | ||||||
VPBuilder MiddleBuilder(NewMiddle); | ||||||
VPBuilder EarlyExitB(VectorEarlyExitVPBB); | ||||||
for (VPRecipeBase &R : VPEarlyExitBlock->phis()) { | ||||||
for (VPRecipeBase &R : EarlyExitVPBB->phis()) { | ||||||
auto *ExitIRI = cast<VPIRPhi>(&R); | ||||||
// Early exit operand should always be last, i.e., 0 if VPEarlyExitBlock has | ||||||
// Early exit operand should always be last, i.e., 0 if EarlyExitVPBB has | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this comment still valid given you've already swapped operands above? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ep, this just re-states the expected order, as explanation for setting early exit index below. |
||||||
// a single predecessor and 1 if it has two. | ||||||
unsigned EarlyExitIdx = ExitIRI->getNumOperands() - 1; | ||||||
if (!VPEarlyExitBlock->getSinglePredecessor()) { | ||||||
// If VPEarlyExitBlock has two predecessors, they are already ordered such | ||||||
// that early exit is second (and latch exit is first), by construction. | ||||||
// But its underlying IRBB (EarlyExitIRBB) may have its predecessors | ||||||
// ordered the other way around, and it is the order of the latter which | ||||||
// corresponds to the order of operands of VPEarlyExitBlock's phi recipes. | ||||||
// Therefore, if early exit (UncountableExitingBlock) is the first | ||||||
// predecessor of EarlyExitIRBB, we swap the operands of phi recipes, | ||||||
// thereby bringing them to match VPEarlyExitBlock's predecessor order, | ||||||
// with early exit being last (second). Otherwise they already match. | ||||||
if (*pred_begin(VPEarlyExitBlock->getIRBasicBlock()) == | ||||||
UncountableExitingBlock) | ||||||
ExitIRI->swapOperands(); | ||||||
|
||||||
if (ExitIRI->getNumOperands() != 1) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not relevant for this patch, but the name There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might be good to improve the naming, but it may be even better to create all required extracts up-front separately, which is something I am looking into |
||||||
// The first of two operands corresponds to the latch exit, via MiddleVPBB | ||||||
// predecessor. Extract its last lane. | ||||||
ExitIRI->extractLastLaneOfFirstOperand(MiddleBuilder); | ||||||
|
@@ -2531,7 +2527,7 @@ void VPlanTransforms::handleUncountableEarlyExit( | |||||
LoopVectorizationPlanner::getDecisionAndClampRange(IsVector, Range)) { | ||||||
// Update the incoming value from the early exit. | ||||||
VPValue *FirstActiveLane = EarlyExitB.createNaryOp( | ||||||
VPInstruction::FirstActiveLane, {EarlyExitTakenCond}, nullptr, | ||||||
VPInstruction::FirstActiveLane, {CondToEarlyExit}, nullptr, | ||||||
"first.active.lane"); | ||||||
IncomingFromEarlyExit = EarlyExitB.createNaryOp( | ||||||
Instruction::ExtractElement, {IncomingFromEarlyExit, FirstActiveLane}, | ||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -69,7 +69,8 @@ struct VPlanTransforms { | |||||
PredicatedScalarEvolution &PSE, | ||||||
bool RequiresScalarEpilogueCheck, | ||||||
bool TailFolded, Loop *TheLoop, | ||||||
DebugLoc IVDL); | ||||||
DebugLoc IVDL, bool HandleUncountableExit, | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated, thanks |
||||||
VFRange &Range); | ||||||
|
||||||
/// Replace loops in \p Plan's flat CFG with VPRegionBlocks, turning \p Plan's | ||||||
/// flat CFG into a hierarchical CFG. | ||||||
|
@@ -173,15 +174,16 @@ struct VPlanTransforms { | |||||
/// Remove dead recipes from \p Plan. | ||||||
static void removeDeadRecipes(VPlan &Plan); | ||||||
|
||||||
/// Update \p Plan to account for the uncountable early exit block in \p | ||||||
/// UncountableExitingBlock by | ||||||
/// Update \p Plan to account for the uncountable early exit from \p | ||||||
/// EarlyExitingVPBB to \p EarlyExitVPBB by | ||||||
/// * updating the condition exiting the vector loop to include the early | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done thanks |
||||||
/// exit conditions | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. updated |
||||||
/// * splitting the original middle block to branch to the early exit block | ||||||
/// if taken. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. updated thanks |
||||||
static void handleUncountableEarlyExit(VPlan &Plan, Loop *OrigLoop, | ||||||
BasicBlock *UncountableExitingBlock, | ||||||
VPRecipeBuilder &RecipeBuilder, | ||||||
static void handleUncountableEarlyExit(VPBasicBlock *EarlyExitingVPBB, | ||||||
VPBasicBlock *EarlyExitVPBB, | ||||||
VPlan &Plan, VPBasicBlock *HeaderVPBB, | ||||||
VPBasicBlock *LatchVPBB, | ||||||
VFRange &Range); | ||||||
|
||||||
/// Lower abstract recipes to concrete ones, that can be codegen'd. Use \p | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Independent) Should
prepareForVectorization
be renamed to a more informative name, perhapscanonicalizeTopLoop
, as it takes care of canonicalizing header and latch blocks, introducing and connecting preheader, middle-block, scalar preheader, canonical IV recipes and trip-count value.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will to separately.