private void SetReturn32(Context context) { context.SetInstruction(IRInstruction.Move32, Operand.CreateCPURegister(context.Operand1.Type, Architecture.ReturnRegister), context.Operand1); }
private static void GetCR0(Context context, MethodCompiler methodCompiler) { context.SetInstruction(X86.MovCRLoad32, context.Result, Operand.CreateCPURegister(methodCompiler.TypeSystem.BuiltIn.U4, ControlRegister.CR0)); }
private void SetReturnR8(Context context) { context.SetInstruction(IRInstruction.MoveR8, Operand.CreateCPURegister(context.Operand1.Type, Architecture.ReturnFloatingPointRegister), context.Operand1); }
protected override void Run() { exceptionVirtualRegisters = new Dictionary <BasicBlock, Operand>(); finallyReturnVirtualRegisters = new Dictionary <BasicBlock, Operand>(); exceptionType = TypeSystem.GetTypeByName("System", "Exception"); var exceptionRegister = Operand.CreateCPURegister(exceptionType, Architecture.ExceptionRegister); var finallyReturnBlockRegister = Operand.CreateCPURegister(TypeSystem.BuiltIn.I4, Architecture.FinallyReturnBlockRegister); var nullOperand = Operand.GetNull(TypeSystem); for (int i = 0; i < BasicBlocks.Count; i++) { var block = BasicBlocks[i]; for (var node = block.First; !node.IsBlockEndInstruction; node = node.Next) { if (node.IsEmpty) { continue; } if (node.Instruction == IRInstruction.Throw) { var method = PlatformInternalRuntimeType.FindMethodByName("ExceptionHandler"); var ctx = new Context(node); ctx.SetInstruction(IRInstruction.Move, exceptionRegister, node.Operand1); //ctx.AppendInstruction(IRInstruction.KillAllExcept, null, exceptionRegister); ctx.AppendInstruction(IRInstruction.Call, null, Operand.CreateSymbolFromMethod(TypeSystem, method)); ctx.InvokeMethod = method; } else if (node.Instruction == IRInstruction.CallFinally) { var target = node.BranchTargets[0]; var finallyReturn = node.BranchTargets[1]; var ctx = new Context(node); ctx.SetInstruction(IRInstruction.KillAll); ctx.AppendInstruction(IRInstruction.Move, exceptionRegister, nullOperand); ctx.AppendInstruction(IRInstruction.Move, finallyReturnBlockRegister, Operand.CreateConstant(TypeSystem, finallyReturn.Label)); ctx.AppendInstruction(IRInstruction.Jmp, target); } else if (node.Instruction == IRInstruction.FinallyStart) { // Remove from header blocks BasicBlocks.RemoveHeaderBlock(node.Block); var exceptionVirtualRegister = node.Result; var finallyReturnBlockVirtualRegister = node.Result2; var ctx = new Context(node); exceptionVirtualRegisters.Add(node.Block, exceptionVirtualRegister); finallyReturnVirtualRegisters.Add(node.Block, finallyReturnBlockRegister); ctx.SetInstruction(IRInstruction.KillAll); ctx.AppendInstruction(IRInstruction.Gen, exceptionRegister); ctx.AppendInstruction(IRInstruction.Gen, finallyReturnBlockRegister); ctx.AppendInstruction(IRInstruction.Move, exceptionVirtualRegister, exceptionRegister); ctx.AppendInstruction(IRInstruction.Move, finallyReturnBlockVirtualRegister, finallyReturnBlockRegister); } else if (node.Instruction == IRInstruction.FinallyEnd) { var header = FindImmediateExceptionHandler(node); var headerBlock = BasicBlocks.GetByLabel(header.HandlerStart); var exceptionVirtualRegister = exceptionVirtualRegisters[headerBlock]; var finallyReturnBlockVirtualRegister = finallyReturnVirtualRegisters[headerBlock]; var newBlocks = CreateNewBlockContexts(1); var ctx = new Context(node); var nextBlock = Split(ctx); ctx.SetInstruction(IRInstruction.IntegerCompareBranch, ConditionCode.NotEqual, null, exceptionVirtualRegister, nullOperand, newBlocks[0].Block); ctx.AppendInstruction(IRInstruction.Jmp, nextBlock.Block); var method = PlatformInternalRuntimeType.FindMethodByName("ExceptionHandler"); newBlocks[0].AppendInstruction(IRInstruction.Move, exceptionRegister, exceptionVirtualRegister); newBlocks[0].AppendInstruction(IRInstruction.Call, null, Operand.CreateSymbolFromMethod(TypeSystem, method)); newBlocks[0].InvokeMethod = method; } else if (node.Instruction == IRInstruction.FinallyReturn) { var targets = node.BranchTargets; var header = FindImmediateExceptionHandler(node); var headerBlock = BasicBlocks.GetByLabel(header.HandlerStart); var finallyReturnBlockVirtualRegister = finallyReturnVirtualRegisters[headerBlock]; Debug.Assert(targets.Count != 0); if (targets.Count == 1) { node.SetInstruction(IRInstruction.Jmp, targets[0]); } else { var newBlocks = CreateNewBlockContexts(targets.Count - 1); var ctx = new Context(node); ctx.SetInstruction(IRInstruction.IntegerCompareBranch, ConditionCode.Equal, null, finallyReturnBlockVirtualRegister, Operand.CreateConstant(TypeSystem, targets[0].Label), targets[0]); ctx.AppendInstruction(IRInstruction.Jmp, newBlocks[0].Block); for (int b = 1; b < targets.Count - 2; b++) { newBlocks[b - 1].AppendInstruction(IRInstruction.IntegerCompareBranch, ConditionCode.Equal, null, finallyReturnBlockVirtualRegister, Operand.CreateConstant(TypeSystem, targets[b].Label), targets[b]); newBlocks[b - 1].AppendInstruction(IRInstruction.Jmp, newBlocks[b + 1].Block); } newBlocks[targets.Count - 2].AppendInstruction(IRInstruction.Jmp, targets[targets.Count - 1]); } } else if (node.Instruction == IRInstruction.ExceptionStart) { var exceptionVirtualRegister = node.Result; var ctx = new Context(node); ctx.SetInstruction(IRInstruction.KillAll); ctx.AppendInstruction(IRInstruction.Gen, exceptionRegister); ctx.AppendInstruction(IRInstruction.Move, exceptionVirtualRegister, exceptionRegister); } else if (node.Instruction == IRInstruction.ExceptionEnd) { node.SetInstruction(IRInstruction.Jmp, node.BranchTargets[0]); } else if (node.Instruction == IRInstruction.Flow) { node.Empty(); } } } }
void IIntrinsicPlatformMethod.ReplaceIntrinsicCall(Context context, MethodCompiler methodCompiler) { context.SetInstruction(X86.MovLoadSeg32, context.Result, Operand.CreateCPURegister(methodCompiler.TypeSystem.BuiltIn.U4, SegmentRegister.CS)); }
void IIntrinsicPlatformMethod.ReplaceIntrinsicCall(Context context, MethodCompiler methodCompiler) { context.SetInstruction(X86.Mov32, context.Result, Operand.CreateCPURegister(methodCompiler.TypeSystem.BuiltIn.U4, GeneralPurposeRegister.EBP)); }
private void SetReturn(Context context) { var operand = context.Operand1; Debug.Assert(operand != null); if (operand.IsR4) { context.SetInstruction(IRInstruction.MoveFloatR4, Operand.CreateCPURegister(operand.Type, Architecture.ReturnFloatingPointRegister), operand); } else if (operand.IsR8) { context.SetInstruction(IRInstruction.MoveFloatR8, Operand.CreateCPURegister(operand.Type, Architecture.ReturnFloatingPointRegister), operand); } else if (operand.IsLong) { var v1 = AllocateVirtualRegister(TypeSystem.BuiltIn.U4); var v2 = AllocateVirtualRegister(TypeSystem.BuiltIn.U4); context.SetInstruction2(IRInstruction.Split64, v1, v2, operand); context.AppendInstruction(IRInstruction.MoveInteger, InstructionSize.Size32, Operand.CreateCPURegister(TypeSystem.BuiltIn.U4, Architecture.Return32BitRegister), v1); context.AppendInstruction(IRInstruction.MoveInteger, InstructionSize.Size32, Operand.CreateCPURegister(TypeSystem.BuiltIn.U4, Architecture.Return64BitRegister), v2); } else if (MosaTypeLayout.IsStoredOnStack(operand.Type)) { var OffsetOfFirstParameterOperand = CreateConstant(Architecture.OffsetOfFirstParameter); context.SetInstruction(IRInstruction.StoreCompound, null, StackFrame, OffsetOfFirstParameterOperand, operand); } else { context.SetInstruction(IRInstruction.MoveInteger, InstructionSize.Size32, Operand.CreateCPURegister(operand.Type, Architecture.Return32BitRegister), operand); } }
private static void GetFS(Context context, MethodCompiler methodCompiler) { context.SetInstruction(X86.MovLoadSeg32, context.Result, Operand.CreateCPURegister(methodCompiler.TypeSystem.BuiltIn.U4, SegmentRegister.FS)); }
private static void SetFS(Context context, MethodCompiler methodCompiler) { context.SetInstruction(X64.MovStoreSeg64, Operand.CreateCPURegister(methodCompiler.TypeSystem.BuiltIn.U8, SegmentRegister.FS), context.Operand1); }
/// <summary> /// Expands method call instruction represented by the context to perform the method call. /// </summary> /// <param name="compiler">The compiler.</param> /// <param name="context">The context.</param> public override void MakeCall(BaseMethodCompiler compiler, 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(compiler.TypeLayout.TypeSystem.BuiltIn.Pointer, scratchRegister); var operands = BuildOperands(context); context.Empty(); int stackSize = 0; int returnSize = 0; if (method != null) { stackSize = CalculateStackSizeForParameters(compiler.TypeLayout, architecture, operands, method); returnSize = CalculateReturnSize(compiler, method); } else { stackSize = CalculateStackSizeForParameters(compiler.TypeLayout, architecture, operands); returnSize = CalculateReturnSize(compiler, result); } if (stackSize != 0 || returnSize != 0) { ReserveStackSizeForCall(compiler, context, returnSize + stackSize, scratch); if (method != null) { PushOperands(compiler, context, method, operands, returnSize + stackSize, scratch); } else { PushOperands(compiler, context, 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, context, result); FreeStackAfterCall(compiler, context, returnSize + stackSize); }