/// <summary> /// Requests the calling convention to create an appropriate move instruction to populate the return /// value of a method. /// </summary> /// <param name="ctx">The context.</param> /// <param name="operand">The operand, that's holding the return value.</param> void ICallingConvention.MoveReturnValue(Context ctx, Operand operand) { int size, alignment; _architecture.GetTypeRequirements(operand.Type, out size, out alignment); // FIXME: Do not issue a move, if the operand is already the destination register if (4 == size || 2 == size || 1 == size) { ctx.SetInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(operand.Type, GeneralPurposeRegister.EAX), operand); return; } if (8 == size && (operand.Type.Type == CilElementType.R4 || operand.Type.Type == CilElementType.R8)) { ctx.SetInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(operand.Type, SSE2Register.XMM0), operand); return; } if (8 == size && (operand.Type.Type == CilElementType.I8 || operand.Type.Type == CilElementType.U8)) { SigType I4 = new SigType(CilElementType.I4); SigType U4 = new SigType(CilElementType.U4); Operand opL, opH; LongOperandTransformationStage.SplitLongOperand(operand, out opL, out opH); // Like Win32: EDX:EAX ctx.SetInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(U4, GeneralPurposeRegister.EAX), opL); ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(I4, GeneralPurposeRegister.EDX), opH); return; } throw new NotSupportedException(); }
/// <summary> /// Replaces the intrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> void IIntrinsicPlatformMethod.ReplaceIntrinsicCall(Context context, BaseMethodCompiler methodCompiler) { Operand n = context.Operand1; Operand d = context.Operand2; Operand result = context.Result; Operand result2 = methodCompiler.CreateVirtualRegister(methodCompiler.TypeSystem.BuiltIn.U4); Operand op0L, op0H; LongOperandTransformationStage.SplitLongOperand(methodCompiler, n, out op0L, out op0H, null); context.SetInstruction2(X86.Div, result2, result, op0H, op0L, d); }
/// <summary> /// Replaces the intrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="methodCompiler">The method compiler.</param> void IIntrinsicPlatformMethod.ReplaceIntrinsicCall(Context context, BaseMethodCompiler methodCompiler) { Operand result = context.Result; Operand methodAddress = context.Operand1; Operand newESP = context.Operand2; Operand eax = Operand.CreateCPURegister(methodCompiler.TypeSystem.BuiltIn.I4, GeneralPurposeRegister.EAX); Operand edx = Operand.CreateCPURegister(methodCompiler.TypeSystem.BuiltIn.I4, GeneralPurposeRegister.EDX); Operand op0L, op0H; LongOperandTransformationStage.SplitLongOperand(methodCompiler, result, out op0L, out op0H); context.SetInstruction(X86.Call, null, methodAddress); context.AppendInstruction(IRInstruction.Gen, eax); context.AppendInstruction(IRInstruction.Gen, edx); context.AppendInstruction(X86.Mov, op0L, eax); context.AppendInstruction(X86.Mov, op0H, edx); }
/// <summary> /// Requests the calling convention to create an appropriate move instruction to populate the return /// value of a method. /// </summary> /// <param name="ctx">The context.</param> /// <param name="operand">The operand, that's holding the return value.</param> void ICallingConvention.MoveReturnValue(Context ctx, Operand operand) { int size, alignment; architecture.GetTypeRequirements(operand.Type, out size, out alignment); // FIXME: Do not issue a move, if the operand is already the destination register if (4 == size || 2 == size || 1 == size) { ctx.SetInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(operand.Type, GeneralPurposeRegister.EAX), operand); return; } else if (8 == size && (operand.Type.Type == CilElementType.R4 || operand.Type.Type == CilElementType.R8)) { if (!(operand is MemoryOperand)) { // Move the operand to memory by prepending an instruction } // BUG: Return values are in FP0, not XMM#0 ctx.SetInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(operand.Type, SSE2Register.XMM0), operand); return; } else if (8 == size && (operand.Type.Type == CilElementType.I8 || operand.Type.Type == CilElementType.U8)) { SigType HighType = (operand.Type.Type == CilElementType.I8) ? new SigType(CilElementType.I4) : new SigType(CilElementType.U4); SigType U4 = new SigType(CilElementType.U4); Operand opL, opH; LongOperandTransformationStage.SplitLongOperand(operand, out opL, out opH); // Like Win32: EDX:EAX ctx.SetInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(U4, GeneralPurposeRegister.EAX), opL); ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(HighType, GeneralPurposeRegister.EDX), opH); return; } else { throw new NotSupportedException(); } }
/// <summary> /// Moves the return value to 64 bit. /// </summary> /// <param name="resultOperand">The result operand.</param> /// <param name="ctx">The context.</param> private static void MoveReturnValueTo64Bit(Operand resultOperand, Context ctx) { SigType I4 = new SigType(CilElementType.I4); SigType U4 = new SigType(CilElementType.U4); MemoryOperand memoryOperand = resultOperand as MemoryOperand; if (memoryOperand == null) { return; } Operand opL, opH; LongOperandTransformationStage.SplitLongOperand(memoryOperand, out opL, out opH); //MemoryOperand opL = new MemoryOperand(U4, memoryOperand.Base, memoryOperand.Offset); //MemoryOperand opH = new MemoryOperand(I4, memoryOperand.Base, new IntPtr(memoryOperand.Offset.ToInt64() + 4)); RegisterOperand eax = new RegisterOperand(U4, GeneralPurposeRegister.EAX); RegisterOperand edx = new RegisterOperand(I4, GeneralPurposeRegister.EDX); ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, opL, eax); ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, opH, edx); }
/// <summary> /// Pushes the specified instructions. /// </summary> /// <param name="ctx">The context.</param> /// <param name="op">The op.</param> /// <param name="stackSize">Size of the stack.</param> private void Push(Context ctx, Operand op, int stackSize) { if (op is MemoryOperand) { RegisterOperand rop; switch (op.StackType) { case StackTypeCode.O: goto case StackTypeCode.N; case StackTypeCode.Ptr: goto case StackTypeCode.N; case StackTypeCode.Int32: goto case StackTypeCode.N; case StackTypeCode.N: rop = new RegisterOperand(op.Type, GeneralPurposeRegister.EAX); break; case StackTypeCode.F: rop = new RegisterOperand(op.Type, SSE2Register.XMM0); break; case StackTypeCode.Int64: { SigType I4 = new SigType(CilElementType.I4); MemoryOperand mop = op as MemoryOperand; Debug.Assert(null != mop, "I8/U8 arg is not in a memory operand."); RegisterOperand eax = new RegisterOperand(I4, GeneralPurposeRegister.EAX); Operand opL, opH; LongOperandTransformationStage.SplitLongOperand(mop, out opL, out opH); //MemoryOperand opL = new MemoryOperand(I4, mop.Base, mop.Offset); //MemoryOperand opH = new MemoryOperand(I4, mop.Base, new IntPtr(mop.Offset.ToInt64() + 4)); ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, eax, opL); ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, new MemoryOperand(op.Type, GeneralPurposeRegister.EDX, new IntPtr(stackSize)), eax); ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, eax, opH); ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, new MemoryOperand(op.Type, GeneralPurposeRegister.EDX, new IntPtr(stackSize + 4)), eax); } return; default: throw new NotSupportedException(); } ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, rop, op); op = rop; } else if (op is ConstantOperand && op.StackType == StackTypeCode.Int64) { Operand opL, opH; SigType I4 = new SigType(CilElementType.I4); RegisterOperand eax = new RegisterOperand(I4, GeneralPurposeRegister.EAX); LongOperandTransformationStage.SplitLongOperand(op, out opL, out opH); ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, eax, opL); ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, new MemoryOperand(I4, GeneralPurposeRegister.EDX, new IntPtr(stackSize)), eax); ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, eax, opH); ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, new MemoryOperand(I4, GeneralPurposeRegister.EDX, new IntPtr(stackSize + 4)), eax); return; } ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, new MemoryOperand(op.Type, GeneralPurposeRegister.EDX, new IntPtr(stackSize)), op); }