Skip to content

Commit

Permalink
JIT: change loop inversion edge weight updates and add phase (#48364)
Browse files Browse the repository at this point in the history
Rename `fgOptWhileLoop` to `optInvertWhileLoop` (using terminology from
Muchnick). Split off this transformation into a new phase so it is easier
to see its impact. Make the block updates / reorderings that follow into
a proper phase as well.

Use the test block exit likelihoods to update the profile weights for the
edges involved in loop inversion. Because edge weight updates are now
consistent we no longer need to recompute edge weights afterwards.

Rename `optOptimizeLoops` to `optFindLoops` since it no longer optimizes.
  • Loading branch information
AndyAyersMS authored Feb 18, 2021
1 parent ba50840 commit 841fc98
Show file tree
Hide file tree
Showing 7 changed files with 401 additions and 232 deletions.
16 changes: 9 additions & 7 deletions src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4838,19 +4838,23 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl

if (opts.OptimizationEnabled())
{
// Invert loops
//
DoPhase(this, PHASE_INVERT_LOOPS, &Compiler::optInvertLoops);

// Optimize block order
//
DoPhase(this, PHASE_OPTIMIZE_LAYOUT, &Compiler::optOptimizeLayout);

// Compute reachability sets and dominators.
//
DoPhase(this, PHASE_COMPUTE_REACHABILITY, &Compiler::fgComputeReachability);

// Perform loop inversion (i.e. transform "while" loops into
// "repeat" loops) and discover and classify natural loops
// Discover and classify natural loops
// (e.g. mark iterative loops as such). Also marks loop blocks
// and sets bbWeight to the loop nesting levels
//
DoPhase(this, PHASE_OPTIMIZE_LOOPS, &Compiler::optOptimizeLoops);
DoPhase(this, PHASE_FIND_LOOPS, &Compiler::optFindLoops);

// Clone loops with optimization opportunities, and
// choose the one based on dynamic condition evaluation.
Expand Down Expand Up @@ -5299,10 +5303,8 @@ void Compiler::RecomputeLoopInfo()
block->bbFlags &= ~BBF_LOOP_FLAGS;
}
fgComputeReachability();
// Rebuild the loop tree annotations themselves. Since this is performed as
// part of 'optOptimizeLoops', this will also re-perform loop rotation, but
// not other optimizations, as the others are not part of 'optOptimizeLoops'.
optOptimizeLoops();
// Rebuild the loop tree annotations themselves
optFindLoops();
}

/*****************************************************************************/
Expand Down
17 changes: 10 additions & 7 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -5383,7 +5383,7 @@ class Compiler
void fgComputeCalledCount(BasicBlock::weight_t returnWeight);
void fgComputeEdgeWeights();

void fgReorderBlocks();
bool fgReorderBlocks();

void fgDetermineFirstColdBlock();

Expand Down Expand Up @@ -5452,8 +5452,13 @@ class Compiler
void fgDebugCheckFlagsHelper(GenTree* tree, unsigned treeFlags, unsigned chkFlags);
void fgDebugCheckTryFinallyExits();
void fgDebugCheckProfileData();
bool fgDebugCheckIncomingProfileData(BasicBlock* block);
bool fgDebugCheckOutgoingProfileData(BasicBlock* block);
#endif

bool fgProfileWeightsEqual(BasicBlock::weight_t weight1, BasicBlock::weight_t weight2);
bool fgProfileWeightsConsistent(BasicBlock::weight_t weight1, BasicBlock::weight_t weight2);

static GenTree* fgGetFirstNode(GenTree* tree);

//--------------------- Walking the trees in the IR -----------------------
Expand Down Expand Up @@ -6120,11 +6125,9 @@ class Compiler
void optOptimizeBoolsGcStress(BasicBlock* condBlock);
#endif
public:
void optOptimizeLayout(); // Optimize the BasicBlock layout of the method

void optOptimizeLoops(); // for "while-do" loops duplicates simple loop conditions and transforms
// the loop into a "do-while" loop
// Also finds all natural loops and records them in the loop table
PhaseStatus optInvertLoops(); // Invert loops so they're entered at top and tested at bottom.
PhaseStatus optOptimizeLayout(); // Optimize the BasicBlock layout of the method
PhaseStatus optFindLoops(); // Finds loops and records them in the loop table

// Optionally clone loops in the loop table.
void optCloneLoops();
Expand Down Expand Up @@ -6450,7 +6453,7 @@ class Compiler
}
}

void fgOptWhileLoop(BasicBlock* block);
void optInvertWhileLoop(BasicBlock* block);

bool optComputeLoopRep(int constInit,
int constLimit,
Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/jit/compphases.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,11 @@ CompPhaseNameMacro(PHASE_COMPUTE_EDGE_WEIGHTS, "Compute edge weights (1, false
CompPhaseNameMacro(PHASE_CREATE_FUNCLETS, "Create EH funclets", "EH-FUNC", false, -1, false)
#endif // FEATURE_EH_FUNCLETS
CompPhaseNameMacro(PHASE_MERGE_THROWS, "Merge throw blocks", "MRGTHROW", false, -1, false)
CompPhaseNameMacro(PHASE_INVERT_LOOPS, "Invert loops", "LOOP-INV", false, -1, false)
CompPhaseNameMacro(PHASE_OPTIMIZE_LAYOUT, "Optimize layout", "LAYOUT", false, -1, false)
CompPhaseNameMacro(PHASE_COMPUTE_REACHABILITY, "Compute blocks reachability", "BL_REACH", false, -1, false)
CompPhaseNameMacro(PHASE_ZERO_INITS, "Redundant zero Inits", "ZERO-INIT", false, -1, false)
CompPhaseNameMacro(PHASE_OPTIMIZE_LOOPS, "Optimize loops", "LOOP-OPT", false, -1, false)
CompPhaseNameMacro(PHASE_FIND_LOOPS, "Find loops", "LOOP-FND", false, -1, false)
CompPhaseNameMacro(PHASE_CLONE_LOOPS, "Clone loops", "LP-CLONE", false, -1, false)
CompPhaseNameMacro(PHASE_UNROLL_LOOPS, "Unroll loops", "UNROLL", false, -1, false)
CompPhaseNameMacro(PHASE_HOIST_LOOP_CODE, "Hoist loop code", "LP-HOIST", false, -1, false)
Expand Down
29 changes: 18 additions & 11 deletions src/coreclr/jit/fgopt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3661,15 +3661,17 @@ bool Compiler::fgOptimizeSwitchJumps()
#pragma warning(push)
#pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
#endif
/*****************************************************************************
*
* Function called to reorder the flowgraph of BasicBlocks such that any
* rarely run blocks are placed at the end of the block list.
* If we have profile information we also use that information to reverse
* all conditional jumps that would benefit.
*/

void Compiler::fgReorderBlocks()
//-----------------------------------------------------------------------------
// fgReorderBlocks: reorder blocks to favor frequent fall through paths,
// move rare blocks to the end of the method/eh region, and move
// funclets to the ends of methods.
//
// Returns:
// True if anything got reordered. Reordering blocks may require changing
// IR to reverse branch conditions.
//
bool Compiler::fgReorderBlocks()
{
noway_assert(opts.compDbgCode == false);

Expand All @@ -3680,12 +3682,13 @@ void Compiler::fgReorderBlocks()
// We can't relocate anything if we only have one block
if (fgFirstBB->bbNext == nullptr)
{
return;
return false;
}

bool newRarelyRun = false;
bool movedBlocks = false;
bool optimizedSwitches = false;
bool optimizedBranches = false;

// First let us expand the set of run rarely blocks
newRarelyRun |= fgExpandRarelyRunBlocks();
Expand Down Expand Up @@ -4094,9 +4097,11 @@ void Compiler::fgReorderBlocks()
// Check for an unconditional branch to a conditional branch
// which also branches back to our next block
//
if (fgOptimizeBranch(bPrev))
const bool optimizedBranch = fgOptimizeBranch(bPrev);
if (optimizedBranch)
{
noway_assert(bPrev->bbJumpKind == BBJ_COND);
optimizedBranches = true;
}
continue;
}
Expand Down Expand Up @@ -4816,7 +4821,7 @@ void Compiler::fgReorderBlocks()

} // end of for loop(bPrev,block)

bool changed = movedBlocks || newRarelyRun || optimizedSwitches;
const bool changed = movedBlocks || newRarelyRun || optimizedSwitches || optimizedBranches;

if (changed)
{
Expand All @@ -4829,6 +4834,8 @@ void Compiler::fgReorderBlocks()
}
#endif // DEBUG
}

return changed;
}
#ifdef _PREFAST_
#pragma warning(pop)
Expand Down
Loading

0 comments on commit 841fc98

Please sign in to comment.