-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
Description
I'm experiencing some behavior in "release" mode that I can't make sense of.
I have a method which contains the following loop
for (var i = 0; i < Vertices.Length; i++)
{
var vert = Vertices[i];
Vertices[i] = new Vertex(vert.Position, vert.TexCoords);
}Vertices here is a property on the method's class that is an array of struct Vertex. The struct has two properties, a Vector3 and Vector2.
After the above loop runs, each Vertex item in the Vertices array does not have the data it should, it's all zeroes. However, if the new struct instance is stored in a local variable first, then assigned to the array's element, the data is as expected:
for (var i = 0; i < Vertices.Length; i++)
{
var vert = Vertices[i];
var newVert = new Vertex(vert.Position, vert.TexCoords);
Vertices[i] = newVert;
}Caveat:
- If the fields on the struct are, for example,
floatinstead ofVector3/2, the issue does not present itself
I've created a minimal reproduction of the issue here: https://github.com/ronbrogan/JitBug/blob/master/JitBug/Program.cs
When run in debug mode, the data is correct, but in release mode, it's zero:


Disassembly
I've tried my hand at grabbing the disassembly for the loops:
Here's the scenario where the data is lost, the elements have zeros for data:
for (var i = 0; i < Vertices.Length; i++)
00007FFE82E488F2 in al,dx
00007FFE82E488F3 pop rax
00007FFE82E488F4 vzeroupper
00007FFE82E488F7 xor eax,eax
00007FFE82E488F9 mov qword ptr [rsp+40h],rax
00007FFE82E488FE mov qword ptr [rsp+48h],rax
00007FFE82E48903 mov qword ptr [rsp+50h],rax
00007FFE82E48908 xor eax,eax
00007FFE82E4890A mov rdx,qword ptr [rcx+8]
00007FFE82E4890E cmp dword ptr [rdx+8],0
00007FFE82E48912 jle 00007FFE82E489C3
00007FFE82E48918 mov rdx,qword ptr [rcx+8]
00007FFE82E4891C cmp eax,dword ptr [rdx+8]
00007FFE82E4891F jae 00007FFE82E489C8
00007FFE82E48925 movsxd r8,eax
00007FFE82E48928 lea r8,[r8+r8*4]
00007FFE82E4892C lea rdx,[rdx+r8*4+10h]
00007FFE82E48931 vmovdqu xmm0,xmmword ptr [rdx]
00007FFE82E48935 vmovdqu xmmword ptr [rsp+40h],xmm0
00007FFE82E4893B mov r8d,dword ptr [rdx+10h]
00007FFE82E4893F mov dword ptr [rsp+50h],r8d
00007FFE82E48944 xor r8d,r8d
00007FFE82E48947 lea r9,[rsp+28h]
00007FFE82E4894C vxorps xmm0,xmm0,xmm0
00007FFE82E48950 vmovdqu xmmword ptr [r9],xmm0
00007FFE82E48955 mov dword ptr [r9+10h],r8d
00007FFE82E48959 lea r8,[rsp+40h]
00007FFE82E4895E vmovss xmm0,dword ptr [r8]
00007FFE82E48963 vmovss xmm1,dword ptr [r8+4]
00007FFE82E48969 vmovss xmm2,dword ptr [r8+8]
00007FFE82E4896F lea r8,[rsp+4Ch]
00007FFE82E48974 vmovss xmm3,dword ptr [r8]
00007FFE82E48979 vmovss xmm4,dword ptr [r8+4]
00007FFE82E4897F lea r8,[rsp+28h]
00007FFE82E48984 vmovss dword ptr [r8],xmm0
00007FFE82E48989 vmovss dword ptr [r8+4],xmm1
00007FFE82E4898F vmovss dword ptr [r8+8],xmm2
00007FFE82E48995 lea r8,[rsp+34h]
00007FFE82E4899A vmovss dword ptr [r8],xmm3
00007FFE82E4899F vmovss dword ptr [r8+4],xmm4
Vertices[i] = new Vertex(vert.Position, vert.TexCoords);
00007FFE82E489A5 xor r8d,r8d
00007FFE82E489A8 vxorps xmm0,xmm0,xmm0
00007FFE82E489AC vmovdqu xmmword ptr [rdx],xmm0
00007FFE82E489B0 mov dword ptr [rdx+10h],r8d
for (var i = 0; i < Vertices.Length; i++)
00007FFE82E489B4 inc eax
00007FFE82E489B6 mov rdx,qword ptr [rcx+8]
00007FFE82E489BA cmp dword ptr [rdx+8],eax
00007FFE82E489BD jg 00007FFE82E48918
00007FFE82E489C3 add rsp,58h
00007FFE82E489C7 ret And here's the asm from when the method works as expected:
for (var i = 0; i < Vertices.Length; i++)
00007FFE82E49B80 push rdi
00007FFE82E49B81 push rsi
00007FFE82E49B82 sub rsp,58h
00007FFE82E49B86 vzeroupper
00007FFE82E49B89 mov rsi,rcx
00007FFE82E49B8C lea rdi,[rsp+28h]
00007FFE82E49B91 mov ecx,0Ch
00007FFE82E49B96 xor eax,eax
00007FFE82E49B98 rep stos dword ptr [rdi]
00007FFE82E49B9A mov rcx,rsi
00007FFE82E49B9D xor eax,eax
00007FFE82E49B9F mov rdx,qword ptr [rcx+8]
00007FFE82E49BA3 cmp dword ptr [rdx+8],0
00007FFE82E49BA7 jle 00007FFE82E49C4B
00007FFE82E49BAD mov rdx,qword ptr [rcx+8]
00007FFE82E49BB1 cmp eax,dword ptr [rdx+8]
00007FFE82E49BB4 jae 00007FFE82E49C52
00007FFE82E49BBA movsxd r8,eax
00007FFE82E49BBD lea r8,[r8+r8*4]
00007FFE82E49BC1 lea rdx,[rdx+r8*4+10h]
00007FFE82E49BC6 vmovdqu xmm0,xmmword ptr [rdx]
00007FFE82E49BCA vmovdqu xmmword ptr [rsp+40h],xmm0
00007FFE82E49BD0 mov r9d,dword ptr [rdx+10h]
00007FFE82E49BD4 mov dword ptr [rsp+50h],r9d
var newVert = new Vertex(vert.Position, vert.TexCoords);
00007FFE82E49BD9 lea rdx,[rsp+40h]
00007FFE82E49BDE vmovss xmm0,dword ptr [rdx]
00007FFE82E49BE2 vmovss xmm1,dword ptr [rdx+4]
00007FFE82E49BE7 vmovss xmm2,dword ptr [rdx+8]
00007FFE82E49BEC lea rdx,[rsp+4Ch]
00007FFE82E49BF1 vmovss xmm3,dword ptr [rdx]
00007FFE82E49BF5 vmovss xmm4,dword ptr [rdx+4]
00007FFE82E49BFA lea rdx,[rsp+28h]
00007FFE82E49BFF vmovss dword ptr [rdx],xmm0
00007FFE82E49C03 vmovss dword ptr [rdx+4],xmm1
00007FFE82E49C08 vmovss dword ptr [rdx+8],xmm2
00007FFE82E49C0D lea rdx,[rsp+34h]
00007FFE82E49C12 vmovss dword ptr [rdx],xmm3
00007FFE82E49C16 vmovss dword ptr [rdx+4],xmm4
00007FFE82E49C1B mov rdx,qword ptr [rcx+8]
00007FFE82E49C1F cmp eax,dword ptr [rdx+8]
00007FFE82E49C22 jae 00007FFE82E49C52
00007FFE82E49C24 lea rdx,[rdx+r8*4+10h]
00007FFE82E49C29 vmovdqu xmm0,xmmword ptr [rsp+28h]
00007FFE82E49C2F vmovdqu xmmword ptr [rdx],xmm0
00007FFE82E49C33 mov r8d,dword ptr [rsp+38h]
00007FFE82E49C38 mov dword ptr [rdx+10h],r8d
for (var i = 0; i < Vertices.Length; i++)
00007FFE82E49C3C inc eax
00007FFE82E49C3E mov rdx,qword ptr [rcx+8]
00007FFE82E49C42 cmp dword ptr [rdx+8],eax
00007FFE82E49C45 jg 00007FFE82E49BAD
00007FFE82E49C4B add rsp,58h
00007FFE82E49C4F pop rsi
00007FFE82E49C50 pop rdi
00007FFE82E49C51 ret I'm not great at reading asm, but it looks like something is going awry when it sets the array element in the failure scenario. I can only assume this presents itself for the Vector types and not floats due to the SIMD instructions for VectorX, but that's just a guess.