/// <summary>
        /// Loop through optimizable statements
        /// </summary>
        /// <param name="statements"></param>
        /// <returns>If we have modified something that has bubble up one level, we return true. This means we've messed up the statement list at the outer level and the optimization loop needs to be re-run.</returns>
        private static bool VisitOptimizableStatements(IStatementCompound statements)
        {
            bool returnModified = false;

            bool modified = true;

            while (modified)
            {
                modified = false;
                var opter = new BlockRenamer(statements.FindBookingParent(), statements.FindBookingParent());
                foreach (var item in statements.Statements)
                {
                    // If it is a compound statement, there may be statements that are "invariant" in it,
                    // so we can lift them out.
                    if (item is IStatementCompound)
                    {
                        // If the statement is a compound statement, then we try to go down a level.
                        modified = VisitOptimizableStatements(item as IStatementCompound);
                    }

                    // Perhaps the whole statement could be pulled up?
                    if (!modified && (item is ICMStatementInfo))
                    {
                        // if we have optimize info, then see what we can do with it.
                        modified = BubbleUp(statements, item);
                        if (modified)
                        {
                            returnModified = true;
                        }
                    }

                    // Finally, check to see if this statement is identical to anyone else further up or not.
                    if (!modified)
                    {
                        modified = BubleUpAndCombine(statements, item, opter);
                    }

                    // If anything was modified, we need to re-run since all the various pointers, etc., will have
                    // been changed.
                    if (modified)
                    {
                        break;
                    }
                }
            }
            return(returnModified);
        }
        /// <summary>
        /// Loop through optimizable statements
        /// </summary>
        /// <param name="statements"></param>
        /// <returns>If we have modified something that has bubble up one level, we return true. This means we've messed up the statement list at the outer level and the optimization loop needs to be re-run.</returns>
        private static bool VisitOptimizableStatements(IStatementCompound statements)
        {
            bool returnModified = false;

            bool modified = true;
            while (modified)
            {
                modified = false;
                var opter = new BlockRenamer(statements.FindBookingParent(), statements.FindBookingParent());
                foreach (var item in statements.Statements)
                {
                    // If it is a compound statement, there may be statements that are "invariant" in it,
                    // so we can lift them out.
                    if (item is IStatementCompound)
                    {
                        // If the statement is a compound statement, then we try to go down a level.
                        modified = VisitOptimizableStatements(item as IStatementCompound);
                    }

                    // Perhaps the whole statement could be pulled up?
                    if (!modified && (item is ICMStatementInfo))
                    {
                        // if we have optimize info, then see what we can do with it.
                        modified = BubbleUp(statements, item);
                        if (modified)
                            returnModified = true;
                    }

                    // Finally, check to see if this statement is identical to anyone else further up or not.
                    if (!modified)
                    {
                        modified = BubleUpAndCombine(statements, item, opter);
                    }

                    // If anything was modified, we need to re-run since all the various pointers, etc., will have
                    // been changed.
                    if (modified)
                        break;
                }
            }
            return returnModified;
        }
Beispiel #3
0
        /// <summary>
        /// See if we can make these two statements the same. If so, then bubble it up and go.
        /// </summary>
        /// <param name="s"></param>
        /// <param name="item"></param>
        /// <returns></returns>
        /// <remarks>
        /// A statement is considered equivalent if it would only take variable renames to adjust the
        /// statements to look identical.
        /// </remarks>
        public static bool MakeStatmentsEquivalent(IStatement s1, IStatement s2)
        {
            // Make sure the meta-data is present to work with.
            var sc1 = s1 as ICMStatementInfo;
            var sc2 = s2 as ICMStatementInfo;

            if (sc1 == null || sc2 == null)
            {
                return(false);
            }

            // Now, see if they are equivalent. If so, perform the required rename.
            var r = sc1.RequiredForEquivalence(sc2);

            if (r.Item1)
            {
                // There is one condition under which this combination should not happen:
                // The statements are identical and they are not idempotent. That means we would
                // have "a = a + 1" twice in a row, and we can't combine those.
                if ((r.Item2 == null || r.Item2.Count() == 0) && !StatementIdempotent(s2))
                {
                    return(false);
                }

                // Ok, go after the parents to see if we can make sure there aren't common variables to be
                // declared.
                var s1Parent = s1.Parent as IBookingStatementBlock;
                var s2Parent = s2.Parent as IBookingStatementBlock;
                if (s1Parent == null || s2Parent == null)
                {
                    return(false);
                }

                // We can't lift unless we can get at the declarations of all variables we want to rename.
                var allVarsDeclaredInS2 = s2Parent.AllDeclaredVariables.Select(v => v.RawValue).ToHashSet();
                var renames             = r.Item2 == null?Enumerable.Empty <Tuple <string, string> >() : r.Item2;

                if (!renames.Select(p => p.Item1).All(v => allVarsDeclaredInS2.Contains(v)))
                {
                    return(false);
                }

                // Key to altering this is that this is the only site that allows modifications for these
                // variables that we are going to rename. If there are more than one, then we can't modify
                // unless we somehow know the modifications are identical.

                if (CheckForVariableAsResult(s2, renames.Select(i => i.Item1)) ||
                    CheckForVariableAsResult(s1, renames.Select(i => i.Item2)))
                {
                    return(false);
                }

                // Remove the statement, and then do the renaming.
                var opt = new BlockRenamer(s2Parent, s1Parent);
                s2Parent.Remove(s2);
                foreach (var item in renames)
                {
                    var declStatement = opt.ForceRemoveDeclaration(item.Item1, s2Parent);
                    if (declStatement == null)
                    {
                        opt.ForceRenameVariable(item.Item1, item.Item2);
                    }
                    else
                    {
                        declStatement.RenameVariable(item.Item1, item.Item2);
                    }
                }

                return(true);
            }
            return(false);
        }
        /// <summary>
        /// See if we can make these two statements the same. If so, then bubble it up and go.
        /// </summary>
        /// <param name="s"></param>
        /// <param name="item"></param>
        /// <returns></returns>
        /// <remarks>
        /// A statement is considered equivalent if it would only take variable renames to adjust the
        /// statements to look identical.
        /// </remarks>
        public static bool MakeStatmentsEquivalent(IStatement s1, IStatement s2)
        {
            // Make sure the meta-data is present to work with.
            var sc1 = s1 as ICMStatementInfo;
            var sc2 = s2 as ICMStatementInfo;

            if (sc1 == null || sc2 == null)
            {
                return false;
            }

            // Now, see if they are equivalent. If so, perform the required rename.
            var r = sc1.RequiredForEquivalence(sc2);
            if (r.Item1)
            {
                // There is one condition under which this combination should not happen:
                // The statements are identical and they are not idempotent. That means we would
                // have "a = a + 1" twice in a row, and we can't combine those.
                if ((r.Item2 == null || r.Item2.Count() == 0) && !StatementIdempotent(s2))
                {
                    return false;
                }

                // Ok, go after the parents to see if we can make sure there aren't common variables to be
                // declared.
                var s1Parent = s1.Parent as IBookingStatementBlock;
                var s2Parent = s2.Parent as IBookingStatementBlock;
                if (s1Parent == null || s2Parent == null)
                {
                    return false;
                }

                // We can't lift unless we can get at the declarations of all variables we want to rename.
                var allVarsDeclaredInS2 = s2Parent.AllDeclaredVariables.Select(v => v.RawValue).ToHashSet();
                var renames = r.Item2 == null ? Enumerable.Empty<Tuple<string, string>>() : r.Item2;
                if (!renames.Select(p => p.Item1).All(v => allVarsDeclaredInS2.Contains(v)))
                {
                    return false;
                }

                // Key to altering this is that this is the only site that allows modifications for these
                // variables that we are going to rename. If there are more than one, then we can't modify
                // unless we somehow know the modifications are identical.

                if (CheckForVariableAsResult(s2, renames.Select(i => i.Item1))
                    || CheckForVariableAsResult(s1, renames.Select(i => i.Item2)))
                {
                    return false;
                }

                // Remove the statement, and then do the renaming.
                var opt = new BlockRenamer(s2Parent, s1Parent);
                s2Parent.Remove(s2);
                foreach (var item in renames)
                {
                    var declStatement = opt.ForceRemoveDeclaration(item.Item1, s2Parent);
                    if (declStatement == null)
                    {
                        opt.ForceRenameVariable(item.Item1, item.Item2);
                    } else
                    {
                        declStatement.RenameVariable(item.Item1, item.Item2);
                    }
                }

                return true;
            }
            return false;
        }