public static Delegate CreateSdfDelegate(SdfInfo sdfInfo, DependencyGraph dpGraph, IList<FullCellAddr> cellList) { Debug.Assert(sdfInfo.inputCells == dpGraph.inputCells); Debug.Assert(sdfInfo.outputCell == dpGraph.outputCell); ProgramLines program = new ProgramLines(sdfInfo.outputCell, sdfInfo.inputCells); program.AddComputeCells(dpGraph, cellList); // TODO: This is not the final program, so order may not respect eval cond dependencies! sdfInfo.Program = program; // Save ComputeCell list for later partial evaluation return program.CompileToDelegate(sdfInfo); }
/// CodeGenerate.Initialize(ilg) must be called first. public void EvalCondReorderCompile() { ComputeEvalConds(); // Re-sort the expressions to reflect new dependencies // introduced by evaluation conditions DependencyGraph augmentedGraph = new DependencyGraph(outputCell, inputCells, GetComputeCell); IList<FullCellAddr> augmentedList = augmentedGraph.PrecedentOrder(); ProgramLines finalProgram = new ProgramLines(outputCell, inputCells); foreach (FullCellAddr cellAddr in augmentedList) { finalProgram.AddComputeCell(cellAddr, GetComputeCell(cellAddr)); } // This relies on all pathconds having been generated at this point: EmitCacheInitializations(); finalProgram.CreateUnwrappedNumberCells(); finalProgram.Compile(); }
/// <summary> /// Compiles the topologically sorted list of Expr to a list (program) /// of ComputeCells, encapsulating CGExprs. Builds a map from cellAddr to /// local variable ids, for compiling sheet-internal cellrefs to ldloc instructions. /// </summary> public void AddComputeCells(DependencyGraph dpGraph, IList<FullCellAddr> cellList) { Debug.Assert(dpGraph.outputCell == cellList[cellList.Count - 1]); CGExpr outputExpr; if (cellList.Count == 0 || cellList.Count == 1 && dpGraph.inputCellSet.Contains(cellList.Single())) { // The output cell is also an input cell; load it: outputExpr = new CGCellRef(dpGraph.outputCell, addressToVariable[dpGraph.outputCell]); } else { // First process all non-output cells, and ignore all input cells: foreach (FullCellAddr cellAddr in cellList) { if (cellAddr.Equals(dpGraph.outputCell)) { continue; } HashSet<FullCellAddr> dependents = dpGraph.GetDependents(cellAddr); int minUses = dependents.Count; if (minUses == 1) { FullCellAddr fromFca = dependents.First(); minUses = Math.Max(minUses, GetCount(fromFca, cellAddr)); } // Now if minUses==1 then there is at most one use of the cell at cellAddr, // and no local variable is needed. Otherwise, allocate a local variable: if (minUses > 1) { CGExpr newExpr = CGExpressionBuilder.BuildExpression(cellAddr, addressToVariable); Variable var = new LocalVariable(cellAddr.ToString(), newExpr.Type()); AddComputeCell(cellAddr, new ComputeCell(newExpr, var, cellAddr)); } } // Then process the output cell: outputExpr = CGExpressionBuilder.BuildExpression(dpGraph.outputCell, addressToVariable); } // Add the output cell expression last, without a variable to bind it to; hence the null, // also indicating that (only) the output cell is in tail position: AddComputeCell(dpGraph.outputCell, new ComputeCell(outputExpr, null, dpGraph.outputCell)); }
private ProgramLines PruneZeroUseCells() { // This is slightly more general than necessary, since we know that the // new order of FullCellAddrs could be embedded in the old one. So it would suffice // to simply count the number of uses of each FullCellAddr rather than do this sort. DependencyGraph dpGraph = new DependencyGraph(outputCell, inputCells, GetComputeCell); IList<FullCellAddr> prunedList = dpGraph.PrecedentOrder(); ProgramLines prunedProgram = new ProgramLines(outputCell, inputCells); foreach (FullCellAddr cellAddr in prunedList) { prunedProgram.AddComputeCell(cellAddr, GetComputeCell(cellAddr)); } return prunedProgram; }
/// <summary> /// Compiles entry code and body of a sheet-defined function /// </summary> /// <param name="info">The SdfInfo object describing the function</param> /// <returns></returns> private static Delegate CompileSdf(SdfInfo info) { // Build dependency graph containing all cells needed by the output cell DependencyGraph dpGraph = new DependencyGraph(info.outputCell, info.inputCells, delegate(FullCellAddr fca) { return fca.sheet[fca.ca]; }); // Topologically sort the graph in calculation order; leave out constants IList<FullCellAddr> cellList = dpGraph.PrecedentOrder(); info.SetVolatility(cellList); // Convert each Expr into a CGExpr while preserving order. Inline single-use expressions cellToFunctionMapper.AddFunction(info, dpGraph.GetAllNodes()); return ProgramLines.CreateSdfDelegate(info, dpGraph, cellList); }