I've got code similar to the following repro:
usingSystem;usingSystem.Runtime.InteropServices;usingSystem.Runtime.CompilerServices;publicclassC{publicstaticvoidMain()=>newC().TryFormat(newchar[4],out_);publicboolTryFormat(Span<char>dst,outintcharsWritten){if(dst.Length>=4){dst[0]='t';dst[1]='r';dst[2]='u';dst[3]='e';charsWritten=4;returntrue;}charsWritten=0;returnfalse;}}I was hoping/expecting the bounds checks on each of those four writes to dst to be eliminated, but they’re not:
G_M404_IG02:
488B02 mov rax, bword ptr [rdx]
8B5208 mov edx, dword ptr [rdx+8]
83FA04 cmp edx, 4
7C3C jl SHORT G_M404_IG04
83FA00 cmp edx, 0
7641 jbe SHORT G_M404_IG06
66C7007400 mov word ptr [rax], 116
83FA01 cmp edx, 1
7637 jbe SHORT G_M404_IG06
66C740027200 mov word ptr [rax+2], 114
83FA02 cmp edx, 2
762C jbe SHORT G_M404_IG06
66C740047500 mov word ptr [rax+4], 117
83FA03 cmp edx, 3
7621 jbe SHORT G_M404_IG06
66C740066500 mov word ptr [rax+6], 101
41C70004000000 mov dword ptr [r8], 4
B801000000 mov eax, 1
To work around that, I can use Unsafe.Add and MemoryMarshal.GetReference, e.g.
publicboolTryFormat(Span<char>dst,outintcharsWritten){if(dst.Length>=4){refcharc=refMemoryMarshal.GetReference(dst);c='t';Unsafe.Add(refc,1)= 'r';
Unsafe.Add(refc,2)='u';Unsafe.Add(refc,3)= 'e';
charsWritten=4;returntrue;}charsWritten=0;returnfalse;}in which case I get the better:
G_M408_IG02:
837A0804 cmp dword ptr [rdx+8], 4
7C27 jl SHORT G_M408_IG04
488B02 mov rax, bword ptr [rdx]
66C7007400 mov word ptr [rax], 116
66C740027200 mov word ptr [rax+2], 114
66C740047500 mov word ptr [rax+4], 117
66C740066500 mov word ptr [rax+6], 101
41C70004000000 mov dword ptr [r8], 4
B801000000 mov eax, 1
but it’d be nice not to have to use Unsafe for cases like this.
cc: @AndyAyersMS
Related: https://github.com/dotnet/coreclr/issues/12639
category:cq
theme:range-check
skill-level:intermediate
cost:medium
I've got code similar to the following repro:
I was hoping/expecting the bounds checks on each of those four writes to dst to be eliminated, but they’re not:
To work around that, I can use Unsafe.Add and MemoryMarshal.GetReference, e.g.
in which case I get the better:
but it’d be nice not to have to use Unsafe for cases like this.
cc: @AndyAyersMS
Related: https://github.com/dotnet/coreclr/issues/12639
category:cq
theme:range-check
skill-level:intermediate
cost:medium