I've been hacking on a prototype that generates matching and simplification code from a meta-description. The goal is to provide a single source of transforms currently spread over the compiler, mostly fold-const.c, gimple-fold.c and tree-ssa-forwprop.c. Another goal is to make these transforms (which are most of the form of generating a simpler form of a pattern-matched IL piece) more readily available to passes like value-numbering so they can be used on-the-fly, using information provided by the pass lattice. The ultimate goal is to generate (most of) fold-const.c and gimple-fold.c and tree-ssa-forwprop.c from a single meta description.
Currently the prototype can generate code to match and simplify on the GIMPLE IL and it uses a very simple description right now (following the lispy style we have for machine descriptions). For example (define_match_and_simplify foo (PLUS_EXPR (MINUS_EXPR integral_op_p@0 @1) @1) @0) Matches (A - B) + B and transforms it to A. More complex replacements involving modifying of matches operands can be done with inlined C code: (define_match_and_simplify bar (PLUS_EXPR INTEGER_CST_P@0 (PLUS_EXPR @1 INTEGER_CST_P@2)) (PLUS_EXPR { int_const_binop (PLUS_EXPR, captures[0], captures[2]); } @1)) which matches CST1 + (X + CST2) and transforms it to (CST1 + CST2) + X (thus it reassociates but it also simplifies the constant part). Writing patterns will require a few new predicates like INTEGER_CST_P or integral_op_p. At this point I'll try integrating the result into a few GIMPLE passes (forwprop and SCCVN) to see if the interface works well enough. Currently the GIMPLE interface is tree gimple_match_and_simplify (tree name, gimple_seq *seq, tree (*valueize)(tree)); where the simplification happens on the defining statement of the SSA name name and a is_gimple_val result is returned. Any intermediate stmts are appended to 'seq' (or NULL_TREE is returned if that would be necessary and 'seq' is NULL) and all SSA names matched and generated are valueized using the valueize callback (if not NULL). Thus for the first example above we'd return A and do not touch seq while for the second example we'd return a new temporary SSA name and append name = CST' + X to seq (we might want to allow in-place modification of the def stmt of name as well, I'm not sure yet - that's the forwprop way of operation) Patch below for reference. Comments or suggestions? Thanks, Richard. Index: gcc/Makefile.in =================================================================== *** gcc/Makefile.in.orig 2014-02-15 10:52:03.466934196 +0100 --- gcc/Makefile.in 2014-02-27 14:30:37.426648887 +0100 *************** OBJS = \ *** 1236,1241 **** --- 1236,1242 ---- gimple-iterator.o \ gimple-fold.o \ gimple-low.o \ + gimple-match.o \ gimple-pretty-print.o \ gimple-ssa-isolate-paths.o \ gimple-ssa-strength-reduction.o \ *************** MOSTLYCLEANFILES = insn-flags.h insn-con *** 1504,1510 **** insn-output.c insn-recog.c insn-emit.c insn-extract.c insn-peep.c \ insn-attr.h insn-attr-common.h insn-attrtab.c insn-dfatab.c \ insn-latencytab.c insn-opinit.c insn-opinit.h insn-preds.c insn-constants.h \ ! tm-preds.h tm-constrs.h checksum-options \ tree-check.h min-insn-modes.c insn-modes.c insn-modes.h \ genrtl.h gt-*.h gtype-*.h gtype-desc.c gtyp-input.list \ xgcc$(exeext) cpp$(exeext) \ --- 1505,1511 ---- insn-output.c insn-recog.c insn-emit.c insn-extract.c insn-peep.c \ insn-attr.h insn-attr-common.h insn-attrtab.c insn-dfatab.c \ insn-latencytab.c insn-opinit.c insn-opinit.h insn-preds.c insn-constants.h \ ! tm-preds.h tm-constrs.h checksum-options gimple-match.c \ tree-check.h min-insn-modes.c insn-modes.c insn-modes.h \ genrtl.h gt-*.h gtype-*.h gtype-desc.c gtyp-input.list \ xgcc$(exeext) cpp$(exeext) \ *************** $(common_out_object_file): $(common_out_ *** 2018,2024 **** .PRECIOUS: insn-config.h insn-flags.h insn-codes.h insn-constants.h \ insn-emit.c insn-recog.c insn-extract.c insn-output.c insn-peep.c \ insn-attr.h insn-attr-common.h insn-attrtab.c insn-dfatab.c \ ! insn-latencytab.c insn-preds.c # Dependencies for the md file. The first time through, we just assume # the md file itself and the generated dependency file (in order to get --- 2019,2025 ---- .PRECIOUS: insn-config.h insn-flags.h insn-codes.h insn-constants.h \ insn-emit.c insn-recog.c insn-extract.c insn-output.c insn-peep.c \ insn-attr.h insn-attr-common.h insn-attrtab.c insn-dfatab.c \ ! insn-latencytab.c insn-preds.c gimple-match.c # Dependencies for the md file. The first time through, we just assume # the md file itself and the generated dependency file (in order to get *************** s-tm-texi: build/genhooks$(build_exeext) *** 2227,2232 **** --- 2228,2242 ---- false; \ fi + gimple-match.c: s-match; @true + + s-match: build/genmatch$(build_exeext) $(srcdir)/match.pd + $(RUN_GEN) build/genmatch$(build_exeext) $(srcdir)/match.pd \ + > tmp-gimple-match.c + $(SHELL) $(srcdir)/../move-if-change tmp-gimple-match.c \ + gimple-match.c + $(STAMP) s-match + GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \ $(host_xm_file_list) \ $(tm_file_list) $(HASHTAB_H) $(SPLAY_TREE_H) $(srcdir)/bitmap.h \ *************** build/genhooks.o : genhooks.c $(TARGET_D *** 2469,2474 **** --- 2479,2486 ---- $(COMMON_TARGET_DEF) $(BCONFIG_H) $(SYSTEM_H) errors.h build/genmddump.o : genmddump.c $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H) \ coretypes.h $(GTM_H) errors.h $(READ_MD_H) gensupport.h + build/genmatch.o : genmatch.c $(BCONFIG_H) $(SYSTEM_H) \ + coretypes.h errors.h # Compile the programs that generate insn-* from the machine description. # They are compiled with $(COMPILER_FOR_BUILD), and associated libraries, *************** genprogerr = $(genprogmd) genrtl modes g *** 2489,2498 **** $(genprogerr:%=build/gen%$(build_exeext)): $(BUILD_ERRORS) # Remaining build programs. ! genprog = $(genprogerr) check checksum condmd # These programs need libs over and above what they get from the above list. build/genautomata$(build_exeext) : BUILD_LIBS += -lm # These programs are not linked with the MD reader. build/gengtype$(build_exeext) : build/gengtype-lex.o build/gengtype-parse.o \ --- 2501,2512 ---- $(genprogerr:%=build/gen%$(build_exeext)): $(BUILD_ERRORS) # Remaining build programs. ! genprog = $(genprogerr) check checksum condmd match # These programs need libs over and above what they get from the above list. build/genautomata$(build_exeext) : BUILD_LIBS += -lm + build/genmatch$(build_exeext) : BUILD_LIBS += $(CPPLIB) $(LIBIBERTY) \ + $(BUILD_ERRORS) build/vec.o # These programs are not linked with the MD reader. build/gengtype$(build_exeext) : build/gengtype-lex.o build/gengtype-parse.o \ Index: gcc/genmatch.c =================================================================== *** /dev/null 1970-01-01 00:00:00.000000000 +0000 --- gcc/genmatch.c 2014-02-27 15:22:27.788434742 +0100 *************** *** 0 **** --- 1,506 ---- + + /* Grammar + + capture = '@' number + op = predicate | expr [capture] + match = 'define_match' name expr + c_expr = '{' ... '}' + genexpr = '(' code genop... ')' + genop = capture | genexpr | c_expr + transform = 'define_match_and_transform' name expr genop + + Match (A + B) - B + (define_match plusminus + (PLUS_EXPR (MINUS_EXPR integral_op_p@0 @1) @1)) + + Match and simplify (A + B) - B -> A + (define_match_and_simplify foo + (PLUS_EXPR (MINUS_EXPR integral_op_p@0 @1) @1) + @0) + + Match and simplify (CST + A) + CST to CST' + A + (define_match_and_simplify bar + (PLUS_EXPR INTEGER_CST_P@0 (PLUS_EXPR @1 INTEGER_CST_P@2)) + (PLUS_EXPR { int_const_binop (PLUS_EXPR, captures[0], captures[2]); } @1)) + */ + + #include "bconfig.h" + #include "system.h" + #include "coretypes.h" + #include <cpplib.h> + #include "errors.h" + #include "hashtab.h" + #include "vec.h" + + enum op_type { OP_PREDICATE, OP_EXPR, OP_CAPTURE, OP_C_EXPR }; + + struct operand { + operand (enum op_type type_) : type (type_) {} + enum op_type type; + virtual void gen_gimple_match (FILE *f, const char *) = 0; + virtual void gen_gimple_transform (FILE *f) = 0; + }; + + struct predicate : public operand + { + predicate (const char *ident_) : operand (OP_PREDICATE), ident (ident_) {} + const char *ident; + virtual void gen_gimple_match (FILE *f, const char *); + virtual void gen_gimple_transform (FILE *) { gcc_unreachable (); } + }; + + struct expr : public operand + { + expr (const char *operation_) + : operand (OP_EXPR), operation (operation_), num_ops (0) {} + void append_op (operand *op) { ops[num_ops++] = op; } + const char *operation; + unsigned num_ops; + operand *ops[4]; + virtual void gen_gimple_match (FILE *f, const char *); + virtual void gen_gimple_transform (FILE *f); + }; + + struct c_expr : public operand + { + c_expr (const char *code_) + : operand (OP_EXPR), code (code_) {} + const char *code; + virtual void gen_gimple_match (FILE *, const char *) { gcc_unreachable (); } + virtual void gen_gimple_transform (FILE *f); + }; + + struct capture : public operand + { + capture (const char *where_, operand *what_) + : operand (OP_CAPTURE), where (where_), what (what_) {} + const char *where; + operand *what; + virtual void gen_gimple_match (FILE *f, const char *); + virtual void gen_gimple_transform (FILE *f); + }; + + struct match { + match (const char *name_, struct operand *op_); + const char *name; + struct operand *op; + void gen_gimple_match (FILE *f); + virtual void gen_gimple (FILE *f) { gen_gimple_match (f); } + }; + + struct simplify : public match { + simplify (const char *name_, struct operand *op_, struct operand *op2_) + : match (name_, op_), op2 (op2_) {} + struct operand *op2; + virtual void gen_gimple (FILE *f); + }; + + match::match (const char *name_, operand *op_) + { + name = name_; + op = op_; + } + + void + predicate::gen_gimple_match (FILE *f, const char *op) + { + fprintf (f, "if (!%s (%s)) return false;\n", ident, op); + } + + void + expr::gen_gimple_match (FILE *f, const char *name) + { + fprintf (f, "{\n"); + fprintf (f, "gimple def_stmt = SSA_NAME_DEF_STMT (%s);\n", name); + fprintf (f, "if (is_gimple_assign (def_stmt)\n" + "\t&& gimple_assign_rhs_code (def_stmt) == %s)\n", operation); + fprintf (f, " {\n"); + fprintf (f, "gcc_assert (gimple_num_ops (def_stmt) == %d + 1);\n", num_ops); + for (unsigned i = 0; i < num_ops; ++i) + { + fprintf (f, " {\n"); + fprintf (f, " tree op = gimple_assign_rhs%d (def_stmt);\n", i + 1); + fprintf (f, " if (valueize && TREE_CODE (op) == SSA_NAME)\n"); + fprintf (f, " {\n"); + fprintf (f, " op = valueize (op);\n"); + fprintf (f, " if (!op) return false;\n"); + fprintf (f, " }\n"); + ops[i]->gen_gimple_match (f, "op"); + fprintf (f, " }\n"); + } + fprintf (f, "}\n"); + fprintf (f, "}\n"); + } + + void + expr::gen_gimple_transform (FILE *f) + { + fprintf (f, "({\n"); + fprintf (f, " if (!seq) return NULL_TREE;\n"); + fprintf (f, " tree ops[%d];\n", num_ops); + for (unsigned i = 0; i < num_ops; ++i) + { + fprintf (f, " ops[%u] = ", i); + ops[i]->gen_gimple_transform (f); + fprintf (f, ";\n"); + } + fprintf (f, " tree res = make_ssa_name (TREE_TYPE (ops[0]), NULL);\n" + " gimple stmt = gimple_build_assign_with_ops (%s, res", + operation); + for (unsigned i = 0; i < num_ops; ++i) + fprintf (f, ", ops[%u]", i); + fprintf (f, ");\n"); + fprintf (f, " gimple_seq_add_stmt_without_update (seq, stmt);\n"); + fprintf (f, " res;\n"); + fprintf (f, "})"); + } + + void + c_expr::gen_gimple_transform (FILE *f) + { + fputs (code, f); + } + + void + capture::gen_gimple_transform (FILE *f) + { + fprintf (f, "captures[%s]", this->where); + } + + void + capture::gen_gimple_match (FILE *f, const char *op) + { + if (this->what) + this->what->gen_gimple_match (f, op); + fprintf (f, "if (!captures[%s])\n" + " captures[%s] = %s;\n" + "else if (captures[%s] != %s)\n" + " return false;", this->where, this->where, op, this->where, op); + } + + + + void + match::gen_gimple_match (FILE *f) + { + fprintf (f, "bool\nmatch_%s (tree name, tree *captures, tree (*valueize)(tree))\n" + "{\n", this->name); + this->op->gen_gimple_match (f, "name"); + fprintf (f, " return true;\n"); + fprintf (f, "}\n"); + } + + + void + simplify::gen_gimple (FILE *f) + { + fprintf (f, "static "); + this->gen_gimple_match (f); + fprintf (f, "static tree\n" + "simplify_%s (tree name, gimple_seq *seq, tree (*valueize)(tree))\n" + "{\n", this->name); + fprintf (f, " tree captures[4] = {};\n" + " if (!match_%s (name, captures, valueize)) return NULL_TREE;\n", + this->name); + fprintf (f, " return "); + this->op2->gen_gimple_transform (f); + fprintf (f, ";\n}\n"); + } + + static const cpp_token * + next (cpp_reader *r) + { + const cpp_token *token; + do + { + token = cpp_get_token (r); + } + while (token->type == CPP_PADDING + && token->type != CPP_EOF); + #if 0 + /* DEBUG */ + if (token->type != CPP_EOF) + printf ("got token '%s'\n", cpp_token_as_text (r, token)); + #endif + return token; + } + + static const cpp_token * + peek (cpp_reader *r) + { + const cpp_token *token; + unsigned i = 0; + do + { + token = cpp_peek_token (r, i++); + } + while (token->type == CPP_PADDING); + #if 0 + /* DEBUG */ + if (token->type != CPP_EOF) + printf ("next token '%s'\n", cpp_token_as_text (r, token)); + #endif + return token; + } + + static bool + is_ident (const cpp_token *token, const char *id) + { + return strcmp ((const char *)CPP_HASHNODE (token->val.node.node)->ident.str, + id) == 0; + } + + static size_t + round_alloc_size (size_t s) + { + return s; + } + + + static const cpp_token * + expect (cpp_reader *r, enum cpp_ttype tk) + { + const cpp_token *token = next (r); + if (token->type != tk) + fatal ("error: expected %s, got %s", + cpp_type2name (tk, 0), cpp_type2name (token->type, 0)); + + return token; + } + + static void + eat_token (cpp_reader *r, enum cpp_ttype tk) + { + expect (r, tk); + } + + const char * + get_string (cpp_reader *r) + { + const cpp_token *token = expect (r, CPP_STRING); + return (const char *)token->val.str.text; + } + + const char * + get_ident (cpp_reader *r) + { + const cpp_token *token = expect (r, CPP_NAME); + return (const char *)CPP_HASHNODE (token->val.node.node)->ident.str; + } + + const char * + get_number (cpp_reader *r) + { + const cpp_token *token = expect (r, CPP_NUMBER); + return (const char *)token->val.str.text; + } + + static const char * + parse_operation (cpp_reader *r) + { + return get_ident (r); + } + + static struct operand * parse_op (cpp_reader *r); + + /* Parse + expr = operation op... */ + static struct operand * + parse_expr (cpp_reader *r) + { + expr *e = new expr (parse_operation (r)); + do + { + const cpp_token *token = peek (r); + if (token->type == CPP_CLOSE_PAREN) + return e; + e->append_op (parse_op (r)); + } + while (1); + return e; + } + + static struct operand * + parse_capture (cpp_reader *r, operand *op) + { + eat_token (r, CPP_ATSIGN); + return new capture (get_number (r), op); + } + + static operand * + parse_c_expr (cpp_reader *r) + { + /* ??? Use an obstack to build the string. */ + const cpp_token *token; + char *code = xstrdup ("({"); + do + { + token = next (r); + char *tk = (char *)cpp_token_as_text (r, token); + code = (char *)xrealloc (code, strlen (code) + strlen (tk) + 2); + if (token->flags & PREV_WHITE) + strcat (code, " "); + strcat (code, tk); + } + while (token->type != CPP_CLOSE_BRACE); + code = (char *)xrealloc (code, strlen (code) + 1 + 1); + strcat (code, ")"); + return new c_expr (code); + } + + /* Parse + op = predicate | ( expr ) */ + + static struct operand * + parse_op (cpp_reader *r) + { + const cpp_token *token = peek (r); + struct operand *op = NULL; + if (token->type == CPP_OPEN_PAREN) + { + eat_token (r, CPP_OPEN_PAREN); + op = parse_expr (r); + eat_token (r, CPP_CLOSE_PAREN); + } + else if (token->type == CPP_OPEN_BRACE) + { + eat_token (r, CPP_OPEN_BRACE); + op = parse_c_expr (r); + } + else if (token->type == CPP_NAME) + op = new predicate (get_ident (r)); + else if (token->type == CPP_ATSIGN) + op = parse_capture (r, op); + else + fatal ("expected expression or predicate"); + + token = peek (r); + if (token->type == CPP_ATSIGN + && !(token->flags & PREV_WHITE)) + op = parse_capture (r, op); + + return op; + } + + /* Parse + (define_match "<ident>" + <op>) */ + + static match * + parse_match (cpp_reader *r) + { + return new match (get_ident (r), parse_op (r)); + } + + /* Parse + (define_match_and_simplify "<ident>" + <op> <op>) */ + + static simplify * + parse_match_and_simplify (cpp_reader *r) + { + return new simplify (get_ident (r), parse_op (r), parse_op (r)); + } + + static void + write_gimple (FILE *f, vec<match *>& matchers, vec<simplify *>& simplifiers) + { + fprintf (f, + "#include \"config.h\"\n" + "#include \"system.h\"\n" + "#include \"coretypes.h\"\n" + "#include \"tree.h\"\n" + "#include \"stringpool.h\"\n" + "#include \"flags.h\"\n" + "#include \"function.h\"\n" + "#include \"basic-block.h\"\n" + "#include \"tree-ssa-alias.h\"\n" + "#include \"internal-fn.h\"\n" + "#include \"gimple-expr.h\"\n" + "#include \"is-a.h\"\n" + "#include \"gimple.h\"\n" + "#include \"gimple-ssa.h\"\n" + "#include \"tree-ssanames.h\"\n" + "\n" + "#define INTEGER_CST_P(node) TREE_CODE(node) == INTEGER_CST\n" + "#define integral_op_p(node) INTEGRAL_TYPE_P(TREE_TYPE(node))\n" + "\n"); + + /* Write matchers and simplifiers. */ + for (unsigned i = 0; i < matchers.length (); ++i) + matchers[i]->gen_gimple (f); + for (unsigned i = 0; i < simplifiers.length (); ++i) + simplifiers[i]->gen_gimple (f); + + /* Write the catch-all simplifier. */ + fprintf (f, "tree\ngimple_match_and_simplify (tree name, gimple_seq *seq, tree (*valueize)(tree))\n" + "{\n" + " tree res;\n"); + for (unsigned i = 0; i < simplifiers.length (); ++i) + fprintf (f, " res = simplify_%s (name, seq, valueize);\n" + " if (res) return res;\n", simplifiers[i]->name); + fprintf (f, " return NULL_TREE;\n" + "}\n"); + } + + int main(int argc, char **argv) + { + cpp_reader *r; + const cpp_token *token; + struct line_maps *line_table; + + progname = "genmatch"; + + if (argc != 2) + return 1; + + line_table = XCNEW (struct line_maps); + linemap_init (line_table); + line_table->reallocator = xrealloc; + line_table->round_alloc_size = round_alloc_size; + + r = cpp_create_reader (CLK_GNUC99, NULL, line_table); + + if (!cpp_read_main_file (r, argv[1])) + return 1; + + #if 0 + do + { + const cpp_token *token = cpp_get_token (r); + fprintf (stdout, "'%s'\n", cpp_token_as_text (r, token)); + } + while (token->type != CPP_EOF); + #endif + + vec<match *> matchers = vNULL; + vec<simplify *> simplifiers = vNULL; + + do + { + token = peek (r); + if (token->type == CPP_EOF) + break; + + /* All clauses start with '('. */ + eat_token (r, CPP_OPEN_PAREN); + + token = next (r); + if (is_ident (token, "define_match")) + matchers.safe_push (parse_match (r)); + else if (is_ident (token, "define_match_and_simplify")) + simplifiers.safe_push (parse_match_and_simplify (r)); + else + exit (1); + + eat_token (r, CPP_CLOSE_PAREN); + } + while (1); + + write_gimple (stdout, matchers, simplifiers); + + cpp_finish (r, NULL); + cpp_destroy (r); + + return 0; + } Index: gcc/gimple-fold.c =================================================================== *** gcc/gimple-fold.c.orig 2014-02-12 09:59:48.898995615 +0100 --- gcc/gimple-fold.c 2014-02-26 12:16:49.573150131 +0100 *************** rewrite_to_defined_overflow (gimple stmt *** 3623,3625 **** --- 3623,3745 ---- return stmts; } + + + /* Or a fancy C++ interface? */ + + class gimple_combiner + { + public: + gimple_combiner (tree (*valueize_)(tree), bool seqp_) + : valueize (valueize_), seqp (seqp_ ? &seq : NULL) {} + + /* Unary, binary and ternary. */ + tree combine_and_fold (enum tree_code code, tree type, + tree arg0); + tree combine_and_fold (enum tree_code code, tree type, + tree arg0, tree arg1); + tree combine_and_fold (enum tree_code code, tree type, + tree arg0, tree arg1, tree arg2); + + /* Unary and binary builtin functions. */ + tree combine_and_fold (enum built_in_function fn, tree arg0); + tree combine_and_fold (enum built_in_function fn, tree arg0, tree arg1); + + /* Value-based entry. */ + tree combine_and_fold (tree name); + + /* Get multiple-stmts result. */ + gimple_seq get_seq () const; + + private: + tree (*valueize)(tree); + gimple_seq seq; + gimple_seq *seqp; + }; + + tree + gimple_combine_and_fold_builtin (enum built_in_function fn, tree arg0, + tree (*valueize)(tree), gimple_seq *stmts); + tree + gimple_combine_and_fold_unary (enum tree_code code, tree arg0, + tree (*valueize)(tree), gimple_seq *stmts); + + tree + gimple_combine_and_fold (tree name, tree (*valueize)(tree), gimple_seq *stmts) + { + gimple stmt = SSA_NAME_DEF_STMT (name); + + switch (gimple_code (stmt)) + { + case GIMPLE_ASSIGN: + switch (gimple_assign_rhs_class (stmt)) + { + case GIMPLE_SINGLE_RHS: + /* We don't handle stores (or plain copies, that is, we expect + valueized 'name' as input). */ + /* ??? Handle tcc_reference ops on SSA names. */ + return NULL_TREE; + case GIMPLE_UNARY_RHS: + { + tree rhs1 = gimple_assign_rhs1 (stmt); + if (valueize) + { + rhs1 = valueize (rhs1); + if (!rhs1) + return NULL_TREE; + } + tree res = fold_unary (gimple_assign_rhs_code (stmt), + TREE_TYPE (name), rhs1); + if (!res) + return NULL_TREE; + if (is_gimple_val (res)) + return res; + if (!stmts) + return NULL_TREE; + return force_gimple_operand (res, stmts, true, NULL_TREE); + } + case GIMPLE_BINARY_RHS: + { + tree rhs1 = gimple_assign_rhs1 (stmt); + tree rhs2 = gimple_assign_rhs2 (stmt); + if (valueize) + { + rhs1 = valueize (rhs1); + if (!rhs1) + return NULL_TREE; + rhs2 = valueize (rhs2); + if (!rhs2) + return NULL_TREE; + } + tree res = fold_binary (gimple_assign_rhs_code (stmt), + TREE_TYPE (name), rhs1, rhs2); + if (!res) + return NULL_TREE; + if (is_gimple_val (res)) + return res; + if (!stmts) + return NULL_TREE; + return force_gimple_operand (res, stmts, true, NULL_TREE); + } + case GIMPLE_TERNARY_RHS: + /* TODO */ + break; + case GIMPLE_INVALID_RHS: + gcc_unreachable (); + } + break; + + case GIMPLE_CALL: + /* TODO */ + break; + + case GIMPLE_ASM: + /* Deliberately not handled. */ + break; + + default: + gcc_unreachable (); + } + + return NULL_TREE; + } Index: gcc/match.pd =================================================================== *** /dev/null 1970-01-01 00:00:00.000000000 +0000 --- gcc/match.pd 2014-02-27 15:33:59.675387107 +0100 *************** *** 0 **** --- 1,18 ---- + /* Match (A - B) + B only. */ + (define_match plusminus + (PLUS_EXPR (MINUS_EXPR integral_op_p@0 @1) @1)) + + /* Match and simplify (A - B) + B -> A. */ + (define_match_and_simplify foo + (PLUS_EXPR (MINUS_EXPR integral_op_p@0 @1) @1) + @0) + + /* Match and simplify CST + CST to CST'. */ + (define_match_and_simplify baz + (PLUS_EXPR INTEGER_CST_P@0 INTEGER_CST_P@1) + { int_const_binop (PLUS_EXPR, captures[0], captures[1]); }) + + /* Match and simplify (CST + A) + CST to CST' + A. */ + (define_match_and_simplify bar + (PLUS_EXPR INTEGER_CST_P@0 (PLUS_EXPR @1 INTEGER_CST_P@2)) + (PLUS_EXPR { int_const_binop (PLUS_EXPR, captures[0], captures[2]); } @1))