/// <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); }
private void RemoveUsesOfDefs(GateBlock gateBlock) { foreach (KeyValuePair <IVariableDeclaration, ExpressionWithBindings> entry in gateBlock.variablesDefined) { IVariableDeclaration ivd = entry.Key; ExpressionWithBindings eb = entry.Value; if (gateBlock.variablesUsed.TryGetValue(ivd, out List <ExpressionWithBindings> ebs)) { List <ExpressionWithBindings> keep = new List <ExpressionWithBindings>(); foreach (ExpressionWithBindings eb2 in ebs) { if (!CouldOverlap(eb, eb2)) { keep.Add(eb2); } } gateBlock.variablesUsed[ivd] = keep; } } }
internal static bool CouldOverlap(ExpressionWithBindings eb1, ExpressionWithBindings eb2) { var emptyBindings = (IEnumerable <IReadOnlyCollection <ConditionBinding> >) new[] { new ConditionBinding[0] }; IEnumerable <IReadOnlyCollection <ConditionBinding> > bindings1 = (eb1.Bindings.Count > 0) ? eb1.Bindings : emptyBindings; IEnumerable <IReadOnlyCollection <ConditionBinding> > bindings2 = (eb2.Bindings.Count > 0) ? eb2.Bindings : emptyBindings; foreach (IReadOnlyCollection <ConditionBinding> binding1 in bindings1) { foreach (IReadOnlyCollection <ConditionBinding> binding2 in bindings2) { // TODO: investigate whether we need to provide local var predicate. if (Recognizer.MutatingFirstAffectsSecond(eb1.Expression, eb2.Expression, binding1, binding2, ivd => false)) { return(true); } } } return(false); }
/// <summary> /// Add expr to currentBlock.variablesDefined or currentBlock.variablesUsed /// </summary> /// <param name="expr"></param> /// <param name="isDef"></param> /// <param name="conditionContext"></param> protected void ProcessUse(IExpression expr, bool isDef, List <ConditionBinding> conditionContext) { IVariableDeclaration ivd = Recognizer.GetVariableDeclaration(expr); if (ivd == null) { return; } if (!CodeRecognizer.IsStochastic(context, ivd)) { return; } if (gateBlockContext.Count == 0) { return; } GateBlock currentBlock = gateBlockContext[gateBlockContext.Count - 1]; GateBlock gateBlockOfVar = context.InputAttributes.Get <GateBlock>(ivd); if (gateBlockOfVar == currentBlock) { return; // local variable of the gateBlock } ExpressionWithBindings eb = new ExpressionWithBindings(); eb.Expression = ReplaceLocalIndices(currentBlock, expr); List <ConditionBinding> bindings = FilterConditionContext(currentBlock, conditionContext); if (bindings.Count > 0) { eb.Bindings.Add(bindings); } //eb.Containers = Containers.InsideOf(context, GetAncestorIndexOfGateBlock(currentBlock)); if (isDef) { ExpressionWithBindings eb2; if (!currentBlock.variablesDefined.TryGetValue(ivd, out eb2)) { currentBlock.variablesDefined[ivd] = eb; } else { // all definitions of the same variable must have a common parent currentBlock.variablesDefined[ivd] = GetCommonParent(eb, eb2); } } else { List <ExpressionWithBindings> ebs; if (!currentBlock.variablesUsed.TryGetValue(ivd, out ebs)) { ebs = new List <ExpressionWithBindings>(); ebs.Add(eb); currentBlock.variablesUsed[ivd] = ebs; } else { // collect all uses that overlap with eb, and replace with their common parent List <ExpressionWithBindings> notOverlapping = new List <ExpressionWithBindings>(); while (true) { foreach (ExpressionWithBindings eb2 in ebs) { ExpressionWithBindings parent = GetCommonParent(eb, eb2); if (CouldOverlap(eb, eb2)) { eb = parent; } else { notOverlapping.Add(eb2); } } if (notOverlapping.Count == ebs.Count) { break; // nothing overlaps } // eb must have changed, so try again using the new eb ebs.Clear(); ebs.AddRange(notOverlapping); notOverlapping.Clear(); } ebs.Add(eb); currentBlock.variablesUsed[ivd] = ebs; } } }
/// <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); } } }
/// <summary> /// Add expr to currentBlock.variablesDefined or currentBlock.variablesUsed /// </summary> /// <param name="expr"></param> /// <param name="isDef"></param> /// <param name="conditionContext"></param> protected void ProcessUse(IExpression expr, bool isDef, List <ConditionBinding> conditionContext) { IVariableDeclaration ivd = Recognizer.GetVariableDeclaration(expr); if (ivd == null) { return; } if (!CodeRecognizer.IsStochastic(context, ivd)) { return; } if (gateBlockContext.Count == 0) { return; } GateBlock currentBlock = gateBlockContext[gateBlockContext.Count - 1]; GateBlock gateBlockOfVar = context.InputAttributes.Get <GateBlock>(ivd); if (gateBlockOfVar == currentBlock) { return; // local variable of the gateBlock } ExpressionWithBindings eb = new ExpressionWithBindings(ReplaceLocalIndices(currentBlock, expr), FilterConditionContext(currentBlock)); if (isDef) { if (currentBlock.variablesDefined.TryGetValue(ivd, out ExpressionWithBindings eb2)) { // all definitions of the same variable must have a common parent currentBlock.variablesDefined[ivd] = GetCommonParent(eb, eb2); } else { currentBlock.variablesDefined[ivd] = eb; } } else { if (currentBlock.variablesUsed.TryGetValue(ivd, out List <ExpressionWithBindings> ebs)) { // collect all uses that overlap with eb, and replace with their common parent List <ExpressionWithBindings> notOverlapping = new List <ExpressionWithBindings>(); while (true) { foreach (ExpressionWithBindings eb2 in ebs) { if (CouldOverlap(eb, eb2, ignoreBindings: GateTransform.DeterministicEnterExit)) { eb = GetCommonParent(eb, eb2); } else { notOverlapping.Add(eb2); } } if (notOverlapping.Count == ebs.Count) { break; // nothing overlaps } // eb must have changed, so try again using the new eb ebs.Clear(); ebs.AddRange(notOverlapping); notOverlapping.Clear(); } ebs.Add(eb); currentBlock.variablesUsed[ivd] = ebs; } else { currentBlock.variablesUsed[ivd] = new List <ExpressionWithBindings> { eb }; } } List <ConditionBinding> FilterConditionContext(GateBlock gateBlock) { return(conditionContext .Where(binding => !CodeRecognizer.IsStochastic(context, binding.lhs) && !ContainsLocalVars(gateBlock, binding.lhs) && !ContainsLocalVars(gateBlock, binding.rhs)) .ToList()); } }