private static Dictionary <Node, ICollection <ILAssignmentStatement> > InsertPhiNodes(ILCompilationUnit unit) { var result = unit.ControlFlowGraph.Nodes.ToDictionary( x => x, x => (ICollection <ILAssignmentStatement>) new List <ILAssignmentStatement>()); // We try to find all variables that have more than one assignment, and therefore have multiple // versions of it during execution of the program. This is only a problem when they have different // values at join nodes, as depicted below. We therefore need to get to the dominance frontier of // those nodes and insert phi nodes there. // // [ x1 <- value1 ] [ x2 <- value2 ] // | | // '------------+-----------' // | // [ x3 <- phi(x1, x2) ] // // Collect all nodes that contain a variable assignment (i.e. a new definition). var variableBlocks = unit.Variables.ToDictionary( x => x, x => new HashSet <Node>(x.AssignedBy.Select(a => a.GetParentNode()))); foreach (var variable in unit.Variables.Where(x => x.AssignedBy.Count > 1 || // If the variable has more than one definition GetNodesReferencingVariable(x).Count() > 1) // Or is used in multiple nodes. ) { var agenda = new Queue <Node>(variableBlocks[variable]); while (agenda.Count > 0) { var current = agenda.Dequeue(); foreach (var frontierNode in unit.DominatorInfo.GetDominanceFrontier(current)) { // If the frontier node does not define a phi node already for this variable, we need to add it. if (result[frontierNode].All(x => x.Variable != variable)) { // Check if the variable is defined in the frontier node. bool defined = variableBlocks[variable].Contains(frontierNode); // Build phi node. // The number of different versions of the variable is equal to the amount of predecessors. var phiExpression = new ILPhiExpression(Enumerable .Repeat(variable, frontierNode.InDegree) .Select(v => new ILVariableExpression(v))); var phiNode = new ILAssignmentStatement(variable, phiExpression); // Insert at top of the current block. var block = (ILAstBlock)frontierNode.UserData[ILAstBlock.AstBlockProperty]; block.Statements.Insert(0, phiNode); // Register phi node. result[frontierNode].Add(phiNode); // We might have to check this node again if we introduce a new version of this variable // at this node. if (!defined) { agenda.Enqueue(frontierNode); } } } } } return(result); }
public virtual bool VisitPhiExpression(ILPhiExpression expression) { return(false); }
public string VisitPhiExpression(ILPhiExpression expression) => "phi";
public void VisitPhiExpression(ILPhiExpression expression) { }