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