Canonicalize argument order for commutative functions
This patch uses information about internal functions to canonicalize the argument order of calls. gcc/ * gimple-fold.c: Include internal-fn.h. (fold_stmt_1): If a function maps to an internal one, use first_commutative_argument to canonicalize the order of commutative arguments. * gimple-match-head.c (gimple_resimplify2, gimple_resimplify3) (gimple_resimplify4, gimple_resimplify5): Extend commutativity checks to functions. gcc/testsuite/ * gcc.dg/fmax-fmin-1.c: New test.
This commit is contained in:
parent
e32b9eb32d
commit
e9fff24cd2
|
@ -69,6 +69,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "varasm.h"
|
||||
#include "memmodel.h"
|
||||
#include "optabs.h"
|
||||
#include "internal-fn.h"
|
||||
|
||||
enum strlen_range_kind {
|
||||
/* Compute the exact constant string length. */
|
||||
|
@ -6109,18 +6110,36 @@ fold_stmt_1 (gimple_stmt_iterator *gsi, bool inplace, tree (*valueize) (tree))
|
|||
break;
|
||||
case GIMPLE_CALL:
|
||||
{
|
||||
for (i = 0; i < gimple_call_num_args (stmt); ++i)
|
||||
gcall *call = as_a<gcall *> (stmt);
|
||||
for (i = 0; i < gimple_call_num_args (call); ++i)
|
||||
{
|
||||
tree *arg = gimple_call_arg_ptr (stmt, i);
|
||||
tree *arg = gimple_call_arg_ptr (call, i);
|
||||
if (REFERENCE_CLASS_P (*arg)
|
||||
&& maybe_canonicalize_mem_ref_addr (arg))
|
||||
changed = true;
|
||||
}
|
||||
tree *lhs = gimple_call_lhs_ptr (stmt);
|
||||
tree *lhs = gimple_call_lhs_ptr (call);
|
||||
if (*lhs
|
||||
&& REFERENCE_CLASS_P (*lhs)
|
||||
&& maybe_canonicalize_mem_ref_addr (lhs))
|
||||
changed = true;
|
||||
if (*lhs)
|
||||
{
|
||||
combined_fn cfn = gimple_call_combined_fn (call);
|
||||
internal_fn ifn = associated_internal_fn (cfn, TREE_TYPE (*lhs));
|
||||
int opno = first_commutative_argument (ifn);
|
||||
if (opno >= 0)
|
||||
{
|
||||
tree arg1 = gimple_call_arg (call, opno);
|
||||
tree arg2 = gimple_call_arg (call, opno + 1);
|
||||
if (tree_swap_operands_p (arg1, arg2))
|
||||
{
|
||||
gimple_call_set_arg (call, opno, arg2);
|
||||
gimple_call_set_arg (call, opno + 1, arg1);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GIMPLE_ASM:
|
||||
|
|
|
@ -294,18 +294,16 @@ gimple_resimplify2 (gimple_seq *seq, gimple_match_op *res_op,
|
|||
|
||||
/* Canonicalize operand order. */
|
||||
bool canonicalized = false;
|
||||
if (res_op->code.is_tree_code ())
|
||||
bool is_comparison
|
||||
= (res_op->code.is_tree_code ()
|
||||
&& TREE_CODE_CLASS (tree_code (res_op->code)) == tcc_comparison);
|
||||
if ((is_comparison || commutative_binary_op_p (res_op->code, res_op->type))
|
||||
&& tree_swap_operands_p (res_op->ops[0], res_op->ops[1]))
|
||||
{
|
||||
auto code = tree_code (res_op->code);
|
||||
if ((TREE_CODE_CLASS (code) == tcc_comparison
|
||||
|| commutative_tree_code (code))
|
||||
&& tree_swap_operands_p (res_op->ops[0], res_op->ops[1]))
|
||||
{
|
||||
std::swap (res_op->ops[0], res_op->ops[1]);
|
||||
if (TREE_CODE_CLASS (code) == tcc_comparison)
|
||||
res_op->code = swap_tree_comparison (code);
|
||||
canonicalized = true;
|
||||
}
|
||||
std::swap (res_op->ops[0], res_op->ops[1]);
|
||||
if (is_comparison)
|
||||
res_op->code = swap_tree_comparison (tree_code (res_op->code));
|
||||
canonicalized = true;
|
||||
}
|
||||
|
||||
/* Limit recursion, see gimple_resimplify1. */
|
||||
|
@ -376,11 +374,11 @@ gimple_resimplify3 (gimple_seq *seq, gimple_match_op *res_op,
|
|||
|
||||
/* Canonicalize operand order. */
|
||||
bool canonicalized = false;
|
||||
if (res_op->code.is_tree_code ()
|
||||
&& commutative_ternary_tree_code (tree_code (res_op->code))
|
||||
&& tree_swap_operands_p (res_op->ops[0], res_op->ops[1]))
|
||||
int argno = first_commutative_argument (res_op->code, res_op->type);
|
||||
if (argno >= 0
|
||||
&& tree_swap_operands_p (res_op->ops[argno], res_op->ops[argno + 1]))
|
||||
{
|
||||
std::swap (res_op->ops[0], res_op->ops[1]);
|
||||
std::swap (res_op->ops[argno], res_op->ops[argno + 1]);
|
||||
canonicalized = true;
|
||||
}
|
||||
|
||||
|
@ -424,6 +422,16 @@ gimple_resimplify4 (gimple_seq *seq, gimple_match_op *res_op,
|
|||
{
|
||||
/* No constant folding is defined for four-operand functions. */
|
||||
|
||||
/* Canonicalize operand order. */
|
||||
bool canonicalized = false;
|
||||
int argno = first_commutative_argument (res_op->code, res_op->type);
|
||||
if (argno >= 0
|
||||
&& tree_swap_operands_p (res_op->ops[argno], res_op->ops[argno + 1]))
|
||||
{
|
||||
std::swap (res_op->ops[argno], res_op->ops[argno + 1]);
|
||||
canonicalized = true;
|
||||
}
|
||||
|
||||
/* Limit recursion, see gimple_resimplify1. */
|
||||
static unsigned depth;
|
||||
if (depth > 10)
|
||||
|
@ -450,7 +458,7 @@ gimple_resimplify4 (gimple_seq *seq, gimple_match_op *res_op,
|
|||
if (maybe_resimplify_conditional_op (seq, res_op, valueize))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return canonicalized;
|
||||
}
|
||||
|
||||
/* Helper that matches and simplifies the toplevel result from
|
||||
|
@ -465,6 +473,16 @@ gimple_resimplify5 (gimple_seq *seq, gimple_match_op *res_op,
|
|||
{
|
||||
/* No constant folding is defined for five-operand functions. */
|
||||
|
||||
/* Canonicalize operand order. */
|
||||
bool canonicalized = false;
|
||||
int argno = first_commutative_argument (res_op->code, res_op->type);
|
||||
if (argno >= 0
|
||||
&& tree_swap_operands_p (res_op->ops[argno], res_op->ops[argno + 1]))
|
||||
{
|
||||
std::swap (res_op->ops[argno], res_op->ops[argno + 1]);
|
||||
canonicalized = true;
|
||||
}
|
||||
|
||||
gimple_match_op res_op2 (*res_op);
|
||||
if (gimple_simplify (&res_op2, seq, valueize,
|
||||
res_op->code, res_op->type,
|
||||
|
@ -478,7 +496,7 @@ gimple_resimplify5 (gimple_seq *seq, gimple_match_op *res_op,
|
|||
if (maybe_resimplify_conditional_op (seq, res_op, valueize))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return canonicalized;
|
||||
}
|
||||
|
||||
/* Match and simplify the toplevel valueized operation THIS.
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/* { dg-options "-O -fdump-tree-optimized" } */
|
||||
|
||||
void
|
||||
f1 (double *res, double x, double y)
|
||||
{
|
||||
res[0] = __builtin_fmax (x, y);
|
||||
res[1] = __builtin_fmax (y, x);
|
||||
}
|
||||
|
||||
void
|
||||
f2 (double *res, double x, double y)
|
||||
{
|
||||
res[0] = __builtin_fmin (x, y);
|
||||
res[1] = __builtin_fmin (y, x);
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times {__builtin_fmax} 1 "optimized" } } */
|
||||
/* { dg-final { scan-tree-dump-times {__builtin_fmin} 1 "optimized" } } */
|
Loading…
Reference in New Issue