/// <summary> /// Performs stage specific processing on the compiler context. /// </summary> void IMethodCompilerStage.Run() { if (AreExceptions) return; foreach (var block in this.basicBlocks) { if (block.Label == Int32.MaxValue) continue; for (var context = new Context(this.instructionSet, block); !context.EndOfInstruction; context.GotoNext()) { if (context.Instruction is PhiInstruction) this.ProcessPhiInstruction(block, context); for (var i = 0; i < context.OperandCount; ++i) { var op = context.GetOperand(i); if (op is SsaOperand) context.SetOperand(i, (op as SsaOperand).Operand); } for (var i = 0; i < context.ResultCount; ++i) { var op = context.GetResult(i); if (op is SsaOperand) context.SetResult(i, (op as SsaOperand).Operand); } } } }
private static void PatchInvoke(BaseMethodCompiler methodCompiler) { // check if instance is null (if so, it's a static call to the methodPointer) MosaField methodPointerField = GetField(methodCompiler.Method.DeclaringType, "methodPointer"); int methodPointerOffset = methodCompiler.TypeLayout.GetFieldOffset(methodPointerField); Operand methodPointerOffsetOperand = Operand.CreateConstant(methodCompiler.TypeSystem, methodPointerOffset); MosaField instanceField = GetField(methodCompiler.Method.DeclaringType, "instance"); int instanceOffset = methodCompiler.TypeLayout.GetFieldOffset(instanceField); Operand instanceOffsetOperand = Operand.CreateConstant(methodCompiler.TypeSystem, instanceOffset); var size = methodCompiler.Architecture.NativeInstructionSize; bool withReturn = (methodCompiler.Method.Signature.ReturnType == null) ? false : !methodCompiler.Method.Signature.ReturnType.IsVoid; Context b0 = new Context(CreateMethodStructure(methodCompiler, false)); Context b1 = new Context(methodCompiler.BasicBlocks.CreateBlock()); Context b2 = new Context(methodCompiler.BasicBlocks.CreateBlock()); Context b3 = new Context(methodCompiler.BasicBlocks.CreateBlock()); Operand[] vrs = new Operand[methodCompiler.Parameters.Length]; for (int i = 0; i < methodCompiler.Parameters.Length; i++) { vrs[i] = methodCompiler.VirtualRegisters.Allocate(methodCompiler.Parameters[i].Type); //fixme: handle structs var loadInstruction = BaseMethodCompilerStage.GetLoadInstruction(vrs[i].Type); var moveSize = BaseMethodCompilerStage.GetInstructionSize(vrs[i].Type); b0.AppendInstruction(loadInstruction, moveSize, vrs[i], methodCompiler.StackFrame, methodCompiler.Parameters[i]); } Operand thisOperand = vrs[0]; Operand opMethod = methodCompiler.VirtualRegisters.Allocate(methodCompiler.TypeSystem.BuiltIn.U4); Operand opInstance = methodCompiler.VirtualRegisters.Allocate(thisOperand.Type); Operand opCompare = methodCompiler.VirtualRegisters.Allocate(methodCompiler.TypeSystem.BuiltIn.I4); Operand opReturn = withReturn ? methodCompiler.AllocateVirtualRegisterOrStackSlot(methodCompiler.Method.Signature.ReturnType) : null; Operand c0 = Operand.CreateConstant(methodCompiler.TypeSystem, 0); b0.AppendInstruction(IRInstruction.LoadInteger, size, opMethod, thisOperand, methodPointerOffsetOperand); b0.AppendInstruction(IRInstruction.LoadInteger, size, opInstance, thisOperand, instanceOffsetOperand); b0.AppendInstruction(IRInstruction.CompareInteger, ConditionCode.Equal, opCompare, opInstance, c0); b0.AppendInstruction(IRInstruction.CompareIntegerBranch, ConditionCode.Equal, null, opCompare, c0); b0.AddBranchTarget(b2.Block); b0.AppendInstruction(IRInstruction.Jmp, b1.Block); // no instance b1.AppendInstruction(IRInstruction.Call, opReturn, opMethod); b1.InvokeMethod = methodCompiler.Method; for (int i = 1; i < methodCompiler.Parameters.Length; i++) b1.AddOperand(vrs[i]); if (withReturn) b1.SetResult(0, opReturn); b1.AppendInstruction(IRInstruction.Jmp, b3.Block); // instance b2.AppendInstruction(IRInstruction.Call, opReturn, opMethod); b2.InvokeMethod = methodCompiler.Method; b2.AddOperand(opInstance); for (int i = 1; i < methodCompiler.Parameters.Length; i++) b2.AddOperand(vrs[i]); if (withReturn) b2.SetResult(0, opReturn); b2.AppendInstruction(IRInstruction.Jmp, b3.Block); // return b3.AppendInstruction(IRInstruction.Return, methodCompiler.BasicBlocks.EpilogueBlock); if (withReturn) b3.SetOperand(0, opReturn); }
/// <summary> /// Replaces the operand. /// </summary> /// <param name="lr">The lr.</param> /// <param name="replacement">The replacement.</param> private void ReplaceOperand(LiveRange lr, RegisterOperand replacement) { int opIdx; // Iterate all definition sites first foreach (int index in lr.Op.Definitions.ToArray()) { Context def = new Context(instructionSet, index); if (def.Offset == lr.Start) { opIdx = 0; foreach (Operand r in def.Results) { // Is this the operand? if (object.ReferenceEquals(r, lr.Op)) def.SetResult(opIdx, replacement); opIdx++; } break; } } // Iterate all use sites foreach (int index in lr.Op.Uses.ToArray()) { Context instr = new Context(instructionSet, index); if (instr.Offset <= lr.Start) { // A use on instr.Offset == lr.Start is one from a previous definition!! } else if (instr.Offset <= lr.End) { opIdx = 0; foreach (Operand r in instr.Operands) { // Is this the operand? if (object.ReferenceEquals(r, lr.Op)) instr.SetOperand(opIdx, replacement); opIdx++; } } else { break; } } }
/// <summary> /// /// </summary> /// <param name="block"></param> private void RenameVariables(BasicBlock block) { for (var context = new Context(this.instructionSet, block); !context.EndOfInstruction; context.GotoNext()) { if (!(context.Instruction is PhiInstruction)) { for (var i = 0; i < context.OperandCount; ++i) { var op = context.GetOperand(i); if (!(op is StackOperand)) continue; var name = NameForOperand(context.GetOperand(i)); if (!this.variableInformation.ContainsKey(name)) throw new Exception(name + " is not in dictionary [block = " + block + "]"); var index = this.variableInformation[name].Stack.Peek(); context.SetOperand(i, new SsaOperand(context.GetOperand(i), index)); } } if (PhiPlacementStage.IsAssignmentToStackVariable(context)) { var name = NameForOperand(context.Result); var index = this.variableInformation[name].Count; context.SetResult(new SsaOperand(context.Result, index)); this.variableInformation[name].Stack.Push(index); ++this.variableInformation[name].Count; } } foreach (var s in block.NextBlocks) { var j = this.WhichPredecessor(s, block); for (var context = new Context(this.instructionSet, s); !context.EndOfInstruction; context.GotoNext()) { if (!(context.Instruction is PhiInstruction)) continue; var name = NameForOperand(context.GetOperand(j)); if (this.variableInformation[name].Stack.Count > 0) { var index = this.variableInformation[name].Stack.Peek(); context.SetOperand(j, new SsaOperand(context.GetOperand(j), index)); } } } foreach (var s in this.dominanceCalculationStage.GetChildren(block)) { this.RenameVariables(s); } for (var context = new Context(this.instructionSet, block); !context.EndOfInstruction; context.GotoNext()) { if (PhiPlacementStage.IsAssignmentToStackVariable(context)) { var instName = context.Label + "." + context.Index; var op = this.oldLefHandSide[instName]; var name = NameForOperand(op); this.variableInformation[name].Stack.Pop(); } } }
private static void PatchInvoke(BaseMethodCompiler methodCompiler) { // check if instance is null (if so, it's a static call to the methodPointer) MosaField methodPointerField = GetField(methodCompiler.Method.DeclaringType, "methodPointer"); int methodPointerOffset = methodCompiler.TypeLayout.GetFieldOffset(methodPointerField); Operand methodPointerOffsetOperand = Operand.CreateConstant(methodCompiler.TypeSystem, methodPointerOffset); MosaField instanceField = GetField(methodCompiler.Method.DeclaringType, "instance"); int instanceOffset = methodCompiler.TypeLayout.GetFieldOffset(instanceField); Operand instanceOffsetOperand = Operand.CreateConstant(methodCompiler.TypeSystem, instanceOffset); var size = methodCompiler.Architecture.NativeInstructionSize; bool withReturn = (methodCompiler.Method.Signature.ReturnType == null) ? false : !methodCompiler.Method.Signature.ReturnType.IsVoid; Context b0 = new Context(CreateMethodStructure(methodCompiler, false)); Context b1 = new Context(methodCompiler.BasicBlocks.CreateBlock()); Context b2 = new Context(methodCompiler.BasicBlocks.CreateBlock()); Context b3 = new Context(methodCompiler.BasicBlocks.CreateBlock()); Operand[] vrs = new Operand[methodCompiler.Parameters.Length]; for (int i = 0; i < methodCompiler.Parameters.Length; i++) { var type = methodCompiler.Parameters[i].Type; if (methodCompiler.StoreOnStack(type)) { b0.AppendInstruction(IRInstruction.LoadParameterCompound, vrs[i], methodCompiler.Parameters[i]); b0.MosaType = type; } else { vrs[i] = methodCompiler.VirtualRegisters.Allocate(methodCompiler.Parameters[i].Type); var loadInstruction = BaseMethodCompilerStage.GetLoadParameterInstruction(vrs[i].Type); var loadsize = BaseMethodCompilerStage.GetInstructionSize(vrs[i].Type); b0.AppendInstruction(loadInstruction, loadsize, vrs[i], methodCompiler.Parameters[i]); b0.MosaType = type; } } Operand thisOperand = vrs[0]; Operand opMethod = methodCompiler.VirtualRegisters.Allocate(methodCompiler.TypeSystem.BuiltIn.U4); Operand opInstance = methodCompiler.VirtualRegisters.Allocate(thisOperand.Type); Operand opCompare = methodCompiler.VirtualRegisters.Allocate(methodCompiler.TypeSystem.BuiltIn.I4); Operand opReturn = withReturn ? methodCompiler.AllocateVirtualRegisterOrStackSlot(methodCompiler.Method.Signature.ReturnType) : null; Operand c0 = Operand.CreateConstant(methodCompiler.TypeSystem, 0); b0.AppendInstruction(IRInstruction.LoadInteger, size, opMethod, thisOperand, methodPointerOffsetOperand); b0.AppendInstruction(IRInstruction.LoadInteger, size, opInstance, thisOperand, instanceOffsetOperand); b0.AppendInstruction(IRInstruction.CompareInteger, ConditionCode.Equal, opCompare, opInstance, c0); b0.AppendInstruction(IRInstruction.CompareIntegerBranch, ConditionCode.Equal, null, opCompare, c0); b0.AddBranchTarget(b2.Block); b0.AppendInstruction(IRInstruction.Jmp, b1.Block); // no instance b1.AppendInstruction(IRInstruction.Call, opReturn, opMethod); b1.InvokeMethod = methodCompiler.Method; for (int i = 1; i < methodCompiler.Parameters.Length; i++) { b1.AddOperand(vrs[i]); } if (withReturn) { b1.SetResult(0, opReturn); } b1.AppendInstruction(IRInstruction.Jmp, b3.Block); // instance b2.AppendInstruction(IRInstruction.Call, opReturn, opMethod); b2.InvokeMethod = methodCompiler.Method; b2.AddOperand(opInstance); for (int i = 1; i < methodCompiler.Parameters.Length; i++) { b2.AddOperand(vrs[i]); } if (withReturn) { b2.SetResult(0, opReturn); } b2.AppendInstruction(IRInstruction.Jmp, b3.Block); // return b3.AppendInstruction(IRInstruction.Return, methodCompiler.BasicBlocks.EpilogueBlock); if (withReturn) { b3.SetOperand(0, opReturn); } }