Skip to content

fix: expand GT_UMOD with constant divisor in morph to enable CSE#127694

Open
mad1081 wants to merge 2 commits intodotnet:mainfrom
mad1081:main
Open

fix: expand GT_UMOD with constant divisor in morph to enable CSE#127694
mad1081 wants to merge 2 commits intodotnet:mainfrom
mad1081:main

Conversation

@mad1081
Copy link
Copy Markdown

@mad1081 mad1081 commented May 3, 2026

Fixes #119131

Related:

On XARCH, fgMorphSmpOp expands a % b into a - (a / b) * b during morph so that CSE can recognize a shared divisor between a division and a modulo with the same operands. This expansion was gated on tree->OperIs(GT_MOD), so unsigned modulo (GT_UMOD) with a non-power-of-2 constant divisor was never expanded in morph — it was
left for lowering instead. Since CSE runs before lowering, patterns like:

uint arrIndex = index / 3;
uint bitIndex = index % 3;

produced two div instructions instead of one.

fgMorphModToSubMulDiv already handles GT_UMOD correctly (it switches the operator to GT_UDIV and calls CheckDivideByConstOptimized), so the fix is to include GT_UMOD in the condition. Power-of-2 unsigned divisors are unaffected — they are already handled earlier by fgMorphUModToAndSub.

Note: ulong UMOD on XARCH is still blocked by a separate early return that predates this fix and is not addressed here.

On XARCH, the transformation of `a % b` into `a - (a / b) * b` was
only applied for signed GT_MOD, not unsigned GT_UMOD. This prevented
CSE from recognizing the shared division in patterns like `x / 3` and
`x % 3`, causing two separate div instructions to be emitted.

Extends the existing else-if condition to include GT_UMOD so unsigned
modulo with a non-power-of-2 constant divisor is also expanded during
morph, matching the behavior already present for GT_MOD.
@github-actions github-actions Bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label May 3, 2026
@dotnet-policy-service dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label May 3, 2026
@dotnet-policy-service
Copy link
Copy Markdown
Contributor

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

@EgorBo EgorBo requested a review from Copilot May 4, 2026 17:43
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Updates XARCH JIT morphing to expand unsigned modulo (GT_UMOD) by a constant divisor into a - (a / b) * b earlier (during morph) so CSE can reuse a shared division when both / and % appear with the same operands.

Changes:

  • Extend the morph-time mod expansion gate from GT_MOD to GT_MOD and GT_UMOD for non-power-of-2 constant divisors.
  • Update the surrounding comment to reflect unsigned modulo handling and the CSE motivation.

Comment thread src/coreclr/jit/morph.cpp Outdated
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 community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CSE seems to fail when writing x / cns and x % cns for unsigned integers

2 participants