void IMethodCompilerStage.Run() { if (AreExceptions) return; foreach (var block in this.basicBlocks) if (block.NextBlocks.Count == 0 && block.PreviousBlocks.Count == 0) return; this.dominanceCalculationStage = this.methodCompiler.Pipeline.FindFirst<DominanceCalculationStage>() as IDominanceProvider; this.phiPlacementStage = this.methodCompiler.Pipeline.FindFirst<PhiPlacementStage>(); var numberOfParameters = this.methodCompiler.Method.Parameters.Count; if (this.methodCompiler.Method.Signature.HasThis) ++numberOfParameters; foreach (var name in this.phiPlacementStage.Assignments.Keys) this.variableInformation[name] = new VariableInformation(); for (var i = 0; i < numberOfParameters; ++i) { var op = this.methodCompiler.GetParameterOperand(i); var name = NameForOperand(op); this.variableInformation[name].Stack.Push(0); this.variableInformation[name].Count = 1; } for (var i = 0; methodCompiler.LocalVariables != null && i < methodCompiler.LocalVariables.Length; ++i) { var op = methodCompiler.LocalVariables[i]; var name = NameForOperand(op); if (!this.variableInformation.ContainsKey(name)) this.variableInformation[name] = new VariableInformation(); this.variableInformation[name].Stack.Push(0); this.variableInformation[name].Count = 1; } this.RenameVariables(this.FindBlock(-1).NextBlocks[0]); Debug.WriteLine("ESSA: " + this.methodCompiler.Method.FullName); }
/// <summary> /// Enters the SSA. /// </summary> /// <param name="headBlock">The head block.</param> private void EnterSSA(BasicBlock headBlock) { dominanceCalculation = methodCompiler.Pipeline.FindFirst<DominanceCalculationStage>().GetDominanceProvider(headBlock); variables = new Dictionary<Operand, Stack<int>>(); counts = new Dictionary<Operand, int>(); foreach (var op in phiPlacementStage.Assignments.Keys) { AddToAssignments(op); } foreach (var op in methodCompiler.Parameters) { AddToAssignments(op); } if (methodCompiler.LocalVariables != null) { foreach (var op in methodCompiler.LocalVariables) { if (op.Uses.Count != 0) { AddToAssignments(op); } } } if (headBlock.NextBlocks.Count > 0) { RenameVariables(headBlock.NextBlocks[0]); } // Clean up dominanceCalculation = null; variables = null; counts = null; }
/// <summary> /// Renames the variables. /// </summary> /// <param name="block">The block.</param> /// <param name="dominanceCalculation">The dominance calculation.</param> /// <param name="variables">The variables.</param> private void RenameVariables(BasicBlock block, IDominanceProvider dominanceCalculation, Dictionary<Operand, Stack<int>> variables) { for (var context = new Context(instructionSet, block); !context.EndOfInstruction; context.GotoNext()) { if (!(context.Instruction is Phi)) { for (var i = 0; i < context.OperandCount; ++i) { var op = context.GetOperand(i); if (!(op is StackOperand)) continue; if (!variables.ContainsKey(op)) throw new Exception(op.ToString() + " is not in dictionary [block = " + block + "]"); var index = variables[op].Peek(); context.SetOperand(i, CreateSsaOperand(context.GetOperand(i), index)); } } if (PhiPlacementStage.IsAssignmentToStackVariable(context)) { var op = context.Result; var index = variables[op].Count; context.SetResult(CreateSsaOperand(op, index)); variables[op].Push(index); } } foreach (var s in block.NextBlocks) { var j = WhichPredecessor(s, block); for (var context = new Context(instructionSet, s); !context.EndOfInstruction; context.GotoNext()) { if (!(context.Instruction is Phi)) continue; var op = context.GetOperand(j); if (variables[op].Count > 0) { var index = variables[op].Peek(); context.SetOperand(j, CreateSsaOperand(context.GetOperand(j), index)); } } } foreach (var s in dominanceCalculation.GetChildren(block)) { RenameVariables(s, dominanceCalculation, variables); } }
internal static void Dump(BasicBlocks basicBlocks, IDominanceProvider provider) { foreach (var b in basicBlocks) { Console.WriteLine(b.ToString() + " -> " + provider.GetImmediateDominator(b)); } Console.WriteLine(); foreach (var b in basicBlocks) { Console.Write(b.ToString() + " -> "); foreach (var d in provider.GetDominators(b)) Console.Write(d.ToString() + " "); Console.WriteLine(); } return; }
/// <summary> /// Performs stage specific processing on the compiler context. /// </summary> public void Run() { _dominanceProvider = (IDominanceProvider)MethodCompiler.GetPreviousStage(typeof(IDominanceProvider)); Debug.Assert(_dominanceProvider != null, "SSA Conversion requires a dominance provider."); if (_dominanceProvider == null) { throw new InvalidOperationException("SSA Conversion requires a dominance provider."); } // Allocate space for live outs _liveness = new IDictionary <StackOperand, StackOperand> [BasicBlocks.Count]; // Retrieve the dominance frontier Blocks _dominanceFrontierBlocks = _dominanceProvider.GetDominanceFrontier(); // Add ref/out parameters to the epilogue block to have uses there... AddPhiFunctionsForOutParameters(); // Transformation worklist Queue <WorkItem> workList = new Queue <WorkItem> (); /* Move parameter operands into the dictionary as version 0, * because they are live at entry and maybe referenced. Anyways, an * assignment to a parameter is also SSA related. */ IDictionary <StackOperand, StackOperand> liveIn = new Dictionary <StackOperand, StackOperand> (s_comparer); int i = 0; if (MethodCompiler.Method.Signature.HasThis) { StackOperand param = (StackOperand)MethodCompiler.GetParameterOperand(0); liveIn.Add(param, param); i++; } for (int j = 0; j < MethodCompiler.Method.Parameters.Count; j++) { StackOperand param = (StackOperand)MethodCompiler.GetParameterOperand(i + j); liveIn.Add(param, param); } // Start with the very first block workList.Enqueue(new WorkItem(BasicBlocks[0], null, liveIn)); // Iterate until the worklist is empty while (workList.Count != 0) { // Remove the block From the queue WorkItem workItem = workList.Dequeue(); // Transform the block BasicBlock block = workItem.block; bool schedule = TransformToSsaForm(new Context(InstructionSet, block), workItem.caller, workItem.liveIn, out liveIn); _liveness[block.Sequence] = liveIn; if (schedule) { // Add all branch targets to the work list foreach (BasicBlock next in block.NextBlocks) { // Only follow backward branches, if we've redefined a variable // this may force us to reinsert a PHI function in a block we // already have completed processing on. workList.Enqueue(new WorkItem(next, block, liveIn)); } } } }