This adds the capability to auto-guess the type of non-outermost conversions by looking at the parent expression type. This also adds fatal () to the cases we can't auto-detect.
Bootstrapped on x86_64-unknown-linux-gnu, testing in progress. Richard. 2014-08-21 Richard Biener <rguent...@suse.de> * genmatch.c (*::gen_transform): Add type parameter. (expr::gen_transform): Handle conversion operators by converting to the parent expression type. Properly pass down the expression type to children. (dt_simplify::gen_gimple): Pass down 'type' to gen_transform. (dt_simplify::gen_generic): Likewise. * match.pd ((T1)(~(T2) X) -> ~(T1) X): New pattern. Index: gcc/match.pd =================================================================== --- gcc/match.pd (revision 214224) +++ gcc/match.pd (working copy) @@ -107,6 +107,19 @@ along with GCC; see the file COPYING3. (abs @0)) +/* From fold_unary. */ + +/* (T1)(~(T2) X) -> ~(T1) X */ +(simplify + (convert (bit_not@0 (convert @1))) + (if (INTEGRAL_TYPE_P (type) + && INTEGRAL_TYPE_P (TREE_TYPE (@0)) + && TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (@0)) + && INTEGRAL_TYPE_P (TREE_TYPE (@1)) + && TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (@1))) + (bit_not (convert (bit_not @0))))) + + #include "match-plusminus.pd" #include "match-bitwise.pd" #include "match-rotate.pd" Index: gcc/genmatch.c =================================================================== --- gcc/genmatch.c (revision 214258) +++ gcc/genmatch.c (working copy) @@ -238,14 +238,14 @@ struct operand { enum op_type { OP_PREDICATE, OP_EXPR, OP_CAPTURE, OP_C_EXPR }; operand (enum op_type type_) : type (type_) {} enum op_type type; - virtual void gen_transform (FILE *f, const char *, bool, int) = 0; + virtual void gen_transform (FILE *f, const char *, bool, int, const char *) = 0; }; struct predicate : public operand { predicate (const char *ident_) : operand (OP_PREDICATE), ident (ident_) {} const char *ident; - virtual void gen_transform (FILE *, const char *, bool, int) + virtual void gen_transform (FILE *, const char *, bool, int, const char *) { gcc_unreachable (); } }; @@ -263,7 +263,7 @@ struct expr : public operand void append_op (operand *op) { ops.safe_push (op); } e_operation *operation; vec<operand *> ops; - virtual void gen_transform (FILE *f, const char *, bool, int); + virtual void gen_transform (FILE *f, const char *, bool, int, const char *); }; struct c_expr : public operand @@ -286,7 +286,7 @@ struct c_expr : public operand char *fname; vec<id_tab> ids; - virtual void gen_transform (FILE *f, const char *, bool, int); + virtual void gen_transform (FILE *f, const char *, bool, int, const char *); void output_code (FILE *f, bool); }; @@ -296,7 +296,7 @@ struct capture : public operand : operand (OP_CAPTURE), where (where_), what (what_) {} const char *where; operand *what; - virtual void gen_transform (FILE *f, const char *, bool, int); + virtual void gen_transform (FILE *f, const char *, bool, int, const char *); }; template<> @@ -860,32 +860,71 @@ check_no_user_id (simplify *s) /* Code gen off the AST. */ void -expr::gen_transform (FILE *f, const char *dest, bool gimple, int depth) +expr::gen_transform (FILE *f, const char *dest, bool gimple, int depth, + const char *in_type) { + bool is_conversion = false; + if (*operation->op == CONVERT_EXPR + || *operation->op == NOP_EXPR + || *operation->op == FLOAT_EXPR + || *operation->op == FIX_TRUNC_EXPR) + is_conversion = true; + + const char *type; + char optype[20]; + if (is_conversion) + /* For conversions we need to build the expression using the + outer type passed in. */ + type = in_type; + else + { + /* Other operations are of the same type as their first operand. */ + sprintf (optype, "TREE_TYPE (ops%d[0])", depth); + type = optype; + } + if (!type) + fatal ("two conversions in a row"); + fprintf (f, "{\n"); fprintf (f, " tree ops%d[%u], res;\n", depth, ops.length ()); for (unsigned i = 0; i < ops.length (); ++i) { char dest[32]; snprintf (dest, 32, " ops%d[%u]", depth, i); - ops[i]->gen_transform (f, dest, gimple, depth + 1); + ops[i]->gen_transform (f, dest, gimple, depth + 1, + is_conversion + /* If this op is a conversion its single + operand has to know its type itself. */ + ? NULL + /* For other ops the type is the type + we got passed in, or if that is from + a conversion we can at most use the + first operand type for all further + operands. So (convert (plus @1 (convert @2)) + is possible while + (convert (plus (convert @1) @2)) + is not unless we somehow discover what + operand we can generate first and do it + in the appropriate order. */ + : (i == 0 ? in_type : type)); } + if (gimple) { /* ??? Have another helper that is like gimple_build but may fail if seq == NULL. */ fprintf (f, " if (!seq)\n" " {\n" - " res = gimple_simplify (%s, TREE_TYPE (ops%d[0])", - operation->op->id, depth); + " res = gimple_simplify (%s, %s", + operation->op->id, type); for (unsigned i = 0; i < ops.length (); ++i) fprintf (f, ", ops%d[%u]", depth, i); fprintf (f, ", seq, valueize);\n"); fprintf (f, " if (!res) return false;\n"); fprintf (f, " }\n"); fprintf (f, " else\n"); - fprintf (f, " res = gimple_build (seq, UNKNOWN_LOCATION, %s, " - "TREE_TYPE (ops%d[0])", operation->op->id, depth); + fprintf (f, " res = gimple_build (seq, UNKNOWN_LOCATION, %s, %s", + operation->op->id, type); for (unsigned i = 0; i < ops.length (); ++i) fprintf (f, ", ops%d[%u]", depth, i); fprintf (f, ", valueize);\n"); @@ -893,8 +932,8 @@ expr::gen_transform (FILE *f, const char else { if (operation->op->kind == id_base::CODE) - fprintf (f, " res = fold_build%d (%s, TREE_TYPE (ops%d[0])", - ops.length(), operation->op->id, depth); + fprintf (f, " res = fold_build%d (%s, %s", + ops.length(), operation->op->id, type); else fprintf (f, " res = build_call_expr (builtin_decl_implicit (%s), %d", operation->op->id, ops.length()); @@ -965,7 +1004,7 @@ c_expr::output_code (FILE *f, bool for_f void -c_expr::gen_transform (FILE *f, const char *dest, bool, int) +c_expr::gen_transform (FILE *f, const char *dest, bool, int, const char *) { /* If this expression has an outlined function variant, call it. */ if (fname) @@ -985,7 +1024,7 @@ c_expr::gen_transform (FILE *f, const ch } void -capture::gen_transform (FILE *f, const char *dest, bool, int) +capture::gen_transform (FILE *f, const char *dest, bool, int, const char *) { fprintf (f, "%s = captures[%s];\n", dest, where); } @@ -1673,7 +1712,7 @@ dt_simplify::gen_gimple (FILE *f) for (unsigned i = s->ifexpr_vec.length (); i; --i) { fprintf (f, "("); - s->ifexpr_vec[i - 1]->gen_transform (f, NULL, true, 1); + s->ifexpr_vec[i - 1]->gen_transform (f, NULL, true, 1, "type"); fprintf (f, ")"); if (i > 1) fprintf (f, " && "); @@ -1691,7 +1730,7 @@ dt_simplify::gen_gimple (FILE *f) { char dest[32]; snprintf (dest, 32, " res_ops[%d]", j); - e->ops[j]->gen_transform (f, dest, true, 1); + e->ops[j]->gen_transform (f, dest, true, 1, "type"); } /* Re-fold the toplevel result. It's basically an embedded gimple_build w/o actually building the stmt. */ @@ -1701,7 +1740,7 @@ dt_simplify::gen_gimple (FILE *f) else if (s->result->type == operand::OP_CAPTURE || s->result->type == operand::OP_C_EXPR) { - s->result->gen_transform (f, "res_ops[0]", true, 1); + s->result->gen_transform (f, "res_ops[0]", true, 1, "type"); fprintf (f, "*res_code = TREE_CODE (res_ops[0]);\n"); } else @@ -1738,7 +1777,7 @@ dt_simplify::gen_generic (FILE *f) for (unsigned i = s->ifexpr_vec.length (); i; --i) { fprintf (f, "("); - s->ifexpr_vec[i - 1]->gen_transform (f, NULL, false, 1); + s->ifexpr_vec[i - 1]->gen_transform (f, NULL, false, 1, "type"); fprintf (f, ")"); if (i > 1) fprintf (f, " && "); @@ -1757,7 +1796,7 @@ dt_simplify::gen_generic (FILE *f) fprintf (f, " tree res_op%d;\n", j); char dest[32]; snprintf (dest, 32, " res_op%d", j); - e->ops[j]->gen_transform (f, dest, false, 1); + e->ops[j]->gen_transform (f, dest, false, 1, "type"); } /* Re-fold the toplevel result. */ if (e->operation->op->kind == id_base::CODE) @@ -1774,7 +1813,7 @@ dt_simplify::gen_generic (FILE *f) || s->result->type == operand::OP_C_EXPR) { fprintf (f, " tree res;\n"); - s->result->gen_transform (f, " res", false, 1); + s->result->gen_transform (f, " res", false, 1, "type"); fprintf (f, " return res;\n"); } else