diff options
author | Richard Sandiford <richard.sandiford@linaro.org> | 2018-07-12 13:01:17 +0000 |
---|---|---|
committer | Richard Sandiford <rsandifo@gcc.gnu.org> | 2018-07-12 13:01:17 +0000 |
commit | 6a86928d9882c17b7526d657a38cb314fa0aaba6 (patch) | |
tree | 57cdf4000ddf7bace5fd55b3cfdb32a5457aa332 /gcc/internal-fn.c | |
parent | d5cbbf873956db1c4eed15a88f935700e7d6012a (diff) | |
download | gcc-6a86928d9882c17b7526d657a38cb314fa0aaba6.zip gcc-6a86928d9882c17b7526d657a38cb314fa0aaba6.tar.gz gcc-6a86928d9882c17b7526d657a38cb314fa0aaba6.tar.bz2 |
Extend tree code folds to IFN_COND_*
This patch adds match.pd support for applying normal folds to their
IFN_COND_* forms. E.g. the rule:
(plus @0 (negate @1)) -> (minus @0 @1)
also allows the fold:
(IFN_COND_ADD @0 @1 (negate @2) @3) -> (IFN_COND_SUB @0 @1 @2 @3)
Actually doing this by direct matches in gimple-match.c would
probably lead to combinatorial explosion, so instead, the patch
makes gimple_match_op carry a condition under which the operation
happens ("cond"), and the value to use when the condition is false
("else_value"). Thus in the example above we'd do the following
(a) convert:
cond:NULL_TREE (IFN_COND_ADD @0 @1 @4 @3) else_value:NULL_TREE
to:
cond:@0 (plus @1 @4) else_value:@3
(b) apply gimple_resimplify to (plus @1 @4)
(c) reintroduce cond and else_value when constructing the result.
Nested operations inherit the condition of the outer operation
(so that we don't introduce extra faults) but have a null else_value.
If we try to build such an operation, the target gets to choose what
else_value it can handle efficiently: obvious choices include one of
the operands or a zero constant. (The alternative would be to have some
representation for an undefined value, but that seems a bit invasive,
and isn't likely to be useful here.)
I've made the condition a mandatory part of the gimple_match_op
constructor so that it doesn't accidentally get dropped.
2018-07-12 Richard Sandiford <richard.sandiford@linaro.org>
gcc/
* target.def (preferred_else_value): New target hook.
* doc/tm.texi.in (TARGET_PREFERRED_ELSE_VALUE): New hook.
* doc/tm.texi: Regenerate.
* targhooks.h (default_preferred_else_value): Declare.
* targhooks.c (default_preferred_else_value): New function.
* internal-fn.h (conditional_internal_fn_code): Declare.
* internal-fn.c (FOR_EACH_CODE_MAPPING): New macro.
(get_conditional_internal_fn): Use it.
(conditional_internal_fn_code): New function.
* gimple-match.h (gimple_match_cond): New struct.
(gimple_match_op): Add a cond member function.
(gimple_match_op::gimple_match_op): Update all forms to take a
gimple_match_cond.
* genmatch.c (expr::gen_transform): Use the same condition as res_op
for the suboperation, but don't specify a particular else_value.
* tree-ssa-sccvn.c (vn_nary_simplify, vn_reference_lookup_3)
(visit_nary_op, visit_reference_op_load): Pass
gimple_match_cond::UNCOND to the gimple_match_op constructor.
* gimple-match-head.c: Include tree-eh.h
(convert_conditional_op): New function.
(maybe_resimplify_conditional_op): Likewise.
(gimple_resimplify1): Call maybe_resimplify_conditional_op.
(gimple_resimplify2): Likewise.
(gimple_resimplify3): Likewise.
(gimple_resimplify4): Likewise.
(maybe_push_res_to_seq): Return null for conditional operations.
(try_conditional_simplification): New function.
(gimple_simplify): Call it. Pass conditions to the gimple_match_op
constructor.
* match.pd: Fold VEC_COND_EXPRs of an IFN_COND_* call to a new
IFN_COND_* call.
* config/aarch64/aarch64.c (aarch64_preferred_else_value): New
function.
(TARGET_PREFERRED_ELSE_VALUE): Redefine.
gcc/testsuite/
* gcc.dg/vect/vect-cond-arith-2.c: New test.
* gcc.target/aarch64/sve/loop_add_6.c: Likewise.
From-SVN: r262586
Diffstat (limited to 'gcc/internal-fn.c')
-rw-r--r-- | gcc/internal-fn.c | 54 |
1 files changed, 34 insertions, 20 deletions
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c index a7bb748..eb5493f 100644 --- a/gcc/internal-fn.c +++ b/gcc/internal-fn.c @@ -3219,6 +3219,21 @@ static void (*const internal_fn_expanders[]) (internal_fn, gcall *) = { 0 }; +/* Invoke T(CODE, IFN) for each conditional function IFN that maps to a + tree code CODE. */ +#define FOR_EACH_CODE_MAPPING(T) \ + T (PLUS_EXPR, IFN_COND_ADD) \ + T (MINUS_EXPR, IFN_COND_SUB) \ + T (MULT_EXPR, IFN_COND_MUL) \ + T (TRUNC_DIV_EXPR, IFN_COND_DIV) \ + T (TRUNC_MOD_EXPR, IFN_COND_MOD) \ + T (RDIV_EXPR, IFN_COND_RDIV) \ + T (MIN_EXPR, IFN_COND_MIN) \ + T (MAX_EXPR, IFN_COND_MAX) \ + T (BIT_AND_EXPR, IFN_COND_AND) \ + T (BIT_IOR_EXPR, IFN_COND_IOR) \ + T (BIT_XOR_EXPR, IFN_COND_XOR) + /* Return a function that only performs CODE when a certain condition is met and that uses a given fallback value otherwise. For example, if CODE is a binary operation associated with conditional function FN: @@ -3238,31 +3253,30 @@ get_conditional_internal_fn (tree_code code) { switch (code) { - case PLUS_EXPR: - return IFN_COND_ADD; - case MINUS_EXPR: - return IFN_COND_SUB; - case MIN_EXPR: - return IFN_COND_MIN; - case MAX_EXPR: - return IFN_COND_MAX; - case TRUNC_DIV_EXPR: - return IFN_COND_DIV; - case TRUNC_MOD_EXPR: - return IFN_COND_MOD; - case RDIV_EXPR: - return IFN_COND_RDIV; - case BIT_AND_EXPR: - return IFN_COND_AND; - case BIT_IOR_EXPR: - return IFN_COND_IOR; - case BIT_XOR_EXPR: - return IFN_COND_XOR; +#define CASE(CODE, IFN) case CODE: return IFN; + FOR_EACH_CODE_MAPPING(CASE) +#undef CASE default: return IFN_LAST; } } +/* If IFN implements the conditional form of a tree code, return that + tree code, otherwise return ERROR_MARK. */ + +tree_code +conditional_internal_fn_code (internal_fn ifn) +{ + switch (ifn) + { +#define CASE(CODE, IFN) case IFN: return CODE; + FOR_EACH_CODE_MAPPING(CASE) +#undef CASE + default: + return ERROR_MARK; + } +} + /* Return true if IFN is some form of load from memory. */ bool |