// Partially evaluate the programList with respect to the given static inputs, // producing a new ProgramLines object. public ProgramLines PEval(Value[] args, FullCellAddr[] residualInputs) { PEnv pEnv = new PEnv(); // Map static input cells to their constant values: for (int i = 0; i < args.Length; i++) { pEnv[inputCells[i]] = CGConst.Make(args[i]); } ProgramLines residual = new ProgramLines(outputCell, residualInputs); // PE-time environment PEnv maps each residual input cell address to the delegate argument: for (int i = 0; i < residualInputs.Length; i++) { FullCellAddr input = residualInputs[i]; pEnv[input] = new CGCellRef(input, residual.addressToVariable[input]); } // Process the given function's compute cells in dependency order, output last: foreach (ComputeCell ccell in programList) { ComputeCell rCcell = ccell.PEval(pEnv); if (rCcell != null) { residual.AddComputeCell(ccell.cellAddr, rCcell); } } residual = residual.PruneZeroUseCells(); return(residual); }
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); }
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)); }
/// <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)); }
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> /// Create a residual (sheet-defined) function for the given FunctionValue. /// As a side effect, register the new SDF and cache it in a dictionary mapping /// function values to residual SDFs. /// </summary> /// <param name="fv">The function value to specialize</param> /// <returns></returns> public static SdfInfo SpecializeAndCompile(FunctionValue fv) { SdfInfo residualSdf; if (!specializations.TryGetValue(fv, out residualSdf)) { FullCellAddr[] residualInputCells = fv.sdfInfo.Program.ResidualInputs(fv); String name = String.Format("{0}#{1}", fv, nextIndex); Console.WriteLine("Created residual function {0}", name); // Register before partial evaluation to enable creation of call cycles residualSdf = Register(fv.sdfInfo.outputCell, residualInputCells, name); specializations.Add(fv, residualSdf); ProgramLines residual = fv.sdfInfo.Program.PEval(fv.args, residualInputCells); residualSdf.Program = residual; Update(residualSdf, residual.CompileToDelegate(residualSdf)); } return(residualSdf); }
/// 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(); }
/// 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(); }
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; }
// Partially evaluate the programList with respect to the given static inputs, // producing a new ProgramLines object. public ProgramLines PEval(Value[] args, FullCellAddr[] residualInputs) { PEnv pEnv = new PEnv(); // Map static input cells to their constant values: for (int i = 0; i < args.Length; i++) { pEnv[inputCells[i]] = CGConst.Make(args[i]); } ProgramLines residual = new ProgramLines(outputCell, residualInputs); // PE-time environment PEnv maps each residual input cell address to the delegate argument: for (int i = 0; i < residualInputs.Length; i++) { FullCellAddr input = residualInputs[i]; pEnv[input] = new CGCellRef(input, residual.addressToVariable[input]); } // Process the given function's compute cells in dependency order, output last: foreach (ComputeCell ccell in programList) { ComputeCell rCcell = ccell.PEval(pEnv); if (rCcell != null) { residual.AddComputeCell(ccell.cellAddr, rCcell); } } residual = residual.PruneZeroUseCells(); return residual; }