/// <summary>
        /// Requests the calling convention to create an appropriate move instruction to populate the return
        /// value of a method.
        /// </summary>
        /// <param name="compiler">The compiler.</param>
        /// <param name="typeLayout">The type layouts.</param>
        /// <param name="context">The context.</param>
        /// <param name="operand">The operand, that's holding the return value.</param>
        public override void SetReturnValue(BaseMethodCompiler compiler, MosaTypeLayout typeLayout, Context context, Operand operand)
        {
            int size, alignment;

            architecture.GetTypeRequirements(typeLayout, operand.Type, out size, out alignment);
            size = Alignment.AlignUp(size, alignment);

            if (operand.IsR4)
            {
                architecture.InsertMoveInstruction(context, Operand.CreateCPURegister(operand.Type, returnFloatingPointRegister), operand);
            }
            else if (operand.IsR8)
            {
                architecture.InsertMoveInstruction(context, Operand.CreateCPURegister(operand.Type, returnFloatingPointRegister), operand);
            }
            else if (operand.IsLong)
            {
                MosaType highType = (operand.IsI8) ? typeLayout.TypeSystem.BuiltIn.I4 : typeLayout.TypeSystem.BuiltIn.U4;

                architecture.InsertMoveInstruction(context, Operand.CreateCPURegister(typeLayout.TypeSystem.BuiltIn.U4, return32BitRegister), operand.Low);
                architecture.InsertMoveInstruction(context, Operand.CreateCPURegister(highType, return64BitRegister), operand.High);
            }
            else if (size == 4 || size == 2 || size == 1)
            {
                architecture.InsertMoveInstruction(context, Operand.CreateCPURegister(operand.Type, return32BitRegister), operand);
            }
            else if (typeLayout.IsCompoundType(operand.Type))
            {
                Operand stackBaseReg = Operand.CreateCPURegister(typeLayout.TypeSystem.BuiltIn.Pointer, architecture.StackFrameRegister);
                architecture.InsertCompoundMoveInstruction(compiler, context, Operand.CreateMemoryAddress(operand.Type, stackBaseReg, OffsetOfFirstParameter), operand, size);
            }
        }
        /// <summary>
        /// Cleanups the return value.
        /// </summary>
        /// <param name="compiler">The compiler.</param>
        /// <param name="typeLayout">The type layouts.</param>
        /// <param name="context">The context.</param>
        /// <param name="result">The result.</param>
        private void CleanupReturnValue(BaseMethodCompiler compiler, MosaTypeLayout typeLayout, Context context, Operand result)
        {
            if (result == null)
            {
                return;
            }

            if (result.IsR)
            {
                Operand returnFP = Operand.CreateCPURegister(result.Type, returnFloatingPointRegister);
                context.AppendInstruction(IRInstruction.Gen, returnFP);
                architecture.InsertMoveInstruction(context, result, returnFP);
            }
            else if (result.Is64BitInteger)
            {
                Operand returnLow  = Operand.CreateCPURegister(result.Type, return32BitRegister);
                Operand returnHigh = Operand.CreateCPURegister(typeLayout.TypeSystem.BuiltIn.U4, return64BitRegister);
                context.AppendInstruction(IRInstruction.Gen, returnLow);
                context.AppendInstruction(IRInstruction.Gen, returnHigh);
                architecture.InsertMoveInstruction(context, result.Low, returnLow);
                architecture.InsertMoveInstruction(context, result.High, returnHigh);
            }
            else if (typeLayout.IsCompoundType(result.Type))
            {
                int     size            = typeLayout.GetTypeSize(result.Type);
                Operand stackPointerReg = Operand.CreateCPURegister(typeLayout.TypeSystem.BuiltIn.Pointer, architecture.StackPointerRegister);
                architecture.InsertCompoundMoveInstruction(compiler, context, result, Operand.CreateMemoryAddress(result.Type, stackPointerReg, 0), size);
            }
            else
            {
                Operand returnLow = Operand.CreateCPURegister(result.Type, return32BitRegister);
                context.AppendInstruction(IRInstruction.Gen, returnLow);
                architecture.InsertMoveInstruction(context, result, returnLow);
            }
        }
 /// <summary>
 /// Pushes the specified instructions.
 /// </summary>
 /// <param name="compiler">The compiler.</param>
 /// <param name="typeLayout">The type layout.</param>
 /// <param name="context">The context.</param>
 /// <param name="op">The op.</param>
 /// <param name="stackSize">Size of the stack.</param>
 /// <param name="parameterSize">Size of the parameter.</param>
 /// <param name="scratch">The scratch.</param>
 private void Push(BaseMethodCompiler compiler, MosaTypeLayout typeLayout, Context context, Operand op, int stackSize, int parameterSize, Operand scratch)
 {
     if (op.Is64BitInteger)
     {
         architecture.InsertMoveInstruction(context, Operand.CreateMemoryAddress(typeLayout.TypeSystem.BuiltIn.I4, scratch, stackSize), op.Low);
         architecture.InsertMoveInstruction(context, Operand.CreateMemoryAddress(typeLayout.TypeSystem.BuiltIn.I4, scratch, stackSize + 4), op.High);
     }
     else if (op.IsR)
     {
         if (op.IsR8 && parameterSize == 4)
         {
             Operand op2 = Operand.CreateCPURegister(typeLayout.TypeSystem.BuiltIn.R4, returnFloatingPointRegister);
             architecture.InsertMoveInstruction(context, op2, op);
             architecture.InsertMoveInstruction(context, Operand.CreateMemoryAddress(scratch.Type, scratch, stackSize), op2);
         }
         else
         {
             architecture.InsertMoveInstruction(context, Operand.CreateMemoryAddress(scratch.Type, scratch, stackSize), op);
         }
     }
     else if (typeLayout.IsCompoundType(op.Type))
     {
         architecture.InsertCompoundMoveInstruction(compiler, context, Operand.CreateMemoryAddress(op.Type, scratch, stackSize), op, typeLayout.GetTypeSize(op.Type));
     }
     else
     {
         architecture.InsertMoveInstruction(context, Operand.CreateMemoryAddress(op.Type, scratch, stackSize), op);
     }
 }
        private static int CalculateReturnSize(MosaTypeLayout typeLayout, MosaMethod method)
        {
            if (typeLayout.IsCompoundType(method.Signature.ReturnType))
            {
                return(typeLayout.GetTypeSize(method.Signature.ReturnType));
            }

            return(0);
        }
        private static int CalculateReturnSize(MosaTypeLayout typeLayout, Operand result)
        {
            if (result == null)
            {
                return(0);
            }

            if (typeLayout.IsCompoundType(result.Type))
            {
                return(typeLayout.GetTypeSize(result.Type));
            }

            return(0);
        }
Beispiel #6
0
        /// <summary>
        /// Expands method call instruction represented by the context to perform the method call.
        /// </summary>
        /// <param name="typeLayout">The type layouts.</param>
        /// <param name="context">The context.</param>
        public override void MakeCall(BaseMethodCompiler compiler, MosaTypeLayout typeLayout, Context context)
        {
            /*
             * Calling convention is right-to-left, pushed on the stack. Return value in EAX for integral
             * types 4 bytes or less, XMM0 for floating point and EAX:EDX for 64-bit. If this is a method
             * of a type, the this argument is moved to ECX right before the call.
             * If return value is value type, a stack local is allocated as a hidden parameter in caller
             * stack, the callee will then store the return value in the allocated space
             * The return value is the first parameter (even before this)
             * The callee will place the address of the return value into EAX and the caller will then
             * either retrieve the return value using compound move or will let one of the callers higher
             * in the caller chain handle the retrieval of the return value using compound move.
             */

            Operand    target = context.Operand1;
            Operand    result = context.Result;
            MosaMethod method = context.InvokeMethod;

            Debug.Assert(method != null, context.ToString());

            Operand scratch = Operand.CreateCPURegister(typeLayout.TypeSystem.BuiltIn.Pointer, scratchRegister);

            List <Operand> operands = BuildOperands(context);

            int stackSize = CalculateStackSizeForParameters(typeLayout, architecture, operands, method);

            context.Empty();

            int returnSize = 0;

            if (typeLayout.IsCompoundType(method.Signature.ReturnType))
            {
                returnSize = typeLayout.GetTypeSize(method.Signature.ReturnType);
            }

            if (stackSize != 0 || returnSize != 0)
            {
                ReserveStackSizeForCall(typeLayout.TypeSystem, context, returnSize + stackSize, scratch);
                PushOperands(compiler, typeLayout, context, method, operands, returnSize + stackSize, scratch);
            }

            // the mov/call two-instructions combo is to help facilitate the register allocator
            architecture.InsertMoveInstruction(context, scratch, target);
            architecture.InsertCallInstruction(context, scratch);

            CleanupReturnValue(compiler, typeLayout, context, result);
            FreeStackAfterCall(typeLayout.TypeSystem, context, returnSize + stackSize);
        }
 /// <summary>
 /// Gets the type memory requirements.
 /// </summary>
 /// <param name="typeLayout">The type layouts.</param>
 /// <param name="type">The signature type.</param>
 /// <param name="size">Receives the memory size of the type.</param>
 /// <param name="alignment">Receives alignment requirements of the type.</param>
 public override void GetTypeRequirements(MosaTypeLayout typeLayout, MosaType type, out int size, out int alignment)
 {
     if (type.IsUI8 || type.IsR8 || !type.IsValueType || type.IsPointer)
     {
         size      = 8;
         alignment = 8;
     }
     else if (typeLayout.IsCompoundType(type))
     {
         size      = typeLayout.GetTypeSize(type);
         alignment = 8;
     }
     else
     {
         size      = 4;
         alignment = 4;
     }
 }
        /// <summary>
        /// Expands method call instruction represented by the context to perform the method call.
        /// </summary>
        /// <param name="typeLayout">The type layouts.</param>
        /// <param name="context">The context.</param>
        public override void MakeCall(BaseMethodCompiler compiler, MosaTypeLayout typeLayout, Context context)
        {
            /*
             * Calling convention is right-to-left, pushed on the stack. Return value in EAX for integral
             * types 4 bytes or less, XMM0 for floating point and EAX:EDX for 64-bit. If this is a method
             * of a type, the this argument is moved to ECX right before the call.
             * If return value is value type, a stack local is allocated as a hidden parameter in caller
             * stack, the callee will then store the return value in the allocated space
             * The return value is the first parameter (even before this)
             * The callee will place the address of the return value into EAX and the caller will then
             * either retrieve the return value using compound move or will let one of the callers higher
             * in the caller chain handle the retrieval of the return value using compound move.
             */

            Operand target = context.Operand1;
            Operand result = context.Result;
            MosaMethod method = context.InvokeMethod;

            Debug.Assert(method != null, context.ToString());

            Operand scratch = Operand.CreateCPURegister(typeLayout.TypeSystem.BuiltIn.Pointer, scratchRegister);

            List<Operand> operands = BuildOperands(context);

            int stackSize = CalculateStackSizeForParameters(typeLayout, architecture, operands, method);

            context.Empty();

            int returnSize = 0;
            if (typeLayout.IsCompoundType(method.Signature.ReturnType))
            {
                returnSize = typeLayout.GetTypeSize(method.Signature.ReturnType);
            }

            if (stackSize != 0 || returnSize != 0)
            {
                ReserveStackSizeForCall(typeLayout.TypeSystem, context, returnSize + stackSize, scratch);
                PushOperands(compiler, typeLayout, context, method, operands, returnSize + stackSize, scratch);
            }

            // the mov/call two-instructions combo is to help facilitate the register allocator
            architecture.InsertMoveInstruction(context, scratch, target);
            architecture.InsertCallInstruction(context, scratch);

            CleanupReturnValue(compiler, typeLayout, context, result);
            FreeStackAfterCall(typeLayout.TypeSystem, context, returnSize + stackSize);
        }
 /// <summary>
 /// Pushes the specified instructions.
 /// </summary>
 /// <param name="compiler">The compiler.</param>
 /// <param name="typeLayout">The type layout.</param>
 /// <param name="context">The context.</param>
 /// <param name="op">The op.</param>
 /// <param name="stackSize">Size of the stack.</param>
 /// <param name="parameterSize">Size of the parameter.</param>
 /// <param name="scratch">The scratch.</param>
 private void Push(BaseMethodCompiler compiler, MosaTypeLayout typeLayout, Context context, Operand op, int stackSize, int parameterSize, Operand scratch)
 {
     if (op.Is64BitInteger)
     {
         architecture.InsertMoveInstruction(context, Operand.CreateMemoryAddress(typeLayout.TypeSystem.BuiltIn.I4, scratch, stackSize), op.Low);
         architecture.InsertMoveInstruction(context, Operand.CreateMemoryAddress(typeLayout.TypeSystem.BuiltIn.I4, scratch, stackSize + 4), op.High);
     }
     else if (op.IsR)
     {
         if (op.IsR8 && parameterSize == 4)
         {
             Operand op2 = Operand.CreateCPURegister(typeLayout.TypeSystem.BuiltIn.R4, returnFloatingPointRegister);
             architecture.InsertMoveInstruction(context, op2, op);
             architecture.InsertMoveInstruction(context, Operand.CreateMemoryAddress(scratch.Type, scratch, stackSize), op2);
         }
         else
         {
             architecture.InsertMoveInstruction(context, Operand.CreateMemoryAddress(scratch.Type, scratch, stackSize), op);
         }
     }
     else if (typeLayout.IsCompoundType(op.Type))
     {
         architecture.InsertCompoundMoveInstruction(compiler, context, Operand.CreateMemoryAddress(op.Type, scratch, stackSize), op, typeLayout.GetTypeSize(op.Type));
     }
     else
     {
         architecture.InsertMoveInstruction(context, Operand.CreateMemoryAddress(op.Type, scratch, stackSize), op);
     }
 }
        /// <summary>
        /// Cleanups the return value.
        /// </summary>
        /// <param name="compiler">The compiler.</param>
        /// <param name="typeLayout">The type layouts.</param>
        /// <param name="context">The context.</param>
        /// <param name="result">The result.</param>
        private void CleanupReturnValue(BaseMethodCompiler compiler, MosaTypeLayout typeLayout, Context context, Operand result)
        {
            if (result == null)
                return;

            if (result.IsR)
            {
                Operand returnFP = Operand.CreateCPURegister(result.Type, returnFloatingPointRegister);
                context.AppendInstruction(IRInstruction.Gen, returnFP);
                architecture.InsertMoveInstruction(context, result, returnFP);
            }
            else if (result.Is64BitInteger)
            {
                Operand returnLow = Operand.CreateCPURegister(result.Type, return32BitRegister);
                Operand returnHigh = Operand.CreateCPURegister(typeLayout.TypeSystem.BuiltIn.U4, return64BitRegister);
                context.AppendInstruction(IRInstruction.Gen, returnLow);
                context.AppendInstruction(IRInstruction.Gen, returnHigh);
                architecture.InsertMoveInstruction(context, result.Low, returnLow);
                architecture.InsertMoveInstruction(context, result.High, returnHigh);
            }
            else if (typeLayout.IsCompoundType(result.Type))
            {
                int size = typeLayout.GetTypeSize(result.Type);
                Operand returnLow = Operand.CreateCPURegister(typeLayout.TypeSystem.BuiltIn.Pointer, return32BitRegister);
                context.AppendInstruction(IRInstruction.Gen, returnLow);
                architecture.InsertCompoundMoveInstruction(compiler, context, result, Operand.CreateMemoryAddress(result.Type, returnLow, 0), size);
            }
            else
            {
                Operand returnLow = Operand.CreateCPURegister(result.Type, return32BitRegister);
                context.AppendInstruction(IRInstruction.Gen, returnLow);
                architecture.InsertMoveInstruction(context, result, returnLow);
            }
        }
        /// <summary>
        /// Requests the calling convention to create an appropriate move instruction to populate the return
        /// value of a method.
        /// </summary>
        /// <param name="compiler">The compiler.</param>
        /// <param name="typeLayout">The type layouts.</param>
        /// <param name="context">The context.</param>
        /// <param name="operand">The operand, that's holding the return value.</param>
        public override void SetReturnValue(BaseMethodCompiler compiler, MosaTypeLayout typeLayout, Context context, Operand operand)
        {
            int size, alignment;
            architecture.GetTypeRequirements(typeLayout, operand.Type, out size, out alignment);
            size = Alignment.AlignUp(size, alignment);

            if (operand.IsR4)
            {
                architecture.InsertMoveInstruction(context, Operand.CreateCPURegister(operand.Type, returnFloatingPointRegister), operand);
            }
            else if (operand.IsR8)
            {
                architecture.InsertMoveInstruction(context, Operand.CreateCPURegister(operand.Type, returnFloatingPointRegister), operand);
            }
            else if (operand.IsLong)
            {
                MosaType highType = (operand.IsI8) ? typeLayout.TypeSystem.BuiltIn.I4 : typeLayout.TypeSystem.BuiltIn.U4;

                architecture.InsertMoveInstruction(context, Operand.CreateCPURegister(typeLayout.TypeSystem.BuiltIn.U4, return32BitRegister), operand.Low);
                architecture.InsertMoveInstruction(context, Operand.CreateCPURegister(highType, return64BitRegister), operand.High);
            }
            else if (size == 4 || size == 2 || size == 1)
            {
                architecture.InsertMoveInstruction(context, Operand.CreateCPURegister(operand.Type, return32BitRegister), operand);
            }
            else if (typeLayout.IsCompoundType(operand.Type))
            {
                architecture.InsertAddressOfInstruction(context, Operand.CreateCPURegister(operand.Type, return32BitRegister), operand);
            }
        }
        private static int CalculateReturnSize(MosaTypeLayout typeLayout, Operand result)
        {
            if (result == null)
                return 0;

            if (typeLayout.IsCompoundType(result.Type))
            {
                return typeLayout.GetTypeSize(result.Type);
            }

            return 0;
        }
        /// <summary>
        /// Requests the calling convention to create an appropriate move instruction to populate the return
        /// value of a method.
        /// </summary>
        /// <param name="typeLayout">The type layouts.</param>
        /// <param name="context">The context.</param>
        /// <param name="operand">The operand, that's holding the return value.</param>
        public override void SetReturnValue(MosaTypeLayout typeLayout, Context context, Operand operand)
        {
            int size, alignment;
            architecture.GetTypeRequirements(typeLayout, operand.Type, out size, out alignment);

            if (size == 4 || size == 2 || size == 1)
            {
                architecture.InsertMoveInstruction(context, Operand.CreateCPURegister(operand.Type, return32BitRegister), operand);
            }
            else if (operand.IsR4)
            {
                architecture.InsertMoveInstruction(context, Operand.CreateCPURegister(operand.Type, returnFloatingPointRegister), operand);
            }
            else if (operand.IsR8)
            {
                architecture.InsertMoveInstruction(context, Operand.CreateCPURegister(operand.Type, returnFloatingPointRegister), operand);
            }
            else if (operand.IsLong)
            {
                MosaType highType = (operand.IsI8) ? typeLayout.TypeSystem.BuiltIn.I4 : typeLayout.TypeSystem.BuiltIn.U4;

                architecture.InsertMoveInstruction(context, Operand.CreateCPURegister(typeLayout.TypeSystem.BuiltIn.U4, return32BitRegister), operand.Low);
                architecture.InsertMoveInstruction(context, Operand.CreateCPURegister(highType, return64BitRegister), operand.High);
            }
            else if (typeLayout.IsCompoundType(operand.Type))
            {
                Operand stackBaseReg = Operand.CreateCPURegister(typeLayout.TypeSystem.BuiltIn.Pointer, architecture.StackFrameRegister);
                architecture.InsertCompoundMoveInstruction(context, Operand.CreateMemoryAddress(operand.Type, stackBaseReg, 8), operand, size);
            }
        }
        private static int CalculateReturnSize(MosaTypeLayout typeLayout, MosaMethod method)
        {
            if (typeLayout.IsCompoundType(method.Signature.ReturnType))
            {
                return typeLayout.GetTypeSize(method.Signature.ReturnType);
            }

            return 0;
        }