JIT: Arithmetic overflow detection blocks certain loop optimizations

Open
#111,516 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
42/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Stale
Tech stack
csharp

Research direction

Start with the Checked and Unchecked C# examples and compare their generated assembly and JitDump output from the linked reproduction. Trace the JIT loop optimization path responsible for strength reduction, down-counting, and overflow-check elimination. Done means checked code receives the intended equivalent optimizations without a redundant overflow branch, with regression coverage for this pattern.

Written by the indexing model from the issue text.

Description

area-CodeGen-coreclr tenet-performance

Enabling arithmetic overflow detection in this simple example blocks strength reduction and down-counting optimization. i can't overflow but the redundant check is not eliminated. https://godbolt.org/z/77eW7YWhe

void Unchecked(int[] dest)
{
    unchecked
    {
        for (int i = 0; i < dest.Length; i++)
        {
            dest[i] = 0;
        }
    }
}

void Checked(int[] dest)
{
    checked
    {
        for (int i = 0; i < dest.Length; i++)
        {
            dest[i] = 0;
        }
    }
}
Program:Unchecked(int[]):this (FullOpts):
       mov      eax, dword ptr [rdx+0x08]
       test     eax, eax
       jle      SHORT G_M20608_IG05
       add      rdx, 16
       align    [0 bytes for IG04]
G_M20608_IG04:  ;; offset=0x000B
       xor      ecx, ecx
       mov      dword ptr [rdx], ecx
       add      rdx, 4
       dec      eax
       jne      SHORT G_M20608_IG04
G_M20608_IG05:  ;; offset=0x0017
       ret      

Program:Checked(int[]):this (FullOpts):
       sub      rsp, 40
       xor      eax, eax
       mov      ecx, dword ptr [rdx+0x08]
       test     ecx, ecx
       jle      SHORT G_M19419_IG04
       align    [0 bytes for IG03]
G_M19419_IG03:  ;; offset=0x000D
       xor      r8d, r8d
       mov      dword ptr [rdx+4*rax+0x10], r8d ; not strength reduced
       add      eax, 1                          ; not down-counting
       jo       SHORT G_M19419_IG05             ; not eliminated redundant check 
       cmp      ecx, eax
       jg       SHORT G_M19419_IG03
G_M19419_IG04:  ;; offset=0x001E
       add      rsp, 40
       ret      
G_M19419_IG05:  ;; offset=0x0023
       call     CORINFO_HELP_OVERFLOW
       int3     

JitDump for Checked:

Optimizing induction variables:
Processing L00 header: BB03
  Members (1): BB03
  Entry: BB02 -> BB03
  Exit: BB03 -> BB04
  Back: BB03 -> BB03
Considering L00 for strength reduction...
  L00 exits when:
  <L00, 1, 1> >= V04.1
  Does not overflow past the test
  Need to prove 1 <= V04.1: true
  Backedge count: (V04.1 + -1)
  Bound on backedge taken count is (V04.1 + -1)
  Considering primary IVs
STMT00006 ( ??? ... ??? )
N004 (  0,  0) [000035] DA---------                         *  STORE_LCL_VAR int    V02 loc0         d:3 $VN.Void
N003 (  0,  0) [000034] -----------                         \--*  PHI       int    $240
N001 (  0,  0) [000037] ----------- pred BB03                  +--*  PHI_ARG   int    V02 loc0         u:4
N002 (  0,  0) [000036] ----------- pred BB02                  \--*  PHI_ARG   int    V02 loc0         u:2 $c3
  => <L00, 0, 1>
  L00 exits when:
  <L00, 1, 1> >= V04.1
  Does not overflow past the test
  Need to prove 1 <= V04.1: true
  Backedge count: (V04.1 + -1)
  Could not create cursors for all loop uses of primary IV
Checking if we should make L00 downwards counted
  Considering exiting block BB03
  Found no potentially removable locals when making this loop downwards counted
Dominant language
C#
Stars
18.3k
Forks
5.6k
PR merge metrics
PR metrics pending

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from dotnet/runtime

All issues in dotnet/runtime

Similar issues

More C# issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.