#include "varasm.h"
#include "memmodel.h"
#include "optabs.h"
+#include "internal-fn.h"
enum strlen_range_kind {
/* Compute the exact constant string length. */
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:
/* 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. */
/* 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;
}
{
/* 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)
if (maybe_resimplify_conditional_op (seq, res_op, valueize))
return true;
- return false;
+ return canonicalized;
}
/* Helper that matches and simplifies the toplevel result from
{
/* 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,
if (maybe_resimplify_conditional_op (seq, res_op, valueize))
return true;
- return false;
+ return canonicalized;
}
/* Match and simplify the toplevel valueized operation THIS.
--- /dev/null
+/* { 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" } } */