protected IList <IStatement> Schedule(IReadOnlyList <IStatement> isc)
        {
            DependencyGraph g = new DependencyGraph(context, isc, ignoreMissingNodes: false, ignoreRequirements: true, readAfterWriteOnly: true);

            // The uniform statements must be removed first, before doing the search backward from outputs.
            // This is important because it allows dependencies of uniform statements to be pruned.
            // For example, suppose A requires B and C, B is uniform.  This means that A is uniform and A will be pruned.
            // As a result, C doesn't need to be computed (even if it might be non-uniform).
            if (PruneUniformStmts)
            {
                g.PropagateUniformNodes();
            }

            // Propagate DependsOnIteration
            DependsOnIteration           attr    = null;
            DepthFirstSearch <NodeIndex> dfsIter = new DepthFirstSearch <EdgeIndex>(g.dependencyGraph.TargetsOf, g.nodeData);

            dfsIter.DiscoverNode += delegate(NodeIndex node) {
                if (!context.OutputAttributes.Has <DependsOnIteration>(isc[node]))
                {
                    context.OutputAttributes.Set(isc[node], attr);
                }
            };
            foreach (NodeIndex node in g.dependencyGraph.Nodes)
            {
                attr = context.GetAttribute <DependsOnIteration>(isc[node]);
                if (attr != null)
                {
                    dfsIter.SearchFrom(node);
                }
            }

            // search backward from the outputs to find statements that are relevant.
            DepthFirstSearch <NodeIndex> dfs = new DepthFirstSearch <NodeIndex>(
                PruneUniformStmts ? (Converter <int, IEnumerable <int> >)g.SourcesNeededForOutput : g.dependencyGraph.SourcesOf,
                g.nodeData);

            dfs.SearchFrom(g.outputNodes);
            List <NodeIndex> schedule = new List <NodeIndex>();

            foreach (NodeIndex node in g.dependencyGraph.Nodes)
            {
                // any statement found in the search is relevant.  other statements are pruned.
                if (dfs.IsVisited[node] == VisitState.Finished)
                {
                    schedule.Add(node);
                }
            }

            if (debug)
            {
                var             itdOut = context.FindOutputForAncestor <ITypeDeclaration, ITypeDeclaration>();
                IBlockStatement block  = Builder.BlockStmt();
                foreach (var line in StringUtil.Lines(g.dependencyGraph.ToString()))
                {
                    block.Statements.Add(Builder.CommentStmt(line));
                }
                foreach (NodeIndex node in g.dependencyGraph.Nodes)
                {
                    block.Statements.Add(Builder.CommentStmt($"{node} {isc[node]}"));
                }
                context.OutputAttributes.Add(itdOut, new DebugInfo()
                {
                    Transform = this,
                    Name      = "Graph",
                    Value     = block
                });
            }

            if (PruneUniformStmts)
            {
                // When statements are pruned from the code, they must also be pruned from the DependencyInformation attributes of all other statements that might refer to them.
                Dictionary <IStatement, IStatement> replacements = new Dictionary <IStatement, IStatement>(ReferenceEqualityComparer <IStatement> .Instance);
                foreach (NodeIndex targetIndex in g.dependencyGraph.Nodes)
                {
                    if (g.isUniform[targetIndex])
                    {
                        IStatement            ist = isc[targetIndex];
                        DependencyInformation di  = context.InputAttributes.Get <DependencyInformation>(ist);
                        // this is needed for detection of non-uniform initializers
                        di.IsUniform = true;
                    }
                    if (g.isUniform[targetIndex] && !g.isEssential[targetIndex])
                    {
                        NodeIndex source = g.FindInitializer(targetIndex);
                        if (source != targetIndex)
                        {
                            IStatement target      = isc[targetIndex];
                            IStatement replacement = isc[source];
                            replacements[target] = replacement;
                        }
                    }
                }
                foreach (NodeIndex targetIndex in schedule)
                {
                    IStatement            target = isc[targetIndex];
                    DependencyInformation di     = context.InputAttributes.Get <DependencyInformation>(target);
                    di.Replace(replacements);
                }
            }

            IList <IStatement> sc = Builder.StmtCollection();

            foreach (NodeIndex i in schedule)
            {
                IStatement st = isc[i];
                sc.Add(st);
            }
            return(sc);
        }