Skip to content

JIT: Transform arithmetic using distributive property#126852

Open
BoyBaykiller wants to merge 3 commits intodotnet:mainfrom
BoyBaykiller:transform-using-distributive-property
Open

JIT: Transform arithmetic using distributive property#126852
BoyBaykiller wants to merge 3 commits intodotnet:mainfrom
BoyBaykiller:transform-using-distributive-property

Conversation

@BoyBaykiller
Copy link
Copy Markdown
Contributor

@BoyBaykiller BoyBaykiller commented Apr 13, 2026

Generalization of #126070

Basically we weren't doing any simplification based on distributive property before. So transforming
((A op1 B) op2 (A op1 C)) => (A op1 (B op2 C)). And this adds at least some simple support. Example:

int MulDistedOverAdd(int A, int B, int C)
{
    return (A * B) + (A * C);
}
;; ------ BASE
G_M000_IG02:
       mov      eax, edx
       imul     eax, r8d
       imul     r9d, edx
       add      eax, r9d

;; ------ DIFF
G_M48043_IG02:  ;; offset=0x0000
       lea      eax, [r8+r9]
       imul     eax, edx

Future work to handle more cases

When I write (A * 10) + (A * 12) there is some previous transformation that gives ((A * 5) << 1) + ((A * 3) << 2). In this form fgOptimizeDistributiveArithemtic no longer picks it up. Ideally it should become A * 120. Either teach fgOptimizeDistributiveArithemtic to see through this or run it before the mul-by-const transform:

int MulDistedOverAddConst(int A, int B, int C)
{
    return (A * 10) + (A * 12);
}

This should be handled too, by transforming into ((A & 4) | (A & 8)) != 0 first perhaps. If I call fgMorphBlockStmt from optimizeBools it gets handled already:

bool OtherTransformNeeded(int A, int B)
{
    return (A & 4) != 0 || (A & 8) != 0;
}

This is similiar to the previous point. We need something that changes order to enable this opt. So (A | B) | C becoming A | (B | C) in this case:

uint Reassociate(uint foo, uint flags)
{
    return (foo | (flags & 256)) | (flags & 512);
}

Lastly two general things.
I am currently not calling this for GT_SUB because it's a mess. I want to rewrite the huge switch (oper) in fgMorphSmpOp to if-statements.
Lastly, I have to check for GTF_ORDER_SIDEEFF to exclude volatile loads but this also causes many false negatives: https://discord.com/channels/143867839282020352/312132327348240384/1487221372899037234

* add OR and AND are 'distributive' over themselves
@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 Apr 13, 2026
@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label Apr 13, 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.

return tree;
}

if (((tree->gtFlags & GTF_PERSISTENT_SIDE_EFFECTS) != 0) || ((tree->gtFlags & GTF_ORDER_SIDEEFF) != 0))
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.

This could use the same optimization you are trying to apply😅... Probably handled by c++ though, so this is purely documentation ;-)

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.

Lol. A new level of self documenting code. I didn't even notice that, I copied this check from elsewhere. I guess this just goes to show how useful the optimization is. Unfortunately even with this PR it's still not handled : (

@BoyBaykiller
Copy link
Copy Markdown
Contributor Author

@EgorBo PTAL. Diffs are rather small, but nonetheless I believe it's a step in the right direction. I've written down some future work (which all improve diffs). I think the most interesting case for real-world code is arround bitwise ops.

@BoyBaykiller BoyBaykiller marked this pull request as ready for review April 15, 2026 01:07
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.

2 participants