Skip to content

Recreating struct containing System.Numerics vectors in loop and setting array element causes data loss #1241

@ronbrogan

Description

@ronbrogan

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, float instead of Vector3/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:
image
image

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.

Metadata

Metadata

Assignees

Labels

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

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions