/// <summary> /// Collect statements that need to re-execute due to initialization. /// </summary> /// <param name="blocks"></param> /// <param name="dependencyGraph"></param> /// <param name="stmts"></param> /// <param name="nodesToMove">Modified on exit</param> private Dictionary <Loop, IBlockStatement> GetFirstIterPostprocessing(List <StatementBlock> blocks, DirectedGraphFilter <NodeIndex, EdgeIndex> dependencyGraph, IList <IStatement> stmts, ICollection <NodeIndex> nodesToMove) { var hasUserInitializedAncestor = dependencyGraph.CreateNodeData(false); DepthFirstSearch <NodeIndex> dfsInitBlock = new DepthFirstSearch <int>(dependencyGraph.SourcesOf, dependencyGraph); List <NodeIndex> nodesToRerun = new List <NodeIndex>(); dfsInitBlock.FinishNode += delegate(NodeIndex node) { var stmt = stmts[node]; if (SchedulingTransform.IsUserInitialized(context, stmt)) { // do nothing } else if (SchedulingTransform.HasUserInitializedInitializer(context, stmt)) { hasUserInitializedAncestor[node] = true; nodesToMove.Add(node); nodesToRerun.Add(node); } else { var inherit = dependencyGraph.SourcesOf(node).Any(source => hasUserInitializedAncestor[source]); if (inherit) { hasUserInitializedAncestor[node] = true; nodesToRerun.Add(node); } } }; Dictionary <Loop, IBlockStatement> firstIterPostprocessing = new Dictionary <Loop, IBlockStatement>(); foreach (StatementBlock block in blocks) { if (block is Loop) { Loop loop = (Loop)block; // find the set of initialized nodes that are ancestors of the loop (and not ancestors of an ancestor loop) // find all nodes that are ancestors of the loop and descendants of (and including) the init nodes - cannot contain any loops // because we do not clear dfs, all previous stmts in loops are excluded. dfsInitBlock.SearchFrom(loop.indices); foreach (var i in loop.indices) { nodesToMove.Remove(i); nodesToRerun.Remove(i); } if (nodesToRerun.Count > 0) { var firstIterPost = Builder.BlockStmt(); foreach (var node in nodesToRerun) { IStatement stmt = stmts[node]; if (nodesToMove.Contains(node)) { firstIterPost.Statements.Add(stmt); } else { // clone the statement this.ShallowCopy = true; var convertedStmt = ConvertStatement(stmt); this.ShallowCopy = false; firstIterPost.Statements.Add(convertedStmt); loopMergingInfo.AddEquivalentStatement(convertedStmt, loopMergingInfo.GetIndexOf(stmt)); clonesOfStatement.Add(stmt, new List <IStatement>() { convertedStmt }); } } firstIterPostprocessing.Add(loop, firstIterPost); nodesToRerun.Clear(); } } } return(firstIterPostprocessing); }
private List <IStatement> Schedule(DependencyGraph g, IList <IStatement> stmts, bool createFirstIterPostBlocks) { List <IStatement> output = new List <IStatement>(); List <StatementBlock> blocks = new List <StatementBlock>(); List <NodeIndex> currentBlock = null; DirectedGraphFilter <NodeIndex, EdgeIndex> graph2 = new DirectedGraphFilter <NodeIndex, EdgeIndex>(g.dependencyGraph, edge => !g.isDeleted[edge]); StrongComponents2 <NodeIndex> scc = new StrongComponents2 <NodeIndex>(graph2.SourcesOf, graph2); scc.AddNode += delegate(NodeIndex node) { currentBlock.Add(node); }; scc.BeginComponent += delegate() { currentBlock = new List <int>(); }; scc.EndComponent += delegate() { bool isCyclic = false; if (currentBlock.Count == 1) { NodeIndex node = currentBlock[0]; foreach (NodeIndex source in graph2.SourcesOf(node)) { if (source == node) { isCyclic = true; break; } } } else { isCyclic = true; } if (isCyclic) { blocks.Add(new Loop() { indices = currentBlock }); } else { blocks.Add(new StraightLine() { indices = currentBlock }); } }; scc.SearchFrom(graph2.Nodes); //scc.SearchFrom(g.outputNodes); bool check = false; if (check) { // check that there are no edges from a later component to an earlier component Set <NodeIndex> earlierNodes = new Set <int>(); foreach (StatementBlock block in blocks) { earlierNodes.AddRange(block.indices); foreach (NodeIndex node in block.indices) { foreach (NodeIndex source in graph2.SourcesOf(node)) { if (!earlierNodes.Contains(source)) { Console.WriteLine(g.NodeToString(node) + Environment.NewLine + " depends on later node " + g.NodeToString(source)); Error("Internal error: Strong components are not ordered properly"); } } } } } Set <NodeIndex> nodesToMove = new Set <NodeIndex>(); Dictionary <Loop, IBlockStatement> firstIterPostprocessing = null; if (createFirstIterPostBlocks) { firstIterPostprocessing = GetFirstIterPostprocessing(blocks, graph2, stmts, nodesToMove); } IVariableDeclaration iteration = Builder.VarDecl("iteration", typeof(int)); IndexedProperty <NodeIndex, bool> isUniform = graph2.CreateNodeData <bool>(true); foreach (StatementBlock block in blocks) { if (block is Loop) { foreach (NodeIndex i in block.indices) { isUniform[i] = false; } IWhileStatement ws = Builder.WhileStmt(Builder.LiteralExpr(true)); IList <IStatement> whileBody = ws.Body.Statements; if (ContainsIterationStatement(stmts, block.indices)) { List <IStatement> nodes = new List <IStatement>(); foreach (NodeIndex i in block.indices) { IStatement ist = stmts[i]; if (!context.InputAttributes.Has <IterationStatement>(ist)) { nodes.Add(ist); } } // build a new dependency graph with the dummy iteration statement removed DependencyGraph g2 = new DependencyGraph(context, nodes, ignoreMissingNodes: true, ignoreRequirements: true); List <IStatement> sc3 = Schedule(g2, nodes, false); if (sc3.Count == 1 && sc3[0] is IWhileStatement) { ws = (IWhileStatement)sc3[0]; } else { // The statements in the outer loop are not strongly connected. // Since we want the next transform to only process strong components, // we mark the outer while loop as DoNotSchedule, leaving only the // inner while loops to be scheduled. // add all statements in sc3 to whileBody, but remove while loops around a single statement. foreach (IStatement ist in sc3) { if (ist is IWhileStatement) { IWhileStatement iws2 = (IWhileStatement)ist; if (iws2.Body.Statements.Count == 1) { whileBody.AddRange(iws2.Body.Statements); continue; } } whileBody.Add(ist); } context.OutputAttributes.Set(ws, new DoNotSchedule()); } } else // !ContainsIterationStatement { foreach (NodeIndex i in block.indices) { IStatement st = stmts[i]; whileBody.Add(st); DependencyInformation di = context.InputAttributes.Get <DependencyInformation>(st); di.AddClones(clonesOfStatement); } RegisterUnchangedStatements(whileBody); } Loop loop = (Loop)block; if (firstIterPostprocessing != null && firstIterPostprocessing.ContainsKey(loop)) { var thenBlock = firstIterPostprocessing[loop]; var iterIsZero = Builder.BinaryExpr(BinaryOperator.ValueEquality, Builder.VarRefExpr(iteration), Builder.LiteralExpr(0)); var firstIterPostStmt = Builder.CondStmt(iterIsZero, thenBlock); context.OutputAttributes.Set(firstIterPostStmt, new FirstIterationPostProcessingBlock()); whileBody.Add(firstIterPostStmt); } output.Add(ws); } else { // not cyclic foreach (NodeIndex i in block.indices) { IStatement st = stmts[i]; if (!nodesToMove.Contains(i)) { output.Add(st); DependencyInformation di = context.InputAttributes.Get <DependencyInformation>(st); di.AddClones(clonesOfStatement); } isUniform[i] = g.IsUniform(i, source => !isUniform[source]); if (isUniform[i] != g.isUniform[i]) { Assert.IsTrue(isUniform[i]); g.isUniform[i] = isUniform[i]; DependencyInformation di = context.InputAttributes.Get <DependencyInformation>(st); di.IsUniform = isUniform[i]; } // mark sources of output statements (for SchedulingTransform) if (g.outputNodes.Contains(i)) { foreach (NodeIndex source in graph2.SourcesOf(i)) { IStatement sourceSt = stmts[source]; if (!context.InputAttributes.Has <OutputSource>(sourceSt)) { context.OutputAttributes.Set(sourceSt, new OutputSource()); } } } } } } return(output); }