public static void Optimize(IExecutableCode code) { foreach (var block in code.QueryCode()) { VisitCodeBlock(block); } }
/// <summary> /// Dump out info from a executable code dude. /// </summary> /// <param name="code"></param> public static IEnumerable <string> DumpCode(this IExecutableCode code) { Console.WriteLine("There are {0} Query Blocks:", code.QueryCode().Count()); foreach (var qb in code.QueryCode()) { yield return("Query Block:"); foreach (var line in qb.DumpCode(" ")) { yield return(line); } ; } foreach (var f in code.Functions) { yield return(string.Format("Function: {0}", f.Name)); yield return(string.Format(" {0} {1} ()", f.ResultType.Name, f.Name)); if (f.StatementBlock != null) { foreach (var line in f.StatementBlock.DumpCode()) { yield return(string.Format(" {0}", line)); } } else { yield return(" ** No statements ever set"); } } if (code.ResultValues == null) { yield return("Result Variable: <not set (null)>"); } else { yield return(string.Format("There are {0} result variables.", code.ResultValues.Count())); foreach (var rv in code.ResultValues) { yield return(string.Format(" Result Variable: {0}", rv.RawValue)); } } }
/// <summary> /// Wherever the oldfname is referenced we need to rename it to be the new one. /// </summary> /// <param name="code"></param> /// <param name="oldfname"></param> /// <param name="newfname"></param> private void RenameFunction(IExecutableCode code, string oldfname, string newfname) { foreach (var qb in code.QueryCode()) { qb.RenameVariable(oldfname, newfname); } foreach (var f in code.Functions) { f.RenameFunctionReference(oldfname, newfname); } }
/// <summary> /// Look through a code block, make sure all the data structures are in order. /// </summary> /// <param name="code"></param> /// <returns></returns> public static bool CheckCodeBlock(this IExecutableCode code) { // Check parent foreach (var block in code.QueryCode()) { var r = CheckQueryCodeBlock(block, null); if (!r) { return(r); } } return(true); }
/// <summary> /// Do the code translation itself. /// </summary> /// <param name="code"></param> /// <returns></returns> public Dictionary <string, object> TranslateGeneratedCode(IExecutableCode code) { if (code == null) { throw new ArgumentNullException("code"); } /// /// Get the variables that we are going to be shipping back and forth. /// Dictionary <string, object> result = new Dictionary <string, object>(); result["ResultVariables"] = TranslateVariable(code.ResultValues, code); /// /// The actual code. This is just a sequence of loops. It would be, under normal circumstances, just that. However, /// there is a limitation in the code generator that means you can't have more than 250 loops in one function. If we aren't /// combining loops it is easy to have more than 250 plots. So we split this up into functions of about 100 outter loops /// per function. We then call these functions from the main loop. Fortunately, there are no local variables. :-) /// We cache the codeing blocks here b/c we have to access them several times. /// const int queriesPerFunction = 100; var queryBlocks = code.QueryCode().ToArray(); int numberOfBlocks = 1 + queryBlocks.Length / queriesPerFunction; result["NumberOfQueryFunctions"] = numberOfBlocks; result["QueryFunctionBlocks"] = TranslateQueryBlocks(queryBlocks, queriesPerFunction, numberOfBlocks); result["SlaveTerminateStatements"] = TranslateFinalizingVariables(code.ResultValues, code); result["InitStatements"] = code.InitalizationStatements.SelectMany(s => s.CodeItUp()); // Functions have to be written out too. result["QueryMemberFunctions"] = code.Functions.SelectMany(f => f.CodeItUp()); result["QueryCacheBools"] = code.Functions.Select(f => f.CacheVariableGood.RawValue); /// /// Next, go through everything and extract the include files /// AddIncludeFiles(code); return(result); }
/// <summary> /// Do the code translation itself. /// </summary> /// <param name="code"></param> /// <returns></returns> public Dictionary<string, object> TranslateGeneratedCode(IExecutableCode code) { if (code == null) throw new ArgumentNullException("code"); /// /// Get the variables that we are going to be shipping back and forth. /// Dictionary<string, object> result = new Dictionary<string, object>(); result["ResultVariables"] = TranslateVariable(code.ResultValues, code); /// /// The actual code. This is just a sequence of loops. It would be, under normal circumstances, just that. However, /// there is a limitation in the code generator that means you can't have more than 250 loops in one function. If we aren't /// combining loops it is easy to have more than 250 plots. So we split this up into functions of about 100 outter loops /// per function. We then call these functions from the main loop. Fortunately, there are no local variables. :-) /// We cache the codeing blocks here b/c we have to access them several times. /// const int queriesPerFunction = 100; var queryBlocks = code.QueryCode().ToArray(); int numberOfBlocks = 1 + queryBlocks.Length / queriesPerFunction; result["NumberOfQueryFunctions"] = numberOfBlocks; result["QueryFunctionBlocks"] = TranslateQueryBlocks(queryBlocks, queriesPerFunction, numberOfBlocks); result["SlaveTerminateStatements"] = TranslateFinalizingVariables(code.ResultValues, code); result["InitStatements"] = code.InitalizationStatements.SelectMany(s => s.CodeItUp()); // Functions have to be written out too. result["QueryMemberFunctions"] = code.Functions.SelectMany(f => f.CodeItUp()); result["QueryCacheBools"] = code.Functions.Select(f => f.CacheVariableGood.RawValue); /// /// Next, go through everything and extract the include files /// AddIncludeFiles(code); return result; }
/// <summary> /// Add one of the query's to our list of queries we are tracking here. /// </summary> /// <param name="code"></param> public void AddGeneratedCode(IExecutableCode code) { /// /// We have some pretty stiff requirements on code /// if (code == null) throw new ArgumentNullException("code cannot be null"); if (code == this) throw new ArgumentException("Can't add code to itself!"); var varsToTrans = code.VariablesToTransfer; if (varsToTrans == null) throw new ArgumentNullException("Generated Code Varaibles to Transfer can't be null"); var includeFiles = code.IncludeFiles; if (includeFiles == null) throw new ArgumentNullException("Generated code Include Files can't be null"); var resultValues = code.ResultValues; if (resultValues == null) throw new ArgumentNullException("Generated code Result Values can't be null"); var codeItems = code.QueryCode().ToArray(); // Functions can be combined, as long as we rewrite their names. A very nice thing // about this is that the query text is basically all that is required for doing // matching: no code analysis. Further, no messing with the code. // Only take functions that were actually populated by us! var goodFunctions = code.Functions.Where(f => f.StatementBlock != null); if (_functions.Count == 0) { _functions.AddRange(goodFunctions); } else { var matchedFunctions = from newFunc in goodFunctions let oldFunc = _functions.Where(f => f.Matches(newFunc)).FirstOrDefault() group Tuple.Create(oldFunc, newFunc) by oldFunc != null; // No match means we add it to our list of functions directly. // Those that don't have to have the renaming propagated through out! foreach (var fgroup in matchedFunctions) { if (fgroup.Key) { // Match. Rename, don't add. foreach (var fpair in fgroup) { // Note, this is the new code and we want it to look like the old code. RenameFunction(code, fpair.Item2.Name, fpair.Item1.Name); } } else { // Not matched. So add it. foreach (var fpair in fgroup) { _functions.Add(fpair.Item2); } } } } /// /// Variables that we need to queue for transfer /// foreach (var v in varsToTrans) { QueueVariableForTransfer(v); } // Initialization code. No combination should be required here. foreach (var s in code.InitalizationStatements) { _initStatements.Add(s); } /// /// Include Files - only add if we don't have them on the list already. /// foreach (var inc in includeFiles) { AddIncludeFile(inc); } /// /// Result values - killer if they are named the same thing! /// foreach (var item in resultValues) { AddResult(item); } // // Add the referenced leaf names // foreach (var leaf in code.ReferencedLeafNames) { AddReferencedLeaf(leaf); } /// /// Finally, we need to combine the query code. Now, there is a limitation (by design) in the C++ compiler: /// http://connect.microsoft.com/VisualStudio/feedback/details/100734/c-function-with-many-unnested-loops-generates-error-fatal-error-c1061-compiler-limit-blocks-nested-too-deeply /// /// So - if we want to generate more than 250 plots in one run, and we are doing no loop combining, then we will be in trouble. To get around this /// Anything that can't folded into itself has to be kept "seperate". Sucks, but what can you do? /// AddQueryBlocks(codeItems); }
/// <summary> /// Add one of the query's to our list of queries we are tracking here. /// </summary> /// <param name="code"></param> public void AddGeneratedCode(IExecutableCode code) { /// /// We have some pretty stiff requirements on code /// if (code == null) { throw new ArgumentNullException("code cannot be null"); } if (code == this) { throw new ArgumentException("Can't add code to itself!"); } var varsToTrans = code.VariablesToTransfer; if (varsToTrans == null) { throw new ArgumentNullException("Generated Code Varaibles to Transfer can't be null"); } var includeFiles = code.IncludeFiles; if (includeFiles == null) { throw new ArgumentNullException("Generated code Include Files can't be null"); } var resultValues = code.ResultValues; if (resultValues == null) { throw new ArgumentNullException("Generated code Result Values can't be null"); } var codeItems = code.QueryCode().ToArray(); // Functions can be combined, as long as we rewrite their names. A very nice thing // about this is that the query text is basically all that is required for doing // matching: no code analysis. Further, no messing with the code. // Only take functions that were actually populated by us! var goodFunctions = code.Functions.Where(f => f.StatementBlock != null); if (_functions.Count == 0) { _functions.AddRange(goodFunctions); } else { var matchedFunctions = from newFunc in goodFunctions let oldFunc = _functions.Where(f => f.Matches(newFunc)).FirstOrDefault() group Tuple.Create(oldFunc, newFunc) by oldFunc != null; // No match means we add it to our list of functions directly. // Those that don't have to have the renaming propagated through out! foreach (var fgroup in matchedFunctions) { if (fgroup.Key) { // Match. Rename, don't add. foreach (var fpair in fgroup) { // Note, this is the new code and we want it to look like the old code. RenameFunction(code, fpair.Item2.Name, fpair.Item1.Name); } } else { // Not matched. So add it. foreach (var fpair in fgroup) { _functions.Add(fpair.Item2); } } } } /// /// Variables that we need to queue for transfer /// foreach (var v in varsToTrans) { QueueVariableForTransfer(v); } // Initialization code. No combination should be required here. foreach (var s in code.InitalizationStatements) { _initStatements.Add(s); } /// /// Include Files - only add if we don't have them on the list already. /// foreach (var inc in includeFiles) { AddIncludeFile(inc); } /// /// Result values - killer if they are named the same thing! /// foreach (var item in resultValues) { AddResult(item); } // // Add the referenced leaf names // foreach (var leaf in code.ReferencedLeafNames) { AddReferencedLeaf(leaf); } /// /// Finally, we need to combine the query code. Now, there is a limitation (by design) in the C++ compiler: /// http://connect.microsoft.com/VisualStudio/feedback/details/100734/c-function-with-many-unnested-loops-generates-error-fatal-error-c1061-compiler-limit-blocks-nested-too-deeply /// /// So - if we want to generate more than 250 plots in one run, and we are doing no loop combining, then we will be in trouble. To get around this /// Anything that can't folded into itself has to be kept "seperate". Sucks, but what can you do? /// AddQueryBlocks(codeItems); }