fix: expand GT_UMOD with constant divisor in morph to enable CSE#127694
fix: expand GT_UMOD with constant divisor in morph to enable CSE#127694mad1081 wants to merge 3 commits into
Conversation
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.
|
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch |
There was a problem hiding this comment.
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_MODtoGT_MODandGT_UMODfor non-power-of-2 constant divisors. - Update the surrounding comment to reflect unsigned modulo handling and the CSE motivation.
|
I am not convinced from the diffs it's a good change from size & perfscore unless there is a strong benchmark justification, so let's keep the existing code as is |
|
I really prefer not to do that this way, expanding |
Closing this PR because we prefer other approach to enable CSE. |



Fixes #119131
Related:
fgMorphModToSubMulDivwas already made to handleGT_UMODcorrectlyx % {pow2_cns}transformation forulongtypes #79676 — unsigned mod support was extended the same way beforeOn XARCH,
fgMorphSmpOpexpandsa % bintoa - (a / b) * bduring morph so that CSE can recognize a shared divisor between a division and a modulo with the same operands. This expansion was gated ontree->OperIs(GT_MOD), so unsigned modulo (GT_UMOD) with a non-power-of-2 constant divisor was never expanded in morph — it wasleft for lowering instead. Since CSE runs before lowering, patterns like:
produced two
divinstructions instead of one.fgMorphModToSubMulDivalready handlesGT_UMODcorrectly (it switches the operator toGT_UDIVand callsCheckDivideByConstOptimized), so the fix is to includeGT_UMODin the condition. Power-of-2 unsigned divisors are unaffected — they are already handled earlier byfgMorphUModToAndSub.Note:
ulongUMOD on XARCH is still blocked by a separate early return that predates this fix and is not addressed here.