Skip to content

Add mulx support to Math.BigMul#128787

Open
Daniel-Svensson wants to merge 15 commits into
dotnet:mainfrom
Daniel-Svensson:x86_multiply
Open

Add mulx support to Math.BigMul#128787
Daniel-Svensson wants to merge 15 commits into
dotnet:mainfrom
Daniel-Svensson:x86_multiply

Conversation

@Daniel-Svensson

@Daniel-Svensson Daniel-Svensson commented May 29, 2026

Copy link
Copy Markdown
Contributor

Follow up to #117261, with added support for mulx to adress performance regression #128594.

@EgorBo I've not yet run the benchmarks, is it easy for you to use your bot against a PR ?
Otherwise you will have to wait for a couple of days for benchmarks results

Corrently both lokal spmi run and
devops build shows an expected improvement to generated code.

Devops spmi results shows nice improvements especially for Linux x64 with >5000 bytes improvement with memory accesses in several locations.

linux x64 asm-diffs (2 juli 2026, PR build)

Collection Base size (bytes) Diff size (bytes) PerfScore in Diffs
aspnet2.run.linux.x64.checked.mch 11,262,831 -153 -7.12%
benchmarks.run.linux.x64.checked.mch 25,248,720 -227 -5.16%
benchmarks.run_pgo.linux.x64.checked.mch 24,649,330 -776 -3.08%
benchmarks.run_pgo_optrepeat.linux.x64.checked.mch 27,676,438 -298 -5.70%
coreclr_tests.run.linux.x64.checked.mch 101,216,657 -1,014 -4.51%
libraries.crossgen2.linux.x64.checked.mch 41,692,435 -223 -9.26%
libraries.pmi.linux.x64.checked.mch 62,478,356 +279 -1.69%
libraries_tests.run.linux.x64.Release.mch 180,481,159 -2,309 -3.74%
libraries_tests_no_tiered_compilation.run.linux.x64.Release.mch 148,084,145 +77 -2.80%
realworld.run.linux.x64.checked.mch 10,904,558 -130 -9.98%
smoke_tests.nativeaot.linux.x64.checked.mch 4,883,920 -114 -20.28%

windows

Collection Base size (bytes) Diff size (bytes) PerfScore in Diffs
aspnet2.run.windows.x64.checked.mch 11,084,647 -189 -5.66%
benchmarks.run.windows.x64.checked.mch 16,909,077 -311 -4.73%
benchmarks.run_pgo.windows.x64.checked.mch 15,359,924 -952 -1.90%
benchmarks.run_pgo_optrepeat.windows.x64.checked.mch 21,231,737 -311 -4.73%
coreclr_tests.run.windows.x64.checked.mch 106,205,457 -419 -1.66%
libraries.crossgen2.windows.x64.checked.mch 41,555,146 -120 -3.59%
libraries.pmi.windows.x64.checked.mch 64,408,586 +164 -2.46%
libraries_tests.run.windows.x64.Release.mch 124,139,090 -213 -1.85%
libraries_tests_no_tiered_compilation.run.windows.x64.Release.mch 152,424,852 +58 -1.70%
realworld.run.windows.x64.checked.mch 10,766,797 -88 -8.06%
smoke_tests.nativeaot.windows.x64.checked.mch 5,378,527 -60 -8.64%

old local resuls (motivation to why op2 is used for rdx instead of op1)

local SPMI results (latest)

FullOpts (-1,488 bytes)
Collection Base size (bytes) Diff size (bytes) PerfScore in Diffs
aspnet2.run.windows.x64.checked.mch 1,958,162 -37 -2.39%
benchmarks.run.windows.x64.checked.mch 17,296,800 -186 -4.61%
benchmarks.run_pgo.windows.x64.checked.mch 17,724,325 -997 -1.59%
benchmarks.run_pgo_optrepeat.windows.x64.checked.mch 16,067,339 -186 -4.61%
libraries.crossgen2.windows.x64.checked.mch 41,522,433 -121 -3.59%
libraries.pmi.windows.x64.checked.mch 64,543,375 +194 -2.43%
libraries_tests.run.windows.x64.Release.mch 126,045,916 -103 -1.64%
libraries_tests_no_tiered_compilation.run.windows.x64.Release.mch 151,916,143 +62 -1.87%
realworld.run.windows.x64.checked.mch 10,544,362 -54 -7.47%
smoke_tests.nativeaot.windows.x64.checked.mch 5,541,852 -60 -8.64%

local SPMI where op1 was fixed

FullOpts (-707 bytes)
Collection Base size (bytes) Diff size (bytes) PerfScore in Diffs
aspnet2.run.windows.x64.checked.mch 1,958,162 -44 -2.55%
benchmarks.run.windows.x64.checked.mch 17,296,800 -161 -2.05%
benchmarks.run_pgo.windows.x64.checked.mch 17,724,325 -928 -0.44%
benchmarks.run_pgo_optrepeat.windows.x64.checked.mch 16,067,339 -161 -2.05%
libraries.crossgen2.windows.x64.checked.mch 41,522,433 -99 +1.35%
libraries.pmi.windows.x64.checked.mch 64,543,375 +676 +7.50%
libraries_tests.run.windows.x64.Release.mch 126,045,916 -306 +0.39%
libraries_tests_no_tiered_compilation.run.windows.x64.Release.mch 151,916,143 +420 -0.78%
realworld.run.windows.x64.checked.mch 10,544,362 -44 -6.64%
smoke_tests.nativeaot.windows.x64.checked.mch 5,541,852 -60 -8.64%

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

@Daniel-Svensson

Copy link
Copy Markdown
Contributor Author

 @JulieLeeMSFT@jakobbotsch @EgorBo is there any more action required from my part here?

The test results seemed unrelated and based on asm diffs the performance regression should be fixed with additional performance improvements expected for decimal and more.

@JulieLeeMSFT

Copy link
Copy Markdown
Member

@Daniel-Svensson, sorry for the delay in review. We are at the end of product cycle, so a bit busy.
@EgorBo, please review.

@github-actions

github-actions Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Workflow state for the Holistic Review Orchestrator.

{
  "version": 5,
  "last_dispatched_commit": "9cfe7116b1db33419ef046cedcb2318027920c66",
  "last_dispatched_base_ref": "main",
  "last_dispatched_base_sha": "8fe2929f5e365d262ca514854330c979fe6ab28b",
  "last_reviewed_commit": "9cfe7116b1db33419ef046cedcb2318027920c66",
  "last_reviewed_base_ref": "main",
  "last_reviewed_base_sha": "8fe2929f5e365d262ca514854330c979fe6ab28b",
  "last_recorded_worker_run_id": "29680698145",
  "review_attempt_commit": "",
  "review_attempt_base_ref": "",
  "review_attempt_count": 0,
  "max_review_attempts": 5,
  "review_history_format": "holistic-review-disclosure-v1",
  "review_history": [
    {
      "commit": "9cfe7116b1db33419ef046cedcb2318027920c66",
      "review_id": 4730526312
    }
  ]
}

@github-actions github-actions Bot 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.

Holistic Review

Motivation: This PR is a follow-up to #117261 that addresses the performance regression tracked in #128594. The unsigned 64-bit Math.BigMul path currently lowers to the legacy mul instruction, which has an implicit EAX/EDX register constraint. On BMI2-capable CPUs the mulx instruction can compute the same unsigned 128-bit product without clobbering flags and, crucially, without forcing the operands and results into fixed registers, giving the register allocator far more freedom. The reported SuperPMI asm-diffs show consistent code-size and PerfScore improvements across nearly all collections, confirming the motivation.

Approach: The change is limited to LSRA (lsraxarch.cpp) and codegen (hwintrinsiccodegenxarch.cpp) for NI_X86Base_X64_BigMul. Both add a new branch, gated on baseType == TYP_ULONG (codegen keys off ins == INS_mulEAX, which is equivalent since INS_mulEAX is only selected for the unsigned long base type) and compOpportunisticallyDependsOn(InstructionSet_AVX2). In LSRA the new branch marks the node non-RMW, forces one source into EDX (preferring op2 when neither is contained, per the SuperPMI data cited in the comment), and defines both results into freely-allocatable (APX-aware) registers instead of the fixed EAX/EDX. Codegen mirrors this by moving the first operand into RDX and emitting mulx hi, lo, rmOp via inst_RV_RV_TT(..., isRMW=false). The signed path and the non-BMI2 unsigned path are preserved unchanged in the else branches. The pattern closely mirrors the pre-existing NI_AVX2_MultiplyNoFlags (mulx) handling, which is a good consistency signal. The remaining diff is whitespace-only comment rewrapping in two unrelated functions.

Summary: This is a focused, well-reasoned CQ improvement that reuses the established mulx codegen pattern already present for MultiplyNoFlags. The register-allocation model (non-RMW, EDX implicit source, free result registers) matches mulx semantics, the feature gate is correct, and the fallback paths are untouched so non-BMI2 and signed cases are unaffected. Containment handling for BigMul was already wired to the shared mulx/BigMul case in lowering, so the new memory-operand path is covered. I found no correctness concerns in the changed lines; the only note is a harmless dead store flagged inline. Verdict: LGTM. Note that I did not build or run tests in this worker — assess CI (JIT SuperPMI / coreclr test legs) for functional confirmation.

Detailed Findings

No blocking issues. One minor, non-blocking observation is left as an inline comment on the isRMW = false; dead store in lsraxarch.cpp.

Note

This review was generated by this repository's Holistic Review agentic workflow to complement the built-in Copilot review.

Generated by Holistic Review · 105.2 AIC · ⌖ 10.6 AIC · ⊞ 10K

ForceLowGprForApxIfNeeded(op1, RBM_NONE, canHWIntrinsicUseApxRegs);
if (baseType == TYP_ULONG && m_compiler->compOpportunisticallyDependsOn(InstructionSet_AVX2))
{
isRMW = false;

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.

Minor: this isRMW = false; assignment is a dead store. In this branch the code sets buildUses = false; and break;s without any further read of isRMW (the RMW-dependent uses only apply to buildUses-driven paths later in the function). It's harmless and arguably documents intent, but if you want to avoid the dead store you could drop it, or convert it to a comment explaining that MULX is a non-destructive 3-operand form (unlike the implicit-EAX mul).

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.

3 participants