Skip to content

Fix Vector.Dot on arm64 - #133215

Merged
dhartglassMSFT merged 2 commits into
dotnet:mainfrom
dhartglassMSFT:132800
Sep 16, 2026
Merged

dhartglassMSFT merged 2 commits into
dotnet:mainfrom
dhartglassMSFT:132800

Conversation

@dhartglassMSFT

@dhartglassMSFT dhartglassMSFT commented Sep 4, 2026 •

Copy link
Copy Markdown
Contributor

Morph removes Create+ToScalar from trees like Create(ToScalar(Dot(...

Leaving something like this, where there's assumed to be an implicit broadcast after the Dot :

HWINTRINSIC simd16 16 uint CompareEqual
-some_vec
-HWINTRINSIC simd16 16 uint Dot

ARM64 currently lowers Vector.Dot into an AddAccross that writes its result into lane 0 of vector reg and zeros other lanes.

To fix ideally we'd instead do the morph transform during lower. However, by that point CSE had replaced the ToScalar(Dot(... which causes bad diffs on x64 in the motivating example.

So instead, leave the morph transform and just insert a broadcast during arm64 lower if the use is not a ToScalar. Gives 0 diffs.

fixes #132800

@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 Sep 4, 2026
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 5 pipeline(s).
11 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.

@dhartglassMSFT
dhartglassMSFT marked this pull request as ready for review September 4, 2026 06:17
Copilot AI lite review requested due to automatic review settings September 4, 2026 06:17
@azure-pipelines

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

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.

🟢 Approval recommended

The fix is narrowly scoped to ARM64 lowering, matches the reported failure mode, and includes targeted regression coverage to prevent recurrence.

Pull request overview

Fixes ARM64 codegen for Vector.Dot when Morph drops Create(ToScalar(Dot(...))) and the remaining Dot value is subsequently consumed as a vector (requiring a broadcast rather than lane-0-only semantics).

Changes:

  • Update ARM64 lowering for NI_Vector_Dot to insert an explicit broadcast when the Dot result is not consumed by ToScalar.
  • Add a JIT regression test covering the motivating Vector128.IndexOf(..., Vector.Dot(...)) pattern and additional Vector64/Vector128.Create(Dot(...)) broadcast cases.
  • Wire the new regression test into the Regression_ro_2.csproj compile items.
File summaries
File Description
src/coreclr/jit/lowerarmarch.cpp Inserts a broadcast during ARM64 lowering of Vector.Dot when the use is not ToScalar, preserving expected “scalar splat” behavior.
src/tests/JIT/Regression/JitBlue/Runtime_132800/Runtime_132800.cs Adds a regression test validating correct broadcast semantics for Vector.Dot/Vector64.Dot/Vector128.Dot patterns on AdvSimd.
src/tests/JIT/Regression/Regression_ro_2.csproj Includes the new Runtime_132800 test file in the regression project build.
Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread src/coreclr/jit/lowerarmarch.cpp Outdated

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.

🟢 Approval recommended

The ARM64 lowering change is narrowly scoped, matches existing intrinsic patterns, and is backed by a targeted regression test exercising the problematic consumption shape.

Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Comment thread src/coreclr/jit/lowerarmarch.cpp

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

Changes look correct to me, but do have a question on the general handling as compared to xarch and whether its potentially missing any cases due to the return type being allowed to be scalar or simd

@EgorBo

EgorBo commented Sep 8, 2026

Copy link
Copy Markdown
Member

To fix ideally we'd instead do the morph transform during lower. However, by that point CSE had replaced the ToScalar(Dot(... which causes bad diffs on x64 in the motivating example.

How big is the impact?

@EgorBo

EgorBo commented Sep 8, 2026 •

Copy link
Copy Markdown
Member

To fix ideally we'd instead do the morph transform during lower. However, by that point CSE had replaced the ToScalar(Dot(... which causes bad diffs on x64 in the motivating example.

How big is the impact?

Tried to run locally against benchmarks.run. collection, it was +96bytes and +24 bytes for libraries.pmi. Perhaps, not too bad to trade for removing an implicit broadcast? (the less implicit rules in IR the better)

@dhartglassMSFT

Copy link
Copy Markdown
Contributor Author

To fix ideally we'd instead do the morph transform during lower. However, by that point CSE had replaced the ToScalar(Dot(... which causes bad diffs on x64 in the motivating example.

How big is the impact?

Tried to run locally against benchmarks.run. collection, it was +96bytes and +24 bytes for libraries.pmi. Perhaps, not too bad to trade for removing an implicit broadcast? (the less implicit rules in IR the better)

right, I think I was scared off here because the diffs looked like they were in the same sort of routines the morph transform was trying to optimize.

Would you prefer instead adding a new HIR node, something like a DotAndBroadcast that makes this as explicit as possible? I think I had some old branch with that change.

@EgorBo

EgorBo commented Sep 8, 2026

Copy link
Copy Markdown
Member

To fix ideally we'd instead do the morph transform during lower. However, by that point CSE had replaced the ToScalar(Dot(... which causes bad diffs on x64 in the motivating example.

How big is the impact?

Tried to run locally against benchmarks.run. collection, it was +96bytes and +24 bytes for libraries.pmi. Perhaps, not too bad to trade for removing an implicit broadcast? (the less implicit rules in IR the better)

right, I think I was scared off here because the diffs looked like they were in the same sort of routines the morph transform was trying to optimize.

Would you prefer instead adding a new HIR node, something like a DotAndBroadcast that makes this as explicit as possible? I think I had some old branch with that change.

I'm fine merging it as is. Was just wondering if the diffs aren't too big, maybe it's not even worth bothering and just remove the questionable transfromation 🤷

@dhartglassMSFT
dhartglassMSFT enabled auto-merge (squash) September 10, 2026 22:33

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.

🔵 Needs a closer look

Gate the regression test on AdvSimd.Arm64.IsSupported to ensure it covers the ARM64 lowering fix.

Review details

Suppressed comments (1)

src/tests/JIT/Regression_ro_2/Runtime_132800.cs:14

  • This regression is specifically for the ARM64 lowering in lowerarmarch.cpp, but AdvSimd.IsSupported is also true on 32-bit Arm. On ARM32 the test can pass through a different JIT path and therefore does not guarantee coverage of this fix; gate it on AdvSimd.Arm64.IsSupported, as in src/tests/JIT/Regression_o_2/Runtime_105716.cs:25.
    [ConditionalFact(typeof(AdvSimd), nameof(AdvSimd.IsSupported))]
  • Files reviewed: 2/2 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@dhartglassMSFT

Copy link
Copy Markdown
Contributor Author

wasm failure is 134018, plus unrelated mono failure in test 133715

@dhartglassMSFT

Copy link
Copy Markdown
Contributor Author

/ba-g unrelated wasm and mono failures

@dhartglassMSFT
dhartglassMSFT merged commit 313ad9c into dotnet:main Sep 16, 2026
140 of 143 checks passed
@dotnet-milestone-bot dotnet-milestone-bot Bot added this to the 12.0-preview1 milestone Sep 17, 2026
jtschuster pushed a commit to jtschuster/runtime that referenced this pull request Sep 18, 2026
Morph removes Create+ToScalar from trees like `Create(ToScalar(Dot(...`

Leaving something like this, where there's assumed to be an implicit
broadcast after the `Dot` :
```
HWINTRINSIC simd16 16 uint CompareEqual
-some_vec
-HWINTRINSIC simd16 16 uint Dot
```

ARM64 currently lowers Vector.Dot into an AddAccross that writes its
result into lane 0 of vector reg and zeros other lanes.

To fix ideally we'd instead do the morph transform during lower.
However, by that point CSE had replaced the `ToScalar(Dot(...` which
causes bad diffs on x64 in the motivating example.

So instead, leave the morph transform and just insert a broadcast during
arm64 lower if the use is not a ToScalar. Gives 0 diffs.

fixes dotnet#132800
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.

ARM64: bad codegen for Vector.Dot

4 participants