public int GetNextOffset()

in src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs [738:1588]


        public int GetNextOffset()
        {
            //            WRAPPER_NO_CONTRACT;
            //            SUPPORTS_DAC;

            if (!_ITERATION_STARTED)
            {
                int numRegistersUsed = 0;

                if (HasThis)
                    numRegistersUsed++;

                if (HasRetBuffArg() && _transitionBlock.IsRetBuffPassedAsFirstArg)
                {
                    numRegistersUsed++;
                }

                Debug.Assert(!IsVarArg || !HasParamType);

                // DESKTOP BEHAVIOR - This block is disabled for x86 as the param arg is the last argument on .NET Framework x86.
                if (!_transitionBlock.IsX86)
                {
                    if (HasParamType)
                    {
                        numRegistersUsed++;
                    }
                }

                if (!_transitionBlock.IsX86 && IsVarArg)
                {
                    numRegistersUsed++;
                }

                switch (_transitionBlock.Architecture)
                {
                    case TargetArchitecture.X86:
                        if (IsVarArg)
                        {
                            numRegistersUsed = _transitionBlock.NumArgumentRegisters; // Nothing else gets passed in registers for varargs
                        }

#if FEATURE_INTERPRETER
                        switch (_interpreterCallingConvention)
                        {
                            case CallingConventions.StdCall:
                                _numRegistersUsed = ArchitectureConstants.NUM_ARGUMENT_REGISTERS;
                                _ofsStack = TransitionBlock.GetOffsetOfArgs() + numRegistersUsed * _transitionBlock.PointerSize + initialArgOffset;
                                break;

                            case CallingConventions.ManagedStatic:
                            case CallingConventions.ManagedInstance:
                                _numRegistersUsed = numRegistersUsed;
                                // DESKTOP BEHAVIOR     _curOfs = (int)(TransitionBlock.GetOffsetOfArgs() + SizeOfArgStack());
                                _ofsStack= (int)(TransitionBlock.GetOffsetOfArgs() + initialArgOffset);
                                break;

                            default:
                                Environment.FailFast("Unsupported calling convention.");
                                break;
                        }
#endif
                        _x86NumRegistersUsed = numRegistersUsed;
                        _x86OfsStack = (int)(_transitionBlock.OffsetOfArgs + SizeOfArgStack());
                        break;

                    case TargetArchitecture.X64:
                        if (_transitionBlock.IsX64UnixABI)
                        {
                            _x64UnixIdxGenReg = numRegistersUsed;
                            _x64UnixIdxStack = 0;
                            _x64UnixIdxFPReg = 0;
                        }
                        else
                        {
                            _x64WindowsCurOfs = _transitionBlock.OffsetOfArgs + numRegistersUsed * _transitionBlock.PointerSize;
                        }
                        break;

                    case TargetArchitecture.ARM:
                        _armIdxGenReg = numRegistersUsed;
                        _armOfsStack = 0;

                        _armWFPRegs = 0;
                        break;

                    case TargetArchitecture.ARM64:
                        _arm64IdxGenReg = numRegistersUsed;
                        _arm64OfsStack = 0;

                        _arm64IdxFPReg = 0;
                        break;

                    case TargetArchitecture.LoongArch64:
                        _loongarch64IdxGenReg = numRegistersUsed;
                        _loongarch64OfsStack = 0;

                        _loongarch64IdxFPReg = 0;
                        break;

                    case TargetArchitecture.RiscV64:
                        _riscv64IdxGenReg = numRegistersUsed;
                        _riscv64OfsStack = 0;

                        _riscv64IdxFPReg = 0;
                        break;
                    default:
                        throw new NotImplementedException();
                }

                _argNum = (_skipFirstArg ? 1 : 0);

                _ITERATION_STARTED = true;
            }

            if (_argNum >= NumFixedArgs)
                return TransitionBlock.InvalidOffset;

            CorElementType argType = GetArgumentType(_argNum, out _argTypeHandle, out _argForceByRef);

            _argTypeHandleOfByRefParam = (argType == CorElementType.ELEMENT_TYPE_BYREF ? _argData.GetByRefArgumentType(_argNum) : default(TypeHandle));

            _argNum++;

            int argSize = TypeHandle.GetElemSize(argType, _argTypeHandle);

            _argType = argType;
            _argSize = argSize;

            argType = _argForceByRef ? CorElementType.ELEMENT_TYPE_BYREF : argType;
            argSize = _argForceByRef ? _transitionBlock.PointerSize : argSize;

            int argOfs;

            switch (_transitionBlock.Architecture)
            {
                case TargetArchitecture.X86:
#if FEATURE_INTERPRETER
                    if (_interpreterCallingConvention != CallingConventions.ManagedStatic && _interpreterCallingConvention != CallingConventions.ManagedInstance)
                    {
                        argOfs = _curOfs;
                        _curOfs += ArchitectureConstants.StackElemSize(argSize);
                        return argOfs;
                    }
#endif
                    if (_transitionBlock.IsArgumentInRegister(ref _x86NumRegistersUsed, argType, _argTypeHandle))
                    {
                        return _transitionBlock.OffsetOfArgumentRegisters + (_transitionBlock.NumArgumentRegisters - _x86NumRegistersUsed) * _transitionBlock.PointerSize;
                    }

                    _x86OfsStack -= _transitionBlock.StackElemSize(argSize);
                    argOfs = _x86OfsStack;

                    Debug.Assert(argOfs >= _transitionBlock.OffsetOfArgs);
                    return argOfs;

                case TargetArchitecture.X64:
                    if (_transitionBlock.IsX64UnixABI)
                    {
                        int cbArg = _transitionBlock.StackElemSize(argSize);

                        _hasArgLocDescForStructInRegs = false;
                        _fX64UnixArgInRegisters = true;
                        int cFPRegs = 0;
                        int cGenRegs = 0;

                        switch (argType)
                        {

                            case CorElementType.ELEMENT_TYPE_R4:
                                // 32-bit floating point argument.
                                cFPRegs = 1;
                                break;

                            case CorElementType.ELEMENT_TYPE_R8:
                                // 64-bit floating point argument.
                                cFPRegs = 1;
                                break;

                            case CorElementType.ELEMENT_TYPE_VALUETYPE:
                            {
                                SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR descriptor;
                                SystemVStructClassificator.GetSystemVAmd64PassStructInRegisterDescriptor(_argTypeHandle.GetRuntimeTypeHandle(), out descriptor);

                                if (descriptor.passedInRegisters)
                                {
                                    cGenRegs = 0;
                                    for (int i = 0; i < descriptor.eightByteCount; i++)
                                    {
                                        switch ((i == 0) ? descriptor.eightByteClassifications0 : descriptor.eightByteClassifications1)
                                        {
                                            case SystemVClassificationType.SystemVClassificationTypeInteger:
                                            case SystemVClassificationType.SystemVClassificationTypeIntegerReference:
                                            case SystemVClassificationType.SystemVClassificationTypeIntegerByRef:
                                                cGenRegs++;
                                                break;
                                            case SystemVClassificationType.SystemVClassificationTypeSSE:
                                                cFPRegs++;
                                                break;
                                            default:
                                                Debug.Assert(false);
                                                break;
                                        }
                                    }

                                    // Check if we have enough registers available for the struct passing
                                    if ((cFPRegs + _x64UnixIdxFPReg <= TransitionBlock.X64UnixTransitionBlock.NUM_FLOAT_ARGUMENT_REGISTERS) && (cGenRegs + _x64UnixIdxGenReg) <= _transitionBlock.NumArgumentRegisters)
                                    {
                                        _argLocDescForStructInRegs = new ArgLocDesc();
                                        _argLocDescForStructInRegs.m_cGenReg = (short)cGenRegs;
                                        _argLocDescForStructInRegs.m_cFloatReg = cFPRegs;
                                        _argLocDescForStructInRegs.m_idxGenReg = _x64UnixIdxGenReg;
                                        _argLocDescForStructInRegs.m_idxFloatReg = _x64UnixIdxFPReg;

                                        _hasArgLocDescForStructInRegs = true;

                                        _x64UnixIdxGenReg += cGenRegs;
                                        _x64UnixIdxFPReg += cFPRegs;

                                        return TransitionBlock.StructInRegsOffset;
                                    }
                                }

                                // Set the register counts to indicate that this argument will not be passed in registers
                                cFPRegs = 0;
                                cGenRegs = 0;
                                break;
                            }

                            default:
                                cGenRegs = cbArg / 8; // GP reg size
                                break;
                        }

                        if (cFPRegs > 0)
                        {
                            if (cFPRegs + _x64UnixIdxFPReg <= TransitionBlock.X64UnixTransitionBlock.NUM_FLOAT_ARGUMENT_REGISTERS)
                            {
                                int argOfsInner = _transitionBlock.OffsetOfFloatArgumentRegisters + _x64UnixIdxFPReg * 8;
                                _x64UnixIdxFPReg += cFPRegs;
                                return argOfsInner;
                            }
                        }
                        else if (cGenRegs > 0)
                        {
                            if (_x64UnixIdxGenReg + cGenRegs <= _transitionBlock.NumArgumentRegisters)
                            {
                                int argOfsInner = _transitionBlock.OffsetOfArgumentRegisters + _x64UnixIdxGenReg * 8;
                                _x64UnixIdxGenReg += cGenRegs;
                                return argOfsInner;
                            }
                        }

                        _fX64UnixArgInRegisters = false;

                        argOfs = _transitionBlock.OffsetOfArgs + _x64UnixIdxStack * 8;
                        int cArgSlots = cbArg / _transitionBlock.PointerSize;

                        _x64UnixIdxStack += cArgSlots;
                        return argOfs;
                    }
                    else
                    {
                        int cFPRegs = 0;

                        switch (argType)
                        {
                            case CorElementType.ELEMENT_TYPE_R4:
                                // 32-bit floating point argument.
                                cFPRegs = 1;
                                break;

                            case CorElementType.ELEMENT_TYPE_R8:
                                // 64-bit floating point argument.
                                cFPRegs = 1;
                                break;
                        }

                        // Each argument takes exactly one slot on AMD64
                        argOfs = _x64WindowsCurOfs - _transitionBlock.OffsetOfArgs;
                        _x64WindowsCurOfs += _transitionBlock.PointerSize;

                        if ((cFPRegs == 0) || (argOfs >= _transitionBlock.SizeOfArgumentRegisters))
                        {
                            return argOfs + _transitionBlock.OffsetOfArgs;
                        }
                        else
                        {
                            int idxFpReg = argOfs / _transitionBlock.PointerSize;
                            return _transitionBlock.OffsetOfFloatArgumentRegisters + idxFpReg * TransitionBlock.SizeOfM128A;
                        }
                    }

                case TargetArchitecture.ARM:
                    {
                        // First look at the underlying type of the argument to determine some basic properties:
                        //  1) The size of the argument in bytes (rounded up to the stack slot size of 4 if necessary).
                        //  2) Whether the argument represents a floating point primitive (ELEMENT_TYPE_R4 or ELEMENT_TYPE_R8).
                        //  3) Whether the argument requires 64-bit alignment (anything that contains a Int64/UInt64).

                        bool fFloatingPoint = false;
                        bool fRequiresAlign64Bit = false;

                        switch (argType)
                        {
                            case CorElementType.ELEMENT_TYPE_I8:
                            case CorElementType.ELEMENT_TYPE_U8:
                                // 64-bit integers require 64-bit alignment on ARM.
                                fRequiresAlign64Bit = true;
                                break;

                            case CorElementType.ELEMENT_TYPE_R4:
                                // 32-bit floating point argument.
                                fFloatingPoint = true;
                                break;

                            case CorElementType.ELEMENT_TYPE_R8:
                                // 64-bit floating point argument.
                                fFloatingPoint = true;
                                fRequiresAlign64Bit = true;
                                break;

                            case CorElementType.ELEMENT_TYPE_VALUETYPE:
                                {
                                    // Value type case: extract the alignment requirement, note that this has to handle 
                                    // the interop "native value types".
                                    fRequiresAlign64Bit = _argTypeHandle.RequiresAlign8();

                                    // Handle HFAs: packed structures of 1-4 floats or doubles that are passed in FP argument
                                    // registers if possible.
                                    if (_argTypeHandle.IsHomogeneousAggregate())
                                        fFloatingPoint = true;

                                    break;
                                }

                            default:
                                // The default is are 4-byte arguments (or promoted to 4 bytes), non-FP and don't require any
                                // 64-bit alignment.
                                break;
                        }

                        // Now attempt to place the argument into some combination of floating point or general registers and
                        // the stack.

                        // Save the alignment requirement
                        _armRequires64BitAlignment = fRequiresAlign64Bit;

                        int cbArg = _transitionBlock.StackElemSize(argSize);
                        Debug.Assert((cbArg % _transitionBlock.PointerSize) == 0);

                        // Ignore floating point argument placement in registers if we're dealing with a vararg function (the ABI
                        // specifies this so that vararg processing on the callee side is simplified).
                        if (fFloatingPoint && _transitionBlock.IsArmhfABI && !IsVarArg)
                        {
                            // Handle floating point (primitive) arguments.

                            // First determine whether we can place the argument in VFP registers. There are 16 32-bit
                            // and 8 64-bit argument registers that share the same register space (e.g. D0 overlaps S0 and
                            // S1). The ABI specifies that VFP values will be passed in the lowest sequence of registers that
                            // haven't been used yet and have the required alignment. So the sequence (float, double, float)
                            // would be mapped to (S0, D1, S1) or (S0, S2/S3, S1).
                            //
                            // We use a 16-bit bitmap to record which registers have been used so far.
                            //
                            // So we can use the same basic loop for each argument type (float, double or HFA struct) we set up
                            // the following input parameters based on the size and alignment requirements of the arguments:
                            //   wAllocMask : bitmask of the number of 32-bit registers we need (1 for 1, 3 for 2, 7 for 3 etc.)
                            //   cSteps     : number of loop iterations it'll take to search the 16 registers
                            //   cShift     : how many bits to shift the allocation mask on each attempt

                            ushort wAllocMask = checked((ushort)((1 << (cbArg / 4)) - 1));
                            ushort cSteps = (ushort)(fRequiresAlign64Bit ? 9 - (cbArg / 8) : 17 - (cbArg / 4));
                            ushort cShift = fRequiresAlign64Bit ? (ushort)2 : (ushort)1;

                            // Look through the availability bitmask for a free register or register pair.
                            for (ushort i = 0; i < cSteps; i++)
                            {
                                if ((_armWFPRegs & wAllocMask) == 0)
                                {
                                    // We found one, mark the register or registers as used. 
                                    _armWFPRegs |= wAllocMask;

                                    // Indicate the registers used to the caller and return.
                                    return _transitionBlock.OffsetOfFloatArgumentRegisters + (i * cShift * 4);
                                }
                                wAllocMask <<= cShift;
                            }

                            // The FP argument is going to live on the stack. Once this happens the ABI demands we mark all FP
                            // registers as unavailable.
                            _armWFPRegs = 0xffff;

                            // Doubles or HFAs containing doubles need the stack aligned appropriately.
                            if (fRequiresAlign64Bit)
                                _armOfsStack = ALIGN_UP(_armOfsStack, _transitionBlock.PointerSize * 2);

                            // Indicate the stack location of the argument to the caller.
                            int argOfsInner = _transitionBlock.OffsetOfArgs + _armOfsStack;

                            // Record the stack usage.
                            _armOfsStack += cbArg;

                            return argOfsInner;
                        }

                        //
                        // Handle the non-floating point case.
                        //

                        if (_armIdxGenReg < 4)
                        {
                            if (fRequiresAlign64Bit)
                            {
                                // The argument requires 64-bit alignment. Align either the next general argument register if
                                // we have any left.  See step C.3 in the algorithm in the ABI spec.       
                                _armIdxGenReg = ALIGN_UP(_armIdxGenReg, 2);
                            }

                            int argOfsInner = _transitionBlock.OffsetOfArgumentRegisters + _armIdxGenReg * 4;

                            int cRemainingRegs = 4 - _armIdxGenReg;
                            if (cbArg <= cRemainingRegs * _transitionBlock.PointerSize)
                            {
                                // Mark the registers just allocated as used.
                                _armIdxGenReg += ALIGN_UP(cbArg, _transitionBlock.PointerSize) / _transitionBlock.PointerSize;
                                return argOfsInner;
                            }

                            // The ABI supports splitting a non-FP argument across registers and the stack. But this is
                            // disabled if the FP arguments already overflowed onto the stack (i.e. the stack index is not
                            // zero). The following code marks the general argument registers as exhausted if this condition
                            // holds.  See steps C.5 in the algorithm in the ABI spec.

                            _armIdxGenReg = 4;

                            if (_armOfsStack == 0)
                            {
                                _armOfsStack += cbArg - cRemainingRegs * _transitionBlock.PointerSize;
                                return argOfsInner;
                            }
                        }

                        if (fRequiresAlign64Bit)
                        {
                            // The argument requires 64-bit alignment. If it is going to be passed on the stack, align
                            // the next stack slot.  See step C.6 in the algorithm in the ABI spec.  
                            _armOfsStack = ALIGN_UP(_armOfsStack, _transitionBlock.PointerSize * 2);
                        }

                        argOfs = _transitionBlock.OffsetOfArgs + _armOfsStack;

                        // Advance the stack pointer over the argument just placed.
                        _armOfsStack += cbArg;

                        return argOfs;
                    }

                case TargetArchitecture.ARM64:
                    {
                        int cFPRegs = 0;
                        bool isFloatHFA = false;

                        switch (argType)
                        {
                            case CorElementType.ELEMENT_TYPE_R4:
                                // 32-bit floating point argument.
                                cFPRegs = 1;
                                break;

                            case CorElementType.ELEMENT_TYPE_R8:
                                // 64-bit floating point argument.
                                cFPRegs = 1;
                                break;

                            case CorElementType.ELEMENT_TYPE_VALUETYPE:
                                {
                                    // Handle HAs: packed structures of 1-4 floats, doubles, or short vectors
                                    // that are passed in FP argument registers if possible.
                                    if (_argTypeHandle.IsHomogeneousAggregate())
                                    {
                                        _argLocDescForStructInRegs = new ArgLocDesc();
                                        _argLocDescForStructInRegs.m_idxFloatReg = _arm64IdxFPReg;

                                        int haElementSize = _argTypeHandle.GetHomogeneousAggregateElementSize();
                                        if (haElementSize == 4)
                                        {
                                            isFloatHFA = true;
                                        }
                                        cFPRegs = argSize / haElementSize;
                                        _argLocDescForStructInRegs.m_cFloatReg = cFPRegs;

                                        // Check if we have enough registers available for the HA passing
                                        if (cFPRegs + _arm64IdxFPReg <= 8)
                                        {
                                            _hasArgLocDescForStructInRegs = true;
                                        }
                                    }
                                    else
                                    {
                                        // Composite greater than 16 bytes should be passed by reference
                                        if (argSize > _transitionBlock.EnregisteredParamTypeMaxSize)
                                        {
                                            argSize = _transitionBlock.PointerSize;
                                        }
                                    }

                                    break;
                                }

                            default:
                                break;
                        }

                        bool isValueType = (argType == CorElementType.ELEMENT_TYPE_VALUETYPE);
                        int cbArg = _transitionBlock.StackElemSize(argSize, isValueType, isFloatHFA);

                        if (cFPRegs > 0 && !IsVarArg)
                        {
                            if (cFPRegs + _arm64IdxFPReg <= 8)
                            {
                                // Each floating point register in the argument area is 16 bytes.
                                int argOfsInner = _transitionBlock.OffsetOfFloatArgumentRegisters + _arm64IdxFPReg * 16;
                                _arm64IdxFPReg += cFPRegs;
                                return argOfsInner;
                            }
                            else
                            {
                                _arm64IdxFPReg = 8;
                            }
                        }
                        else
                        {
                            Debug.Assert(_transitionBlock.IsAppleArm64ABI || (cbArg % _transitionBlock.PointerSize) == 0);

                            int regSlots = ALIGN_UP(cbArg, _transitionBlock.PointerSize) / _transitionBlock.PointerSize;
                            // Only x0-x7 are valid argument registers (x8 is always the return buffer)
                            if (_arm64IdxGenReg + regSlots <= 8)
                            {
                                // The entirety of the arg fits in the register slots.
                                int argOfsInner = _transitionBlock.OffsetOfArgumentRegisters + _arm64IdxGenReg * 8;
                                _arm64IdxGenReg += regSlots;
                                return argOfsInner;
                            }
                            else if (_context.Target.IsWindows && IsVarArg && (_arm64IdxGenReg < 8))
                            {
                                // Address the Windows ARM64 varargs case where an arg is split between regs and stack.
                                // This can happen in the varargs case because the first 64 bytes of the stack are loaded
                                // into x0-x7, and any remaining stack arguments are placed normally.
                                int argOfsInner = _transitionBlock.OffsetOfArgumentRegisters + _arm64IdxGenReg * 8;

                                // Increase m_ofsStack to account for the space used for the remainder of the arg after
                                // registers are filled.
                                _arm64OfsStack += cbArg + (_arm64IdxGenReg - 8) * _transitionBlock.PointerSize;

                                // We used up the remaining reg slots.
                                _arm64IdxGenReg = 8;

                                return argOfsInner;
                            }
                            else
                            {
                                // Don't use reg slots for this. It will be passed purely on the stack arg space.
                                _arm64IdxGenReg = 8;
                            }
                        }

                        if (_transitionBlock.IsAppleArm64ABI)
                        {
                            int alignment;
                            if (!isValueType)
                            {
                                Debug.Assert((cbArg & (cbArg - 1)) == 0);
                                alignment = cbArg;
                            }
                            else if (isFloatHFA)
                            {
                                alignment = 4;
                            }
                            else
                            {
                                alignment = 8;
                            }
                            _arm64OfsStack = ALIGN_UP(_arm64OfsStack, alignment);
                        }

                        argOfs = _transitionBlock.OffsetOfArgs + _arm64OfsStack;
                        _arm64OfsStack += cbArg;
                        return argOfs;
                    }

                case TargetArchitecture.LoongArch64:
                    {
                        int cFPRegs = 0;
                        uint floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD;
                        _hasArgLocDescForStructInRegs = false;

                        switch (argType)
                        {
                            case CorElementType.ELEMENT_TYPE_R4:
                                // 32-bit floating point argument.
                                cFPRegs = 1;
                                break;

                            case CorElementType.ELEMENT_TYPE_R8:
                                // 64-bit floating point argument.
                                cFPRegs = 1;
                                break;

                            case CorElementType.ELEMENT_TYPE_VALUETYPE:
                                {
                                    // Composite greater than 16 bytes should be passed by reference
                                    if (argSize > _transitionBlock.EnregisteredParamTypeMaxSize)
                                    {
                                        argSize = _transitionBlock.PointerSize;
                                    }
                                    else
                                    {
                                        floatFieldFlags = LoongArch64PassStructInRegister.GetLoongArch64PassStructInRegisterFlags(_argTypeHandle.GetRuntimeTypeHandle());
                                        if ((floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_TWO) != 0)
                                        {
                                            cFPRegs = 2;
                                        }
                                        else if ((floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_HAS_FLOAT_FIELDS_MASK) != 0)
                                        {
                                            cFPRegs = 1;
                                        }
                                    }

                                    break;
                                }

                            default:
                                break;
                        }

                        bool isValueType = (argType == CorElementType.ELEMENT_TYPE_VALUETYPE);
                        int cbArg = _transitionBlock.StackElemSize(argSize, isValueType, false);

                        if (cFPRegs > 0 && !IsVarArg)
                        {
                            if (isValueType && ((floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_HAS_ONE_FLOAT_MASK) != 0))
                            {
                                Debug.Assert(cFPRegs == 1);
                                if ((_loongarch64IdxFPReg < 8) && (_loongarch64IdxGenReg < 8))
                                {
                                    _argLocDescForStructInRegs = new ArgLocDesc();
                                    _argLocDescForStructInRegs.m_idxFloatReg = _loongarch64IdxFPReg;
                                    _argLocDescForStructInRegs.m_cFloatReg = 1;

                                    _argLocDescForStructInRegs.m_idxGenReg = _loongarch64IdxGenReg;
                                    _argLocDescForStructInRegs.m_cGenReg = 1;

                                    _hasArgLocDescForStructInRegs = true;
                                    _argLocDescForStructInRegs.m_floatFlags = floatFieldFlags;

                                    int argOfsInner = 0;
                                    if ((floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_SECOND) != 0)
                                    {
                                        argOfsInner = _transitionBlock.OffsetOfArgumentRegisters + _loongarch64IdxGenReg * 8;
                                    }
                                    else
                                    {
                                        argOfsInner = _transitionBlock.OffsetOfFloatArgumentRegisters + _loongarch64IdxFPReg * 8;
                                    }

                                    _loongarch64IdxFPReg++;
                                    _loongarch64IdxGenReg++;
                                    return argOfsInner;
                                }
                            }
                            else if (cFPRegs + _loongarch64IdxFPReg <= 8)
                            {
                                // Each floating point register in the argument area is 8 bytes.
                                int argOfsInner = _transitionBlock.OffsetOfFloatArgumentRegisters + _loongarch64IdxFPReg * 8;
                                if (floatFieldFlags == (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_TWO)
                                {
                                    // struct with two single-float fields.
                                    _argLocDescForStructInRegs = new ArgLocDesc();
                                    _argLocDescForStructInRegs.m_idxFloatReg = _loongarch64IdxFPReg;
                                    _argLocDescForStructInRegs.m_cFloatReg = 2;
                                    Debug.Assert(cFPRegs == 2);
                                    Debug.Assert(argSize == 8);

                                    _hasArgLocDescForStructInRegs = true;
                                    _argLocDescForStructInRegs.m_floatFlags = (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_TWO;
                                }
                                _loongarch64IdxFPReg += cFPRegs;
                                return argOfsInner;
                            }
                            else
                            {
                                _loongarch64IdxFPReg = 8;
                            }
                        }

                        {
                            Debug.Assert((cbArg % _transitionBlock.PointerSize) == 0);

                            int regSlots = ALIGN_UP(cbArg, _transitionBlock.PointerSize) / _transitionBlock.PointerSize;
                            // Only R4-R11 are valid argument registers.
                            if (_loongarch64IdxGenReg + regSlots <= 8)
                            {
                                // The entirety of the arg fits in the register slots.
                                int argOfsInner = _transitionBlock.OffsetOfArgumentRegisters + _loongarch64IdxGenReg * 8;
                                _loongarch64IdxGenReg += regSlots;
                                return argOfsInner;
                            }
                            else if (_loongarch64IdxGenReg < 8)
                            {
                                int argOfsInner = _transitionBlock.OffsetOfArgumentRegisters + _loongarch64IdxGenReg * 8;
                                _loongarch64IdxGenReg = 8;
                                _loongarch64OfsStack += 8;
                                return argOfsInner;
                            }
                        }

                        argOfs = _transitionBlock.OffsetOfArgs + _loongarch64OfsStack;
                        _loongarch64OfsStack += cbArg;
                        return argOfs;
                    }

                case TargetArchitecture.RiscV64:
                    {
                        int cFPRegs = 0;
                        uint floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD;
                        _hasArgLocDescForStructInRegs = false;

                        switch (argType)
                        {
                            case CorElementType.ELEMENT_TYPE_R4:
                                // 32-bit floating point argument.
                                cFPRegs = 1;
                                break;

                            case CorElementType.ELEMENT_TYPE_R8:
                                // 64-bit floating point argument.
                                cFPRegs = 1;
                                break;

                            case CorElementType.ELEMENT_TYPE_VALUETYPE:
                                {
                                    // Composite greater than 16 bytes should be passed by reference
                                    if (argSize > _transitionBlock.EnregisteredParamTypeMaxSize)
                                    {
                                        argSize = _transitionBlock.PointerSize;
                                    }
                                    else
                                    {
                                        floatFieldFlags = RISCV64PassStructInRegister.GetRISCV64PassStructInRegisterFlags(_argTypeHandle.GetRuntimeTypeHandle());
                                        if ((floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_TWO) != 0)
                                        {
                                            cFPRegs = 2;
                                        }
                                        else if ((floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_HAS_FLOAT_FIELDS_MASK) != 0)
                                        {
                                            cFPRegs = 1;
                                        }
                                    }

                                    break;
                                }

                            default:
                                break;
                        }

                        bool isValueType = (argType == CorElementType.ELEMENT_TYPE_VALUETYPE);
                        int cbArg = _transitionBlock.StackElemSize(argSize, isValueType, false);

                        if (cFPRegs > 0 && !IsVarArg)
                        {
                            if (isValueType && ((floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_HAS_ONE_FLOAT_MASK) != 0))
                            {
                                Debug.Assert(cFPRegs == 1);
                                if ((_riscv64IdxFPReg < 8) && (_riscv64IdxGenReg < 8))
                                {
                                    _argLocDescForStructInRegs = new ArgLocDesc();
                                    _argLocDescForStructInRegs.m_idxFloatReg = _riscv64IdxFPReg;
                                    _argLocDescForStructInRegs.m_cFloatReg = 1;

                                    _argLocDescForStructInRegs.m_idxGenReg = _riscv64IdxGenReg;
                                    _argLocDescForStructInRegs.m_cGenReg = 1;

                                    _hasArgLocDescForStructInRegs = true;
                                    _argLocDescForStructInRegs.m_floatFlags = floatFieldFlags;

                                    int argOfsInner =
                                        ((floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_SECOND) != 0)
                                            ? _transitionBlock.OffsetOfArgumentRegisters + _riscv64IdxGenReg * 8
                                            : _transitionBlock.OffsetOfFloatArgumentRegisters + _riscv64IdxFPReg * 8;

                                    _riscv64IdxFPReg++;
                                    _riscv64IdxGenReg++;
                                    return argOfsInner;
                                }
                            }
                            else if (cFPRegs + _riscv64IdxFPReg <= 8)
                            {
                                // Each floating point register in the argument area is 8 bytes.
                                int argOfsInner = _transitionBlock.OffsetOfFloatArgumentRegisters + _riscv64IdxFPReg * 8;
                                if (floatFieldFlags == (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_TWO)
                                {
                                    // struct with two single-float fields.
                                    _argLocDescForStructInRegs = new ArgLocDesc();
                                    _argLocDescForStructInRegs.m_idxFloatReg = _riscv64IdxFPReg;
                                    _argLocDescForStructInRegs.m_cFloatReg = 2;
                                    Debug.Assert(cFPRegs == 2);
                                    Debug.Assert(argSize == 8);

                                    _hasArgLocDescForStructInRegs = true;
                                    _argLocDescForStructInRegs.m_floatFlags = (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_TWO;
                                }
                                _riscv64IdxFPReg += cFPRegs;
                                return argOfsInner;
                            }
                            else
                            {
                                _riscv64IdxFPReg = 8;
                            }
                        }

                        {
                            Debug.Assert((cbArg % _transitionBlock.PointerSize) == 0);

                            int regSlots = ALIGN_UP(cbArg, _transitionBlock.PointerSize) / _transitionBlock.PointerSize;
                            // Only a0-a7 are valid argument registers.
                            if (_riscv64IdxGenReg + regSlots <= 8)
                            {
                                // The entirety of the arg fits in the register slots.
                                int argOfsInner = _transitionBlock.OffsetOfArgumentRegisters + _riscv64IdxGenReg * 8;
                                _riscv64IdxGenReg += regSlots;
                                return argOfsInner;
                            }
                            else if (_riscv64IdxGenReg < 8)
                            {
                                int argOfsInner = _transitionBlock.OffsetOfArgumentRegisters + _riscv64IdxGenReg * 8;
                                _riscv64IdxGenReg = 8;
                                _riscv64OfsStack += 8;
                                return argOfsInner;
                            }
                        }

                        argOfs = _transitionBlock.OffsetOfArgs + _riscv64OfsStack;
                        _riscv64OfsStack += cbArg;
                        return argOfs;
                    }

                default:
                    throw new NotImplementedException();
            }
        }