The following finishes call matching support (see the added pattern and the testcase amendment). It also adds basic support for matching GENERIC expressions and calls - to eventually handle the weird case of GIMPLE containing a GENERIC tcc_comparison as operand zero of a COND_EXPR rhs.
Committed. Richard. 2014-03-13 Richard Biener <rguent...@suse.de> * match.pd: Add pattern matching a call in a sub-expression. * genmatch.c (expr::gen_gimple_match): Complete call handling. Support matching GENERIC. testsuite/ * gcc.dg/tree-ssa/match-1.c: Adjust. Index: gcc/match.pd =================================================================== --- gcc/match.pd (revision 208478) +++ gcc/match.pd (working copy) @@ -159,6 +202,10 @@ to (minus @1 @0) (match_and_simplify (BUILT_IN_CABS (complex @0 @0)) (mult (BUILT_IN_FABS @0) { build_real (TREE_TYPE (@0), real_value_truncate (TYPE_MODE (TREE_TYPE (@0)), dconst_sqrt2 ())); })) +/* One nested fn. */ +(match_and_simplify + (mult (BUILT_IN_POW @0 @1) @0) + (BUILT_IN_POW @0 (PLUS_EXPR @1 { build_one_cst (TREE_TYPE (@1)); }))) /* ????s Index: gcc/genmatch.c =================================================================== --- gcc/genmatch.c (revision 208539) +++ gcc/genmatch.c (working copy) @@ -278,9 +278,9 @@ expr::gen_gimple_match (FILE *f, const c if (operation->op->kind == id_base::CODE) { operator_id *op = static_cast <operator_id *> (operation->op); - fprintf (f, "{\n"); - fprintf (f, "if (TREE_CODE (%s) != SSA_NAME) ", name); - gen_gimple_match_fail (f, label); + /* The GIMPLE variant. */ + fprintf (f, "if (TREE_CODE (%s) == SSA_NAME)\n", 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" " || gimple_assign_rhs_code (def_stmt) != %s) ", op->id); @@ -321,11 +321,83 @@ expr::gen_gimple_match (FILE *f, const c fprintf (f, " }\n"); } } - fprintf (f, "}\n"); + fprintf (f, " }\n"); + /* The GENERIC variant. */ + fprintf (f, "else if (TREE_CODE (%s) == %s)\n", name, op->id); + fprintf (f, " {\n"); + for (unsigned i = 0; i < ops.length (); ++i) + { + fprintf (f, " {\n"); + fprintf (f, " tree op = TREE_OPERAND (%s, %d);\n", name, i); + fprintf (f, " if (valueize && TREE_CODE (op) == SSA_NAME)\n"); + fprintf (f, " {\n"); + fprintf (f, " op = valueize (op);\n"); + fprintf (f, " if (!op) "); + gen_gimple_match_fail (f, label); + fprintf (f, " }\n"); + ops[i]->gen_gimple_match (f, "op", label); + fprintf (f, " }\n"); + } + fprintf (f, " }\n"); + fprintf (f, "else "); + gen_gimple_match_fail (f, label); + } + else if (operation->op->kind == id_base::FN) + { + fn_id *op = static_cast <fn_id *> (operation->op); + /* The GIMPLE variant. */ + fprintf (f, "if (TREE_CODE (%s) == SSA_NAME)\n", name); + fprintf (f, " {\n"); + fprintf (f, "gimple def_stmt = SSA_NAME_DEF_STMT (%s);\n", name); + fprintf (f, "tree fndecl;\n"); + fprintf (f, "if (!gimple_call_builtin_p (def_stmt, %s)) ", op->id); + gen_gimple_match_fail (f, label); + for (unsigned i = 0; i < ops.length (); ++i) + { + fprintf (f, " {\n"); + fprintf (f, " tree op = gimple_call_arg (def_stmt, %d);\n", i); + fprintf (f, " if (valueize && TREE_CODE (op) == SSA_NAME)\n"); + fprintf (f, " {\n"); + fprintf (f, " op = valueize (op);\n"); + fprintf (f, " if (!op) "); + gen_gimple_match_fail (f, label); + fprintf (f, " }\n"); + ops[i]->gen_gimple_match (f, "op", label); + fprintf (f, " }\n"); + } + fprintf (f, " }\n"); + /* GENERIC handling for calls. */ + fprintf (f, "else if (TREE_CODE (%s) == CALL_EXPR\n" + " && TREE_CODE (CALL_EXPR_FN (%s)) == ADDR_EXPR\n" + " && TREE_CODE (TREE_OPERAND (CALL_EXPR_FN (%s), 0)) == FUNCTION_DECL\n" + " && DECL_BUILT_IN_CLASS (TREE_OPERAND (CALL_EXPR_FN (%s), 0)) == BUILT_IN_NORMAL\n" + " && DECL_FUNCTION_CODE (TREE_OPERAND (CALL_EXPR_FN (%s), 0)) == %s)\n", + name, name, name, name, name, op->id); + fprintf (f, " {\n"); + for (unsigned i = 0; i < ops.length (); ++i) + { + fprintf (f, " {\n"); + fprintf (f, " tree op = CALL_EXPR_ARG (%s, %d);\n", name, i); + fprintf (f, " if (valueize && TREE_CODE (op) == SSA_NAME)\n"); + fprintf (f, " {\n"); + fprintf (f, " op = valueize (op);\n"); + fprintf (f, " if (!op) "); + gen_gimple_match_fail (f, label); + fprintf (f, " }\n"); + ops[i]->gen_gimple_match (f, "op", label); + fprintf (f, " }\n"); + } + fprintf (f, " }\n"); + fprintf (f, "else "); + gen_gimple_match_fail (f, label); } - else - /* FIXME - implement call support. */ - gcc_unreachable (); + /* ??? Specifically COND_EXPR could also match on CFG diamonds. + (cond@3 @0 @1 @2) is + if (@0) goto bb2; + bb3: + bb2: + @3 = PHI <@1(2), @2(3)> + */ } void Index: gcc/testsuite/gcc.dg/tree-ssa/match-1.c =================================================================== --- gcc/testsuite/gcc.dg/tree-ssa/match-1.c (revision 208478) +++ gcc/testsuite/gcc.dg/tree-ssa/match-1.c (working copy) @@ -1,19 +1,25 @@ /* { dg-do compile } */ -/* { dg-options "-O -fdump-tree-forwprop2" } */ +/* { dg-options "-O -fdump-tree-forwprop" } */ -double foo (_Complex double z) +double test1 (_Complex double z) { __imag z = 0.; return __builtin_cabs (z); } -/* We don't have a lattice in forwprop, so the following needs two steps... */ -double bar (double x) +double test2 (double x) { _Complex z = x; __imag z = x; return __builtin_cabs (z); } -/* { dg-final { scan-tree-dump-not "cabs" "forwprop2" } } */ +double test3 (double x) +{ + double y = __builtin_pow (x, 5.); + return y * x; +} + +/* { dg-final { scan-tree-dump-not "cabs" "forwprop1" } } */ +/* { dg-final { scan-tree-dump "pow \\\(\[^,\]*, 6" "forwprop1" } } */ /* { dg-final { cleanup-tree-dump "forwprop2" } } */