Skip to content

Use flags for x +/- compare with GT_{ADD,SUB}_HI - #135678

Open
am11 wants to merge 1 commit into
dotnet:mainfrom
am11:feature/jit/bool-opts
Open

am11 wants to merge 1 commit into
dotnet:mainfrom
am11:feature/jit/bool-opts

Conversation

@am11

@am11 am11 commented Oct 13, 2026

Copy link
Copy Markdown
Member

Fixes #135647

Adding or subtracting a compare result currently materializes it with
setcc/cset before the add/sub. Use the flags set by the compare
directly instead:

xarch:  x + (a <u b)   =>  cmp a, b; adc x, 0
        x - (a <u b)   =>  cmp a, b; sbb x, 0
        x + (a >=u b)  =>  cmp a, b; sbb x, -1
        x - (a >=u b)  =>  cmp a, b; adc x, -1
arm:    x + (a >=u b)  =>  cmp a, b; adc x, x, zr
        x - (a <u b)   =>  cmp a, b; sbc x, x, zr
arm64:  x + cond       =>  cmp a, b; cinc x, x, cond   (any other condition)

a == 0 and a != 0 are handled as a <u 1 and a >=u 1, and
a <=u c / a >u c as a <u c+1 / a >=u c+1. An added constant,
x +/- (cond + k), is folded into the carry op's immediate where the
target has one (xarch, arm32). This does not rely on bools being
normalized to 0/1, so for example num - (r ? 0 : 1) becomes
cmp r, 1; sbb num, 0 on x64.
GT_ADD_HI/GT_SUB_HI, previously only defined for long decomposition
on 32-bit targets, are now defined for all targets, like the other
flags consuming nodes (GT_JCC, GT_SETCC, GT_SELECTCC). The
transformation lives in common lowering (TryLowerAddSubOfCompare);
each target's TryGetCarryOp decides which add/subtract with carry, if
any, computes the result:

  • xarch: adc adds the borrow and sbb subtracts it, any constant.
  • arm32/arm64: adc adds the carry (the inverse of the borrow) and
    sbc subtracts the borrow; arm64 has no immediate form, so only
    without a constant. Remaining additions on arm64 use cinc
    (TryLowerAddOfCompareToCinc), which works for any condition.
  • riscv64, loongarch64, wasm: no flags register, nothing changes.

Diffs

SuperPMI asmdiffs on the benchmarks collections:

Target Contexts with diffs Improvements / regressions Bytes
windows-x64 135 135 / 0 -1,203
linux-arm64 60 55 / 0 -400
linux-arm 6 6 / 0 -36
linux-riscv64 0 - 0
linux-loongarch64 0 - 0
Example (x64), num - (r ? 0 : 1):
-       test     dl, dl
-       sete     al
-       movzx    rax, al
-       sub      ecx, eax
-       mov      eax, ecx
+       cmp      dl, 1
+       mov      eax, ecx
+       sbb      eax, 0

Note

This description was generated with AI assistance.

@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 Oct 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 Oct 13, 2026
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 8 pipeline(s).
8 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@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.

@am11

am11 commented Oct 13, 2026 •

Copy link
Copy Markdown
Member Author

Wasm failure is unrelated (infra) issue.

cc @EgorBo

Diffs

This branch has not been deployed

No deployments
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.

Inefficient codegen with ternary and additive inverse

1 participant