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 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 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; }
//Simple expr contains dynamic variables? private static bool m_simpleExprContainsDynamicVariables(ILExpression expr, AbstractEnvironment env) { if (expr.Type == ILExpressionType.FunctionCall) { if (expr.Function.EmbeddedBody != null && !expr.Function.CanBeCalculatedWithoutRun) return true; foreach (var arg in expr.VAList) { if (env.IsDynamic(arg.Const.ToString())) return true; } if (expr.Function.CanBeCalculatedWithoutRun == false) { return true; } } else if (expr.Type == ILExpressionType.VariableAccess) { if (env.IsDynamic(expr.Const.ToString())) return true; } else { if (expr.LeftNode != null) { if (env.IsDynamic(expr.LeftNode.Const.ToString())) return true; } if (expr.RightNode != null) { if (env.IsDynamic(expr.RightNode.Const.ToString())) return true; } } return false; }
//Reduce RIGHT part of il_expression public object AbstactReduce(string leftVariable, AbstractEnvironment state, Dictionary<string, VariableType> localTypeScope) { if (Type == ILExpressionType.Const) { if (Const is string) { var s = (string)Const; var a = new object[s.Length]; for (int i = 0; i < s.Length; ++i) { a[i] = (int)s[i]; } return a; } return Const; } //Only variable else if (Type == ILExpressionType.VariableAccess) { if (state.IsDynamic(Const.ToString())) return Const.ToString(); else return state.GetValue(Const.ToString()); } else if (Type == ILExpressionType.Alloc) { bool isDynamicLeftPart = state.IsDynamic(leftVariable); if (isDynamicLeftPart || state.IsDynamic(LeftNode.Const.ToString())) { return "new " + localTypeScope[leftVariable].NestedType.ToCompileableString() + "[" + v(state, LeftNode.Const.ToString()) + "]"; } else { int arraySize = (int)state.GetValue(LeftNode.Const.ToString()); var a = new object[arraySize]; object defElem = null; if (localTypeScope[leftVariable].NestedType.TypeEnum == VariableTypeEnum.Integer) { defElem = 0; } if (localTypeScope[leftVariable].NestedType.TypeEnum == VariableTypeEnum.Bool) { defElem = false; } for (int i = 0; i < arraySize; ++i) { a[i] = defElem; } return a; } } else if (Type == ILExpressionType.FunctionCall) { return this; } //Binary expression & unary else { object r = Eval(state); if (r == Dynamic.Value) return GetOp(LeftNode.Const.ToString(), (RightNode != null) ? RightNode.Const.ToString() : "", Type, state); else return r; } }
//REDNER variable or it's value private object v(AbstractEnvironment env, string vname) { if (env.IsDynamic(vname)) return vname; else return rc(env.GetValue(vname)); }