Repository: dotnet/runtime
File: src/coreclr/jit/lclvars.cpp (C++)

Code before:
    //  1) We need to save the entire 128-bits of xmm register to stack, since amd64
    //     prolog unwind codes allow encoding of an instruction that stores the entire xmm reg
    //     at an offset relative to SP
    //  2) We adjust frame size so that SP is aligned at 16-bytes after pushing integer registers.
    //     This means while saving the first xmm register to its allocated stack location we might
    //     have to skip 8-bytes.  The reason for padding is to use efficient "movaps" to save/restore
    //     xmm registers to/from stack to match Jit64 codegen.  Without the aligning on 16-byte
    //     boundary we would have to use movups when offset turns out unaligned.  Movaps is more
    //     performant than movups.
    const unsigned calleeFPRegsSavedSize = genCountBits(compCalleeFPRegsSavedMask) * XMM_REGSIZE_BYTES;

    // For OSR the alignment pad computation should not take the original frame into account.
    // Original frame size includes the pseudo-saved RA and so is always = 8 mod 16.
    const int offsetForAlign = -(stkOffs + originalFrameSize);

    if ((calleeFPRegsSavedSize > 0) && ((offsetForAlign % XMM_REGSIZE_BYTES) != 0))
    {
        // Take care of alignment
        int alignPad = (int)AlignmentPad((unsigned)offsetForAlign, XMM_REGSIZE_BYTES);
        assert(alignPad != 0);
        stkOffs -= alignPad;
        lvaIncrementFrameSize(alignPad);
    }

    stkOffs -= calleeFPRegsSavedSize;
    lvaIncrementFrameSize(calleeFPRegsSavedSize);

#endif // TARGET_AMD64

    if (!opts.IsOSR())
    {
        if (lvaMonAcquired != BAD_VAR_NUM)
        {
            // This var must go first, in what is called the 'frame header' for EnC so that it is
            // preserved when remapping occurs.  See vm\eetwain.cpp for detailed comment specifying frame
            // layout requirements for EnC to work.
            stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaMonAcquired, lvaLclStackHomeSize(lvaMonAcquired), stkOffs);
        }

#ifndef JIT32_GCENCODER
        // In this case the async contexts are part of the EnC frame header and the generic context is _not_.
        // Preserving the generic context is handled as if it was a normal IL local.
        //
        // For jit32 the generic context is considered part of the EnC frame header too, and the async contexts
        // come after it, so we allocate them later.
        //
        stkOffs = lvaAllocAsyncContexts(stkOffs);
#endif
    }

    if (mustDoubleAlign)

Review comment (suggestion):
This case (along with the async context locals) gets handled under the later `lvaIsOSRLocal` path now.

Code after:
    // need to be pushed.  But Amd64 doesn't support push/pop of xmm registers.
    // Instead we need to allocate space for them on the stack and save them in prolog.
    // Therefore, we consider xmm registers being saved while computing stack offsets
    // but space for xmm registers is considered part of compLclFrameSize.
    // Notes
    //  1) We need to save the entire 128-bits of xmm register to stack, since amd64
    //     prolog unwind codes allow encoding of an instruction that stores the entire xmm reg
    //     at an offset relative to SP
    //  2) We adjust frame size so that SP is aligned at 16-bytes after pushing integer registers.
    //     This means while saving the first xmm register to its allocated stack location we might
    //     have to skip 8-bytes.  The reason for padding is to use efficient "movaps" to save/restore
    //     xmm registers to/from stack to match Jit64 codegen.  Without the aligning on 16-byte
    //     boundary we would have to use movups when offset turns out unaligned.  Movaps is more
    //     performant than movups.
    const unsigned calleeFPRegsSavedSize = genCountBits(compCalleeFPRegsSavedMask) * XMM_REGSIZE_BYTES;

    // For OSR the alignment pad computation should not take the original frame into account.
    // Original frame size includes the pseudo-saved RA and so is always = 8 mod 16.
    const int offsetForAlign = -(stkOffs + originalFrameSize);

    if ((calleeFPRegsSavedSize > 0) && ((offsetForAlign % XMM_REGSIZE_BYTES) != 0))
    {
        // Take care of alignment
        int alignPad = (int)AlignmentPad((unsigned)offsetForAlign, XMM_REGSIZE_BYTES);
        assert(alignPad != 0);
        stkOffs -= alignPad;
        lvaIncrementFrameSize(alignPad);
    }

    stkOffs -= calleeFPRegsSavedSize;
    lvaIncrementFrameSize(calleeFPRegsSavedSize);

#endif // TARGET_AMD64

    if (!opts.IsOSR())
    {
        if (lvaMonAcquired != BAD_VAR_NUM)
        {
            // This var must go first, in what is called the 'frame header' for EnC so that it is
            // preserved when remapping occurs.  See vm\eetwain.cpp for detailed comment specifying frame
            // layout requirements for EnC to work.
            stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaMonAcquired, lvaLclStackHomeSize(lvaMonAcquired), stkOffs);
        }

#ifndef JIT32_GCENCODER
        // In this case the async contexts are part of the EnC frame header and the generic context is _not_.
        // Preserving the generic context is handled as if it was a normal IL local.
        //
        // For jit32 the generic context is considered part of the EnC frame header too, and the async contexts
        // come after it, so we allocate them later.
        //