// TODO: Restrict movement across try/catch/finally borders

        public static ICode V(ICode ast) {
            var v = new VisitorSsaCopyPropagation();
            var ast2 = v.Visit(ast);
            var alreadyReplaced = new Dictionary<Expr, Expr>();
            foreach (var a in v.assignments.Values) {
                if (a.mustKeep) {
                    continue;
                }
                if (a.assignment == null) {
                    continue;
                }
                if (a.count == 1) {
                    if (!VisitorFindSpecials.Any(a.assignment, Expr.Special.PossibleSideEffects)) {
                        ast2 = VisitorReplace.V(ast2, a.assignment, null);
                    }
                } else if (a.count == 2 /*|| 
                    (IsSimple(alreadyReplaced.ValueOrDefault(a.assignment.Expr, a.assignment.Expr)) && !a.assignment.Expr.Type.IsNonPrimitiveValueType())*/) {
                    var updater = new Updater(a.assignment.Target);
                    ast2 = updater.Visit(ast2);
                    foreach (var replaced in updater.Replaced) {
                        alreadyReplaced[replaced.Item1] = replaced.Item2;
                    }
                }
            }
            return ast2;
        }
        // TODO: Restrict movement across try/catch/finally borders

        public static ICode V(ICode ast)
        {
            var v               = new VisitorSsaCopyPropagation();
            var ast2            = v.Visit(ast);
            var alreadyReplaced = new Dictionary <Expr, Expr>();

            foreach (var a in v.assignments.Values)
            {
                if (a.mustKeep)
                {
                    continue;
                }
                if (a.assignment == null)
                {
                    continue;
                }
                if (a.count == 1)
                {
                    if (!VisitorFindSpecials.Any(a.assignment, Expr.Special.PossibleSideEffects))
                    {
                        ast2 = VisitorReplace.V(ast2, a.assignment, null);
                    }
                }
                else if (a.count == 2 /*||
                                       * (IsSimple(alreadyReplaced.ValueOrDefault(a.assignment.Expr, a.assignment.Expr)) && !a.assignment.Expr.Type.IsNonPrimitiveValueType())*/)
                {
                    var updater = new Updater(a.assignment.Target);
                    ast2 = updater.Visit(ast2);
                    foreach (var replaced in updater.Replaced)
                    {
                        alreadyReplaced[replaced.Item1] = replaced.Item2;
                    }
                }
            }
            return(ast2);
        }