Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

[ARM32/RyuJIT] Enable passing struct argument that use stack only#11541

Merged
BruceForstall merged 5 commits into
dotnet:masterfrom
hseok-oh:ryujit/struct_arg_stack
May 22, 2017
Merged

[ARM32/RyuJIT] Enable passing struct argument that use stack only#11541
BruceForstall merged 5 commits into
dotnet:masterfrom
hseok-oh:ryujit/struct_arg_stack

Conversation

@hseok-oh
Copy link
Copy Markdown

Enable passing struct argument when it uses stack only.
Cannot pass splitted struct argument that uses stack and register(s) yet.

related issue: #10722

Enable passing struct argument when it uses stack only.
Cannot pass splitted struct argument that uses stack and register(s) yet.
@hseok-oh
Copy link
Copy Markdown
Author

cc/ @dotnet/arm32-contrib

Example

using System;
using System.Runtime.CompilerServices;

public struct IntStruct
{   
    public int num1;
    public int num2;
    public int num3;
    public int num4;
    public int num5;
}

public class BringUpTest
{
    const int Pass = 100;
    const int Fail = -1;

    [MethodImplAttribute(MethodImplOptions.NoInlining)]
    public static int StructAdd(int a, int b, int c, int d, IntStruct rp)
    {   
        return a + b+ c + d + rp.num1 + rp.num2 + rp.num3 + rp.num4 + rp.num5;
    }

    public static int Main()
    {   
        IntStruct a = new IntStruct();
        
        a.num1 = 3;
        a.num2 = 2;
        a.num3 = 4;
        a.num4 = 1;
        a.num5 = 6;

        int y = StructAdd(1, 2, 3, 4, a);
        if (y == 16) return Pass;
        else return Fail;
    }
}

Before

Assert failure(PID 11626 [0x00002d6a], Thread: 11626 [0x2d6a]): Assertion failed 'NYI: Unimplemented node type obj' in 'BringUpTest:Main():int' (IL size 11894)

    File: /home/sjsujinkim/works/dotnet/coreclr/src/jit/lsraarm.cpp Line: 702
    Image: /nfs/rbp3/test/coreoverlay_checked/corerun

Aborted

After

generated code to call StructAdd

Generating: N043 (  3,  2) [000040] -------N-----       t40 =    &lclVar   byref  V00 loc0         u:8 (last use) REG NA
                                                              /--*  t40    byref
Generating: N045 (  9,  7) [000043] -------------       t43 = *  obj(20)   struct REG NA $101
                                                              /--*  t43    struct  
Generating: N047 (???,???) [000080] -------------             *  putarg_stk [+0x00] struct REG NA  
IN0011:             ldr     r0, [sp+0x1c]       // [V00 loc0]
IN0012:             str     r0, [sp]    // [V01 OutArgs]
IN0013:             ldr     r0, [sp+0x1c]       // [V00 loc0]    
IN0014:             str     r0, [sp+0x04]       // [V01 OutArgs+0x04]
IN0015:             ldr     r0, [sp+0x1c]       // [V00 loc0] 
IN0016:             str     r0, [sp+0x08]       // [V01 OutArgs+0x08]
IN0017:             ldr     r0, [sp+0x1c]       // [V00 loc0] 
IN0018:             str     r0, [sp+0x0c]       // [V01 OutArgs+0x0c]
IN0019:             ldr     r0, [sp+0x1c]       // [V00 loc0]
IN001a:             str     r0, [sp+0x10]       // [V01 OutArgs+0x10]
Generating: N049 (  1,  1) [000036] -------------       t36 =    const     int    1 REG r0 $85
IN001b:             movs    r0, 1
                                                              /--*  t36    int
Generating: N051 (???,???) [000081] -------------       t81 = *  putarg_reg int    REG r0
Generating: N053 (  1,  1) [000037] -------------       t37 =    const     int    2 REG r1 $83
IN001c:             movs    r1, 2
                                                              /--*  t37    int
Generating: N055 (???,???) [000082] -------------       t82 = *  putarg_reg int    REG r1
Generating: N057 (  1,  1) [000038] -------------       t38 =    const     int    3 REG r2 $82
IN001d:             movs    r2, 3
                                                              /--*  t38    int    
Generating: N059 (???,???) [000083] -------------       t83 = *  putarg_reg int    REG r2
Generating: N061 (  1,  1) [000039] -------------       t39 =    const     int    4 REG r3 $84
IN001e:             movs    r3, 4
                                                              /--*  t39    int    
Generating: N063 (???,???) [000084] -------------       t84 = *  putarg_reg int    REG r3
Generating: N065 (  3,  7) [000085] -------------       t85 =    const(h)  int    0x74F57A14 ftn REG lr
IN001f:             movw    lr, 0x7a14
IN0020:             movt    lr, 0x74f5
                                                              /--*  t85    int
Generating: N067 (  6,  9) [000086] -------------       t86 = *  indir     int    REG lr
IN0021:             ldr     lr, [lr]
                                                              /--*  t81    int    arg0 in r0
                                                              +--*  t82    int    arg1 in r1
                                                              +--*  t83    int    arg2 in r2
                                                              +--*  t84    int    arg3 in r3
                                                              +--*  t86    int    control expr
Generating: N069 ( 32, 26) [000041] --C-G--------       t41 = *  call      int    BringUpTest.StructAdd $204
Call: GCvars=00000000 {}, gcrefRegs=0000 {}, byrefRegs=0000 {}
IN0022:             blx     lr          // BringUpTest:StructAdd(int,int,int,int,struct):int

hseok-oh added 2 commits May 12, 2017 14:23
Fix formatting
Fix formatting error
@BruceForstall BruceForstall self-requested a review May 12, 2017 06:46
{
return;
}
#endif // _TARGET_ARM_
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't look necessary (or desirable).

However, it looks like there is an existing bug where nextType/nextAttr below is accessed even if remainingSize==0. That could be fixed by pushing these declarations within the first if, and then deleting the

nextType = compiler->getJitGCType(gcPtrs[nextIndex]);
nextAttr = emitTypeSize(nextType);

at the end of the first if.

unsigned gcPtrCount; // The count of GC pointers in the struct
BYTE* gcPtrs = nullptr;
BYTE gcPtrArray[MAX_ARG_REG_COUNT] = {}; // TYPE_GC_NONE = 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For simplicity, you could just always initialize gcPtrs to gcPtrArray:

            BYTE  gcPtrArray[MAX_ARG_REG_COUNT] = {}; // TYPE_GC_NONE = 0
            BYTE* gcPtrs                        = gcPtrArray;

@BruceForstall
Copy link
Copy Markdown

There is code in Lowering::TreeNodeInfoInitPutArgStk() that is specific to ARM64 that needs adjusting:

            // We could use a ldp/stp sequence so we need two internal registers
            argNode->gtLsraInfo.internalIntCount = 2;

For arm32, you only need one internal register.

gcPtrs = treeNode->gtGcPtrs;
gcPtrCount = treeNode->gtNumSlots;
#endif // _TARGET_ARM_
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why this is ARM32-specific? Why does ARM64 do something different here?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

treeNode->gtGcPtrs and treeNode->gtNumSlots can be used when FEATURE_PUT_STRUCT_ARG_STK is set, but ARM64 is not use this feature.

hseok-oh added 2 commits May 15, 2017 10:58
- Remove redundant GC type assignment in genPutArgStk
- Fix internal register count for ARM32: 2 -> 1
Fix formatting
@hseok-oh
Copy link
Copy Markdown
Author

@BruceForstall Fixed it by applying your review. PTAL

#else // _TARGET_ARM_
// For a >= 4 byte structSize we will generate a ldr and str instruction each loop
// ldr r2, [r0]
// str r2, [sp, #16]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about str r2, [sp, #4] ?
Because we are going to increase offset by TARGET_POINTER_SIZE for ARM32 here.

Copy link
Copy Markdown
Member

@hqueue hqueue May 18, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or does the offset start from 16 and increase by 4 ?

Copy link
Copy Markdown
Author

@hseok-oh hseok-oh May 18, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's not important what the offset value is. It is just example. This offset value isn't offset of this struct argument. It means stack offset in all of arguments for method.

@hseok-oh
Copy link
Copy Markdown
Author

hseok-oh commented May 18, 2017

Please merge this after merging #11709.
Whitout #11709, it can make new runtime error when remorphing phase.

@hseok-oh
Copy link
Copy Markdown
Author

Please merge this after merging #11709.
Whitout #11709, it can make new runtime error when remorphing phase.

This PR is independent with #11709. It was my mistake.

@BruceForstall
Copy link
Copy Markdown

@dotnet-bot test this please

@BruceForstall
Copy link
Copy Markdown

@dotnet-bot test Windows_NT arm64 Checked

@BruceForstall
Copy link
Copy Markdown

@dotnet-bot test Tizen armel Cross Debug Build
@dotnet-bot test Windows_NT arm64 Checked

@BruceForstall BruceForstall merged commit 4349824 into dotnet:master May 22, 2017
@hseok-oh hseok-oh deleted the ryujit/struct_arg_stack branch May 31, 2017 04:31
@karelz karelz modified the milestone: 2.1.0 Aug 28, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants