/// <summary> /// Replaces the intrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> void IIntrinsicPlatformMethod.ReplaceIntrinsicCall(Context context, BaseMethodCompiler methodCompiler) { Operand v0 = context.Operand1; Operand v1 = context.Operand2; Operand v2 = context.Operand3; Operand v3 = context.GetOperand(3); Operand esp = Operand.CreateCPURegister(methodCompiler.TypeSystem.BuiltIn.I4, GeneralPurposeRegister.ESP); Operand ebp = Operand.CreateCPURegister(methodCompiler.TypeSystem.BuiltIn.I4, GeneralPurposeRegister.EBP); Operand eax = Operand.CreateCPURegister(methodCompiler.TypeSystem.BuiltIn.I4, GeneralPurposeRegister.EAX); Operand ebx = Operand.CreateCPURegister(methodCompiler.TypeSystem.BuiltIn.I4, GeneralPurposeRegister.EBX); Operand ecx = Operand.CreateCPURegister(methodCompiler.TypeSystem.BuiltIn.I4, GeneralPurposeRegister.ECX); Operand exceptionRegister = Operand.CreateCPURegister(methodCompiler.TypeSystem.BuiltIn.Object, methodCompiler.Architecture.ExceptionRegister); // Move all virtual registers into physical registers - necessary since stack frame pointer will change context.SetInstruction(X86.Mov, eax, v0); context.AppendInstruction(X86.Mov, ebx, v1); context.AppendInstruction(X86.Mov, ecx, v2); context.AppendInstruction(X86.Mov, exceptionRegister, v3); // Update the frame and stack registers context.AppendInstruction(X86.Mov, ebp, ecx); context.AppendInstruction(X86.Mov, esp, ebx); context.AppendInstruction(X86.Jmp, null, eax); // future - common code (refactor opportunity) context.GotoNext(); // Remove all remaining instructions in block and clear next block list while (!context.IsBlockEndInstruction) { if (!context.IsEmpty) { context.SetInstruction(X86.Nop); } context.GotoNext(); } var nextBlocks = context.Block.NextBlocks; foreach (var next in nextBlocks) { next.PreviousBlocks.Remove(context.Block); } nextBlocks.Clear(); }
/// <summary> /// Performs stage specific processing on the compiler context. /// </summary> void IMethodCompilerStage.Run() { Dictionary<Operand, int> list = new Dictionary<Operand, int>(); foreach (var block in this.basicBlocks) { for (var context = new Context(this.instructionSet, block); !context.EndOfInstruction; context.GotoNext()) { context.Marked = false; if (context.Result == null) continue; int index = 0; if (list.TryGetValue(context.Result, out index)) { instructionSet.Data[index].Marked = true; context.Marked = true; } else { list.Add(context.Result, context.Index); } } } }
/// <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); } } } }
/// <summary> /// Inserts the copy statement. /// </summary> /// <param name="predecessor">The predecessor.</param> /// <param name="result">The result.</param> /// <param name="operand">The operand.</param> private void InsertCopyStatement(BasicBlock predecessor, Operand result, Operand operand) { var context = new Context(this.instructionSet, predecessor); while (!context.EndOfInstruction && IsBranchInstruction(context)) context.GotoNext(); if (context.Index != -1) context = context.InsertBefore(); var source = operand is SsaOperand ? (operand as SsaOperand).Operand : operand; var destination = result is SsaOperand ? (result as SsaOperand).Operand : result; Debug.Assert(!(source is SsaOperand)); Debug.Assert(!(destination is SsaOperand)); context.SetInstruction(IR.Instruction.MoveInstruction, destination, source); }
protected override void Run() { foreach (var block in BasicBlocks) { for (var context = new Context(this.InstructionSet, block); !context.IsBlockEndInstruction; context.GotoNext()) { if (!(context.Instruction is X86Instruction)) continue; if (context.OperandCount != context.Instruction.DefaultOperandCount || context.ResultCount != context.Instruction.DefaultResultCount) { context.Marked = true; } } } }
protected override void Run() { foreach (var block in BasicBlocks) { for (var context = new Context(this.InstructionSet, block); !context.IsBlockEndInstruction; context.GotoNext()) { if (context.IsEmpty || !(context.Instruction is X86Instruction)) continue; if (context.Instruction == X86.Jmp || context.Instruction == X86.FarJmp) continue; // Convert any floating point constants into labels EmitFloatingPointConstants(context); // No floating point opcode allows both the result and operand to be a memory location // if necessary, load into register first if (context.OperandCount == 1 && context.ResultCount == 1 && context.Operand1.IsMemoryAddress && context.Result.IsMemoryAddress && (context.Result.IsR || context.Operand1.IsR)) { LoadFirstOperandIntoRegister(context); } else // No two-operand floating point opcode allows the first operand to a memory operand if (context.OperandCount == 2 && context.Operand1.IsMemoryAddress && context.Operand1.IsR) { if (IsCommutative(context.Instruction)) { // swap operands var t = context.Operand2; context.Operand2 = context.Operand1; context.Operand1 = t; } else { LoadFirstOperandIntoRegister(context); } } } } }
/// <summary> /// Performs stage specific processing on the compiler context. /// </summary> void IMethodCompilerStage.Run() { if (AreExceptions) return; foreach (var block in this.basicBlocks) if (block.NextBlocks.Count == 0 && block.PreviousBlocks.Count == 0) return; foreach (var block in this.basicBlocks) { for (var context = new Context(this.instructionSet, block); !context.EndOfInstruction; context.GotoNext()) { if (!this.IsFoldableInstruction(context)) continue; if (!this.HasFoldableArguments(context)) continue; this.FoldInstruction(context); } } }
/// <summary> /// Enumerates all instructions and eliminates floating point constants from them. /// </summary> /// <param name="ctx">The context.</param> /// <param name="ctxEpilogue">The context of the epilogue.</param> private void ProcessInstructions(Context ctx, Context ctxEpilogue) { // Current constant operand ConstantOperand co = null; for (; !ctx.EndOfInstruction; ctx.GotoNext()) { // A constant may only appear on the right side of an expression, so we ignore constants in // result - there should never be one there. foreach (Operand op in ctx.Operands) { co = op as ConstantOperand; if (co != null && IsLargeConstant(co)) { // Move the constant out of the code stream and place it right after the code. ctxEpilogue.AppendInstruction(Instruction.LiteralInstruction); ctxEpilogue.LiteralData = new IR.LiteralData(ctx.Label, co.Type, co.Value); op.Replace(((ctxEpilogue.Instruction) as Instructions.LiteralInstruction).CreateOperand(ctxEpilogue), instructionSet); _constantRemoved = true; } } } }
/// <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(); } } }
/// <summary> /// Determines whether [is empty block with single jump] [the specified block]. /// </summary> /// <param name="block">The block.</param> /// <returns> /// <c>true</c> if [is empty block with single jump] [the specified block]; otherwise, <c>false</c>. /// </returns> protected bool IsEmptyBlockWithSingleJump(BasicBlock block) { if (block.NextBlocks.Count != 1) return false; var ctx = new Context(InstructionSet, block); Debug.Assert(ctx.IsBlockStartInstruction); ctx.GotoNext(); while (!ctx.IsBlockEndInstruction) { if (!ctx.IsEmpty) { if (ctx.Instruction.FlowControl != FlowControl.UnconditionalBranch) return false; } ctx.GotoNext(); } return true; }
/// <summary> /// Called to emit a list of instructions offered by the instruction provider. /// </summary> protected virtual void EmitInstructions() { foreach (BasicBlock block in basicBlocks) { BlockStart(block); for (Context context = new Context(instructionSet, block); !context.EndOfInstruction; context.GotoNext()) if (context.Instruction != null) if (!context.Ignore) { IPlatformInstruction instruction = context.Instruction as IPlatformInstruction; if (instruction != null) instruction.Emit(context, codeEmitter); else Trace(InternalTrace.CompilerEvent.Error, "Missing Code Transformation: " + context.ToString()); } BlockEnd(block); } }
/// <summary> /// Eliminates the common subexpressions. /// </summary> /// <param name="ctx">The context.</param> private static void EliminateCommonSubexpressions(Context ctx) { List<AEBinExp> AEB = new List<AEBinExp>(); List<AEBinExp> tmp; AEBinExp aeb; for (; !ctx.EndOfInstruction; ctx.GotoNext()) { IInstruction instruction = ctx.Instruction; // block.Instructions[i]; RegisterOperand temp = null; bool found = false; if ((instruction is CIL.ArithmeticInstruction) && (instruction is CIL.BinaryInstruction)) { tmp = new List<AEBinExp>(AEB); while (tmp.Count > 0) { aeb = tmp[0]; tmp.RemoveAt(0); // Match current instruction's expression against those // in AEB, including commutativity if (IsCommutative(instruction)) { //int position = aeb.Position; found = true; // If no variable in tuple, create a new temporary and // insert an instruction evaluating the expression // and assigning it to the temporary if (aeb.Var == null) { // new_tmp() AEB.Remove(aeb); AEB.Add(new AEBinExp(aeb.Position, aeb.Operand1, aeb.Operator, aeb.Operand2, temp)); // Insert new assignment to instruction stream in block Context inserted = ctx.InsertBefore(); switch (aeb.Operator) { case Operation.Add: inserted.SetInstruction(CIL.Instruction.Get(CIL.OpCode.Add), temp, aeb.Operand1, aeb.Operand2); break; case Operation.Mul: inserted.SetInstruction(CIL.Instruction.Get(CIL.OpCode.Mul), temp, aeb.Operand1, aeb.Operand2); break; case Operation.Or: inserted.SetInstruction(CIL.Instruction.Get(CIL.OpCode.Or), temp, aeb.Operand1, aeb.Operand2); break; case Operation.Xor: inserted.SetInstruction(CIL.Instruction.Get(CIL.OpCode.Xor), temp, aeb.Operand1, aeb.Operand2); break; default: break; } //block.Instructions.Insert(position, inst); //++position; //++i; // Replace current instruction by one that copies // the temporary instruction // FIXME PG: // block.Instructions[position] = new IR.MoveInstruction(block.Instructions[position].Results[0], temp); // ctx.SetInstruction(IR.MoveInstruction); // FIXME PG // ctx.Result = block.Instructions[position].Results[0]; // FIXME PG ctx.Operand1 = temp; } else { temp = (RegisterOperand)aeb.Var; } // FIXME PG // block.Instructions[i] = new IR.MoveInstruction(instruction.Results[0], temp); } } if (!found) { Operation opr = Operation.None; if (instruction is CIL.AddInstruction) opr = Operation.Add; else if (instruction is CIL.MulInstruction) opr = Operation.Mul; else if (instruction is IR.LogicalAndInstruction) opr = Operation.And; // Insert new tuple AEB.Add(new AEBinExp(ctx.Index, ctx.Operand1, opr, ctx.Operand2, null)); } // Remove all tuples that use the variable assigned to by // the current instruction tmp = new List<AEBinExp>(AEB); while (tmp.Count > 0) { aeb = tmp[0]; tmp.RemoveAt(0); if (ctx.Operand1 == aeb.Operand1 || ctx.Operand2 == aeb.Operand2) AEB.Remove(aeb); } } } }
/// <summary> /// Empties the block of all instructions. /// </summary> /// <param name="block">The block.</param> protected void EmptyBlockOfAllInstructions(BasicBlock block) { var ctx = new Context(InstructionSet, block); Debug.Assert(ctx.IsBlockStartInstruction); ctx.GotoNext(); while (!ctx.IsBlockEndInstruction) { if (!ctx.IsEmpty) { ctx.Remove(); } ctx.GotoNext(); } }
/// <summary> /// Logs the instructions in the given enumerable to the trace. /// </summary> /// <param name="ctx">The context.</param> private static void LogInstructions(StringBuilder text, Context ctx) { for (; !ctx.EndOfInstruction; ctx.GotoNext()) { if (ctx.Instruction == null) continue; if (ctx.Ignore) text.Append("; "); if (ctx.Marked) text.AppendFormat("L_{0:X4}* {1}", ctx.Label, ctx.Instruction.ToString(ctx)); else text.AppendFormat("L_{0:X4}: {1}", ctx.Label, ctx.Instruction.ToString(ctx)); text.AppendLine(); } }
private void NumberInstructions() { int index = 2; foreach (BasicBlock block in basicBlocks) { for (Context context = new Context(methodCompiler.InstructionSet, block); !context.EndOfInstruction; context.GotoNext()) { if (!context.IsEmpty) { instructionNumbering[context.Index] = index; index = index + 2; } } } }
private IEnumerable<Context> ScanForOperatorNew() { foreach (BasicBlock block in this.basicBlocks) { Context context = new Context(instructionSet, block); while (!context.EndOfInstruction) { if (context.Instruction is NewobjInstruction || context.Instruction is NewarrInstruction) { Debug.WriteLine(@"StaticAllocationResolutionStage: Found a newobj or newarr instruction."); yield return context.Clone(); } context.GotoNext(); } } }
/// <summary> /// Updates the prologue. /// </summary> private void UpdatePrologue() { // Update prologue Block var prologueBlock = this.BasicBlocks.PrologueBlock; if (prologueBlock != null) { Context prologueContext = new Context(InstructionSet, prologueBlock); prologueContext.GotoNext(); Debug.Assert(prologueContext.Instruction is Prologue); AddPrologueInstructions(prologueContext); } }
/// <summary> /// Updates the epilogue. /// </summary> private void UpdateEpilogue() { // Update epilogue Block var epilogueBlock = this.BasicBlocks.EpilogueBlock; if (epilogueBlock != null) { Context epilogueContext = new Context(InstructionSet, epilogueBlock); epilogueContext.GotoNext(); while (epilogueContext.IsEmpty) { epilogueContext.GotoNext(); } Debug.Assert(epilogueContext.Instruction is Epilogue); AddEpilogueInstructions(epilogueContext); } }
/// <summary> /// Collects all local variables assignments into a list. /// </summary> /// <param name="locals">Holds all locals found by the stage.</param> /// <param name="block">The block.</param> private void CollectLocalVariables(List<StackOperand> locals, BasicBlock block) { for (Context ctx = new Context(instructionSet, block); !ctx.EndOfInstruction; ctx.GotoNext()) { // Does this instruction define a new stack variable? foreach (Operand op in ctx.Results) { // The instruction list may not be in SSA form, so we have to check existence again here unfortunately. // FIXME: Allow us to detect the state of blocks LocalVariableOperand lvop = op as LocalVariableOperand; if (lvop != null && !locals.Contains(lvop)) locals.Add(lvop); } } }
/// <summary> /// Logs the instructions in the given enumerable to the trace. /// </summary> /// <param name="ctx">The context.</param> private static void LogInstructions(StringBuilder text, Context ctx) { for (; ctx.Index >= 0; ctx.GotoNext()) { if (ctx.IsEmpty) continue; text.AppendFormat("L_{0:X4}", ctx.Label); if (ctx.Marked) text.AppendFormat("*"); else text.AppendFormat(" "); //if (ctx.SlotNumber != 0) // text.AppendFormat("/{0}", ctx.SlotNumber.ToString()); text.AppendFormat("{0}", ctx.Instruction.ToString(ctx)); text.AppendLine(); if (ctx.IsBlockEndInstruction) return; } }
/// <summary> /// Dumps this instance. /// </summary> protected void Dump(bool before) { Debug.WriteLine(string.Empty); Debug.WriteLine("METHOD: " + MethodCompiler.Method.FullName); Debug.WriteLine("STAGE : " + (before ? "[BEFORE] " : "[AFTER] ") + GetType().Name); Debug.WriteLine(string.Empty); for (int index = 0; index < BasicBlocks.Count; index++) for (Context ctx = new Context(BasicBlocks[index]); !ctx.IsBlockEndInstruction; ctx.GotoNext()) if (!ctx.IsEmpty) Debug.WriteLine(ctx.ToString()); }
/// <summary> /// Assigns the operands. /// </summary> /// <param name="block">The block.</param> /// <param name="operandStack">The operand stack.</param> private void AssignOperands(BasicBlock block, Stack<Operand> operandStack) { for (var ctx = new Context(instructionSet, block); !ctx.EndOfInstruction; ctx.GotoNext()) { if (ctx.Instruction == null) continue; if (ctx.Instruction is IR.JmpInstruction) continue; if (!(ctx.Instruction is IBranchInstruction) && !(ctx.Instruction is ICILInstruction) && !(ctx.Instruction is IR.ExceptionPrologueInstruction)) continue; if (ctx.Instruction is IR.ExceptionPrologueInstruction) { AssignOperandsFromCILStack(ctx, operandStack); PushResultOperands(ctx, operandStack); } else //if (!(ctx.Instruction is IR.JmpInstruction)) { AssignOperandsFromCILStack(ctx, operandStack); (ctx.Instruction as ICILInstruction).Validate(ctx, methodCompiler); PushResultOperands(ctx, operandStack); } } }
/// <summary> /// Dumps this instance. /// </summary> protected void Dump(bool before) { Debug.WriteLine(string.Empty); Debug.WriteLine("METHOD: " + MethodCompiler.Method.FullName); Debug.WriteLine("STAGE : " + (before ? "[BEFORE] " : "[AFTER] ") + GetType().Name); Debug.WriteLine(string.Empty); for (int index = 0; index < BasicBlocks.Count; index++) { for (Context ctx = new Context(BasicBlocks[index]); !ctx.IsBlockEndInstruction; ctx.GotoNext()) { if (!ctx.IsEmpty) { Debug.WriteLine(ctx.ToString()); } } } }
/// <summary> /// Creates the outgoing moves. /// </summary> /// <param name="block">The block.</param> /// <param name="operandStack">The operand stack.</param> /// <param name="joinStack">The join stack.</param> private void CreateOutgoingMoves(BasicBlock block, Stack<Operand> operandStack, Stack<Operand> joinStack) { var context = new Context(instructionSet, block); while (!context.EndOfInstruction && !(context.Instruction is IBranchInstruction)) { context.GotoNext(); } while (operandStack.Count > 0) { var operand = operandStack.Pop(); var destination = joinStack.Pop(); context.InsertBefore().SetInstruction(IR.Instruction.MoveInstruction, destination, operand); } }