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); }
/// <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 }); }