Skip to content

Clear some stale GTF_ORDER_SIDEEFF flags#130007

Open
dhartglassMSFT wants to merge 4 commits into
dotnet:mainfrom
dhartglassMSFT:129055_p2_method3
Open

Clear some stale GTF_ORDER_SIDEEFF flags#130007
dhartglassMSFT wants to merge 4 commits into
dotnet:mainfrom
dhartglassMSFT:129055_p2_method3

Conversation

@dhartglassMSFT

@dhartglassMSFT dhartglassMSFT commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Clear stale GTF_ORDER_SIDEEFF flags to enable more if-conversion and optimize bools.

Motivating example was o.GetType() == typeof(int) || o.GetType() == typeof(uint) || o.GetType() == typeof(long) - we couldn't combine into OR because leftover side effect bit in one of the blocks.

If an op doesn't itself support side effects, and none of node's children have the bit, then the node may have the bit cleared.

Diffs show more optimize bools+if conversion taking place.
One of the bad diffs was block layout changing and causing LSRA to spill slightly different.
Another bad diff exposed an issue where edge-likelihoods weren't recalculated properly after optimize bools, and caused perfscore to balloon. I'm working on a fix for that seperately.

Copilot AI review requested due to automatic review settings June 29, 2026 22:37
@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 Jun 29, 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.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR adjusts JIT tree side-effect flag maintenance by attempting to clear stale GTF_ORDER_SIDEEFF bits during Compiler::gtUpdateStmtSideEffects, to unblock downstream optimizations that are inhibited by incorrectly-propagated ordering constraints.

Changes:

  • Add logic in gtUpdateStmtSideEffects to clear GTF_ORDER_SIDEEFF on nodes that don’t support ordering side effects when none of their operands still carry the flag.

Comment thread src/coreclr/jit/gentree.cpp Outdated
Comment on lines +11599 to +11603
if (((tree->gtFlags & GTF_ORDER_SIDEEFF) != 0) && !tree->OperSupportsOrderingSideEffect())
{
bool hasChildWithOrderSideEff = false;
tree->VisitOperands([&hasChildWithOrderSideEff](GenTree* operand) -> GenTree::VisitResult {
if ((operand->gtFlags & GTF_ORDER_SIDEEFF) != 0)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

seems reasonable

@dhartglassMSFT dhartglassMSFT marked this pull request as ready for review July 2, 2026 21:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

@dhartglassMSFT

Copy link
Copy Markdown
Contributor Author

link to diffs https://dev.azure.com/dnceng-public/public/_build/results?buildId=1486826&view=ms.vss-build-web.run-extensions-tab

Example (more ccmp in a method similar to the motivating example)

-4 (-7.14%) : AggregateSymbol:IsRefType():bool:this (FullOpts)
@@ -22,30 +22,27 @@ G_M9025_IG02:        ; bbWeight=1, gcrefRegs=0001 {x0}, byrefRegs=0000 {}, byref
             ; gcrRegs +[x0]
             ldr     w1, [x0, #0x90]
             cmp     w1, #1
-            beq     G_M9025_IG04
+            bne     G_M9025_IG05
                         ;; size=12 bbWeight=1 PerfScore 4.50
-G_M9025_IG03:        ; bbWeight=0.50, gcrefRegs=0000 {}, byrefRegs=0000 {}, byref, isz
+G_M9025_IG03:        ; bbWeight=0.50, gcrefRegs=0000 {}, byrefRegs=0000 {}, byref
             ; gcrRegs -[x0]
-            cmp     w1, #3
-            bne     G_M9025_IG06
-                        ;; size=8 bbWeight=0.50 PerfScore 0.75
-G_M9025_IG04:        ; bbWeight=0.50, gcrefRegs=0000 {}, byrefRegs=0000 {}, byref
             mov     w0, #1
                         ;; size=4 bbWeight=0.50 PerfScore 0.25
-G_M9025_IG05:        ; bbWeight=0.50, epilog, nogc, extend
+G_M9025_IG04:        ; bbWeight=0.50, epilog, nogc, extend
             ldp     fp, lr, [sp], #0x10
             ret     lr
                         ;; size=8 bbWeight=0.50 PerfScore 1.00
-G_M9025_IG06:        ; bbWeight=0.50, gcVars=0000000000000000 {}, gcrefRegs=0000 {}, byrefRegs=0000 {}, gcvars, byref
-            cmp     w1, #2
+G_M9025_IG05:        ; bbWeight=0.50, gcVars=0000000000000000 {}, gcrefRegs=0000 {}, byrefRegs=0000 {}, gcvars, byref
+            cmp     w1, #3
+            ccmp    w1, #2, z, ne
             cset    x0, eq
-                        ;; size=8 bbWeight=0.50 PerfScore 0.50
-G_M9025_IG07:        ; bbWeight=0.50, epilog, nogc, extend
+                        ;; size=12 bbWeight=0.50 PerfScore 0.75
+G_M9025_IG06:        ; bbWeight=0.50, epilog, nogc, extend
             ldp     fp, lr, [sp], #0x10
             ret     lr
                         ;; size=8 bbWeight=0.50 PerfScore 1.00
 
-; Total bytes of code 56, prolog size 8, PerfScore 9.50, instruction count 14, allocated bytes for code 56 (MethodHash=4337dcbe) for method Microsoft.CSharp.RuntimeBinder.Semantics.AggregateSymbol:IsRefType():bool:this (FullOpts)
+; Total bytes of code 52, prolog size 8, PerfScore 9.00, instruction count 13, allocated bytes for code 52 (MethodHash=4337dcbe) for method Microsoft.CSharp.RuntimeBinder.Semantics.AggregateSymbol:IsRefType():bool:this (FullOpts)
 ; ============================================================

@AndyAyersMS AndyAyersMS left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I assume we end up in this state because we fail to clear the flag when we change the oper?

Should we add an IR check that we never see GTF_ORDER_SIDEEFF on a node where it isn't expected?

// Attempt to clear stale SIDEEFF bits
// if this node does indeed need GTF_ORDER_SIDEEFF, then the bit will later be propagated up and re-set
// during the child's post-order visit
if (!tree->OperSupportsOrderingSideEffect())

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
if (!tree->OperSupportsOrderingSideEffect())
if (((tree->gtFlags & GTF_ORDER_SIDEEFF) != 0) && !tree->OperSupportsOrderingSideEffect())

For TP

@jakobbotsch

Copy link
Copy Markdown
Member

I assume we end up in this state because we fail to clear the flag when we change the oper?

Should we add an IR check that we never see GTF_ORDER_SIDEEFF on a node where it isn't expected?

I agree it would be nice to make fgDebugCheckFlags check this flag more thoroughly. There will likely be some fallout if you do that -- for one you will probably need to change gtUpdateNodeOperSideEffects to remove this flag. Morph uses that to do a similar update of flags as gtUpdateStmtSideEffects inline during its walk.

@dhartglassMSFT

Copy link
Copy Markdown
Contributor Author

I assume we end up in this state because we fail to clear the flag when we change the oper?
Should we add an IR check that we never see GTF_ORDER_SIDEEFF on a node where it isn't expected?

I agree it would be nice to make fgDebugCheckFlags check this flag more thoroughly. There will likely be some fallout if you do that -- for one you will probably need to change gtUpdateNodeOperSideEffects to remove this flag. Morph uses that to do a similar update of flags as gtUpdateStmtSideEffects inline during its walk.

@jakobbotsch + @AndyAyersMS sequence of steps here was, null check gets removed on an IND so it + the parent EQ is marked SIDEEFFECT:

 [000019] -----O-----   JTRUE
 [000018] J----O-N---     EQ
 [000017] #----O-----        IND    long
 [000011] -----+-----           LCL_VAR ref V00
 [000013] H----+-----        CNS_INT(h) ...

IND gets CSE'd with a local, but EQ retains the bit (the gtUpdateStmtSideEffects method im changing here is called immediately after the CSE)

 [000018] J----O-N---   EQ         int 
 [000037] -----------      LCL_VAR long V02 cse0 
 [000013] H----+-----      CNS_INT(h) ...

@dhartglassMSFT

Copy link
Copy Markdown
Contributor Author

Opened #130150 to track the bad diff with the ballooned perfscore

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.

4 participants