/// <summary> /// Use wildcards to replace any indices in expr which involve local variables of the gateBlock /// </summary> /// <param name="gateBlock"></param> /// <param name="expr"></param> /// <returns></returns> private IExpression ReplaceLocalIndices(GateBlock gateBlock, IExpression expr) { if (expr is IArrayIndexerExpression iaie) { IExpression target = ReplaceLocalIndices(gateBlock, iaie.Target); List <IExpression> indices = new List <IExpression>(); bool replaced = !ReferenceEquals(target, iaie.Target); foreach (IExpression index in iaie.Indices) { if (ContainsLocalVars(gateBlock, index)) { indices.Add(Builder.StaticMethod(new Func <int>(GateAnalysisTransform.AnyIndex))); replaced = true; } else { indices.Add(index); } } if (replaced) { expr = Builder.ArrayIndex(target, indices); } } return(expr); }
private List <ConditionBinding> FilterConditionContext(GateBlock gateBlock, List <ConditionBinding> conditionContext) { return(conditionContext .Where(binding => !CodeRecognizer.IsStochastic(context, binding.lhs) && !ContainsLocalVars(gateBlock, binding.lhs) && !ContainsLocalVars(gateBlock, binding.rhs)) .ToList()); }
protected override IVariableDeclaration ConvertVariableDecl(IVariableDeclaration ivd) { context.InputAttributes.Remove <GateBlock>(ivd); if (gateBlockContext.Count > 0) { GateBlock currentBlock = gateBlockContext[gateBlockContext.Count - 1]; context.InputAttributes.Set(ivd, currentBlock); } RegisterDeclaration(ivd); return(ivd); }
private int GetAncestorIndexOfGateBlock(GateBlock gateBlock) { for (int i = 0; i < context.InputStack.Count; i++) { if (context.InputStack[i].inputElement is IStatement st && context.InputAttributes.Get <GateBlock>(st) == gateBlock) { return(i); } } return(-1); }
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; } } }
private bool ContainsLocalVars(GateBlock gateBlock, IExpression expr) { return(Recognizer.GetVariables(expr).Any(ivd => (context.InputAttributes.Get <GateBlock>(ivd) == gateBlock) )); }
protected override IStatement ConvertCondition(IConditionStatement ics) { context.SetPrimaryOutput(ics); ConvertExpression(ics.Condition); ConditionBinding binding = GateTransform.GetConditionBinding(ics.Condition, context, out IForStatement loop); IExpression caseValue = binding.rhs; if (!GateTransform.IsLiteralOrLoopVar(context, caseValue, out loop)) { Error("If statement condition must compare to a literal or loop counter, was: " + ics.Condition); return(ics); } bool isStochastic = CodeRecognizer.IsStochastic(context, binding.lhs); IExpression gateBlockKey; if (isStochastic) { gateBlockKey = binding.lhs; } else { // definitions must not be unified across deterministic gate conditions gateBlockKey = binding.GetExpression(); } GateBlock gateBlock = null; Set <ConditionBinding> bindings = ConditionBinding.Copy(conditionContext); Dictionary <IExpression, GateBlock> blockMap; if (!gateBlocks.TryGetValue(bindings, out blockMap)) { // first time seeing these bindings blockMap = new Dictionary <IExpression, GateBlock>(); gateBlocks[bindings] = blockMap; } if (!blockMap.TryGetValue(gateBlockKey, out gateBlock)) { // first time seeing this lhs gateBlock = new GateBlock(); blockMap[gateBlockKey] = gateBlock; } if (gateBlock.hasLoopCaseValue && loop == null) { Error("Cannot compare " + binding.lhs + " to a literal, since it was previously compared to a loop counter. Put this test inside the loop."); } if (!gateBlock.hasLoopCaseValue && gateBlock.caseValues.Count > 0 && loop != null) { Error("Cannot compare " + binding.lhs + " to a loop counter, since it was previously compared to a literal. Put the literal case inside the loop."); } gateBlock.caseValues.Add(caseValue); if (loop != null) { gateBlock.hasLoopCaseValue = true; } gateBlockContext.Add(gateBlock); context.OutputAttributes.Set(ics, gateBlock); int startIndex = conditionContext.Count; conditionContext.Add(binding); ConvertBlock(ics.Then); if (ics.Else != null) { conditionContext.RemoveRange(startIndex, conditionContext.Count - startIndex); binding = binding.FlipCondition(); conditionContext.Add(binding); ConvertBlock(ics.Else); } conditionContext.RemoveRange(startIndex, conditionContext.Count - startIndex); gateBlockContext.RemoveAt(gateBlockContext.Count - 1); // remove any uses that match a def //RemoveUsesOfDefs(gateBlock); if (gateBlockContext.Count > 0) { GateBlock currentBlock = gateBlockContext[gateBlockContext.Count - 1]; // all variables defined/used in the inner block must be processed by the outer block foreach (ExpressionWithBindings eb in gateBlock.variablesDefined.Values) { if (eb.Bindings.Count > 0) { foreach (List <ConditionBinding> binding2 in eb.Bindings) { ProcessUse(eb.Expression, true, Union(conditionContext, binding2)); } } else { ProcessUse(eb.Expression, true, conditionContext); } } foreach (List <ExpressionWithBindings> ebs in gateBlock.variablesUsed.Values) { foreach (ExpressionWithBindings eb in ebs) { if (eb.Bindings.Count > 0) { foreach (ICollection <ConditionBinding> binding2 in eb.Bindings) { ProcessUse(eb.Expression, false, Union(conditionContext, binding2)); } } else { ProcessUse(eb.Expression, false, conditionContext); } } } } return(ics); }
/// <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> /// 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()); } }