Esempio n. 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);
        }
Esempio n. 2
0
        public static void Move(List <string> output, DataType dataType, X64StorageLocation targetLocation, X64StorageLocation sourceLocation, bool includeOperandSize)
        {
            if (targetLocation.Equals(sourceLocation))
            {
                return;
            }

            var x64DataType = X64DataTypeProperties.GetProperties(dataType.Kind);

            //Values on stack are not aligned, so we need to distinguish
            X64Instruction instruction;

            if (sourceLocation.IsMemory || targetLocation.IsMemory)
            {
                instruction = x64DataType.MoveInstructionUnaligned;
            }
            else
            {
                instruction = x64DataType.MoveInstructionAligned;
            }

            var targetLocStr = targetLocation.ToCode();
            var sourceLocStr = sourceLocation.ToCode();

            if (includeOperandSize)
            {
                if (targetLocation.IsMemory)
                {
                    targetLocStr = x64DataType.OperandSize + " " + targetLocStr;
                }
                if (sourceLocation.IsMemory)
                {
                    sourceLocStr = x64DataType.OperandSize + " " + sourceLocStr;
                }
            }

            if (sourceLocation.IsMemory && targetLocation.IsMemory)
            {
                //Cannot directly move between two memory locations, need to use accumulator register as temp location and do it in two steps
                var accLocation = X64StorageLocation.AsRegister(x64DataType.Accumulator);
                output.Add(X64CodeFormat.FormatOperation(instruction, accLocation.ToCode(), sourceLocStr));
                output.Add(X64CodeFormat.FormatOperation(instruction, targetLocStr, accLocation.ToCode()));
            }
            else
            {
                output.Add(X64CodeFormat.FormatOperation(instruction, targetLocStr, sourceLocStr));
            }
        }
Esempio n. 3
0
        public X64FunctionFrame CreateFunctionScope(IMFunction function)
        {
            var registerPool = new X64RegisterPool();
            var locationMap  = new Dictionary <string, X64StorageLocation>();

            //First the parameters
            var paramFrame = GetParameterFrame(function.Definition);
            var paramIndex = 1;

            foreach (var location in paramFrame.ParameterLocations)
            {
                var name         = IMOperand.ParameterPrefix + paramIndex;
                var realLocation = location;

                //If parameter is on stack, calculate correct offset (+16, 8 saved RBP + 8 return address)
                if (realLocation.Kind == X64StorageLocationKind.StackFromTop)
                {
                    realLocation = X64StorageLocation.StackFromBase(location.Offset + 16);
                }

                locationMap.Add(name, realLocation);

                if (realLocation.Kind == X64StorageLocationKind.Register)
                {
                    registerPool.Use(realLocation.Register);
                }

                paramIndex += 1;
            }

            //If return value is stored in register, make sure it is reserved
            var returnLocation = GetFunctionReturnLocation(function.Definition);

            if (returnLocation != null)
            {
                if (returnLocation.Kind == X64StorageLocationKind.Register)
                {
                    registerPool.Use(returnLocation.Register);
                }
            }

            //Gather list of operands that are referenced with LEA instruction. Those cannot be in registers.
            var referencedOperands = new HashSet <string>();

            foreach (var operation in function.Body)
            {
                if (operation.Instruction.Kind == IMInstructionKind.LEA)
                {
                    var source = operation.Operands[1];
                    referencedOperands.Add(source.FullName);
                }
            }

            //Now the local variables. Intentionally do no look into sub-values. These must be "defined" before already.
            var usedNonVolatileRegisters = new HashSet <X64RegisterGroup>();
            var usesDynamicStack         = false;
            var stackOffset = 0L;

            foreach (var operation in function.Body)
            {
                if (operation.Instruction.Kind == IMInstructionKind.FREE)
                {
                    var operand  = operation.Operands[0];
                    var location = locationMap[operand.FullName];
                    if (location.Kind == X64StorageLocationKind.Register)
                    {
                        registerPool.Free(location.Register);
                    }
                }
                else
                {
                    foreach (var operand in operation.Operands)
                    {
                        if (operand != null && !locationMap.ContainsKey(operand.FullName))
                        {
                            if (operand.Kind == IMOperandKind.Local)
                            {
                                X64Register register = null;
                                if (!referencedOperands.Contains(operand.FullName))
                                {
                                    //"Take" returns null if no register available or data type cannot be stored in register (structures)
                                    register = registerPool.Take(operand.DataType);
                                }

                                X64StorageLocation location = null;

                                if (register != null)
                                {
                                    location = X64StorageLocation.AsRegister(register);
                                    if (!register.IsVolatile)
                                    {
                                        usedNonVolatileRegisters.Add(register.Group);
                                    }
                                }
                                else
                                {
                                    //If no register, use stack
                                    stackOffset += operand.DataType.ByteSize;
                                    location     = X64StorageLocation.StackFromBase(-stackOffset);
                                }

                                Assert.True(location != null, "No location found for operand!");
                                locationMap.Add(operand.FullName, location);
                            }
                            else if (operand.Kind == IMOperandKind.Reference)
                            {
                                var addressLocation = locationMap[operand.ChildValue.FullName];
                                Assert.True(addressLocation.Kind == X64StorageLocationKind.Register, "Address location for reference operand must be in register!");
                                locationMap.Add(operand.FullName, X64StorageLocation.HeapInRegister(addressLocation.Register, 0));
                            }
                        }
                    }
                }

                //Reserve space for static stack allocation (size known at compile time)
                if (operation.Instruction.Kind == IMInstructionKind.SALOC)
                {
                    var target      = operation.Operands[0];
                    var sizeOperand = operation.Operands[1];
                    if (sizeOperand.Kind == IMOperandKind.Immediate)
                    {
                        var numBytes = (long)sizeOperand.ImmediateValue;

                        //Increment stack offset first so target points to bottom of reserved memory.
                        stackOffset += numBytes;
                        var arrayLocation = X64StorageLocation.StackFromBase(-stackOffset);

                        locationMap.Add(IMOperand.GetMemLocationName(target), arrayLocation);
                    }
                    else
                    {
                        usesDynamicStack = true;
                    }
                }
            }

            //Data Section (immediates)
            var dataEntries = new List <Tuple <DataType, string> >();

            foreach (var operation in function.Body)
            {
                //Vector constructor with all immediate values are handled specifically by native code generator, so skip them here
                if (operation.Instruction.Kind == IMInstructionKind.GVEC)
                {
                    var values = operation.Operands.GetRange(1, operation.Operands.Count - 1);
                    if (values.TrueForAll((v) => v.Kind == IMOperandKind.Immediate))
                    {
                        continue;
                    }
                }

                foreach (var operand in operation.Operands)
                {
                    if (operand != null && !locationMap.ContainsKey(operand.FullName))
                    {
                        if (operand.Kind == IMOperandKind.Immediate)
                        {
                            var elementType    = operand.DataType;
                            var x64ElementType = X64DataTypeProperties.GetProperties(elementType.Kind);
                            var valStr         = x64ElementType.ImmediateValueToAsmCode(operand);

                            _immediateCounter += 1;
                            var immediateName = "imm_" + _immediateCounter;

                            var x64DataType = X64DataTypeProperties.GetProperties(operand.DataType.Kind);
                            var entry       = immediateName + " " + x64DataType.ImmediateSize + " " + valStr;

                            dataEntries.Add(new Tuple <DataType, string>(operand.DataType, entry));
                            locationMap.Add(operand.FullName, X64StorageLocation.DataSection(immediateName));
                        }
                    }
                }
            }

            //If stack is used, make sure size is multiple of 8
            if (stackOffset > 0)
            {
                stackOffset = ((stackOffset / 8) + 1) * 8;
            }

            return(new X64FunctionFrame()
            {
                LocalsLocations = locationMap,
                LocalsStackFrameSize = stackOffset,
                ParameterStackFrameSize = paramFrame.ParameterStackSize,
                DataEntries = dataEntries,
                ReturnLocation = returnLocation,
                UsesDynamicStackAllocation = usesDynamicStack,
                UsedNonVolatileRegisters = usedNonVolatileRegisters
            });
        }