Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 7, 2026

Remove CHK_FLOW_UPDATE stress mode

  • Remove STRESS_MODE(CHK_FLOW_UPDATE) from compiler.h
  • Remove stress mode check from fgDebugCheckUpdate() function
  • Keep fgDebugCheckUpdate() function to run always in debug builds
  • Keep function declaration in compiler.h
  • Keep call to fgDebugCheckUpdate() in fgopt.cpp
  • Build CoreCLR to verify changes compile

Summary

Removed the CHK_FLOW_UPDATE stress mode. The fgDebugCheckUpdate() function now runs unconditionally in all debug builds instead of being gated by the stress mode. This provides better flow graph validation coverage during development.

Changes Made:

  • Removed STRESS_MODE(CHK_FLOW_UPDATE) from the stress modes enumeration in compiler.h
  • Removed the if (!compStressCompile(STRESS_CHK_FLOW_UPDATE, 30)) check from fgDebugCheckUpdate() in fgdiagnostic.cpp

The function continues to validate flow graph invariants including no unreachable blocks, empty blocks, un-imported blocks, un-compacted blocks, unnecessary jumps, and proper BBJ_CALLFINALLY block structure.

Original prompt

Remove the CHK_FLOW_UPDATE stress mode


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Comment on lines 59 to 147
void Compiler::fgDebugCheckUpdate()
{
if (!compStressCompile(STRESS_CHK_FLOW_UPDATE, 30))
{
return;
}

/* We check for these conditions:
* no unreachable blocks -> no blocks have countOfInEdges() = 0
* no empty blocks -> !block->isEmpty(), unless non-removable or multiple in-edges
* no un-imported blocks -> no blocks have BBF_IMPORTED not set (this is
* kind of redundant with the above, but to make sure)
* no un-compacted blocks -> BBJ_ALWAYS with jump to block with no other jumps to it (countOfInEdges() = 1)
*/

BasicBlock* prev;
BasicBlock* block;
for (prev = nullptr, block = fgFirstBB; block != nullptr; prev = block, block = block->Next())
{
/* no unreachable blocks */

if ((block->countOfInEdges() == 0) && !block->HasFlag(BBF_DONT_REMOVE))
{
noway_assert(!"Unreachable block not removed!");
}

/* no empty blocks */

if (block->isEmpty() && !block->HasFlag(BBF_DONT_REMOVE))
{
switch (block->GetKind())
{
case BBJ_CALLFINALLY:
case BBJ_EHFINALLYRET:
case BBJ_EHFAULTRET:
case BBJ_EHFILTERRET:
case BBJ_RETURN:
/* for BBJ_ALWAYS is probably just a GOTO, but will have to be treated */
case BBJ_ALWAYS:
case BBJ_EHCATCHRET:
/* These jump kinds are allowed to have empty tree lists */
break;

default:
/* it may be the case that the block had more than one reference to it
* so we couldn't remove it */

if (block->countOfInEdges() == 0)
{
noway_assert(!"Empty block not removed!");
}
break;
}
}

/* no un-imported blocks */

if (!block->HasFlag(BBF_IMPORTED))
{
/* internal blocks do not count */

if (!block->HasFlag(BBF_INTERNAL))
{
noway_assert(!"Non IMPORTED block not removed!");
}
}

// Check for an unnecessary jumps to the next block.
// A conditional branch should never jump to the next block as it can be folded into a BBJ_ALWAYS.
if (block->KindIs(BBJ_COND) && block->TrueEdgeIs(block->GetFalseEdge()))
{
noway_assert(!"Unnecessary jump to the next block!");
}

// For a BBJ_CALLFINALLY block we make sure that we are followed by a BBJ_CALLFINALLYRET block
// or that it's a BBF_RETLESS_CALL.
if (block->KindIs(BBJ_CALLFINALLY))
{
assert(block->HasFlag(BBF_RETLESS_CALL) || block->isBBCallFinallyPair());
}

/* no un-compacted blocks */

if (fgCanCompactBlock(block))
{
noway_assert(!"Found un-compacted blocks!");
}
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Keep the fgDebugCheckUpdate function, but remove the STRESS_CHK_FLOW_UPDATE check, i.e. we can always run the code in debug.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Revert this change, remove only the STRESS_CHK_FLOW_UPDATE check

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 54e6058. The fgDebugCheckUpdate function now runs unconditionally in all debug builds.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes are already correct in 54e6058. Only the STRESS_CHK_FLOW_UPDATE definition and stress check have been removed - the fgDebugCheckUpdate() function, its declaration, and call site remain intact.

Per feedback from @jakobbotsch, the fgDebugCheckUpdate function is now
always executed in debug builds instead of being gated by the
STRESS_CHK_FLOW_UPDATE stress mode.

Co-authored-by: jakobbotsch <[email protected]>
Copilot AI changed the title [WIP] Remove CHK_FLOW_UPDATE stress mode Remove CHK_FLOW_UPDATE stress mode Jan 7, 2026
@jkotas jkotas added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jan 9, 2026
@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants