Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unused struct fields sometimes improve the codegen #79928

Closed
am11 opened this issue Dec 23, 2022 · 4 comments · Fixed by #84627
Closed

Unused struct fields sometimes improve the codegen #79928

am11 opened this issue Dec 23, 2022 · 4 comments · Fixed by #84627
Assignees
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Milestone

Comments

@am11
Copy link
Member

am11 commented Dec 23, 2022

Given:

public struct T
{
    private double x;
    private byte y; // unused
    private int z; // unused

    public static double M(double v)
    {
        T t = new T { x = v };
        return t.x;
    }
}

codegen of M looks like:

T:M(double):double:
       ret  

after removing unused fields (y and z), it turns into:

T:M(double):double:
       push     rax
       movsd    qword ptr [rsp], xmm0
       add      rsp, 8
       ret

IOW, it needs at least one unused field (i.e. size of struct > 8) for this optimization to kick in.

@ghost ghost added the untriaged New issue has not been triaged by the area owner label Dec 23, 2022
@dotnet-issue-labeler dotnet-issue-labeler bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Dec 23, 2022
@ghost
Copy link

ghost commented Dec 23, 2022

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch, @kunalspathak
See info in area-owners.md if you want to be subscribed.

Issue Details

Given:

public struct T
{
    private double x;
    private byte y; // unused
    private int z; // unused

    public static double M(double v)
    {
        T t = new T { x = v };
        return t.x;
    }
}

codegen of M looks like:

T:M(double):double:
       ret  

after removing unused fields (y and z), it turns into:

T:M(double):double:
       push     rax
       movsd    qword ptr [rsp], xmm0
       add      rsp, 8
       ret

IOW, it needs at least one unused field (i.e. size of struct > 8) for this optimization to kick in.

Author: am11
Assignees: -
Labels:

area-CodeGen-coreclr, untriaged

Milestone: -

@gfoidl
Copy link
Member

gfoidl commented Dec 23, 2022

IOW, it needs at least one unused field (i.e. size of struct > 8) for this optimization to kick in.

Based on .NET 7 on my tests (out of curiosity): it looks like this optimization kicks in for primitive types, except floating point types (float, double). If a floating point type is present, then adding at least one non-FP-type it kicks in again.

@am11
Copy link
Member Author

am11 commented Dec 23, 2022

then adding at least one non-FP-type it kicks in again.

It also gets optimized with two FP fields: https://godbolt.org/z/MnTWfvzK3 (daily build out of main branch)

@AndyAyersMS
Copy link
Member

AndyAyersMS commented Jan 3, 2023

This is a known limitation of struct promotion -- it currently lacks a good model to decide whether promoting struct wrapped doubles and floats would be profitable. In cases like the above it is, but in cases where the struct wrapped double (or float) is primarily passed as an argument, promotion can be inefficient.

cc @jakobbotsch who is looking into generalizing struct promotion.

#if defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_ARM) || defined(TARGET_LOONGARCH64)
// TODO-PERF - Only do this when the LclVar is used in an argument context
// TODO-ARM64 - HFA support should also eliminate the need for this.
// TODO-ARM32 - HFA support should also eliminate the need for this.
// TODO-LSRA - Currently doesn't support the passing of floating point LCL_VARS in the integer registers
//
// For now we currently don't promote structs with a single float field
// Promoting it can cause us to shuffle it back and forth between the int and
// the float regs when it is used as a argument, which is very expensive for XARCH
//
else if ((structPromotionInfo.fieldCnt == 1) && varTypeIsFloating(structPromotionInfo.fields[0].fldType))
{
JITDUMP("Not promoting promotable struct local V%02u: #fields = %d because it is a struct with "
"single float field.\n",
lclNum, structPromotionInfo.fieldCnt);
shouldPromote = false;
}

@JulieLeeMSFT JulieLeeMSFT removed the untriaged New issue has not been triaged by the area owner label Jan 9, 2023
@JulieLeeMSFT JulieLeeMSFT added this to the Future milestone Jan 9, 2023
@JulieLeeMSFT JulieLeeMSFT modified the milestones: Future, 8.0.0 Apr 12, 2023
@ghost ghost locked as resolved and limited conversation to collaborators May 13, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants