protected override IStatement DoConvertStatement(IStatement ist) { if (ist is IExpressionStatement) { bool isAccumulator = false; IExpressionStatement ies = (IExpressionStatement)ist; if (ies.Expression is IAssignExpression) { IAssignExpression iae = (IAssignExpression)ies.Expression; AccumulationInfo ac = context.InputAttributes.Get <AccumulationInfo>(ies); if (ac != null) { // This statement defines an accumulator. // Delete the statement and replace with any remaining accumulations. if (!ac.isInitialized) { context.AddStatementBeforeCurrent(ac.initializer); } ac.isInitialized = false; context.AddStatementsBeforeCurrent(ac.statements); isAccumulator = true; } object ivd = Recognizer.GetVariableDeclaration(iae.Target); if (ivd == null) { ivd = Recognizer.GetFieldReference(iae.Target); } if (ivd != null) { MessageArrayInformation mai = context.InputAttributes.Get <MessageArrayInformation>(ivd); bool oneUse = (mai != null) && (mai.useCount == 1); List <AccumulationInfo> ais = context.InputAttributes.GetAll <AccumulationInfo>(ivd); foreach (AccumulationInfo ai in ais) { if (!context.InputAttributes.Has <OperatorStatement>(ist)) { if (oneUse) { return(null); // remove the statement } else { continue; } } // assuming that we only accumulate one statement, we should always initialize if (true || !ai.isInitialized) { // add the initializer in the same containers as the original accumulation statement int ancIndex = ai.containers.GetMatchingAncestorIndex(context); Containers missing = ai.containers.GetContainersNotInContext(context, ancIndex); context.AddStatementBeforeAncestorIndex(ancIndex, Containers.WrapWithContainers(ai.initializer, missing.outputs)); ai.isInitialized = true; } // This statement defines a variable that contributes to an accumulator. IList <IStatement> stmts = Builder.StmtCollection(); IExpression target = iae.Target; Type exprType = target.GetExpressionType(); IExpression accumulator = ai.accumulator; Type accumulatorType = ai.type; int rank; Type eltType = Util.GetElementType(exprType, out rank); if (rank == 1 && eltType == accumulatorType) { // This statement defines an array of items to be accumulated. VariableInformation varInfo = context.InputAttributes.Get <VariableInformation>(mai.ci.decl); int indexingDepth = Recognizer.GetIndexingDepth(iae.Target); if (mai.loopVarInfo != null) { indexingDepth -= mai.loopVarInfo.indexVarRefs.Length; } IExpression size = varInfo.sizes[indexingDepth][0]; IVariableDeclaration indexVar = varInfo.indexVars[indexingDepth][0]; IForStatement ifs = Builder.ForStmt(indexVar, size); target = Builder.ArrayIndex(target, Builder.VarRefExpr(indexVar)); ifs.Body.Statements.Add(ai.GetAccumulateStatement(context, accumulator, target)); stmts.Add(ifs); } else { Stack <IList <IExpression> > indexStack = new Stack <IList <IExpression> >(); while (exprType != accumulatorType && target is IArrayIndexerExpression) { // The accumulator is an array type, and this statement defines an element of the accumulator type. // Peel off the indices of the target. IArrayIndexerExpression iaie = (IArrayIndexerExpression)target; indexStack.Push(iaie.Indices); target = iaie.Target; accumulatorType = Util.GetElementType(accumulatorType); } while (indexStack.Count > 0) { // Attach the indices of the target to the accumulator, in reverse order that they were peeled. accumulator = Builder.ArrayIndex(accumulator, indexStack.Pop()); } if (exprType == accumulatorType) { if (oneUse && !isAccumulator) { // convert // msg = expr; // into // T temp = expr; // acc = SetToProduct(acc, temp); // and move into ai.statement. tempVarCount++; string name = "_temp" + tempVarCount; IVariableDeclaration tempVar = Builder.VarDecl(name, exprType); IStatement newStatement = Builder.AssignStmt(Builder.VarDeclExpr(tempVar), iae.Expression); context.AddStatementBeforeCurrent(newStatement); context.AddStatementBeforeCurrent(ai.GetAccumulateStatement(context, accumulator, Builder.VarRefExpr(tempVar))); return(null); } else { // must keep the original statement. // add // acc = SetToProduct(acc, msg); // to ai.statements. context.AddStatementAfterCurrent(ai.GetAccumulateStatement(context, accumulator, iae.Target)); } } else { Error("Unrecognized variable type: " + StringUtil.TypeToString(exprType)); } } Containers containers = new Containers(context); containers = containers.Remove(ai.containers); IList <IStatement> output2 = Builder.StmtCollection(); Containers.AddStatementWithContainers(output2, stmts, containers.inputs); foreach (IStatement ist2 in output2) { context.AddStatementAfterCurrent(ist2); } } } } if (!isAccumulator) { return(ist); } else { return(null); } } else { return(base.DoConvertStatement(ist)); } }
/// <summary> /// Converts variable declarations inside loops into array declarations at the top level. /// </summary> /// <param name="ivde"></param> /// <returns></returns> protected override IExpression ConvertVariableDeclExpr(IVariableDeclarationExpression ivde) { IVariableDeclaration ivd = ivde.Variable; bool isLoneDeclaration = (context.FindAncestorIndex <IExpressionStatement>() == context.Depth - 2); List <IForStatement> loops = context.FindAncestors <IForStatement>(); if (loops.Count == 0) { List <IConditionStatement> ifs = context.FindAncestors <IConditionStatement>(); if (ifs.Count == 0) { return(ivde); } // Add declaration outside the if IStatement outermostContainer = ifs[0]; int ancIndex = context.GetAncestorIndex(outermostContainer); var defaultExpr = Builder.DefaultExpr(ivd.VariableType); var assignSt = Builder.AssignStmt(ivde, defaultExpr); context.OutputAttributes.Set(assignSt, new Initializer()); context.AddStatementBeforeAncestorIndex(ancIndex, assignSt); if (isLoneDeclaration) { return(null); } else { return(Builder.VarRefExpr(ivd)); } } // ignore declaration of a loop variable if (Recognizer.LoopVariable(loops[loops.Count - 1]) == ivd) { return(ivde); } // Declaration is inside one or more loops, find their sizes and index variables Type type = Builder.ToType(ivd.VariableType); Type arrayType = type; LoopVarInfo lvi = new LoopVarInfo(loops); for (int i = 0; i < loops.Count; i++) { IForStatement loop = loops[i]; lvi.indexVarRefs[i] = Builder.VarRefExpr(Recognizer.LoopVariable(loop)); arrayType = Util.MakeArrayType(arrayType, 1); } Predicate <int> isPartitionedAtDepth = (depth => context.InputAttributes.Has <Partitioned>(Recognizer.GetVariableDeclaration(lvi.indexVarRefs[depth]))); Type messageType = Distributions.Distribution.IsDistributionType(type) ? MessageTransform.GetDistributionType(arrayType, type, type, 0, loops.Count, isPartitionedAtDepth) : MessageTransform.GetArrayType(arrayType, type, 0, isPartitionedAtDepth); lvi.arrayvd = Builder.VarDecl(ivd.Name, messageType); loopVarInfos[ivd] = lvi; MessageArrayInformation mai = context.InputAttributes.Get <MessageArrayInformation>(ivd); if (mai != null) { mai.loopVarInfo = lvi; } context.InputAttributes.CopyObjectAttributesTo(ivd, context.OutputAttributes, lvi.arrayvd); context.InputAttributes.Remove <VariableInformation>(lvi.arrayvd); VariableInformation vi = VariableInformation.GetVariableInformation(context, ivd); VariableInformation vi2 = VariableInformation.GetVariableInformation(context, lvi.arrayvd); vi2.IsStochastic = vi.IsStochastic; // Initialise the array to the appropriate sizes // TODO: change to work over loop brackets not loops IExpression expr = Builder.VarDeclExpr(lvi.arrayvd); for (int i = 0; i < loops.Count; i++) { IForStatement loop = loops[i]; IExpression loopSize = Recognizer.LoopSizeExpression(loop); IExpressionStatement assignSt = Builder.AssignStmt(expr, MessageTransform.GetArrayCreateExpression(expr, expr.GetExpressionType(), new IExpression[] { loopSize })); context.OutputAttributes.Set(assignSt.Expression, new DescriptionAttribute("Create array for replicates of '" + ivd.Name + "'")); context.OutputAttributes.Set(assignSt, new Initializer()); if (expr is IVariableDeclarationExpression) { expr = Builder.VarRefExpr(lvi.arrayvd); } expr = Builder.ArrayIndex(expr, lvi.indexVarRefs[i]); vi2.indexVars.Add(new IVariableDeclaration[] { Recognizer.GetVariableDeclaration(lvi.indexVarRefs[i]) }); vi2.sizes.Add(new IExpression[] { loopSize }); // Add declaration outside the loop int ancIndex = context.GetAncestorIndex(loop); context.AddStatementBeforeAncestorIndex(ancIndex, assignSt); } vi2.indexVars.AddRange(vi.indexVars); vi2.sizes.AddRange(vi.sizes); // If the variable declaration was a statement by itself, then return null (i.e. delete the statement). if (isLoneDeclaration) { return(null); } // Return a reference to the newly created array else { return(expr); } }