Пример #1
0
        private static X64StorageLocation GetFunctionReturnLocation(DataType returnType)
        {
            //ENUM is missing here because it is converted to int in previous step

            if (returnType.Group == DataTypeGroup.ScalarInteger)
            {
                return(X64StorageLocation.AsRegister(X64Register.GroupToSpecificRegister(X64RegisterGroup.A, returnType)));
            }
            else if (returnType.Kind == DataTypeKind.POINTER || returnType.Kind == DataTypeKind.ARRAY)
            {
                return(X64StorageLocation.AsRegister(X64Register.RAX));
            }
            else if (returnType.Kind == DataTypeKind.BOOL)
            {
                return(X64StorageLocation.AsRegister(X64DataTypeProperties.GetProperties(returnType.Kind).Accumulator));
            }
            else if (returnType.Group == DataTypeGroup.ScalarFloat)
            {
                return(X64StorageLocation.AsRegister(X64Register.XMM0));
            }
            else if (returnType.Kind == DataTypeKind.VEC4F || returnType.Kind == DataTypeKind.VEC2D)
            {
                return(X64StorageLocation.AsRegister(X64Register.XMM0));
            }
            else if (returnType.Kind == DataTypeKind.VEC8F || returnType.Kind == DataTypeKind.VEC4D)
            {
                return(X64StorageLocation.AsRegister(X64Register.YMM0));
            }
            else if (returnType.Kind != DataTypeKind.VOID)
            {
                throw new Exception("Unknown function return type: " + returnType);
            }

            return(null);
        }
Пример #2
0
        /// <summary>
        /// Get storage locations for parameter of given function.
        /// </summary>
        /// <param name="function">The function.</param>
        /// <returns>List of locations in the order of the parameters.</returns>
        public X64ParameterFrame GetParameterFrame(List <DataType> parameterTypes)
        {
            //TODO: Variadic functions have a special parameter passing convention. See MS x64 calling convention docs.

            var locations = new List <X64StorageLocation>();

            const long alignment   = 8;
            long       paramOffset = 0;

            for (int p = 0; p < parameterTypes.Count; p++)
            {
                var paramType = parameterTypes[p];

                switch (paramType.Kind)
                {
                case DataTypeKind.I8:
                case DataTypeKind.I16:
                case DataTypeKind.I32:
                case DataTypeKind.I64:
                case DataTypeKind.U8:
                case DataTypeKind.U16:
                case DataTypeKind.U32:
                case DataTypeKind.U64:
                case DataTypeKind.BOOL:
                case DataTypeKind.POINTER:
                case DataTypeKind.ARRAY:
                case DataTypeKind.CHAR8:
                case DataTypeKind.STRING8:
                    if (p < _generalPurposeParameterRegisters.Length)
                    {
                        var group = _generalPurposeParameterRegisters[p];
                        locations.Add(X64StorageLocation.AsRegister(X64Register.GroupToSpecificRegister(group, paramType)));
                    }
                    else
                    {
                        locations.Add(X64StorageLocation.StackFromBase(-paramOffset));
                        //Parameter value on stack must be 8 byte aligned
                        paramOffset += (paramType.ByteSize & -alignment) + alignment;
                    }
                    break;

                case DataTypeKind.F32:
                case DataTypeKind.F64:
                    if (p < _floatVectorParameterRegisters.Length)
                    {
                        var group = _floatVectorParameterRegisters[p];
                        locations.Add(X64StorageLocation.AsRegister(X64Register.GroupToSpecificRegister(group, paramType)));
                    }
                    else
                    {
                        locations.Add(X64StorageLocation.StackFromBase(-paramOffset));
                        //Parameter value on stck must be 8 byte aligned
                        paramOffset += (paramType.ByteSize & -alignment) + alignment;
                    }
                    break;

                case DataTypeKind.VEC4F:
                case DataTypeKind.VEC8F:
                case DataTypeKind.VEC2D:
                case DataTypeKind.VEC4D:
                    //This differs from Win64 calling convention. The registers are there, why not use them?
                    //TODO: Use correct Win64 calling convetion for external functions!
                    if (p < _floatVectorParameterRegisters.Length)
                    {
                        var group = _floatVectorParameterRegisters[p];
                        locations.Add(X64StorageLocation.AsRegister(X64Register.GroupToSpecificRegister(group, paramType)));
                    }
                    else
                    {
                        locations.Add(X64StorageLocation.StackFromBase(-paramOffset));
                        //No alignment required here, as the vectors are already either 16 or 32 byte, which are multiples of 8
                        paramOffset += paramType.ByteSize;
                    }
                    break;

                default:
                    throw new Exception("Unknown/invalid parameter data type: " + paramType);
                }
            }

            var paramStackSize = paramOffset;

            //Reverse stack offsets as they are addressed from RSP, not RBP
            for (int i = locations.Count - 1; i >= 0; i--)
            {
                var location = locations[i];
                if (location.Kind == X64StorageLocationKind.StackFromBase)
                {
                    locations[i] = X64StorageLocation.StackFromTop(paramStackSize + location.Offset);
                }
            }

            //We always need the shadow space for the first four register parameters, so add it here to the total parameter stack size.
            //The offsets of the parameters calculated above are still correct, because the shadow space is before those!
            var stackSize = paramStackSize + 32;

            return(new X64ParameterFrame
            {
                ParameterLocations = locations,
                ParameterStackSize = stackSize
            });
        }