예제 #1
0
 private void SetReturn32(Context context)
 {
     context.SetInstruction(IRInstruction.Move32, Operand.CreateCPURegister(context.Operand1.Type, Architecture.ReturnRegister), context.Operand1);
 }
예제 #2
0
 private static void GetCR0(Context context, MethodCompiler methodCompiler)
 {
     context.SetInstruction(X86.MovCRLoad32, context.Result, Operand.CreateCPURegister(methodCompiler.TypeSystem.BuiltIn.U4, ControlRegister.CR0));
 }
예제 #3
0
 private void SetReturnR8(Context context)
 {
     context.SetInstruction(IRInstruction.MoveR8, Operand.CreateCPURegister(context.Operand1.Type, Architecture.ReturnFloatingPointRegister), context.Operand1);
 }
예제 #4
0
        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();
                    }
                }
            }
        }
예제 #5
0
 void IIntrinsicPlatformMethod.ReplaceIntrinsicCall(Context context, MethodCompiler methodCompiler)
 {
     context.SetInstruction(X86.MovLoadSeg32, context.Result, Operand.CreateCPURegister(methodCompiler.TypeSystem.BuiltIn.U4, SegmentRegister.CS));
 }
예제 #6
0
 void IIntrinsicPlatformMethod.ReplaceIntrinsicCall(Context context, MethodCompiler methodCompiler)
 {
     context.SetInstruction(X86.Mov32, context.Result, Operand.CreateCPURegister(methodCompiler.TypeSystem.BuiltIn.U4, GeneralPurposeRegister.EBP));
 }
예제 #7
0
        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);
            }
        }
예제 #8
0
 private static void GetFS(Context context, MethodCompiler methodCompiler)
 {
     context.SetInstruction(X86.MovLoadSeg32, context.Result, Operand.CreateCPURegister(methodCompiler.TypeSystem.BuiltIn.U4, SegmentRegister.FS));
 }
예제 #9
0
 private static void SetFS(Context context, MethodCompiler methodCompiler)
 {
     context.SetInstruction(X64.MovStoreSeg64, Operand.CreateCPURegister(methodCompiler.TypeSystem.BuiltIn.U8, SegmentRegister.FS), context.Operand1);
 }
예제 #10
0
        /// <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);
        }