Example #1
0
        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);
        }
Example #2
0
 public virtual bool VisitPhiExpression(ILPhiExpression expression)
 {
     return(false);
 }
Example #3
0
 public string VisitPhiExpression(ILPhiExpression expression) => "phi";
Example #4
0
 public void VisitPhiExpression(ILPhiExpression expression)
 {
 }