Skip to content

Commit

Permalink
JIT: Port loop unrolling to new loop representation (#96454)
Browse files Browse the repository at this point in the history
Port loop unrolling to the new loop representation. Switch strategy slightly
with how loop unrolling works:

- If the bottom block of the loop is a `BBJ_COND`, create a "redirection" block
  to jump to its fallthrough. This is similar to how loop cloning works and
  saves a lot of annoying special casing around updating pred lists.

- Leave the old loop unreachable in the flow graph after loop unrolling. Remove
  these blocks by running `fgDfsBlocksAndRemove`. Previously we would create a
  chain of `BBJ_ALWAYS` going through all the previous blocks, keeping them all
  reachable, likely because the old fgComputeDoms does not handle statically
  unreachable blocks correctly.

- We run unrolling in a sort of "closure" algorithm, allowing only one unrolling
  in each loop nest per iteration. This avoids us having to maintain changed
  blocks of descendant loops on the side as we unroll.

Some minor diffs are expected:

- We no longer recompute the old loop table in some cases (unrolling nested
  loops). This means for instance that hoisting may not kick in for some those
  loops because of the "has matching old loop" quirk in hoisting. This should go
  away later when we remove that quirk.

- Different weights because the old unrolling leaves the loop around as a chain
  of BBJ_ALWAYS, keeping their weight; when we later compact them, we propagate
  the original "loop" weight to the blocks we compact with. This causes
  differences in if-conversion, register allocation and block layout.
  • Loading branch information
jakobbotsch authored Jan 4, 2024
1 parent db90a84 commit 045e55a
Show file tree
Hide file tree
Showing 7 changed files with 309 additions and 294 deletions.
1 change: 0 additions & 1 deletion src/coreclr/jit/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -801,7 +801,6 @@ bool BasicBlock::CloneBlockState(
assert(to->bbStmtList == nullptr);
to->CopyFlags(from);
to->bbWeight = from->bbWeight;
BlockSetOps::AssignAllowUninitRhs(compiler, to->bbReach, from->bbReach);
to->copyEHRegion(from);
to->bbCatchTyp = from->bbCatchTyp;
to->bbStkTempsIn = from->bbStkTempsIn;
Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4920,6 +4920,8 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl

while (iterations > 0)
{
fgModified = false;

if (doSsa)
{
// Build up SSA form for the IR
Expand Down Expand Up @@ -5012,8 +5014,6 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
{
// update the flowgraph if we modified it during the optimization phase
//
// Note: this invalidates loops, dominators and reachability
//
DoPhase(this, PHASE_OPT_UPDATE_FLOW_GRAPH, &Compiler::fgUpdateFlowGraphPhase);

// Recompute the edge weight if we have modified the flow graph
Expand Down
5 changes: 4 additions & 1 deletion src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -2029,12 +2029,15 @@ struct NaturalLoopIterInfo
int ConstInitValue = 0;

// Block outside the loop that initializes the induction variable. Only
// value if HasConstInit is true.
// valid if HasConstInit is true.
BasicBlock* InitBlock = nullptr;

// Tree that has the loop test for the induction variable.
GenTree* TestTree = nullptr;

// Block that has the loop test.
BasicBlock* TestBlock = nullptr;

// Tree that mutates the induction variable.
GenTree* IterTree = nullptr;

Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/compmemkind.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ CompMemKindMacro(DebugOnly)
CompMemKindMacro(Codegen)
CompMemKindMacro(LoopOpt)
CompMemKindMacro(LoopClone)
CompMemKindMacro(LoopUnroll)
CompMemKindMacro(LoopHoist)
CompMemKindMacro(Unknown)
CompMemKindMacro(RangeCheck)
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/jit/fgdiagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2573,6 +2573,10 @@ void Compiler::fgDumpBlockMemorySsaIn(BasicBlock* block)
{
printf(" = m:%u\n", block->bbMemorySsaNumIn[memoryKind]);
}
else if (block->bbMemorySsaPhiFunc[memoryKind] == BasicBlock::EmptyMemoryPhiDef)
{
printf(" = phi([not filled])\n");
}
else
{
printf(" = phi(");
Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/jit/flowgraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4963,7 +4963,8 @@ bool FlowGraphNaturalLoop::AnalyzeIteration(NaturalLoopIterInfo* info)
return false;
}

info->IterVar = comp->optIsLoopIncrTree(info->IterTree);
info->TestBlock = cond;
info->IterVar = comp->optIsLoopIncrTree(info->IterTree);

assert(info->IterVar != BAD_VAR_NUM);
LclVarDsc* const iterVarDsc = comp->lvaGetDesc(info->IterVar);
Expand Down
Loading

0 comments on commit 045e55a

Please sign in to comment.