/// <summary> /// Return the common parent of the two expressions, and indicate if the expressions overlap /// </summary> /// <param name="eb1"></param> /// <param name="eb2"></param> /// <returns></returns> /// <remarks> /// When finding the common parent, we want to preserve any array slicing. Indexing brackets are not removed if present in both expressions. /// Mismatching indices are replaced by AnyIndex. /// Examples: /// i = loop index inside the gate block /// j = loop index outside the gate block, or a method parameter /// (a,a[i]) => (a,true) /// (a,a[j]) => (a,true) /// (a[i],a[0]) => (a[*],true) /// (a[i],a[j]) => (a[*],true) /// (a[j],a[0]) => (a[*],assumeMatch) /// (a[0],a[1]) => (a[*],false) /// (a[0][0],a[1][0]) => (a[*][0],false) /// (a[0][0],a[1][1]) => (a[*][*],false) /// </remarks> private static ExpressionWithBindings GetCommonParent(ExpressionWithBindings eb1, ExpressionWithBindings eb2) { List <IExpression> prefixes1 = Recognizer.GetAllPrefixes(eb1.Expression); List <IExpression> prefixes2 = Recognizer.GetAllPrefixes(eb2.Expression); if (!prefixes1[0].Equals(prefixes2[0])) { throw new Exception("Expressions have no overlap: " + eb1 + "," + eb2); } IExpression parent = prefixes1[0]; int count = System.Math.Min(prefixes1.Count, prefixes2.Count); for (int i = 1; i < count; i++) { IExpression prefix1 = prefixes1[i]; IExpression prefix2 = prefixes2[i]; if (prefix1 is IArrayIndexerExpression) { IArrayIndexerExpression iaie1 = (IArrayIndexerExpression)prefix1; if (prefix2 is IArrayIndexerExpression) { IArrayIndexerExpression iaie2 = (IArrayIndexerExpression)prefix2; if (iaie1.Indices.Count != iaie2.Indices.Count) { throw new Exception("Array rank mismatch: " + eb1 + "," + eb2); } IList <IExpression> indices = Builder.ExprCollection(); for (int ind = 0; ind < iaie1.Indices.Count; ind++) { IExpression index1 = iaie1.Indices[ind]; IExpression index2 = iaie2.Indices[ind]; IExpression index = Unify(index1, eb1.Bindings, index2, eb2.Bindings); indices.Add(index); } parent = Builder.ArrayIndex(parent, indices); } else { break; } } else { throw new Exception("Unhandled expression type: " + prefix1); } } ExpressionWithBindings result = new ExpressionWithBindings(); result.Expression = parent; if (eb1.Bindings.Count > 0 && eb2.Bindings.Count > 0) { result.Bindings.AddRange(eb1.Bindings); result.Bindings.AddRange(eb2.Bindings); } return(result); }
protected static IExpression GetCommonPrefix(IExpression expr, IExpression expr2) { List <IExpression> prefixes1 = Recognizer.GetAllPrefixes(expr); List <IExpression> prefixes2 = Recognizer.GetAllPrefixes(expr2); if (!prefixes1[0].Equals(prefixes2[0])) { throw new Exception($"Expressions have no overlap: {expr}, {expr2}"); } int count = System.Math.Min(prefixes1.Count, prefixes2.Count); for (int i = 1; i < count; i++) { IExpression prefix1 = prefixes1[i]; IExpression prefix2 = prefixes2[i]; if (!prefix1.Equals(prefix2)) { return(prefixes1[i - 1]); } } return(prefixes1[count - 1]); }
/// <summary> /// Return the common parent of the two expressions, and indicate if the expressions overlap /// </summary> /// <param name="eb1"></param> /// <param name="eb2"></param> /// <returns></returns> /// <remarks> /// When finding the common parent, we want to preserve any array slicing. Indexing brackets are not removed if present in both expressions. /// Mismatching indices are replaced by AnyIndex. /// Examples: /// i = loop index inside the gate block /// j = loop index outside the gate block, or a method parameter /// (a,a[i]) => (a,true) /// (a,a[j]) => (a,true) /// (a[i],a[0]) => (a[*],true) /// (a[i],a[j]) => (a[*],true) /// (a[j],a[0]) => (a[*],assumeMatch) /// (a[0],a[1]) => (a[*],false) /// (a[0][0],a[1][0]) => (a[*][0],false) /// (a[0][0],a[1][1]) => (a[*][*],false) /// </remarks> private static ExpressionWithBindings GetCommonParent(ExpressionWithBindings eb1, ExpressionWithBindings eb2) { List <IExpression> prefixes1 = Recognizer.GetAllPrefixes(eb1.Expression); List <IExpression> prefixes2 = Recognizer.GetAllPrefixes(eb2.Expression); if (!prefixes1[0].Equals(prefixes2[0])) { throw new Exception("Expressions have no overlap: " + eb1 + "," + eb2); } IExpression parent = prefixes1[0]; int count = System.Math.Min(prefixes1.Count, prefixes2.Count); for (int i = 1; i < count; i++) { IExpression prefix1 = prefixes1[i]; IExpression prefix2 = prefixes2[i]; if (prefix1 is IArrayIndexerExpression iaie1) { if (prefix2 is IArrayIndexerExpression iaie2) { if (iaie1.Indices.Count != iaie2.Indices.Count) { throw new Exception("Array rank mismatch: " + eb1 + "," + eb2); } IList <IExpression> indices = Builder.ExprCollection(); for (int ind = 0; ind < iaie1.Indices.Count; ind++) { IExpression index1 = iaie1.Indices[ind]; IExpression index2 = iaie2.Indices[ind]; IExpression index = Unify(index1, eb1.Bindings, index2, eb2.Bindings); indices.Add(index); } parent = Builder.ArrayIndex(parent, indices); } else { break; } } else { throw new Exception("Unhandled expression type: " + prefix1); } } ExpressionWithBindings result = new ExpressionWithBindings(); result.Expression = parent; if (eb1.Bindings.Count > 0 && eb2.Bindings.Count > 0) { result.Bindings.AddRange(eb1.Bindings); result.Bindings.AddRange(eb2.Bindings); } return(result); // Returns an expression equal to expr1 and expr2 under their respective bindings, or null if the expressions are not equal. IExpression Unify( IExpression expr1, IEnumerable <IReadOnlyCollection <ConditionBinding> > bindings1, IExpression expr2, IEnumerable <IReadOnlyCollection <ConditionBinding> > bindings2) { if (expr1.Equals(expr2)) { return(expr1); } foreach (IReadOnlyCollection <ConditionBinding> binding2 in bindings2) { IExpression expr1b = ReplaceExpression(binding2, expr1); if (expr1b.Equals(expr2)) { return(expr1); } } foreach (IReadOnlyCollection <ConditionBinding> binding1 in bindings1) { IExpression expr2b = ReplaceExpression(binding1, expr2); if (expr2b.Equals(expr1)) { return(expr2); } } bool lift = false; if (lift) { IExpression lifted1 = GetLiftedExpression(expr1, bindings1); IExpression lifted2 = GetLiftedExpression(expr2, bindings2); if (lifted1 != null && lifted1.Equals(lifted2)) { return(lifted1); } } return(Builder.StaticMethod(new Func <int>(GateAnalysisTransform.AnyIndex))); IExpression GetLiftedExpression(IExpression expr, IEnumerable <IReadOnlyCollection <ConditionBinding> > bindings) { IExpression lifted = null; foreach (IReadOnlyCollection <ConditionBinding> binding in bindings) { IExpression lhs = null; foreach (ConditionBinding b in binding) { if (b.rhs.Equals(expr)) { lhs = b.lhs; } } if (lifted == null) { lifted = lhs; } else if (lhs == null || !lifted.Equals(lhs)) { return(null); } } return(lifted); } } }