Exemple #1
0
        /// <summary>
        /// Inserts the copy statement.
        /// </summary>
        /// <param name="predecessor">The predecessor.</param>
        /// <param name="destination">The result.</param>
        /// <param name="source">The operand.</param>
        private void InsertCopyStatement(BasicBlock predecessor, Operand destination, Operand source)
        {
            if (destination == source)
            {
                return;
            }

            var node = predecessor.BeforeLast;

            while (node.Instruction != IRInstruction.Jmp)
            {
                node = node.Previous;
            }

            node = node.Previous;

            Debug.Assert(node.Instruction != IRInstruction.Branch32);
            Debug.Assert(node.Instruction != IRInstruction.Branch64);
            Debug.Assert(node.Instruction != IRInstruction.BranchObject);

            var context = new Context(node);

            if (!MosaTypeLayout.CanFitInRegister(destination))
            {
                context.AppendInstruction(IRInstruction.MoveCompound, destination, source);
                context.MosaType = destination.Type;
            }
            else
            {
                var moveInstruction = GetMoveInstruction(destination.Type);
                context.AppendInstruction(moveInstruction, destination, source);
            }
        }
Exemple #2
0
        private void Push(Context context, Operand operand, int offset, Operand scratch)
        {
            var offsetOperand = CreateConstant(offset);

            if (operand.IsInteger)
            {
                context.AppendInstruction(Select(operand, IRInstruction.Store32, IRInstruction.Store64), null, scratch, offsetOperand, operand);
            }
            else if (operand.IsR4)
            {
                context.AppendInstruction(IRInstruction.StoreR4, null, scratch, offsetOperand, operand);
            }
            else if (operand.IsR8)
            {
                context.AppendInstruction(IRInstruction.StoreR8, null, scratch, offsetOperand, operand);
            }
            else if (!MosaTypeLayout.CanFitInRegister(operand.Type))
            {
                context.AppendInstruction(IRInstruction.StoreCompound, null, scratch, offsetOperand, operand);
            }
            else
            {
                // note: same for integer logic (above)
                context.AppendInstruction(Select(operand, IRInstruction.Store32, IRInstruction.Store64), null, scratch, offsetOperand, operand);
            }
        }
Exemple #3
0
        private void AddMoves(BasicBlock block, List <Operand> sourceOperands, List <Operand> destinationOperands)
        {
            var context = new Context(block.Last);

            context.GotoPrevious();

            while (context.IsEmpty ||
                   context.Instruction.FlowControl == FlowControl.ConditionalBranch ||
                   context.Instruction.FlowControl == FlowControl.UnconditionalBranch ||
                   context.Instruction.FlowControl == FlowControl.Return ||
                   context.Instruction == IRInstruction.Jmp)
            {
                context.GotoPrevious();
            }

            for (int i = 0; i < sourceOperands.Count; i++)
            {
                var source      = sourceOperands[i];
                var destination = destinationOperands[i];

                if (!MosaTypeLayout.CanFitInRegister(source.Type))
                {
                    context.AppendInstruction(IRInstruction.MoveCompound, destination, source);
                }
                else
                {
                    var moveInstruction = GetMoveInstruction(source.Type);
                    context.AppendInstruction(moveInstruction, destination, source);
                }
            }
        }
Exemple #4
0
        private void Push(Context context, Operand operand, int offset)
        {
            var offsetOperand = CreateConstant32(offset);

            if (operand.IsReferenceType)
            {
                context.AppendInstruction(IRInstruction.StoreObject, null, StackPointer, offsetOperand, operand);
            }
            else if (operand.IsInteger32)
            {
                context.AppendInstruction(IRInstruction.Store32, null, StackPointer, offsetOperand, operand);
            }
            else if (operand.IsInteger64)
            {
                context.AppendInstruction(IRInstruction.Store64, null, StackPointer, offsetOperand, operand);
            }
            else if (operand.IsR4)
            {
                context.AppendInstruction(IRInstruction.StoreR4, null, StackPointer, offsetOperand, operand);
            }
            else if (operand.IsR8)
            {
                context.AppendInstruction(IRInstruction.StoreR8, null, StackPointer, offsetOperand, operand);
            }
            else if (!MosaTypeLayout.CanFitInRegister(operand.Type))
            {
                context.AppendInstruction(IRInstruction.StoreCompound, null, StackPointer, offsetOperand, operand);
            }
            else
            {
                context.AppendInstruction(StoreInstruction, null, StackPointer, offsetOperand, operand);
            }
        }
Exemple #5
0
        private void GetReturnValue(Context context, Operand result)
        {
            if (result == null)
            {
                return;
            }

            if (result.IsReferenceType)
            {
                var returnLow = Operand.CreateCPURegister(result.Type, Architecture.ReturnRegister);
                context.AppendInstruction(IRInstruction.Gen, returnLow);
                context.AppendInstruction(IRInstruction.MoveObject, result, returnLow);
            }
            else if (result.IsInteger64 && Is32BitPlatform)
            {
                var returnLow  = Operand.CreateCPURegister(result.Type, Architecture.ReturnRegister);
                var returnHigh = Operand.CreateCPURegister(TypeSystem.BuiltIn.U4, Architecture.ReturnHighRegister);

                context.AppendInstruction(IRInstruction.Gen, returnLow);
                context.AppendInstruction(IRInstruction.Gen, returnHigh);
                context.AppendInstruction(IRInstruction.To64, result, returnLow, returnHigh);
            }
            else if (result.IsInteger)
            {
                var returnLow = Operand.CreateCPURegister(result.Type, Architecture.ReturnRegister);
                context.AppendInstruction(IRInstruction.Gen, returnLow);
                context.AppendInstruction(MoveInstruction, result, returnLow);
            }
            else if (result.IsR4)
            {
                var returnFP = Operand.CreateCPURegister(result.Type, Architecture.ReturnFloatingPointRegister);
                context.AppendInstruction(IRInstruction.Gen, returnFP);
                context.AppendInstruction(IRInstruction.MoveR4, result, returnFP);
            }
            else if (result.IsR8)
            {
                var returnFP = Operand.CreateCPURegister(result.Type, Architecture.ReturnFloatingPointRegister);
                context.AppendInstruction(IRInstruction.Gen, returnFP);
                context.AppendInstruction(IRInstruction.MoveR8, result, returnFP);
            }
            else if (!MosaTypeLayout.CanFitInRegister(result.Type))
            {
                Debug.Assert(result.IsStackLocal);
                context.AppendInstruction(IRInstruction.LoadCompound, result, StackPointer, ConstantZero);
            }
            else
            {
                // note: same for integer logic (above)
                var returnLow = Operand.CreateCPURegister(result.Type, Architecture.ReturnRegister);
                context.AppendInstruction(IRInstruction.Gen, returnLow);
                context.AppendInstruction(MoveInstruction, result, returnLow);
            }
        }
        protected bool CanPromote(Operand operand)
        {
            trace?.Log($"Check: {operand}");

            if (operand.Uses.Count == 0)
            {
                trace?.Log($"No uses: {operand}");
                return(false);
            }

            if (!MosaTypeLayout.CanFitInRegister(operand))
            {
                trace?.Log($"incompatible type: {operand}");
                return(false);
            }

            foreach (var node in operand.Uses)
            {
                if (node.Instruction == IRInstruction.AddressOf)
                {
                    Debug.Assert(node.Operand1 == operand);

                    foreach (var node2 in node.Result.Uses)
                    {
                        if (!Check(node2))
                        {
                            return(false);
                        }
                    }
                    continue;
                }
                else if (node.Instruction == IRInstruction.Load32 || node.Instruction == IRInstruction.Load64)
                {
                    Debug.Assert(node.Operand2 == operand);
                    continue;
                }
                else if (node.Instruction == IRInstruction.Store32 || node.Instruction == IRInstruction.Store64)
                {
                    Debug.Assert(node.Operand2 == operand);
                    continue;
                }

                trace?.Log($"A-No: {node}");
                return(false);
            }

            return(true);
        }
Exemple #7
0
        private int CalculateReturnSize(Operand result)
        {
            if (result == null)
            {
                return(0);
            }

            var returnType = result.Type;

            if (!MosaTypeLayout.CanFitInRegister(returnType))
            {
                return(Alignment.AlignUp(TypeLayout.GetTypeSize(returnType), NativeAlignment));
            }

            return(0);
        }
Exemple #8
0
        protected BasicBlocks CopyInstructions()
        {
            var newBasicBlocks = new BasicBlocks();
            var mapBlocks      = new Dictionary <BasicBlock, BasicBlock>(BasicBlocks.Count);
            var map            = new Dictionary <Operand, Operand>();
            var staticCalls    = new List <MosaMethod>();

            foreach (var block in BasicBlocks)
            {
                var newBlock = newBasicBlocks.CreateBlock(block.Label);
                mapBlocks.Add(block, newBlock);
            }

            var newPrologueBlock = newBasicBlocks.GetByLabel(BasicBlock.PrologueLabel);

            foreach (var operand in MethodCompiler.Parameters)
            {
                if (operand.Definitions.Count > 0)
                {
                    var newOp = Map(operand, map);

                    var newOperand = Operand.CreateVirtualRegister(operand.Type, -operand.Index);

                    var moveInstruction = !MosaTypeLayout.CanFitInRegister(newOperand)
                                                ? IRInstruction.MoveCompound
                                                : GetMoveInstruction(newOperand.Type);

                    var moveNode = new InstructionNode(moveInstruction, newOperand, newOp);

                    newPrologueBlock.BeforeLast.Insert(moveNode);

                    // redirect map from parameter to virtual register going forward
                    map.Remove(operand);
                    map.Add(operand, newOperand);
                }
            }

            foreach (var block in BasicBlocks)
            {
                var newBlock = newBasicBlocks.GetByLabel(block.Label);

                for (var node = block.AfterFirst; !node.IsBlockEndInstruction; node = node.Next)
                {
                    if (node.IsEmptyOrNop)
                    {
                        continue;
                    }

                    if (node.Instruction == IRInstruction.CallStatic)
                    {
                        staticCalls.AddIfNew(node.Operand1.Method);
                    }

                    var newNode = new InstructionNode(node.Instruction, node.OperandCount, node.ResultCount)
                    {
                        ConditionCode = node.ConditionCode,
                        InvokeMethod  = node.InvokeMethod,
                        MosaField     = node.MosaField,
                        MosaType      = node.MosaType,

                        //Label = callSiteNode.Label,
                    };

                    if (node.BranchTargets != null)
                    {
                        // copy targets
                        foreach (var target in node.BranchTargets)
                        {
                            newNode.AddBranchTarget(mapBlocks[target]);
                        }
                    }

                    // copy results
                    for (int i = 0; i < node.ResultCount; i++)
                    {
                        var op    = node.GetResult(i);
                        var newOp = Map(op, map);

                        newNode.SetResult(i, newOp);
                    }

                    // copy operands
                    for (int i = 0; i < node.OperandCount; i++)
                    {
                        var op    = node.GetOperand(i);
                        var newOp = Map(op, map);

                        newNode.SetOperand(i, newOp);
                    }

                    // copy other
                    if (node.MosaType != null)
                    {
                        newNode.MosaType = node.MosaType;
                    }

                    if (node.MosaField != null)
                    {
                        newNode.MosaField = node.MosaField;
                    }

                    newBlock.BeforeLast.Insert(newNode);
                }
            }

            var trace = CreateTraceLog("InlineMap", 9);

            if (trace != null)
            {
                foreach (var entry in map)
                {
                    trace.Log($"{entry.Value} from: {entry.Key}");
                }
            }

            return(newBasicBlocks);
        }
Exemple #9
0
        private bool StaticCanNotInline(MethodData methodData)
        {
            if (InlineExplicitOnly && !methodData.HasAggressiveInliningAttribute)
            {
                return(true);
            }

            if (methodData.HasDoNotInlineAttribute)
            {
                return(true);
            }

            if (methodData.IsMethodImplementationReplaced)
            {
                return(true);
            }

            if (methodData.HasProtectedRegions)
            {
                return(true);
            }

            if (methodData.HasMethodPointerReferenced)
            {
                return(true);
            }

            var method = methodData.Method;

            if (method.IsVirtual && !methodData.IsDevirtualized)
            {
                return(true);
            }

            if (methodData.DoNotInline)
            {
                return(true);
            }

            if (method.DeclaringType.IsValueType &&
                method.IsVirtual &&
                !method.IsConstructor &&
                !method.IsStatic)
            {
                return(true);
            }

            var returnType = methodData.Method.Signature.ReturnType;

            // FIXME: Add rational
            if (!MosaTypeLayout.CanFitInRegister(returnType) && !returnType.IsUI8 && !returnType.IsR8)
            {
                return(true);
            }

            // FUTURE: Don't hardcode namepsace
            if (((method.MethodAttributes & MosaMethodAttributes.Public) == MosaMethodAttributes.Public) && method.DeclaringType.BaseType != null && method.DeclaringType.BaseType.Namespace == "Mosa.UnitTests")
            {
                return(true);
            }

            return(false);
        }