private static FunctionSpecializationResult SpecializeFunction( ILFunction function, Dictionary<string, object> pars, List<string> forceDynamic) { var source = new StringBuilder(1024 * 1024); int LabelId = 1; var visited = new SpecPointContainer(); var q = new Queue<SpecPoint>(); var initEnv = new AbstractEnvironment(); foreach (var kvp in pars) { initEnv.SetValue(kvp.Key, kvp.Value); } foreach (var kvp in function.LocalTypes) { if (pars.ContainsKey(kvp.Key)) continue; object val = null; if (kvp.Value.TypeEnum == L1Runtime.SyntaxTree.VariableTypeEnum.Integer) val = 0; if (kvp.Value.TypeEnum == L1Runtime.SyntaxTree.VariableTypeEnum.Bool) val = false; if (kvp.Value.TypeEnum == L1Runtime.SyntaxTree.VariableTypeEnum.Char) val = (char)0; initEnv.SetValue(kvp.Key, val); } foreach (var d in forceDynamic) { initEnv.SetValue(d, Dynamic.Value); } initEnv = _bindTimeAnalyze(function, initEnv); initEnv.Trace(); Dictionary<VariableType, List<string>> localVarsInfo = new Dictionary<VariableType, List<string>>(); foreach (var kvp in function.LocalTypes) { if (initEnv.IsDynamic(kvp.Key) && !function.Parameters.Contains(kvp.Key)) { if (localVarsInfo.ContainsKey(kvp.Value) == false) { localVarsInfo.Add(kvp.Value, new List<string>()); } localVarsInfo[kvp.Value].Add(kvp.Key); } } foreach (var kvp in localVarsInfo) { source.Append("\t"); source.Append(kvp.Key.ToCompileableString()); source.Append(" "); for (int i = 0; i < kvp.Value.Count; ++i) { source.Append(kvp.Value[i]); if (i != kvp.Value.Count - 1) source.Append(", "); } source.Append(";"); source.Append(System.Environment.NewLine); } foreach (var kvp in pars) { if (kvp.Value != Dynamic.Value && initEnv.IsDynamic(kvp.Key)) { source.Append("\t"); source.Append(function.LocalTypes[kvp.Key].ToCompileableString()); source.Append(" "); source.Append(kvp.Key); source.Append(" := "); source.Append(RenderConst(kvp.Value)); source.Append(";"); source.AppendLine(); } } source.Append("* Begin of function specialized body"); source.Append(System.Environment.NewLine); var initialSp = new SpecPoint { Env = initEnv, P = 1, L = LabelId++ } ; q.Enqueue(initialSp); initialSp.Env.Freeze(); visited.AddSpecPoint(initialSp); int operations = 0; var calls = new List<FunctionCallContainer>(); while (q.Count != 0) { operations++; var sp = q.Dequeue(); var env = sp.Env.Clone(); source.Append("L_"); source.Append(sp.L); source.Append(":"); source.Append(System.Environment.NewLine); bool stopped = false; int p = sp.P; while (!stopped) { var instr = function.Body[p - 1]; if (instr is ILExpression) { var expr = instr as ILExpression; stopped = SpecializeExpression(function, expr, env, source, calls); p++; } else if (instr is ILBranch) { var br = (instr as ILBranch); var condVar = br.Condition.Const.ToString(); if (env.IsDynamic(condVar)) { env.Freeze(); var succSp = visited.GetSpecPoint(br.SuccessJump, env); var failSp = visited.GetSpecPoint(br.FailJump, env); if (succSp == null) { succSp = new SpecPoint { Env = env, P = br.SuccessJump, L = LabelId++ }; q.Enqueue(succSp); visited.AddSpecPoint(succSp); } if (failSp == null) { failSp = new SpecPoint { Env = env, P = br.FailJump, L = LabelId++ }; q.Enqueue(failSp); visited.AddSpecPoint(failSp); } source.Append("\tif "); source.Append(condVar); source.Append(" then "); source.Append("goto "); source.Append("L_"); source.Append(succSp.L); source.Append(" else "); source.Append("goto "); source.Append("L_"); source.Append(failSp.L); source.Append(" end;"); source.Append(System.Environment.NewLine); stopped = true; } else { var cond = (bool)env.GetValue(condVar); if (cond) p = br.SuccessJump; else p = br.FailJump; } } else if (instr is ILGoto) { p = (instr as ILGoto).GoTo; } else if (instr is ILReturn) { var ret = (instr as ILReturn); if (ret.Return == null) { source.Append("\treturn;"); source.Append(System.Environment.NewLine); } else { source.Append("\treturn "); var retVar = ret.Return.Const.ToString(); if (env.IsDynamic(retVar)) { source.Append(retVar); } else { m_renderConst(source, env.GetValue(retVar)); } source.Append(";"); source.Append(System.Environment.NewLine); } stopped = true; } } //TODO: Stop if too big query and try with more dynamic variables if (operations >= MaximimOperations) { var ch = visited.GetMostChangeableVariables(); forceDynamic = forceDynamic.Union(ch).ToList(); var res1 = SpecializeFunction(function, pars, forceDynamic); return res1; } } source.Append("0").AppendLine(); //System.Console.WriteLine(source.ToString()); var r = new FunctionSpecializationResult { FunctionCallsNeedToResolve = calls, Source = source, Function = function, SpecializationRules = pars }; return r; }
private static void SpecializeFunctionCall(ILFunction context, ILExpression fcall, string resultVar, StringBuilder source, AbstractEnvironment env, List<FunctionCallContainer> calls) { var f = fcall.Function; //Stdlib function if (f.EmbeddedBody != null) { if (f.CanBeCalculatedWithoutRun && !fcall.VAList.Any(pexpr => env.IsDynamic(pexpr.Const.ToString()))) { var args = fcall.VAList.Select(ilexpr => ilexpr.Eval(env)) .Select(o => (o is Int32) ? o : ( (o is Boolean) ? o : L1Runtime.L1Runtime.GetArrayFromObjectArray((object[])o))).ToArray(); var result = f.EmbeddedBody.Invoke(null, args); if (env.IsDynamic(resultVar)) { source.Append("\t"); source.Append(resultVar); source.Append(" := "); RenderConst(result); source.Append(");"); source.Append(System.Environment.NewLine); } else { if (result is L1Runtime.L1Array<int>) { var l1arr = result as L1Runtime.L1Array<int>; var a = new object[l1arr.GetLength()]; for (int i = 0; i < a.Length; ++i) { a[i] = l1arr.GetValue(i); } result = a; } env.SetValue(resultVar, result); } } else { source.Append("\t"); source.Append(resultVar); source.Append(" := "); source.Append(f.Name); source.Append("("); for (int i = 0; i < fcall.VAList.Count; ++i) { var p = fcall.VAList[i].Const.ToString(); if (env.IsDynamic(p)) { source.Append(p); } else { source.Append(RenderConst(env.GetValue(p))); } if (i != fcall.VAList.Count - 1) source.Append(", "); } source.Append(");"); source.Append(System.Environment.NewLine); } } else { if (f.CanBeCalculatedWithoutRun && !fcall.VAList.Any(pexpr => env.IsDynamic(pexpr.Const.ToString()))) { var args = fcall.VAList.Select(ilexpr => ilexpr.Eval(env)).ToArray(); var res = f.Call(args); if (env.IsDynamic(resultVar)) { source.Append("\t").Append(resultVar).Append(" := ").Append(RenderConst(res)).Append(";").AppendLine(); } else { env.SetValue(resultVar, res); } } else { var functionCallRef = new FunctionCallContainer { Function = fcall.Function, SourceFunction = context, ResultVariable = resultVar, Parameters = fcall.VAList.Select(ilexpr => env.IsDynamic(ilexpr.Const.ToString()) ? ilexpr.Const.ToString() : env.GetValue(ilexpr.Const.ToString())).ToList() }; calls.Add(functionCallRef); source.Append("\t").Append(functionCallRef.ToString()).AppendLine(); } } }
private static bool SpecializeExpression(ILFunction f, ILExpression expr, AbstractEnvironment env, StringBuilder source, List<FunctionCallContainer> calls) { if (expr.Type == ILExpressionType.Assign) { var left = expr.LeftNode; var right = expr.RightNode; if (left.Type == ILExpressionType.VariableAccess) { var varName = left.Const.ToString(); try { var rightRed = right.AbstactReduce(varName, env, f.LocalTypes); if (rightRed is ILExpression) { var fcall = rightRed as ILExpression; SpecializeFunctionCall(f, fcall, varName, source, env, calls); //source.Append("<<FUNCTION_CALL>>"); } else if (env.IsDynamic(varName)) { //source.Append(varName); source.Append(" := "); if (rightRed is string) { source.Append("\t"); source.Append(varName); source.Append(" := "); source.Append((string)rightRed); source.Append(";"); source.Append(System.Environment.NewLine); } else { source.Append("\t"); source.Append(varName); source.Append(" := "); source.Append(RenderConst(rightRed)); source.Append(";"); source.Append(System.Environment.NewLine); } } else { object val = rightRed; System.Diagnostics.Debug.Assert(val is string == false); System.Diagnostics.Debug.Assert(val is ILExpression == false); env.SetValue(varName, val); } } catch (NullReferenceException) { source.Append("\t__spec_raise_null_ref_exception();"); source.Append(System.Environment.NewLine); } catch (IndexOutOfRangeException) { source.Append("\t__spec_raise_index_out_of_range_exception();"); source.Append(System.Environment.NewLine); } } else { System.Diagnostics.Debug.Assert(left.Type == ILExpressionType.ArrayAccess); try { var arrayName = left.LeftNode.Const.ToString(); object index = null; if (env.IsDynamic(left.RightNode.Const.ToString())) { index = left.RightNode.Const.ToString(); } else { index = env.GetValue(left.RightNode.Const.ToString()); } object rightVar = null; if (env.IsDynamic(right.Const.ToString())) { rightVar = right.Const.ToString(); } else { rightVar = env.GetValue(right.Const.ToString()); } if (env.IsDynamic(arrayName)) { source.Append("\t"); source.Append(arrayName); source.Append("["); source.Append(index); source.Append("] := "); source.Append(rightVar); source.Append(";"); source.Append(System.Environment.NewLine); } else { object[] a = (object[])env.GetValue(arrayName); a[Convert.ToInt32(index)] = rightVar; } } catch (NullReferenceException) { source.Append("\t__spec_raise_null_ref_exception();"); source.Append(System.Environment.NewLine); } catch (IndexOutOfRangeException) { source.Append("\t__spec_raise_index_out_of_range_exception();"); source.Append(System.Environment.NewLine); } } } else if (expr.Type == ILExpressionType.FunctionCall) { source.Append("\t"); source.Append(expr.Const.ToString()); source.Append("("); for (int i = 0; i < expr.VAList.Count; ++i) { string p = null; if (env.IsDynamic(expr.VAList[i].Const.ToString())) { p = expr.VAList[i].Const.ToString(); } else { p = RenderConst(env.GetValue(expr.VAList[i].Const.ToString())); } source.Append(p); if (i != expr.VAList.Count - 1) source.Append(", "); } source.Append(");"); source.Append(System.Environment.NewLine); } return false; }
internal static AbstractEnvironment _bindTimeAnalyze(ILFunction func, AbstractEnvironment initialEnvironment) { var env = initialEnvironment; int dynamicAdded = 0; do { dynamicAdded = 0; foreach (var instr in func.Body) { if (instr is ILExpression) { var expr = instr as ILExpression; if (expr.Type == ILExpressionType.Assign) { //Case 1 - assign to local variable if (expr.LeftNode.Type == ILExpressionType.VariableAccess) { if (m_simpleExprContainsDynamicVariables(expr.RightNode, env)) { //If reading from static array by dynamic index if (expr.RightNode.Type == ILExpressionType.ArrayAccess) { if (env.IsDynamic(expr.RightNode.LeftNode.Const.ToString()) == false) { env.SetValue(expr.RightNode.LeftNode.Const.ToString(), Dynamic.Value); dynamicAdded++; } } if (env.IsDynamic(expr.LeftNode.Const.ToString()) == false) { env.SetValue(expr.LeftNode.Const.ToString(), Dynamic.Value); dynamicAdded++; } } } //Case 2 - assign to array else if (expr.LeftNode.Type == ILExpressionType.ArrayAccess) { // A(s,d)[D] = S, D -> A:=D if (m_simpleExprContainsDynamicVariables(expr.LeftNode, env)) { if (env.IsDynamic(expr.LeftNode.LeftNode.Const.ToString()) == false) { env.SetValue(expr.LeftNode.LeftNode.Const.ToString(), Dynamic.Value); dynamicAdded++; } } // A(s)[S] = D -> A:=D else if (m_simpleExprContainsDynamicVariables(expr.RightNode, env)) { if (env.IsDynamic(expr.LeftNode.LeftNode.Const.ToString()) == false) { env.SetValue(expr.LeftNode.LeftNode.Const.ToString(), Dynamic.Value); dynamicAdded++; } } // A(s)[S] = S - do nothing, array is static (in this scope } } } } } while (dynamicAdded != 0); return env; }
public static List<ILFunction> EmitProgram(L1Program program) { f_functionFindMap = new Dictionary<FunctionDefinition, ILFunction>(); f_ilProgram = new List<ILFunction>(); foreach (var fDef in program.Functions) { ILFunction ilFun = new ILFunction(); ilFun.ReturnType = fDef.Header.ReturnType; if (fDef.Header.ReturnType == null) { ilFun.IsVoidReturn = true; } ilFun.Name = fDef.Header.FunctionName; foreach (var p in fDef.Header.Parameters) { ilFun.Parameters.Add(p.Name); } if (fDef.IsEmbedded) { ilFun.EmbeddedBody = fDef.Body; bool t = !L1Runtime.DynamicResultAttribute.IsDynamic(fDef.Body); ilFun.CanBeCalculatedWithoutRun = t; } else { f_ilProgram.Add(ilFun); } f_functionFindMap.Add(fDef, ilFun); } foreach (var KV in f_functionFindMap) { if (KV.Key.IsEmbedded == false) { //EmitStatementList(KV.Key.Statements, KV.Value.Body); CurrentFunction = KV.Value; foreach (var p in KV.Key.Header.Parameters) { CurrentFunction.AddLocal(p.Name, p.Type); } _EmitStatementList(KV.Key.Statements, KV.Value.Body); KV.Value.Body = ReduceList(KV.Value.Body); CurrentFunction = null; } } MarkDynamicFunctions(); //Debug output foreach (var KV in f_functionFindMap) { if (KV.Key.IsEmbedded == false) { Console.WriteLine (String.Format(".specentry {0} {1}", KV.Value.Name, KV.Value.CanBeCalculatedWithoutRun ? "" : ".dynamic")); foreach (ILInstuction inst in KV.Value.Body) Console.WriteLine(String.Format("{0}\t\t{1}", inst.Line, inst)); Console.WriteLine(".end"); Console.WriteLine(""); Console.WriteLine (".f_calls " + KV.Value.Name); var fcalls = FindAllFunctionCalls(KV.Value); foreach (var fcall in fcalls) Console.WriteLine(String.Format("{0}", fcall)); Console.WriteLine(".end"); Console.WriteLine(""); } } return f_ilProgram; }
public static List<ILExpression> FindAllFunctionCalls(ILFunction function, Func<ILExpression, bool> predicate) { List<ILExpression> result = new List<ILExpression>(); foreach (ILInstuction inst in function.Body) { if (inst is ILExpression) result.AddRange(FindAllFunctionCallsInExpr((ILExpression)inst).Where(predicate)); else if (inst is ILBranch) result.AddRange(FindAllFunctionCallsInExpr((inst as ILBranch).Condition).Where(predicate)); else if (inst is ILReturn) result.AddRange(FindAllFunctionCallsInExpr((inst as ILReturn).Return).Where(predicate)); } return result; }
public static List<ILExpression> FindAllFunctionCalls(ILFunction function) { return FindAllFunctionCalls(function, ilExpr => true); }