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