public static void CreateFunction(string name, FullCellAddr outputCell, FullCellAddr[] inputCells) { name = name.ToUpper(); // If the function exists, with the same input and output cells, keep it. // If it is a placeholder, overwrite its applier; if its input and output // cells have changed, recreate it (including its SdfInfo record). Function oldFunction = Function.Get(name); if (oldFunction != null) { if (!oldFunction.IsPlaceHolder) { return; } } // Registering the function before compilation allows it to call itself recursively SdfInfo sdfInfo = Register(outputCell, inputCells, name); // Console.WriteLine("Compiling {0} as #{1}", name, info.index); Update(sdfInfo, CompileSdf(sdfInfo)); if (oldFunction != null) // ... and is not a placeholder { oldFunction.UpdateApplier(sdfInfo.Apply, sdfInfo.IsVolatile); } else { new Function(name, sdfInfo.Apply, isVolatile: sdfInfo.IsVolatile); } }
// Register, unregister, update and look up the SDF tables /// <summary> /// Allocate an index for a new SDF, but do not bind its SdfDelegate /// </summary> /// <param name="outputCell"></param> /// <param name="inputCells"></param> /// <param name="name"></param> /// <returns></returns> public static SdfInfo Register(FullCellAddr outputCell, FullCellAddr[] inputCells, string name) { name = name.ToUpper(); SdfInfo sdfInfo = GetInfo(name); if (sdfInfo == null) // New SDF, register it { sdfInfo = new SdfInfo(outputCell, inputCells, name, nextIndex++); Debug.Assert(sdfInfo.index == nextIndex - 1); sdfNameToInfo[name] = sdfInfo; if (sdfInfo.index >= sdfDelegates.Length) { Debug.Assert(sdfDelegates.Length == sdfInfos.Length); // Reallocate sdfDelegates array Delegate[] newSdfs = new Delegate[2 * sdfDelegates.Length]; Array.Copy(sdfDelegates, newSdfs, sdfDelegates.Length); sdfDelegates = newSdfs; // Reallocate sdfInfos array SdfInfo[] newSdfInfos = new SdfInfo[2 * sdfInfos.Length]; Array.Copy(sdfInfos, newSdfInfos, sdfInfos.Length); sdfInfos = newSdfInfos; } sdfInfos[sdfInfo.index] = sdfInfo; // Update SDF function listbox if created and visible SdfForm sdfForm = System.Windows.Forms.Application.OpenForms["sdf"] as SdfForm; if (sdfForm != null && sdfForm.Visible) { sdfForm.PopulateFunctionListBox(false); sdfForm.PopulateFunctionListBox(name); sdfForm.Invalidate(); } } return(sdfInfo); }
public static void ShowIL(SdfInfo info) { MethodInfo mif = sdfDelegates[info.index].Method; ClrTest.Reflection.MethodBodyViewer viewer = new ClrTest.Reflection.MethodBodyViewer(); viewer.Text = info.ToString(); viewer.SetMethodBase(mif); viewer.ShowDialog(); }
/// <summary> /// Generate code again for the given SDF with unchanged input and output cells, /// recreate the corresponding Function, and update the delegate table entry /// </summary> /// <param name="info"></param> // TODO: This should *not* be applied to SDF's resulting from partial evaluation. public static void Regenerate(SdfInfo info) { cellToFunctionMapper.RemoveFunction(info); // Removing the SDF from Function enables CreateFunction to overwrite it Function.Remove(info.name); // Rebuild and add it back CreateFunction(info.name, info.outputCell, info.inputCells); }
public static void Regenerate(String name) { SdfInfo info = GetInfo(name); if (info != null) { Regenerate(info); } }
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)); }
public static void DeleteFunction(string methodName) { SdfInfo info = GetInfo(methodName); if (info != null) { Unregister(info); cellToFunctionMapper.RemoveFunction(info); Function.Remove(methodName); } }
internal void RemoveFunction(SdfInfo info) { inputCellBag.RemoveAll(info.inputCells); outputCellBag.Remove(info.outputCell); List<FullCellAddr> addresses; if (!functionToAddressList.TryGetValue(info.name, out addresses)) { return; } foreach (FullCellAddr addr in addresses) { addressToFunctionList.Remove(addr); } functionToAddressList.Remove(info.name); }
internal void AddFunction(SdfInfo info, ICollection<FullCellAddr> addrs) { HashSet<FullCellAddr> inputCellSet = new HashSet<FullCellAddr>(); inputCellSet.UnionWith(info.inputCells); foreach (FullCellAddr addr in addrs) if (!inputCellSet.Contains(addr)) AddCellToFunction(info.name, addr); List<FullCellAddr> addrsList = new List<FullCellAddr>(addrs); functionToAddressList[info.name] = addrsList; inputCellBag.AddAll(info.inputCells); outputCellBag.Add(info.outputCell); }
public Delegate CompileToDelegate(SdfInfo sdfInfo) { Debug.Assert(sdfInfo.Program == this); // Which is silly, lots of redundancy // Create dynamic method with signature: Value CGMethod(Value, Value, ...) in class Function: DynamicMethod method = new DynamicMethod("CGMethod", Value.type, sdfInfo.MyArgumentTypes, Function.type, true); ILGenerator ilg = method.GetILGenerator(); CodeGenerate.Initialize(ilg); sdfInfo.Program.EvalCondReorderCompile(); ilg.Emit(OpCodes.Ret); return method.CreateDelegate(sdfInfo.MyType); }
/// <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)); }
internal void RemoveFunction(SdfInfo info) { inputCellBag.RemoveAll(info.inputCells); outputCellBag.Remove(info.outputCell); List <FullCellAddr> addresses; if (!functionToAddressList.TryGetValue(info.name, out addresses)) { return; } foreach (FullCellAddr addr in addresses) { addressToFunctionList.Remove(addr); } functionToAddressList.Remove(info.name); }
public Delegate CompileToDelegate(SdfInfo sdfInfo) { Debug.Assert(sdfInfo.Program == this); // Which is silly, lots of redundancy // Create dynamic method with signature: Value CGMethod(Value, Value, ...) in class Function: DynamicMethod method = new DynamicMethod("CGMethod", Value.type, sdfInfo.MyArgumentTypes, Function.type, true); ILGenerator ilg = method.GetILGenerator(); CodeGenerate.Initialize(ilg); sdfInfo.Program.EvalCondReorderCompile(); ilg.Emit(OpCodes.Ret); return(method.CreateDelegate(sdfInfo.MyType)); }
private CGSdfCall Specialize(CGExpr[] res, Value[] args) { FunctionValue fv = new FunctionValue(sdfInfo, args); SdfInfo residualSdf = SdfManager.SpecializeAndCompile(fv); CGExpr[] residualArgs = new CGExpr[fv.Arity]; int j = 0; for (int i = 0; i < args.Length; i++) { if (args[i] == ErrorValue.naError) { residualArgs[j++] = res[i]; } } return(new CGSdfCall(residualSdf, residualArgs)); }
internal void AddFunction(SdfInfo info, ICollection <FullCellAddr> addrs) { HashSet <FullCellAddr> inputCellSet = new HashSet <FullCellAddr>(); inputCellSet.UnionWith(info.inputCells); foreach (FullCellAddr addr in addrs) { if (!inputCellSet.Contains(addr)) { AddCellToFunction(info.name, addr); } } List <FullCellAddr> addrsList = new List <FullCellAddr>(addrs); functionToAddressList[info.name] = addrsList; inputCellBag.AddAll(info.inputCells); outputCellBag.Add(info.outputCell); }
public FunctionValue(SdfInfo sdfInfo, Value[] args) { this.sdfInfo = sdfInfo; // A null or empty args array is equivalent to an array of all NA if (args == null || args.Length == 0) { args = new Value[sdfInfo.arity]; for (int i = 0; i < args.Length; i++) { args[i] = ErrorValue.naError; } } // Requirement: There will be no further writes to the args array this.args = args; int k = 0; for (int i = 0; i < args.Length; i++) { if (args[i] == ErrorValue.naError) { k++; } } this.arity = k; this.mergeAndCall = MakeMergeAndCallMethod(); }
public override void Compile() { int argCount = es.Length - 1; if (es.Length < 1) { LoadErrorValue(ErrorValue.argCountError); } else if (es[0] is CGTextConst) { String name = (es[0] as CGTextConst).value.value; SdfInfo sdfInfo = SdfManager.GetInfo(name); if (sdfInfo == null) { LoadErrorValue(ErrorValue.nameError); } else if (argCount != 0 && argCount != sdfInfo.arity) { LoadErrorValue(ErrorValue.argCountError); } else { ilg.Emit(OpCodes.Ldc_I4, sdfInfo.index); CompileToValueArray(argCount, 1, es); ilg.Emit(OpCodes.Call, FunctionValue.makeMethod); } } else { es[0].Compile(); CheckType(FunctionValue.type, new Gen(delegate { CompileToValueArray(argCount, 1, es); ilg.Emit(OpCodes.Call, FunctionValue.furtherApplyMethod); }), GenLoadErrorValue(ErrorValue.argTypeError)); } }
public CGSdfCall(SdfInfo sdfInfo, CGExpr[] es) : base(es, null) { this.sdfInfo = sdfInfo; }
// Register, unregister, update and look up the SDF tables /// <summary> /// Allocate an index for a new SDF, but do not bind its SdfDelegate /// </summary> /// <param name="outputCell"></param> /// <param name="inputCells"></param> /// <param name="name"></param> /// <returns></returns> public static SdfInfo Register(FullCellAddr outputCell, FullCellAddr[] inputCells, string name) { name = name.ToUpper(); SdfInfo sdfInfo = GetInfo(name); if (sdfInfo == null) { // New SDF, register it sdfInfo = new SdfInfo(outputCell, inputCells, name, nextIndex++); Debug.Assert(sdfInfo.index == nextIndex - 1); sdfNameToInfo[name] = sdfInfo; if (sdfInfo.index >= sdfDelegates.Length) { Debug.Assert(sdfDelegates.Length == sdfInfos.Length); // Reallocate sdfDelegates array Delegate[] newSdfs = new Delegate[2 * sdfDelegates.Length]; Array.Copy(sdfDelegates, newSdfs, sdfDelegates.Length); sdfDelegates = newSdfs; // Reallocate sdfInfos array SdfInfo[] newSdfInfos = new SdfInfo[2 * sdfInfos.Length]; Array.Copy(sdfInfos, newSdfInfos, sdfInfos.Length); sdfInfos = newSdfInfos; } sdfInfos[sdfInfo.index] = sdfInfo; // Update SDF function listbox if created and visible GUI.SdfForm sdfForm = System.Windows.Forms.Application.OpenForms["sdf"] as GUI.SdfForm; if (sdfForm != null && sdfForm.Visible) { sdfForm.PopulateFunctionListBox(false); sdfForm.PopulateFunctionListBox(name); sdfForm.Invalidate(); } } return sdfInfo; }
private static void Update(SdfInfo info, Delegate method) { sdfDelegates[info.index] = method; }
private static void Unregister(SdfInfo info) { sdfNameToInfo.Remove(info.name); sdfDelegates[info.index] = sdfDeleted[info.arity]; sdfInfos[info.index] = null; }
/// <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); }
public static CGExpr Make(String name, CGExpr[] es) { name = name.ToUpper(); // This switch should agree with the function table in Functions.cs switch (name) { case "+": return(new CGArithmetic2(OpCodes.Add, name, es)); case "*": return(new CGArithmetic2(OpCodes.Mul, name, es)); case "-": return(new CGArithmetic2(OpCodes.Sub, name, es)); case "/": return(new CGArithmetic2(OpCodes.Div, name, es)); case "=": return(CGEqual.Make(es)); case "<>": return(CGNotEqual.Make(es)); case ">": return(new CGGreaterThan(es)); case "<=": return(new CGLessThanOrEqual(es)); case "<": return(new CGLessThan(es)); case ">=": return(new CGGreaterThanOrEqual(es)); // Non-strict, or other special treatment case "AND": return(new CGAnd(es)); case "APPLY": return(new CGApply(es)); case "CHOOSE": return(new CGChoose(es)); case "CLOSURE": return(new CGClosure(es)); case "ERR": return(new CGError(es)); case "EXTERN": return(new CGExtern(es)); case "IF": return(new CGIf(es)); case "NA": if (es.Length == 0) { return(new CGError(ErrorValue.naError)); } else { return(new CGError(ErrorValue.argCountError)); } case "NEG": return(new CGNeg(es)); case "NOT": return(new CGNot(es)); case "OR": return(new CGOr(es)); case "PI": if (es.Length == 0) { return(new CGNumberConst(NumberValue.PI)); } else { return(new CGError(ErrorValue.argCountError)); } case "VOLATILIZE": if (es.Length == 1) { return(es[0]); } else { return(new CGError(ErrorValue.argCountError)); } default: // The general case for most built-in functions with unspecific argument types FunctionInfo functionInfo; if (FunctionInfo.Find(name, out functionInfo)) { return(new CGFunctionCall(functionInfo, es)); } else // May be a sheet-defined function { SdfInfo sdfInfo = SdfManager.GetInfo(name); if (sdfInfo != null) { return(new CGSdfCall(sdfInfo, es)); } else { return(new CGError(ErrorValue.nameError)); } } } }