Skip to content

Variable not promoted to register due to unrelated pointer assignment #35495

@damageboy

Description

@damageboy

I've chased the exact cause for this issue for a long long time, and I finally managed to narrow it down to a reproducible issue.

Environment

I'm using .NET 5.0 preview 3:

dotnet --info                                        
.NET Core SDK (reflecting any global.json):
 Version:   5.0.100-preview.3.20216.6
 Commit:    9f62a32109

Runtime Environment:
 OS Name:     clear-linux-os
 OS Version:  32910
 OS Platform: Linux
 RID:         linux-x64
 Base Path:   /home/dmg/dotnet/sdk/5.0.100-preview.3.20216.6/

Host (useful for support):
  Version: 5.0.0-preview.3.20214.6
  Commit:  b037784658

.NET SDKs installed:
  3.1.101 [/home/dmg/dotnet/sdk]
  3.1.102 [/home/dmg/dotnet/sdk]
  3.1.201 [/home/dmg/dotnet/sdk]
  5.0.100-preview.3.20216.6 [/home/dmg/dotnet/sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 3.1.1 [/home/dmg/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.2 [/home/dmg/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.3 [/home/dmg/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 5.0.0-preview.3.20215.14 [/home/dmg/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 3.1.1 [/home/dmg/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.2 [/home/dmg/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.3 [/home/dmg/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.0-preview.3.20214.6 [/home/dmg/dotnet/shared/Microsoft.NETCore.App]

To install additional .NET runtimes or SDKs:
  https://aka.ms/dotnet-download

Buggy JIT behavior

The issue can be clearly seen when comparing the generated ASM between this buggy version:

Where in this order of variable declarations:

                var tmpLeft = _tempStart;
                var tmpRight = _tempEnd - N;
                var writeLeft = left;
                var writeRight = right - N - 1;


                var pBase = Int32PermTables.IntPermTablePtr;

Where the writeRight variable is declared before the pBase pointer is initialized, leads to the JIT incorrectly deciding to NOT promote writeRight into a register, later within the function:

M08_L00:
       mov       rcx,rsi
       sub       rcx,rax
       mov       r8,rcx
       sar       r8,3F
       and       r8,3
       add       rcx,r8
       sar       rcx,2
       mov       r8,[rbp-38] ; This is writeRight!
       mov       r9,r8
       sub       r9,rdx
       mov       r10,r9
       sar       r10,3F
       and       r10,3
       add       r9,r10
       sar       r9,2
       cmp       rcx,r9
       jg        short M08_L02
       lea       rcx,[rsi+20]
       jmp       short M08_L03

Workaround / Bug

By changing the order of declaration, as I did in my workaround version:

                // This time pBase is initialized BEFORE the other variables
                var pBase = Int32PermTables.IntPermTablePtr;


                var tmpLeft = _tempStart;
                var tmpRight = _tempEnd - N;
                var writeLeft = left;
                var writeRight = right - N - 1;

The generated assembly now correctly promotes the writeRight variable into a full fledged register without performing needless stack reads and write within my main loop:

M08_L00:
       mov       r8,rax
       sub       r8,r15
       mov       r9,r8
       sar       r9,3F
       and       r9,3
       add       r8,r9
       sar       r8,2
       mov       r9,rdx
       sub       r9,rcx
       mov       r10,r9
       sar       r10,3F
       and       r10,3
       add       r9,r10
       sar       r9,2
       cmp       r8,r9
       jg        short M08_L02
       lea       r8,[rax+20]
       jmp       short M08_L03

The full disassembly can be viewed here, in case someone is interested:

https://gist.github.com/damageboy/c09fc710d2b9010fe176645fa526a170

category:cq
theme:register-allocator
skill-level:expert
cost:medium

Metadata

Metadata

Assignees

No one assigned

    Labels

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

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions