public void TestNoDeclare() { var i = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int)); var sv = new ValSimple("5", typeof(int)); var s1 = new StatementAssign(i, sv); Assert.IsTrue(s1.CodeItUp().First().Trim().StartsWith("aInt32_"), "Check for decl: " + s1.CodeItUp().First()); }
public void TryCombineTwoNoneDeclaresDeclFound() { var i = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int)); var sv = new ValSimple("5", typeof(int)); var s1 = new StatementAssign(i, sv); var s2 = new StatementAssign(i, sv); Assert.IsTrue(s1.TryCombineStatement(s2, new DummyTrackingOptimizationService(true)), "Combine when no decl found"); }
public void TestBasicCMValues() { var i = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int)); var sv = new ValSimple("5", typeof(int)); var s1 = new StatementAssign(i, sv); Assert.AreEqual(1, s1.ResultVariables.Count(), "# result variables"); Assert.AreEqual(i.RawValue, s1.ResultVariables.First(), "the name"); Assert.AreEqual(0, s1.DependentVariables.Count(), "no dependent variables"); }
public void AssignDependents() { var p1 = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int)); var p2 = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int)); var v = new ValSimple($"{p2.RawValue}+10", typeof(int), new IDeclaredParameter[] { p2 }); var a = new StatementAssign(p1, v); Assert.AreEqual(1, a.DependentVariables.Count()); Assert.AreEqual(p2.RawValue, a.DependentVariables.First()); }
public void TestCMValuesForSimpleExpression() { var i = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int)); var di = DeclarableParameter.CreateDeclarableParameterExpression(typeof(double)); var sv = new ValSimple("5", typeof(int), new IDeclaredParameter[] { di }); var s1 = new StatementAssign(i, sv); Assert.AreEqual(1, s1.ResultVariables.Count(), "# result variables"); Assert.AreEqual(i.RawValue, s1.ResultVariables.First(), "the name"); Assert.AreEqual(1, s1.DependentVariables.Count(), "no dependent variables"); Assert.AreEqual(di.RawValue, s1.DependentVariables.First(), "a dependent variable"); }
public void TestCombineDifferentInitialValues() { IValue initial1 = new ValSimple("0", typeof(int)); IValue initial2 = new ValSimple("1", typeof(int)); IValue size = new ValSimple("10", typeof(int)); var lv1 = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int)); var lv2 = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int)); var p1 = new StatementForLoop(lv1, size, initial1); var p2 = new StatementForLoop(lv2, size, initial2); var r = p1.TryCombineStatement(p2, new dummyOpt()); Assert.IsFalse(r, "different initial conditions, should be null"); }
public void TestRememberEmbededConstExpr() { var gc = new GeneratedCode(); var c1 = Expression.Constant(new ROOTNET.NTH1F("hi", "there", 100, 0.0, 10.0)); var c2 = Expression.Constant(new ROOTNET.NTH1F("no", "way", 100, 0.0, 10.0)); var n1 = Expression.Call(c1, typeof(ROOTNET.NTH1F).GetMethod("GetNbinsX")); var n2 = Expression.Call(c2, typeof(ROOTNET.NTH1F).GetMethod("GetNbinsX")); var r1 = new ValSimple("1", typeof(int)); var r2 = new ValSimple("2", typeof(int)); gc.RememberSubexpression(n1, r1); gc.RememberSubexpression(n2, r2); Assert.AreEqual(r1, gc.LookupSubexpression(n1), "lookup n1"); Assert.AreEqual(r2, gc.LookupSubexpression(n2), "lookup n2"); }
public void AggregateCombineWithRenameNoChance() { // a = a + b // c = c + b // These two should combine correctly, somehow. var a = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int)); var ainc = new ValSimple(string.Format("{0}+b", a.ParameterName), typeof(int)); var s1 = new StatementAggregate(a, ainc); var c = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int)); var cinc = new ValSimple(string.Format("{0}+b", c.ParameterName), typeof(int)); var s2 = new StatementAggregate(c, cinc); var opt = new MyCodeOptimizer(false); var result = s1.TryCombineStatement(s2, opt); Assert.IsFalse(result, "Expected combination would work"); }
/// <summary> /// We are looking at a&&b or a||b. We wnat to make sure we evaluate b iff we need it, depending on the result of a. /// </summary> /// <param name="expr"></param> /// <param name="ce"></param> /// <param name="cc"></param> /// <param name="container"></param> /// <returns></returns> /// <remarks> /// To prevent us from updating variables (which makes optmization harder), we will implement the code as follows for a&&b: /// bool_1 = false; bool_2 = false; bool_3 = false; /// bool_1 = a /// if (bool_1) bool_2 = b /// bool_3 = bool_1 && bool_2 ///</remarks> private static IValue GetExpressionForBoolAndOr(Expression expr, IGeneratedQueryCode ce, ICodeContext cc, CompositionContainer container) { // Svae to make sure we can get back. var outterScope = ce.CurrentScope; // Create a variable to hold the result of this test var resultBool3 = DeclarableParameter.CreateDeclarableParameterExpression(typeof(bool)); resultBool3.InitialValue = new ValSimple("false", typeof(bool)); ce.Add(resultBool3); // Create and evaluate bool_1 var binaryExpression = expr as BinaryExpression; DeclarableParameter resultBool1 = AssignExpreaaionToEvaluationIfNeededBool(ce, cc, container, binaryExpression.Left); // Now, see if we need to evalute the right hand operand. if (expr.NodeType == ExpressionType.AndAlso) { ce.Add(new Statements.StatementFilter(resultBool1)); } else { var notYet = new ValSimple($"!{resultBool1.RawValue}", typeof(bool), new IDeclaredParameter[] { resultBool1 }); ce.Add(new Statements.StatementFilter(notYet)); } // Create and evaluate bool 1. var resultBool2 = AssignExpreaaionToEvaluationIfNeededBool(ce, cc, container, binaryExpression.Right, outterScope); ce.CurrentScope = outterScope; // Finally, evaluate bool3. var termEvaluation = expr.NodeType == ExpressionType.AndAlso ? $"{resultBool1.RawValue}&&{resultBool2.RawValue}" : $"{resultBool1.RawValue}||{resultBool2.RawValue}"; ce.Add(new Statements.StatementAssign(resultBool3, new ValSimple(termEvaluation, typeof(bool), new[] { resultBool1, resultBool2 }))); // Return the value we've now filled. return(resultBool3); }
public void AggregateCombineWithRename() { // a = a + b // c = c + b // These two should combine correctly, somehow. var a = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int)); var ainc = new ValSimple(string.Format("{0}+b", a.ParameterName), typeof(int)); var s1 = new StatementAggregate(a, ainc); var c = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int)); var cinc = new ValSimple(string.Format("{0}+b", c.ParameterName), typeof(int)); var s2 = new StatementAggregate(c, cinc); var opt = new MyCodeOptimizer(true); var result = s1.TryCombineStatement(s2, opt); Assert.IsTrue(result, "Expected combination would work"); Assert.AreEqual(a.ParameterName, opt.NewVariable.ParameterName, "new name not renamed to"); Assert.AreEqual(c.ParameterName, opt.OldName, "old name for rename not right"); }
/// <summary> /// New a ROOT object. Make sure that it gets dtor'd! /// </summary> /// <param name="expression"></param> /// <param name="result"></param> /// <param name="gc"></param> /// <param name="context"></param> /// <param name="container"></param> /// <returns></returns> public Expression ProcessNew(NewExpression expression, out IValue result, IGeneratedQueryCode gc, CompositionContainer container) { /// /// Do checks /// if (gc == null) { throw new ArgumentException("gc"); } if (expression == null) { throw new ArgumentNullException("expression"); } /// /// Figure out the type. We can only get here if we get through ROOTNET.xxx /// result = null; string tname = expression.Type.FullName.Substring(8); if (tname[0] != 'N') { throw new ArgumentException(string.Format("Don't know how to translate to a ROOT type '{0}'", expression.Type.FullName)); } tname = tname.Substring(1); /// /// We assume the include file "just works" - this is ROOT, after all. But lets hope. /// This is something we might have to deal with later. :-) /// gc.AddIncludeFile(string.Format("{0}.h", tname)); /// /// Now, build the constructor, and add it to the statement list. /// var ctor = new StringBuilder(); var ctorName = expression.Type.CreateUniqueVariableName(); ctor.AppendFormat("{0} {1}", tname, ctorName); var argDep = AddMethodArguments(expression.Arguments, gc, container, ctor).ToArray(); gc.Add(new Statements.StatementSimpleStatement(ctor.ToString(), dependentVars: argDep.Select(i => i.RawValue).ToArray(), resultVars: new string[] { ctorName })); /// /// Now, everything in the C++ translation is a pointer, so we will /// not create a pointer to this guy. /// var ptrDecl = new StringBuilder(); var ptrName = expression.Type.CreateUniqueVariableName(); ptrDecl.AppendFormat("{0} *{1} = &{2}", tname, ptrName, ctorName); gc.Add(new Statements.StatementSimpleStatement(ptrDecl.ToString(), dependentVars: new string[] { ctorName }, resultVars: new string[] { ptrName })); /// /// That pointer is what we return for later use! /// result = new ValSimple(ptrName, expression.Type, argDep); return(expression); }
/// <summary> /// Translate the method call /// </summary> /// <param name="expr"></param> /// <param name="result"></param> /// <param name="gc"></param> /// <param name="context"></param> /// <returns></returns> public IValue CodeMethodCall(MethodCallExpression expr, IGeneratedQueryCode gc, CompositionContainer container) { Init(); /// /// First see if we can't locate the method call that at least matches in names /// var matchingMethodNames = from kt in _knownTypes where kt.Name == expr.Method.DeclaringType.Name from m in kt.Methods where m.Name == expr.Method.Name select new { theType = kt, theMethod = m }; /// /// Next, match with the arguments /// var matchingMethod = from m in matchingMethodNames where m.theMethod.Arguments.Length == expr.Arguments.Count where m.theMethod.Arguments.Zip(expr.Arguments, (us, them) => new Tuple <KnownTypeInfo.MechodArg, Expression>(us, them)).All(apair => apair.Item1.Type == apair.Item2.Type.FullName) select m; /// /// Ok, at this point, we should have only one guy. If we have more then just choose the first /// var method = matchingMethod.FirstOrDefault(); if (method == null) { throw new ArgumentException("Could not find a matching method to translate for the call " + expr.ToString()); } /// /// And now translate the call /// StringBuilder rawValue = new StringBuilder(); rawValue.Append(method.theMethod.CPPName); rawValue.Append("("); bool first = true; var dependents = Enumerable.Empty <IDeclaredParameter>(); foreach (var arg in expr.Arguments.Zip(method.theMethod.Arguments, (m, a) => Tuple.Create(m, a))) { if (!first) { rawValue.Append(","); } first = false; var e = ExpressionToCPP.InternalGetExpression(arg.Item1, gc, null, container); rawValue.AppendFormat("({0}){1}", arg.Item2.CPPType, e.RawValue); dependents = dependents.Concat(e.Dependants); } rawValue.Append(")"); var result = new ValSimple(rawValue.ToString(), expr.Type, dependents); /// /// Include files /// foreach (var ifile in method.theMethod.IncludeFiles) { gc.AddIncludeFile(ifile); } /// /// We aren't re-writing this expression, so just return it. /// return(result); }
/// <summary> /// Build a code statement from the include files, the expression for the method call, and the generated lines of code. /// </summary> /// <param name="expr"></param> /// <param name="gc"></param> /// <param name="container"></param> /// <param name="includeFiles"></param> /// <param name="loc"></param> /// <returns></returns> public static IValue BuildCPPCodeStatement(MethodCallExpression expr, IGeneratedQueryCode gc, CompositionContainer container, string[] includeFiles, string[] loc) { // Get include files in. if (includeFiles != null) { foreach (var inc in includeFiles) { gc.AddIncludeFile(inc); } } // Next, go after the lines of code. We have to first sort out what parameter names we are looking at, // and then force a translation of those parameters into simple values we can pass to the C++ code we // are going to pull back. var paramsTranslated = from p in expr.Arguments.Zip(expr.Method.GetParameters(), (arg, param) => Tuple.Create(arg, param)) select new { Name = p.Item2.Name, Translated = ExpressionToCPP.InternalGetExpression(p.Item1, gc, null, container) }; var paramLookup = paramsTranslated.ToDictionary(v => v.Name, v => v.Translated.ApplyParensIfNeeded()); // Parse out the list of variables that are used. We will be passing these up the line as needed // so that we can tell how to optimize things. var dependents = new HashSet <string>(FindDeclarableParameters.FindAll(expr).Select(e => e.RawValue)); // We also need a return variable. Since this can be multiple lines of code and we don't // know how the result will be used, we have to declare it up front... and pray they // use it correctly! :-) var cppResult = DeclarableParameter.CreateDeclarableParameterExpression(expr.Type); var cppStatement = new CPPCodeStatement(expr.Method, cppResult, loc, dependents); gc.Add(cppStatement); gc.Add(cppResult); paramLookup.Add(expr.Method.Name, cppResult.RawValue); var result = new ValSimple(cppResult.RawValue, expr.Type, DeclarableParameter.CreateDeclarableParameterExpression(cppResult.RawValue, expr.Type).AsArray()); // Make sure a result exists in here! This at least will prevent some bad C++ code from getting generated! var lookForResult = new Regex(string.Format(@"\b{0}\b", expr.Method.Name)); bool didReference = loc.Any(l => lookForResult.Match(l).Success); if (!didReference) { throw new ArgumentException(string.Format("The C++ code attached to the method '{0}' doesn't seem to set a result.", expr.Method.Name)); } // Figure out if there are any Unique variables. If there are, then we need to do // a replacement on them. var findUnique = new Regex(@"\b\w*Unique\b"); var varUniqueRequests = (from l in loc let matches = findUnique.Matches(l) from m in Enumerable.Range(0, matches.Count) select matches[m].Value).Distinct(); foreach (var varRepl in varUniqueRequests) { var uniqueName = varRepl.Substring(0, varRepl.Length - "Unique".Length); var uniqueTranslated = uniqueName + _uniqueCounter.ToString(); cppStatement.AddUniqueVariable(varRepl, uniqueTranslated); _uniqueCounter++; } // Add the parameters that need to be translated here. foreach (var paramName in paramLookup) { cppStatement.AddParamReplacement(paramName.Key, paramName.Value); } return(result); }