镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

JIT should optimize {array | span}.Length division by constant that is power of 2 #59922

Closed

Description

@gfoidl

E.g.

Span<byte> span = ...
nint n = span.Length / 8;    // or any constant that is a power of two

produces integer division by consant
(Also tested with .NET 6 RC 1, and didn't find an issue or PR that addressed this.)

JIT should be able to recnogize that .Length isn't negative, so produce code that is equivalent to

nint n = (nint)(uint)span.Length / 8;

which produces (on x86)

shr rax, 3

This pattern is quite common, so it's tedious and a bit unreadable to have the "cast-hacks".

category:cq
theme:expression-opts
skill-level:intermediate
cost:small
impact:small

Activity

  1. ghost added
    untriagedNew issue has not been triaged by the area owner
    on Oct 4, 2021
  2. EgorBo commented on Oct 4, 2021

    @EgorBo
    Member

    heh, I did for arrays (GT_ARRLEN) #32368 🙂

  3. gfoidl commented on Oct 4, 2021

    @gfoidl
    MemberAuthor

    Perfect 👍🏻, so the step to enable this for Span too isn't that big (hopefully).

  4. SingleAccretion commented on Oct 4, 2021

    @SingleAccretion
    Contributor

    It was somewhat trivial for arrays, it is not so trivial for spans, unfortunately, the reason being that most often the span's length is just a GT_LCL_VAR. Perhaps we can mark a local produced for the length specially when promoting the span.

  5. added
    area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
    on Oct 4, 2021
  6. EgorBo commented on Oct 4, 2021

    @EgorBo
    Member

    I made a quick fix and checking diffs now

  7. stephentoub commented on Oct 4, 2021

    @stephentoub
    Member

    How many other optimizations are there that currently apply only to arrays but could also be relevant to spans? It'd be great to drive that list to zero and then ensure no additional ones creep in. More and more code is being converted from arrays to spans, and we want to avoid unnecessary regressions.

  8. SingleAccretion commented on Oct 4, 2021

    @SingleAccretion
    Contributor

    There are certainly some optimizations that do not benefit spans equally.

    The most obvious example is VN, which can "see" through assignments to array elements (because there is intrinsic understanding of array indexing similar to that of fields built into the compiler):

    private static int RedundantBranchSpan(Span<int> a)
    {
        a[1] = 0;
    
        if (a[1] is 0)
        {
            return 1;
        }
    
        a[2] = 1;
    
        if (a[1] is 0) // The compiler will not see this branch as redundant, there was a write to memory.
        {
            return 1;
        }
    
        return 2;
    }
    
    private static int RedundantBranchArray(int[] a)
    {
        a[1] = 0;
    
        if (a[1] is 0)
        {
            return 1;
        }
    
        a[2] = 1;
    
        if (a[1] is 0) // The compiler will see this branch as redundant since it knows a[1] and a[2] don't interfere
        {
            return 1;
        }
    
        return 2;
    }
    
    // VNs are also used for CSE purposes, so redundant loads may not be optimized as well.
    private static int SpanDoubleLoad(Span<int> a)
    {
        int sum = 0;
    
        sum += a[1];
    
        a[2] = 1;
    
        sum += a[1]; // This will be a load
        
        return sum;
    }
    
    private static int ArrayDoubleLoad(int[] a)
    {
        int sum = 0;
    
        sum += a[1];
    
        a[2] = 1;
    
        sum += a[1]; // a[1] will be CSEed and used from a register
        
        return sum;
    }

    It is hard for me to say which other optimizations are affected (and how), and how impactful the above is in real-world code, or how hard would the fix be (I suspect though that it will not be so trivial, because the existing mechanism already has some unsightly maintainability problems).

  9. JulieLeeMSFT commented on Oct 4, 2021

    @JulieLeeMSFT
    Member

    The most obvious example is VN,

    cc @jakobbotsch for VN on span.
    cc @dotnet/jit-contrib

  10. removed
    untriagedNew issue has not been triaged by the area owner
    on Oct 4, 2021
  11. added this to the 7.0.0 milestone on Oct 4, 2021
  12. modified the milestones: 7.0.0, 8.0.0 on Jul 10, 2022
  13. ghost added
    in-prThere is an active PR which will close this issue when it is merged
    on Jan 23, 2023
  14. ghost removed
    in-prThere is an active PR which will close this issue when it is merged
    on Jan 26, 2023
  15. ghost locked as resolved and limited conversation to collaborators on Feb 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions