Skip to content

Optimize stackalloc zeroing on arm64 via STORE_BLK - #121986

Merged
EgorBo merged 3 commits into
dotnet:mainfrom
EgorBo:optimize-stackalloc-zeroing-arm64
Nov 27, 2025
Merged

Optimize stackalloc zeroing on arm64 via STORE_BLK#121986
EgorBo merged 3 commits into
dotnet:mainfrom
EgorBo:optimize-stackalloc-zeroing-arm64

Conversation

@EgorBo

@EgorBoEgorBo commented Nov 26, 2025

Copy link
Copy Markdown
Member

Enable X64's optimization where we clear LCLHEAP via STORE_BLK inserted in Lower on arm64.

staticvoidTest128()=>Consume(stackallocchar[128]);

was:

 stp xzr, xzr,[sp, #-0x10]! stp xzr, xzr,[sp, #-0xF0]! stp xzr, xzr,[sp, #0x10] stp xzr, xzr,[sp, #0x20] stp xzr, xzr,[sp, #0x30] stp xzr, xzr,[sp, #0x40] stp xzr, xzr,[sp, #0x50] stp xzr, xzr,[sp, #0x60] stp xzr, xzr,[sp, #0x70] stp xzr, xzr,[sp, #0x80] stp xzr, xzr,[sp, #0x90] stp xzr, xzr,[sp, #0xA0] stp xzr, xzr,[sp, #0xB0] stp xzr, xzr,[sp, #0xC0] stp xzr, xzr,[sp, #0xD0] stp xzr, xzr,[sp, #0xE0]

now:

 movi v16.16b, #0 stp q16, q16,[x0] stp q16, q16,[x0, #0x20] stp q16, q16,[x0, #0x40] stp q16, q16,[x0, #0x60] stp q16, q16,[x0, #0x80] stp q16, q16,[x0, #0xA0] stp q16, q16,[x0, #0xC0] stp q16, q16,[x0, #0xE0]

Also, for larger sizes the previous logic used to emit a slow loop (e.g. 1024 bytes):

mov w0, #0x400G_M30953_IG03: stp xzr, xzr,[sp, #-0x10]! subs x0, x0, #16 bne G_M30953_IG03

Now it will emit a call to CORINFO_HELP_MEMZERO

Benchmarks.

usingSystem.Runtime.CompilerServices;usingBenchmarkDotNet.Attributes;publicclassBenchmarks{[Benchmark]publicvoidStackalloc64()=>Consume(stackallocbyte[64]);[Benchmark]publicvoidStackalloc128()=>Consume(stackallocbyte[128]);[Benchmark]publicvoidStackalloc256()=>Consume(stackallocbyte[256]);[Benchmark]publicvoidStackalloc512()=>Consume(stackallocbyte[512]);[Benchmark]publicvoidStackalloc1024()=>Consume(stackallocbyte[1024]);[Benchmark]publicvoidStackalloc16384()=>Consume(stackallocbyte[16384]);[MethodImpl(MethodImplOptions.NoInlining)]staticvoidConsume(Span<byte>x){}}
MethodToolchainMeanErrorRatio
Stackalloc64Main3.425 ns0.0004 ns1.00
Stackalloc64PR2.559 ns0.0008 ns0.75
Stackalloc128Main3.999 ns0.0002 ns1.00
Stackalloc128PR2.404 ns0.0003 ns0.60
Stackalloc256Main5.431 ns0.0005 ns1.00
Stackalloc256PR2.754 ns0.0003 ns0.51
Stackalloc512Main12.661 ns0.2744 ns1.00
Stackalloc512PR7.423 ns0.0008 ns0.59
Stackalloc1024Main24.958 ns0.5326 ns1.00
Stackalloc1024PR14.031 ns0.0040 ns0.56
Stackalloc16384Main374.899 ns0.0130 ns1.00
Stackalloc16384PR111.029 ns1.2123 ns0.30

@github-actionsgithub-actionsBot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Nov 26, 2025
@EgorBo

Copy link
Copy Markdown
MemberAuthor

@EgorBot -arm

usingSystem.Runtime.CompilerServices;usingBenchmarkDotNet.Attributes;publicclassBenchmarks{[Benchmark]publicvoidStackalloc64()=>Consume(stackallocbyte[64]);[Benchmark]publicvoidStackalloc128()=>Consume(stackallocbyte[128]);[Benchmark]publicvoidStackalloc256()=>Consume(stackallocbyte[256]);[Benchmark]publicvoidStackalloc512()=>Consume(stackallocbyte[512]);[Benchmark]publicvoidStackalloc1024()=>Consume(stackallocbyte[1024]);[Benchmark]publicvoidStackalloc16384()=>Consume(stackallocbyte[16384]);[MethodImpl(MethodImplOptions.NoInlining)]staticvoidConsume(Span<byte>x){}}

@EgorBo
EgorBo marked this pull request as ready for review November 26, 2025 13:01
CopilotAI review requested due to automatic review settings November 26, 2025 13:01
@EgorBoEgorBo added area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Nov 26, 2025
@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.

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

Pull request overview

This PR optimizes stackalloc zeroing on ARM64 by enabling the same STORE_BLK optimization that already exists for X64. When the allocation size is a constant, the lowering phase now takes responsibility for clearing memory via an unrolled STORE_BLK node, allowing the backend to skip loop-based zeroing and use more efficient SIMD instructions.

Key changes:

  • Enables Lower's STORE_BLK optimization for constant-sized stackalloc on ARM64
  • Introduces clearMemory local variable to track whether backend should clear memory
  • Updates register allocation and code generation to skip clearing when Lower handles it

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

FileDescription
src/coreclr/jit/lower.cppExtends the constant-sized LCLHEAP optimization to TARGET_ARM64
src/coreclr/jit/lsraarm64.cppUpdates register allocation to track when Lower handles memory clearing
src/coreclr/jit/codegenarm64.cppUpdates code generation to skip clearing when Lower took responsibility

Comment threadsrc/coreclr/jit/lsraarm64.cpp Outdated
Comment threadsrc/coreclr/jit/codegenarm64.cpp Outdated
@jakobbotsch

Copy link
Copy Markdown
Member

The superpmi-replay asserts look related

@EgorBo
EgorBoforce-pushed the optimize-stackalloc-zeroing-arm64 branch from c61e795 to 8746f45CompareNovember 26, 2025 20:41
@EgorBo

EgorBo commented Nov 27, 2025

Copy link
Copy Markdown
MemberAuthor

@jakobbotsch @dotnet/jit-contrib PTAL

So today if the Size is a constant and it's contained it means it's either already cleared by GT_STORE_BLK or initMem is false. It may be not contained if it's too big (GT_STORE_BLK is effectively limited with 4GB while LCLHEAP accepts size_t length) or it's unused (this can be handled by removing unused LCLHEAP in Lower, but it's a separate issue).

For all size it seems to be a clear win (for 32b and less we don't emit LCLHEAP and convert it to locals instead)

Comment threadsrc/coreclr/jit/codegenarm64.cpp Outdated
Comment threadsrc/coreclr/jit/codegenarm64.cpp Outdated

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

LGTM beyond the nits

EgorBoand others added 2 commits November 27, 2025 13:20
Co-authored-by: Jakob Botsch Nielsen <Jakob.botsch.nielsen@gmail.com>
@EgorBo
EgorBo enabled auto-merge (squash) November 27, 2025 13:30
@EgorBo
EgorBo merged commit ffb52e9 into dotnet:mainNov 27, 2025
110 of 117 checks passed
@EgorBo
EgorBo deleted the optimize-stackalloc-zeroing-arm64 branch November 27, 2025 15:48
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Dec 28, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMIreduce-unsafe

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@EgorBo@jakobbotsch