public void InheritSourceConflicts(NodeIndex newNode, NodeIndex oldNode) { foreach (EdgeIndex edge in graph.EdgesInto(oldNode).ToArray()) { int source = graph.SourceOf(edge); EdgeIndex edge2 = graph.AddEdge(source, newNode); prohibitedLoopVars[edge2] = prohibitedLoopVars[edge]; offsetInfos[edge2] = offsetInfos[edge]; } }
/// <summary> /// Analyse equality constraints, which appear as static method calls to Constrain.Equal /// </summary> /// <param name="imie"></param> /// <returns></returns> protected override IExpression ConvertMethodInvoke(IMethodInvokeExpression imie) { // If this is a constrain equal, then we will add the equality to the equality map. if (Recognizer.IsStaticGenericMethod(imie, new Action <PlaceHolder, PlaceHolder>(Constrain.Equal <PlaceHolder>))) { int node0 = CreateNodeAndEdges(imie.Arguments[0]); int node1 = CreateNodeAndEdges(imie.Arguments[1]); graph.AddEdge(node0, node1); graph.AddEdge(node1, node0); } return(base.ConvertMethodInvoke(imie)); }
public void IndexedGraphTest() { IndexedGraph g = new IndexedGraph(); int a = g.AddNode(); int b = g.AddNode(); int c = g.AddNode(); int ab = g.AddEdge(a, b); int bb = g.AddEdge(b, b); // self loop int bc = g.AddEdge(b, c); int bc2 = g.AddEdge(b, c); // double edge Assert.Equal(c, g.TargetOf(bc)); Assert.Equal(bb, g.GetEdge(b, b)); Assert.Equal(0, g.EdgeCount(a, c)); Assert.Equal(2, g.EdgeCount(b, c)); Assert.Equal(4, g.EdgeCount()); Assert.Equal(1, g.NeighborCount(a)); Assert.Equal(2, g.NeighborCount(c)); Assert.Equal(1, g.TargetCount(a)); Assert.Equal(0, g.SourceCount(a)); Console.Write("EdgesOf(b):"); foreach (int edge in g.EdgesOf(b)) { Console.Write(" {0}", edge); } Console.WriteLine(); Console.Write("EdgesInto(b):"); foreach (int edge in g.EdgesInto(b)) { Console.Write(" {0}", edge); } Console.WriteLine(); Console.Write("EdgesOutOf(b):"); foreach (int edge in g.EdgesOutOf(b)) { Console.Write(" {0}", edge); } Console.WriteLine(); Console.Write("EdgesLinking(b,c):"); foreach (int edge in g.EdgesLinking(b, c)) { Console.Write(" {0}", edge); } Console.WriteLine(); }
protected override IExpression ConvertMethodInvoke(IMethodInvokeExpression imie) { if (imie.Method.Target is IThisReferenceExpression) { IMethodDeclaration imd = context.FindAncestor <IMethodDeclaration>(); int sourceMethod = GetMethodIndex(imd); int targetMethod = GetMethodIndex(imie.Method.Method); MethodGraph.AddEdge(sourceMethod, targetMethod); //Trace.WriteLine($"{sourceMethod} {methods[sourceMethod].Name} called {targetMethod} {methods[targetMethod].Name}"); } return(base.ConvertMethodInvoke(imie)); }
public void GroupGraphTest() { IndexedGraph g = new IndexedGraph(2); g.AddEdge(1, 0); int[] groupOf = new int[] { -1, 2, -1 }; GroupGraph groupGraph = new GroupGraph(g, groupOf, g.Nodes.Count); groupGraph.BuildGroupEdges(); var schedule = groupGraph.GetScheduleWithGroups(groupGraph.SourcesOf); Assert.True(schedule[0] == 1); Assert.True(schedule[1] == 0); }
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); } } }
protected override void DoConvertMethodBody(IList <IStatement> outputs, IList <IStatement> inputs) { List <int> whileNumberOfNode = new List <int>(); List <int> fusedCountOfNode = new List <int>(); List <List <IStatement> > containersOfNode = new List <List <IStatement> >(); // the code may have multiple while(true) loops, however these must be disjoint. // therefore we treat 'while' as one container, but give each loop a different 'while number'. int outerWhileCount = 0; int currentOuterWhileNumber = 0; int currentFusedCount = 0; List <Set <IVariableDeclaration> > loopVarsOfWhileNumber = new List <Set <IVariableDeclaration> >(); // build the dependency graph var g = new DependencyGraph2(context, inputs, DependencyGraph2.BackEdgeHandling.Ignore, delegate(IWhileStatement iws) { if (iws is IFusedBlockStatement) { if (iws.Condition is IVariableReferenceExpression) { currentFusedCount++; } } else { outerWhileCount++; currentOuterWhileNumber = outerWhileCount; } }, delegate(IWhileStatement iws) { if (iws is IFusedBlockStatement) { if (iws.Condition is IVariableReferenceExpression) { currentFusedCount--; } } else { currentOuterWhileNumber = 0; } }, delegate(IConditionStatement ics) { }, delegate(IConditionStatement ics) { }, delegate(IStatement ist, int targetIndex) { int whileNumber = currentOuterWhileNumber; whileNumberOfNode.Add(whileNumber); fusedCountOfNode.Add(currentFusedCount); List <IStatement> containers = new List <IStatement>(); LoopMergingTransform.UnwrapStatement(ist, containers); containersOfNode.Add(containers); for (int i = 0; i < currentFusedCount; i++) { if (containers[i] is IForStatement ifs) { var loopVar = Recognizer.LoopVariable(ifs); if (loopVarsOfWhileNumber.Count <= whileNumber) { while (loopVarsOfWhileNumber.Count <= whileNumber) { loopVarsOfWhileNumber.Add(new Set <IVariableDeclaration>()); } } Set <IVariableDeclaration> loopVars = loopVarsOfWhileNumber[whileNumber]; loopVars.Add(loopVar); } } }); var nodes = g.nodes; var dependencyGraph = g.dependencyGraph; for (int whileNumber = 1; whileNumber < loopVarsOfWhileNumber.Count; whileNumber++) { foreach (var loopVar in loopVarsOfWhileNumber[whileNumber]) { // Any statement (in the while loop) that has a forward descendant and a backward descendant will be cloned, so we want to minimize the number of such nodes. // The free variables in this problem are the loop directions at the leaf statements, since all other loop directions are forced by these. // We find the optimal labeling of the free variables by solving a min cut problem on a special network. // The network is constructed so that the cost of a cut is equal to the number of statements that will be cloned. // The network has 2 nodes for every statement: an in-node and an out-node. // For a non-leaf statement, there is a capacity 1 edge from the in-node to out-node. This edge is cut when the statement is cloned. // For a leaf statement, there is an infinite capacity edge in both directions, or equivalently a single node. // If statement A depends on statement B, then there is an infinite capacity edge from in-A to in-B, and from out-B to out-A, // representing the fact that cloning A requires cloning B, but not the reverse. // If a statement must appear with a forward loop, it is connected to the source. // If a statement must appear with a backward loop, it is connected to the sink. // construct a capacitated graph int inNodeStart = 0; int outNodeStart = inNodeStart + dependencyGraph.Nodes.Count; int sourceNode = outNodeStart + dependencyGraph.Nodes.Count; int sinkNode = sourceNode + 1; int cutNodeCount = sinkNode + 1; Func <NodeIndex, int> getInNode = node => node + inNodeStart; Func <NodeIndex, int> getOutNode = node => node + outNodeStart; IndexedGraph network = new IndexedGraph(cutNodeCount); const float infinity = 1000000f; List <float> capacity = new List <float>(); List <NodeIndex> nodesOfInterest = new List <NodeIndex>(); foreach (var node in dependencyGraph.Nodes) { if (whileNumberOfNode[node] != whileNumber) { continue; } NodeIndex source = node; List <IStatement> containersOfSource = containersOfNode[source]; bool hasLoopVar = containersOfSource.Any(container => container is IForStatement && Recognizer.LoopVariable((IForStatement)container) == loopVar); if (!hasLoopVar) { continue; } nodesOfInterest.Add(node); IStatement sourceSt = nodes[source]; var readAfterWriteEdges = dependencyGraph.EdgesOutOf(source).Where(edge => !g.isWriteAfterRead[edge]); bool isLeaf = true; int inNode = getInNode(node); int outNode = getOutNode(node); foreach (var target in readAfterWriteEdges.Select(dependencyGraph.TargetOf)) { List <IStatement> containersOfTarget = containersOfNode[target]; IStatement targetSt = nodes[target]; ForEachMatchingLoopVariable(containersOfSource, containersOfTarget, (loopVar2, afs, bfs) => { if (loopVar2 == loopVar) { int inTarget = getInNode(target); int outTarget = getOutNode(target); network.AddEdge(inTarget, inNode); capacity.Add(infinity); network.AddEdge(outNode, outTarget); capacity.Add(infinity); isLeaf = false; } }); } if (isLeaf) { if (debug) { log.Add($"loopVar={loopVar.Name} leaf {sourceSt}"); } network.AddEdge(inNode, outNode); capacity.Add(infinity); network.AddEdge(outNode, inNode); capacity.Add(infinity); } else { network.AddEdge(inNode, outNode); capacity.Add(1f); } int fusedCount = fusedCountOfNode[node]; Direction desiredDirectionOfSource = GetDesiredDirection(loopVar, containersOfSource, fusedCount); if (desiredDirectionOfSource == Direction.Forward) { if (debug) { log.Add($"loopVar={loopVar.Name} forward {sourceSt}"); } network.AddEdge(sourceNode, inNode); capacity.Add(infinity); } else if (desiredDirectionOfSource == Direction.Backward) { if (debug) { log.Add($"loopVar={loopVar.Name} backward {sourceSt}"); } network.AddEdge(outNode, sinkNode); capacity.Add(infinity); } } network.IsReadOnly = true; // compute the min cut MinCut <NodeIndex, EdgeIndex> mc = new MinCut <EdgeIndex, EdgeIndex>(network, e => capacity[e]); mc.Sources.Add(sourceNode); mc.Sinks.Add(sinkNode); Set <NodeIndex> sourceGroup = mc.GetSourceGroup(); foreach (NodeIndex node in nodesOfInterest) { IStatement sourceSt = nodes[node]; bool forwardIn = sourceGroup.Contains(getInNode(node)); bool forwardOut = sourceGroup.Contains(getOutNode(node)); if (forwardIn != forwardOut) { if (debug) { log.Add($"loopVar={loopVar.Name} will clone {sourceSt}"); } } else if (forwardIn) { if (debug) { log.Add($"loopVar={loopVar.Name} wants forward {sourceSt}"); } } else { if (debug) { log.Add($"loopVar={loopVar.Name} wants backward {sourceSt}"); } var containers = containersOfNode[node]; bool isForwardLoop = true; foreach (var container in containers) { if (container is IForStatement) { IForStatement ifs = (IForStatement)container; if (Recognizer.LoopVariable(ifs) == loopVar) { isForwardLoop = Recognizer.IsForwardLoop(ifs); } } } if (isForwardLoop) { Set <IVariableDeclaration> loopVarsToReverse; if (!loopVarsToReverseInStatement.TryGetValue(sourceSt, out loopVarsToReverse)) { // TODO: re-use equivalent sets loopVarsToReverse = new Set <IVariableDeclaration>(); loopVarsToReverseInStatement.Add(sourceSt, loopVarsToReverse); } loopVarsToReverse.Add(loopVar); } } } } } base.DoConvertMethodBody(outputs, inputs); }
#pragma warning restore 162 #endif private void PostProcess() { // create a dependency graph between MethodInvokes Dictionary <IVariableDeclaration, List <int> > mutationsOfVariable = new Dictionary <IVariableDeclaration, List <NodeIndex> >(); IndexedGraph g = new IndexedGraph(factorExprs.Count); foreach (NodeIndex node in g.Nodes) { IExpression factor = factorExprs[node]; NodeInfo info = GetNodeInfo(factor); for (int i = 0; i < info.arguments.Count; i++) { if (info.isReturnOrOut[i]) { // this is a mutation. add to mutationsOfVariable. IVariableDeclaration ivd = Recognizer.GetVariableDeclaration(info.arguments[i]); if (ivd != null && CodeRecognizer.IsStochastic(context, ivd)) { List <int> nodes; if (!mutationsOfVariable.TryGetValue(ivd, out nodes)) { nodes = new List <NodeIndex>(); mutationsOfVariable[ivd] = nodes; } nodes.Add(node); } } } } foreach (NodeIndex node in g.Nodes) { IExpression factor = factorExprs[node]; NodeInfo info = GetNodeInfo(factor); for (int i = 0; i < info.arguments.Count; i++) { if (!info.isReturnOrOut[i]) { // not a mutation. create a dependency on all mutations. IVariableDeclaration ivd = Recognizer.GetVariableDeclaration(info.arguments[i]); if (ivd != null && CodeRecognizer.IsStochastic(context, ivd)) { foreach (NodeIndex source in mutationsOfVariable[ivd]) { g.AddEdge(source, node); } } } } } List <NodeIndex> topo_nodes = new List <NodeIndex>(); DepthFirstSearch <NodeIndex> dfs = new DepthFirstSearch <NodeIndex>(g.SourcesOf, g); dfs.FinishNode += delegate(NodeIndex node) { IExpression factor = factorExprs[node]; ProcessFactor(factor, MessageDirection.Forwards); topo_nodes.Add(node); }; // process nodes forward dfs.SearchFrom(g.Nodes); // process nodes backward for (int i = topo_nodes.Count - 1; i >= 0; i--) { NodeIndex node = topo_nodes[i]; IExpression factor = factorExprs[node]; ProcessFactor(factor, MessageDirection.Backwards); } }