Skip to content

[release/11.0] Avoid reducing unused Vector2 and Vector3 elements - #133607

Merged
tannergooding merged 1 commit into
release/11.0from
backport/pr-133527-to-release/11.0
Sep 14, 2026
Merged

tannergooding merged 1 commit into
release/11.0from
backport/pr-133527-to-release/11.0

Conversation

@github-actions

@github-actions github-actions Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Backport of #133527 to release/11.0.

Customer Impact

  • Customer reported
  • Found internally

This is a performance fix, not a correctness fix.

Customers reported slower Vector2/Vector3 dot products and squared lengths in .NET 11 compared with .NET 10 in #133297. The generated code unnecessarily clears and reduces unused SIMD elements. This fix reduces only the meaningful elements and keeps vector intermediates for normalization and reflection.

Local Release x64 codegen shows the Vector2.LengthSquared benchmark loop shrinking from 46 to 30 bytes. This addresses the Vector2/Vector3 reduction portion of the report, not Vector4 or loop alignment; it does not claim to eliminate the entire reported throughput regression.

Regression

  • Yes
  • No

Reported in .NET 11 Preview 7 relative to .NET 10. The report shows multiply/shuffle/add reductions replacing dpps, exposing unnecessary work on unused elements. The exact introducing commit has not been established; this backport improves the managed reductions rather than reverting the JIT lowering.

Testing

The source change was built locally on Windows x64, and all 7,523 System.Numerics.Vectors.Tests tests passed. The added Vector2 nonfinite coverage also passed with hardware intrinsics disabled. Regression coverage includes signed zero, reduction grouping, NaN/infinity, and poisoned unused upper elements where the backend retains those lanes.

Only the Vector3 all-negative-zero case is skipped on Mono because its existing intrinsic implementation independently reduces the unused fourth lane. Other scenarios remain enabled. Existing coverage did not explicitly exercise these signed-zero and unused-lane cases; generated-code inspection was needed to identify the redundant arithmetic.

The automated backport applied without conflicts; all four file patches match the merged source change. These local results are for the source change, not a separate release-branch build. Backport CI provides release-branch validation. The source PR's remaining socket and Mono Windows CI failures were unrelated; the Mono crash cluster also occurs on upstream main without this change.

Risk

Low. The change is limited to portable managed Vector2/Vector3 reductions and their tests, with no public API additions, native changes, or architecture-specific implementations. Numerical edge cases are covered explicitly. There is an intentional signed-zero correction: reducing all-negative-zero meaningful elements preserves negative zero instead of adding an irrelevant positive zero.

ARM and WASM performance has not been measured. The portable Vector3 broadcast uses five instructions / 25 reduction bytes rather than four / 18 for a rejected SSE-only alternative; local reflection benchmarks were 11-12% slower than that alternative, not than upstream. The source PR records the full measurements and scope.

IMPORTANT: If this backport is for a servicing release, please verify that:

  • For .NET 8 and .NET 9: The PR target branch is release/X.0-staging, not release/X.0.
  • For .NET 10+: The PR target branch is release/X.0 (no -staging suffix).

Confirmed target: dotnet/runtime:release/11.0.

Package authoring no longer needed in .NET 9

IMPORTANT: Starting with .NET 9, you no longer need to edit a NuGet package's csproj to enable building and bump the version.
Keep in mind that we still need package authoring in .NET 8 and older versions.

Note

This backport description was drafted with GitHub Copilot.

Reduce only the meaningful `Vector2` and `Vector3` elements, avoiding
zero-extension and extra arithmetic from four-element reductions. Keep
intermediates in SIMD form, with scalar reductions for dot products,
lengths, and distances, and vector results for normalization and
reflection. The implementations use portable `Vector128` operations,
without architecture-specific paths.

This also preserves negative zero when all summed elements are negative
zero, rather than adding an irrelevant positive zero. Adds coverage for
signed zero, grouping, nonfinite inputs, and unused upper elements.

Addresses the `Vector2`/`Vector3` reduction portion of
#133297. `Vector4`, JIT simplifications, and loop
alignment are out of scope.

----------

Release x64 codegen for the local `VectorBench` loops, compared with the
original upstream implementation:

| Method | Before | After |
|---|---:|---:|
| `LengthSquared2` | 66 bytes | 63 bytes |
| `LengthSquared3` | 73 bytes | 67 bytes |
| `Normalize3` | 95 bytes | 94 bytes |
| `Reflect3` | 117 bytes | 116 bytes |

These are whole-method sizes including alignment; the `LengthSquared2`
loop itself shrinks from 46 to 30 bytes.

The portable `Vector3` broadcast costs five instructions / 25 reduction
bytes versus four / 18 for an investigated SSE specialization. In local
Ryzen 9 7950X `VectorBench` loops over 1,000 vectors, `Normalize3` was
within 1% faster and `Reflect3` was 11-12% slower than that
specialization in both runtime orders. This comparison is against the
rejected specialization, not upstream; portability is preferred over
separate target-specific reduction paths. ARM and WASM performance has
not been measured.

> [!NOTE]
> This description was drafted with GitHub Copilot.

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 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: @dotnet/area-system-numerics
See info in area-owners.md if you want to be subscribed.

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

regression. customer reported. performance. approved.
Clean build analysis required before merge.

@artl93 artl93 added the Servicing-approved Approved for servicing release label Sep 14, 2026
@tannergooding

Copy link
Copy Markdown
Member

/ba-g All known and unrelated failures

@tannergooding

Copy link
Copy Markdown
Member
Failure Classification Evidence
SendReceive_Eap.TcpReceiveSendGetsCanceledByDispose — macOS 26 ARM64 Known, but unrecognized; unrelated Matches #131990, including its ordered error signature and timeout at the same peer-receive statement.
nativeruntimeeventsource.cmd Known; unrelated Build Analysis matched #90605.
WebSockets SendAsync_Cancel_Success Known; unrelated Build Analysis matched #132031, which was still open when this build ran and closed September 14.
DoubleTests_GenericMath.MinTest / MaxTest — two browser configurations Known; unrelated Build Analysis matched #133311: Mono’s existing double NaN sign/payload issue, not the changed Vector2/Vector3 reductions.

The only one build-analysis didn't mark was SendReceive_Eap.TcpReceiveSendGetsCanceledByDispose, which has been fixed in main.

@tannergooding
tannergooding merged commit 0090e56 into release/11.0 Sep 14, 2026
146 of 151 checks passed
@tannergooding
tannergooding deleted the backport/pr-133527-to-release/11.0 branch September 14, 2026 20:35
@dotnet-milestone-bot dotnet-milestone-bot Bot added this to the 11.0-rc2 milestone Sep 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-System.Numerics Servicing-approved Approved for servicing release tenet-performance Performance related issue

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants