// note. pattern #1:
        // * ref = atom
        // * read(ref)
        // conditions:
        // 1) ref is read only once after it had been assigned
        // 2) atom isn't reassigned before read(ref) takes place
        // 3) if ref is CF$XXXX then atom can be of any node type (not only an atom)
        // transformed into:
        // * read(atom)
        private static bool TryMatchPattern1(DfaHelper dfa, Expression atom)
        {
            var p1_ref = atom as Ref;

            if (p1_ref == null)
            {
                return(false);
            }

            var p1_lastass = dfa.Writes(p1_ref).LastOrDefault();

            if (p1_lastass == null)
            {
                return(false);
            }

            var p1_ref_onlyread_afterass = dfa.Reads(p1_ref).SingleOrDefault2(
                r => dfa.ExecOrderOfStmt(r) >= dfa.ExecOrderOfStmt(p1_lastass));

            if (p1_ref_onlyread_afterass == null)
            {
                return(false);
            }

            var p1_atom = p1_lastass.Rhs;

            if (!p1_ref.Sym.Name.StartsWith("CF$") &&
                !p1_ref.Sym.Name.StartsWith("CS$"))
            {
                if (!p1_atom.IsAtom())
                {
                    return(false);
                }

                var p1_atom_reasses = dfa.Writes(p1_atom).Where(w =>
                                                                dfa.ExecOrderOfStmt(p1_lastass) <= dfa.ExecOrderOfStmt(w) &&
                                                                dfa.ExecOrderOfStmt(w) <= dfa.ExecOrderOfStmt(p1_ref_onlyread_afterass));
                if (p1_atom_reasses.IsNotEmpty())
                {
                    return(false);
                }
            }

            dfa.Remove(p1_lastass);
            var p1_ref_onlyread_stmt = p1_ref_onlyread_afterass.Stmt();

            dfa.ReplaceRecursive(p1_ref_onlyread_stmt, p1_ref, p1_atom);
            return(true);
        }
        // note. pattern #4
        // <hoard> ref = atom
        // <op> atom = ref op any
        // <usage> read(ref)
        // conditions:
        // 1) exactly one read of ref
        // 2) <hoard> comes before <op> and <usage>
        // 3) <op> and <usage> may be ordered arbitrarily
        // 4) op is either an increment or a decrement
        // transformed into either:
        // * read(atom++), if op is an increment (use IsInc() method to test)
        // * read(atom--), if op is a decrement (use IsDec() method to test)
        private static bool TryMatchPattern4(DfaHelper dfa, Expression atom)
        {
            var p4_ref = atom as Ref;

            if (p4_ref == null)
            {
                return(false);
            }
            var p4_usages = dfa.Usages(p4_ref);

            if (p4_usages.Count() != 3)
            {
                return(false);
            }

            var p4_op = p4_usages.Select(u => u.Stmt()).OfType <Assign>().SingleOrDefault2(ass =>
            {
                var bo = ass.Rhs as BinaryOperator;
                if (bo == null)
                {
                    return(false);
                }
                return(bo.Lhs.Equiv(p4_ref));
            });

            if (p4_op == null)
            {
                return(false);
            }
            var p4_atom = p4_op.Lhs;

            if (!p4_atom.IsAtom())
            {
                return(false);
            }
            var p4_bop = p4_op.Rhs as BinaryOperator;

            if (p4_bop == null)
            {
                return(false);
            }
            if (!p4_bop.Lhs.Equiv(p4_ref))
            {
                return(false);
            }
            var p4_optype = p4_bop.OperatorType;
            var p4_any    = p4_bop.Rhs;

            var p4_hoard          = p4_usages.First().Stmt();
            var p4_hoard_template = new Assign(p4_ref, p4_atom);

            if (!p4_hoard.Equiv(p4_hoard_template))
            {
                return(false);
            }
            var p4_usage = p4_usages.Select(u => u.Stmt()).Except(p4_op).Last();

            var p4_opeq = p4_atom.CreateOpPostAssign(p4_optype, p4_any);

            if (p4_opeq == null)
            {
                return(false);
            }

            dfa.Remove(p4_hoard, p4_op);
            dfa.ReplaceRecursive(p4_usage, p4_ref, p4_opeq);
            return(true);
        }
        // note. pattern #3:
        // <op> ref = atom op any
        // <wb> atom = ref
        // <usage> read(ref)
        // conditions:
        // 1) exactly one read of ref
        // 2) <op> comes before <wb> and <usage>
        // 3) <wb> and <usage> may be ordered arbitrarily
        // transformed into either:
        // * read(++atom), if op is an increment (use IsInc() method to test)
        // * read(--atom), if op is a decrement (use IsDec() method to test)
        // * read(atom [op=] any), otherwise
        private static bool TryMatchPattern3(DfaHelper dfa, Expression atom)
        {
            var p3_ref = atom as Ref;

            if (p3_ref == null)
            {
                return(false);
            }
            var p3_usages = dfa.Usages(p3_ref);

            if (p3_usages.Count() != 3)
            {
                return(false);
            }

            var p3_op = p3_usages.First() as Assign;

            if (p3_op == null)
            {
                return(false);
            }
            if (!p3_op.Lhs.Equiv(p3_ref))
            {
                return(false);
            }
            var p3_bop = p3_op.Rhs as BinaryOperator;

            if (p3_bop == null)
            {
                return(false);
            }
            var p3_atom   = p3_bop.Lhs;
            var p3_optype = p3_bop.OperatorType;
            var p3_any    = p3_bop.Rhs;

            if (!p3_atom.IsAtom())
            {
                return(false);
            }

            var        p3_usage2_stmt = p3_usages.Second().Stmt();
            var        p3_usage3_stmt = p3_usages.Third().Stmt();
            Expression p3_wb, p3_usage;
            var        p3_wb_template = new Assign(p3_atom, p3_ref);

            if (p3_usage2_stmt.Equiv(p3_wb_template))
            {
                p3_wb = (Expression)p3_usage2_stmt; p3_usage = (Expression)p3_usage3_stmt;
            }
            else if (p3_usage3_stmt.Equiv(p3_wb_template))
            {
                p3_wb = (Expression)p3_usage3_stmt; p3_usage = (Expression)p3_usage2_stmt;
            }
            else
            {
                return(false);
            }

            var p3_opeq = p3_atom.CreateOpPreAssign(p3_optype, p3_any);

            if (p3_opeq == null)
            {
                return(false);
            }

            dfa.Remove(p3_op, p3_wb);
            dfa.ReplaceRecursive(p3_usage, p3_ref, p3_opeq);
            return(true);
        }