private void PostProcessDependencies(ICollection <IStatement> outputs)
 {
     if (replacements.Count > 0)
     {
         // contexts are bodies of innermost while statements
         DeadCodeTransform.ForEachStatement(outputs,
                                            delegate(IWhileStatement iws)
         {
         },
                                            delegate(IWhileStatement iws)
         {
         },
                                            _ =>
         {
         },
                                            _ =>
         {
         },
                                            delegate(IStatement ist)
         {
             if (replacements != null)
             {
                 DependencyInformation di = context.InputAttributes.Get <DependencyInformation>(ist);
                 if (di != null)
                 {
                     // must make a clone since this statement may appear in multiple contexts
                     DependencyInformation di2 = (DependencyInformation)di.Clone();
                     di2.Replace(replacements);
                     context.OutputAttributes.Remove <DependencyInformation>(ist);
                     context.OutputAttributes.Set(ist, di2);
                 }
             }
         });
     }
 }
        public DependencyGraph2(BasicTransformContext context,
                                IEnumerable <IStatement> inputs,
                                BackEdgeHandling backEdgeHandling,
                                Action <IWhileStatement> beginWhile,
                                Action <IWhileStatement> endWhile,
                                Action <IConditionStatement> beginFirstIterPost,
                                Action <IConditionStatement> endFirstIterPost,
                                Action <IStatement, NodeIndex> action)
        {
            Set <NodeIndex> nodesInCurrentWhile = new Set <EdgeIndex>();
            int             whileDepth          = 0;

            // create a dependency graph where while loops are flattened (the while loops themselves are not nodes)
            // the graph will only contain read-after-write and write-after-alloc dependencies for now
            // add write-after-read dependencies
            isWriteAfterRead = dependencyGraph.CreateEdgeData(false);
            DeadCodeTransform.ForEachStatement(inputs,
                                               delegate(IWhileStatement iws)
            {
                beginWhile(iws);
                nodesInCurrentWhile.Clear();
                whileDepth++;
            },
                                               delegate(IWhileStatement iws)
            {
                // all duplicates in a while loop should share all targets
                foreach (KeyValuePair <IStatement, Set <NodeIndex> > entry in duplicates)
                {
                    IStatement ist          = entry.Key;
                    Set <NodeIndex> set     = entry.Value;
                    Set <NodeIndex> targets = new Set <EdgeIndex>();
                    // collect all targets in the while loop
                    foreach (NodeIndex node in set)
                    {
                        foreach (NodeIndex target in dependencyGraph.TargetsOf(node))
                        {
                            if (nodesInCurrentWhile.Contains(target))
                            {
                                targets.Add(target);
                            }
                        }
                    }
                    Set <NodeIndex> backEdgeTargets = null;
                    if (!backEdges.TryGetValue(ist, out backEdgeTargets))
                    {
                        backEdgeTargets = new Set <EdgeIndex>();
                        backEdges[ist]  = backEdgeTargets;
                    }
                    // add all targets to all duplicates in the loop
                    foreach (NodeIndex node in set)
                    {
                        if (!nodesInCurrentWhile.Contains(node))
                        {
                            continue;
                        }
                        foreach (NodeIndex target in targets)
                        {
                            if (!dependencyGraph.ContainsEdge(node, target))
                            {
                                if (backEdgeHandling == BackEdgeHandling.Include)
                                {
                                    dependencyGraph.AddEdge(node, target);
                                }
                                else if (backEdgeHandling == BackEdgeHandling.Reverse)
                                {
                                    if (!dependencyGraph.ContainsEdge(target, node))
                                    {
                                        dependencyGraph.AddEdge(target, node);
                                    }
                                }
                                if (target < node)
                                {
                                    if (backEdgeTargets == null && !backEdges.TryGetValue(ist, out backEdgeTargets))
                                    {
                                        backEdgeTargets = new Set <EdgeIndex>();
                                        backEdges[ist]  = backEdgeTargets;
                                    }
                                    backEdgeTargets.Add(target);
                                }
                            }
                        }
                    }
                }
                endWhile(iws);
                whileDepth--;
            },
                                               beginFirstIterPost,
                                               endFirstIterPost,
                                               delegate(IStatement ist)
            {
                DependencyInformation di = context.InputAttributes.Get <DependencyInformation>(ist);
                if (di == null)
                {
                    context.Error("Dependency information not found for statement: " + ist);
                    di = new DependencyInformation();
                }
                NodeIndex targetIndex = dependencyGraph.AddNode();
                Set <NodeIndex> backEdgeTargets;
                Set <NodeIndex> sources = new Set <NodeIndex>();                                  // for fast checking of duplicate sources
                foreach (IStatement source in
                         di.GetDependenciesOfType(DependencyType.Dependency | DependencyType.Declaration))
                {
                    int sourceIndex;
                    // we assume that the statements are already ordered properly to respect dependencies.
                    // if the source is not in indexOfNode, then it must be a cyclic dependency in this while loop.
                    if (indexOfNode.TryGetValue(source, out sourceIndex))
                    {
                        if (!sources.Contains(sourceIndex))
                        {
                            sources.Add(sourceIndex);
                            EdgeIndex edge = dependencyGraph.AddEdge(sourceIndex, targetIndex);
                        }
                    }
                    else
                    {
                        sourceIndex = -1;
                    }
                    if (sourceIndex == -1)
                    {
                        // add a back edge
                        if (!backEdges.TryGetValue(source, out backEdgeTargets))
                        {
                            backEdgeTargets   = new Set <EdgeIndex>();
                            backEdges[source] = backEdgeTargets;
                        }
                        backEdgeTargets.Add(targetIndex);
                        // add a dependency on the initializers of source
                        Stack <IStatement> todo = new Stack <IStatement>();
                        todo.Push(source);
                        while (todo.Count > 0)
                        {
                            IStatement source2        = todo.Pop();
                            DependencyInformation di2 = context.InputAttributes.Get <DependencyInformation>(source2);
                            if (di2 == null)
                            {
                                context.Error("Dependency information not found for statement: " + source2);
                                continue;
                            }
                            foreach (IStatement init in di2.Overwrites)
                            {
                                int initIndex;
                                if (indexOfNode.TryGetValue(init, out initIndex))
                                {
                                    if (!sources.Contains(initIndex))
                                    {
                                        sources.Add(initIndex);
                                        EdgeIndex edge = dependencyGraph.AddEdge(initIndex, targetIndex);
                                    }
                                }
                                else
                                {
                                    todo.Push(init);
                                }
                            }
                        }
                    }
                }
                if (indexOfNode.ContainsKey(ist))
                {
                    Set <int> set;
                    if (!duplicates.TryGetValue(ist, out set))
                    {
                        set             = new Set <int>();
                        duplicates[ist] = set;
                        set.Add(indexOfNode[ist]);
                    }
                    set.Add(targetIndex);
                }
                // the same statement may appear multiple times.  when looking up indexOfNode, we want to use the last occurrence of the statement.
                indexOfNode[ist] = targetIndex;                                    // must do this at the end, in case the stmt depends on a previous occurrence of itself
                nodesInCurrentWhile.Add(targetIndex);
                nodes.Add(ist);
                if (backEdgeHandling != BackEdgeHandling.Ignore && backEdges.TryGetValue(ist, out backEdgeTargets))
                {
                    // now that ist has an index, we can fill in the back edges
                    foreach (NodeIndex node in backEdgeTargets)
                    {
                        if (backEdgeHandling == BackEdgeHandling.Include)
                        {
                            if (dependencyGraph.ContainsEdge(targetIndex, node))
                            {
                                throw new Exception("Internal: back edge already present");
                            }
                            dependencyGraph.AddEdge(targetIndex, node);
                        }
                        else
                        {
                            // make a new edge, even if one exists.
                            EdgeIndex edge         = dependencyGraph.AddEdge(node, targetIndex);
                            isWriteAfterRead[edge] = true;
                        }
                    }
                }
                action(ist, targetIndex);
            });
            if (string.Empty.Length > 0)
            {
                // loop statements in their original order
                foreach (NodeIndex target in dependencyGraph.Nodes)
                {
                    IStatement ist = nodes[target];
                    if (ist is IWhileStatement)
                    {
                        continue;
                    }
                    foreach (NodeIndex source in GetPreviousReaders(context, dependencyGraph, target, nodes, indexOfNode).ToReadOnlyList())
                    {
                        if (source > target)
                        {
                            throw new Exception("Internal: source statement follows target");
                        }
                        // make a new edge, even if one exists.
                        EdgeIndex edge = dependencyGraph.AddEdge(source, target);
                        isWriteAfterRead[edge] = true;
                    }
                }
            }
            isWriteAfterWrite = dependencyGraph.CreateEdgeData(false);
            // loop statements in their original order
            foreach (NodeIndex target in dependencyGraph.Nodes)
            {
                IStatement ist = nodes[target];
                if (ist is IWhileStatement)
                {
                    continue;
                }

                foreach (NodeIndex source in GetOverwrites(context, dependencyGraph, target, nodes, indexOfNode).ToReadOnlyList())
                {
                    if (source > target)
                    {
                        throw new Exception("Internal: source statement follows target");
                    }
                    if (dependencyGraph.ContainsEdge(source, target))
                    {
                        foreach (EdgeIndex edge in dependencyGraph.EdgesLinking(source, target))
                        {
                            isWriteAfterWrite[edge] = true;
                        }
                    }
                    else
                    {
                        EdgeIndex edge = dependencyGraph.AddEdge(source, target);
                        isWriteAfterWrite[edge] = true;
                    }
                }
            }

            dependencyGraph.NodeCountIsConstant = true;
            dependencyGraph.IsReadOnly          = true;
            for (int targetIndex = 0; targetIndex < dependencyGraph.Nodes.Count; targetIndex++)
            {
                IStatement            ist = nodes[targetIndex];
                DependencyInformation di  = context.InputAttributes.Get <DependencyInformation>(ist);
                if (di == null)
                {
                    continue;
                }
                if (di.IsOutput)
                {
                    outputNodes.Add(targetIndex);
                }
            }
        }
        /// <summary>
        /// Update the dependency information of all statements, assuming that the original statements have been permuted and duplicated, but not transformed.
        /// </summary>
        /// <param name="outputs"></param>
        private void PostProcessDependencies(ICollection <IStatement> outputs)
        {
            Dictionary <IStatement, int> indexOfStatement = new Dictionary <IStatement, NodeIndex>(ReferenceEqualityComparer <IStatement> .Instance);

            if (clonesOfStatement.Count == 0)
            {
                return;
            }
            DeadCodeTransform.ForEachStatement(outputs,
                                               _ => { },
                                               _ => { },
                                               _ => { },
                                               _ => { },
                                               ist =>
            {
                DependencyInformation di = context.InputAttributes.Get <DependencyInformation>(ist);
                if (di != null)
                {
                    // must make a clone since this statement may appear in multiple contexts
                    DependencyInformation di2 = (DependencyInformation)di.Clone();
                    di2.AddClones(clonesOfStatement);
                    IStatement originalStatement;
                    originalStatementOfClone.TryGetValue(ist, out originalStatement);
                    // originalStatement is non-null iff ist is a clone
                    IEnumerable <IStatement> clones;
                    if (clonesOfStatement.TryGetValue(originalStatement ?? ist, out clones))
                    {
                        // clones become Overwrites
                        foreach (var clone in clones)
                        {
                            di2.Add(DependencyType.Overwrite, clone);
                        }
                        if (originalStatement != null)
                        {
                            di2.Add(DependencyType.Overwrite, originalStatement);
                        }
                    }
                    // keep only the most recent overwrite that is not an allocation, and all overwrites that are allocations.
                    IStatement mostRecentWriter   = null;
                    int mostRecentWriterIndex     = 0;
                    List <IStatement> allocations = new List <IStatement>();
                    foreach (var writer in di2.Overwrites)
                    {
                        int index;
                        indexOfStatement.TryGetValue(writer, out index);
                        if (index > mostRecentWriterIndex)
                        {
                            mostRecentWriterIndex = index;
                            mostRecentWriter      = writer;
                        }
                        if (di2.HasDependency(DependencyType.Declaration, writer))
                        {
                            allocations.Add(writer);
                        }
                    }
                    di2.Remove(DependencyType.Overwrite);
                    // all allocations must remain as Overwrites
                    foreach (var dep in allocations)
                    {
                        di2.Add(DependencyType.Overwrite, dep);
                    }
                    if (mostRecentWriter != null)
                    {
                        di2.Add(DependencyType.Overwrite, mostRecentWriter);
                    }
                    context.OutputAttributes.Remove <DependencyInformation>(ist);
                    context.OutputAttributes.Set(ist, di2);
                }
                indexOfStatement[ist] = indexOfStatement.Count + 1;
            });
        }
        protected override IStatement ConvertWhile(IWhileStatement iws)
        {
            bool wasInWhileLoop = this.inWhileLoop;

            if (!wasInWhileLoop)
            {
                // collect all statements in the body of this loop (and any nested loops).
                DeadCodeTransform.ForEachStatement(iws.Body.Statements,
                                                   _ =>
                {
                }, _ =>
                {
                },
                                                   _ =>
                {
                }, _ =>
                {
                },
                                                   ist =>
                {
                    visitedStatements.Add(ist);
                });
                // collect all IncrementStatement attributes in the body of this loop (and any nested loops).
                DeadCodeTransform.ForEachStatement(iws.Body.Statements,
                                                   _ =>
                {
                }, _ =>
                {
                },
                                                   _ =>
                {
                }, _ =>
                {
                },
                                                   ist =>
                {
                    var incrementStatement = context.GetAttribute <IncrementStatement>(ist);
                    if (incrementStatement != null)
                    {
                        DependencyInformation di = context.GetAttribute <DependencyInformation>(ist);
                        if (di != null && !di.GetDependenciesOfType(DependencyType.Cancels).All(visitedStatements.Contains))
                        {
                            // Remove increment statements whose Cancels input is not available, implying that there is no purpose in carrying out the increment.
                            // This happens because IterationTransform ignores Cancels edges.
                            replacements[ist] = null;
                        }
                        else
                        {
                            incrementStatements.Add(incrementStatement);
                        }
                    }
                });
                ancestorIndexOfWhile = context.Depth - 1;
            }
            this.inWhileLoop = true;
            var ws = base.ConvertWhile(iws);

            this.inWhileLoop = wasInWhileLoop;
            if (!wasInWhileLoop)
            {
                incrementStatements.Clear();
            }
            return(ws);
        }