/* Preamble and helpers for the autogenerated gimple-match.c file.
- Copyright (C) 2014-2018 Free Software Foundation, Inc.
+ Copyright (C) 2014-2021 Free Software Foundation, Inc.
This file is part of GCC.
#include "gimple.h"
#include "ssa.h"
#include "cgraph.h"
+#include "vec-perm-indices.h"
#include "fold-const.h"
#include "fold-const-call.h"
#include "stor-layout.h"
#include "gimplify.h"
#include "optabs-tree.h"
#include "tree-eh.h"
-
+#include "dbgcnt.h"
+#include "tm.h"
+#include "gimple-range.h"
/* Forward declarations of the private auto-generated matchers.
They expect valueized operands in canonical order and do not
code_helper, tree, tree, tree, tree, tree);
static bool gimple_simplify (gimple_match_op *, gimple_seq *, tree (*)(tree),
code_helper, tree, tree, tree, tree, tree, tree);
+static bool gimple_resimplify1 (gimple_seq *, gimple_match_op *,
+ tree (*)(tree));
+static bool gimple_resimplify2 (gimple_seq *, gimple_match_op *,
+ tree (*)(tree));
+static bool gimple_resimplify3 (gimple_seq *, gimple_match_op *,
+ tree (*)(tree));
+static bool gimple_resimplify4 (gimple_seq *, gimple_match_op *,
+ tree (*)(tree));
+static bool gimple_resimplify5 (gimple_seq *, gimple_match_op *,
+ tree (*)(tree));
const unsigned int gimple_match_op::MAX_NUM_OPS;
/* Likewise if the operation would not trap. */
bool honor_trapv = (INTEGRAL_TYPE_P (res_op->type)
&& TYPE_OVERFLOW_TRAPS (res_op->type));
- if (!operation_could_trap_p ((tree_code) res_op->code,
- FLOAT_TYPE_P (res_op->type),
- honor_trapv, res_op->op_or_null (1)))
+ tree_code op_code = (tree_code) res_op->code;
+ bool op_could_trap;
+
+ /* COND_EXPR will trap if, and only if, the condition
+ traps and hence we have to check this. For all other operations, we
+ don't need to consider the operands. */
+ if (op_code == COND_EXPR)
+ op_could_trap = generic_expr_could_trap_p (res_op->ops[0]);
+ else
+ op_could_trap = operation_could_trap_p ((tree_code) res_op->code,
+ FLOAT_TYPE_P (res_op->type),
+ honor_trapv,
+ res_op->op_or_null (1));
+
+ if (!op_could_trap)
{
res_op->cond.cond = NULL_TREE;
return false;
RES_OP with a simplified and/or canonicalized result and
returns whether any change was made. */
-bool
+static bool
gimple_resimplify1 (gimple_seq *seq, gimple_match_op *res_op,
tree (*valueize)(tree))
{
{
tree tem = NULL_TREE;
if (res_op->code.is_tree_code ())
- tem = const_unop (res_op->code, res_op->type, res_op->ops[0]);
+ {
+ tree_code code = res_op->code;
+ if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
+ && TREE_CODE_LENGTH (code) == 1)
+ tem = const_unop (res_op->code, res_op->type, res_op->ops[0]);
+ }
else
tem = fold_const_call (combined_fn (res_op->code), res_op->type,
res_op->ops[0]);
RES_OP with a simplified and/or canonicalized result and
returns whether any change was made. */
-bool
+static bool
gimple_resimplify2 (gimple_seq *seq, gimple_match_op *res_op,
tree (*valueize)(tree))
{
{
tree tem = NULL_TREE;
if (res_op->code.is_tree_code ())
- tem = const_binop (res_op->code, res_op->type,
- res_op->ops[0], res_op->ops[1]);
+ {
+ tree_code code = res_op->code;
+ if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
+ && TREE_CODE_LENGTH (code) == 2)
+ tem = const_binop (res_op->code, res_op->type,
+ res_op->ops[0], res_op->ops[1]);
+ }
else
tem = fold_const_call (combined_fn (res_op->code), res_op->type,
res_op->ops[0], res_op->ops[1]);
RES_OP with a simplified and/or canonicalized result and
returns whether any change was made. */
-bool
+static bool
gimple_resimplify3 (gimple_seq *seq, gimple_match_op *res_op,
tree (*valueize)(tree))
{
{
tree tem = NULL_TREE;
if (res_op->code.is_tree_code ())
- tem = fold_ternary/*_to_constant*/ (res_op->code, res_op->type,
- res_op->ops[0], res_op->ops[1],
- res_op->ops[2]);
+ {
+ tree_code code = res_op->code;
+ if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
+ && TREE_CODE_LENGTH (code) == 3)
+ tem = fold_ternary/*_to_constant*/ (res_op->code, res_op->type,
+ res_op->ops[0], res_op->ops[1],
+ res_op->ops[2]);
+ }
else
tem = fold_const_call (combined_fn (res_op->code), res_op->type,
res_op->ops[0], res_op->ops[1], res_op->ops[2]);
RES_OP with a simplified and/or canonicalized result and
returns whether any change was made. */
-bool
+static bool
gimple_resimplify4 (gimple_seq *seq, gimple_match_op *res_op,
tree (*valueize)(tree))
{
RES_OP with a simplified and/or canonicalized result and
returns whether any change was made. */
-bool
+static bool
gimple_resimplify5 (gimple_seq *seq, gimple_match_op *res_op,
tree (*valueize)(tree))
{
return false;
}
+/* Match and simplify the toplevel valueized operation THIS.
+ Replaces THIS with a simplified and/or canonicalized result and
+ returns whether any change was made. */
+
+bool
+gimple_match_op::resimplify (gimple_seq *seq, tree (*valueize)(tree))
+{
+ switch (num_ops)
+ {
+ case 1:
+ return gimple_resimplify1 (seq, this, valueize);
+ case 2:
+ return gimple_resimplify2 (seq, this, valueize);
+ case 3:
+ return gimple_resimplify3 (seq, this, valueize);
+ case 4:
+ return gimple_resimplify4 (seq, this, valueize);
+ case 5:
+ return gimple_resimplify5 (seq, this, valueize);
+ default:
+ gcc_unreachable ();
+ }
+}
+
/* If in GIMPLE the operation described by RES_OP should be single-rhs,
build a GENERIC tree for that expression and update RES_OP accordingly. */
maybe_build_generic_op (gimple_match_op *res_op)
{
tree_code code = (tree_code) res_op->code;
+ tree val;
switch (code)
{
case REALPART_EXPR:
case IMAGPART_EXPR:
case VIEW_CONVERT_EXPR:
- res_op->set_value (build1 (code, res_op->type, res_op->ops[0]));
+ val = build1 (code, res_op->type, res_op->ops[0]);
+ res_op->set_value (val);
break;
case BIT_FIELD_REF:
- res_op->set_value (build3 (code, res_op->type, res_op->ops[0],
- res_op->ops[1], res_op->ops[2]));
+ val = build3 (code, res_op->type, res_op->ops[0], res_op->ops[1],
+ res_op->ops[2]);
+ REF_REVERSE_STORAGE_ORDER (val) = res_op->reverse;
+ res_op->set_value (val);
break;
default:;
}
gimple_match_op cond_op (gimple_match_cond (res_op->ops[0],
res_op->ops[num_ops - 1]),
op, res_op->type, num_ops - 2);
- for (unsigned int i = 1; i < num_ops - 1; ++i)
- cond_op.ops[i - 1] = res_op->ops[i];
+
+ memcpy (cond_op.ops, res_op->ops + 1, (num_ops - 1) * sizeof *cond_op.ops);
switch (num_ops - 2)
{
case 2:
op0 = do_valueize (op0, top_valueize, valueized);
res_op->set_op (code, type, op0,
TREE_OPERAND (rhs1, 1),
- TREE_OPERAND (rhs1, 2));
+ TREE_OPERAND (rhs1, 2),
+ REF_REVERSE_STORAGE_ORDER (rhs1));
+ if (res_op->reverse)
+ return valueized;
return (gimple_resimplify3 (seq, res_op, valueize)
|| valueized);
}
{
bool valueized = false;
tree rhs1 = gimple_assign_rhs1 (stmt);
- /* If this is a [VEC_]COND_EXPR first try to simplify an
+ /* If this is a COND_EXPR first try to simplify an
embedded GENERIC condition. */
- if (code == COND_EXPR
- || code == VEC_COND_EXPR)
+ if (code == COND_EXPR)
{
if (COMPARISON_CLASS_P (rhs1))
{
return !cfun || (cfun->curr_properties & PROP_gimple_lvec) != 0;
}
+/* Return true if we can still perform transformations that may introduce
+ vector operations that are not supported by the target. Vector lowering
+ normally handles those, but after that pass, it becomes unsafe. */
+
+static inline bool
+optimize_vectors_before_lowering_p ()
+{
+ return !cfun || (cfun->curr_properties & PROP_gimple_lvec) == 0;
+}
+
/* Return true if pow(cst, x) should be optimized into exp(log(cst) * x).
As a workaround for SPEC CPU2017 628.pop2_s, don't do it if arg0
is an exact integer, arg1 = phi_res +/- cst1 and phi_res = PHI <cst2, ...>
return false;
return true;
}
+
+/* Return true if a division INNER_DIV / DIVISOR where INNER_DIV
+ is another division can be optimized. Don't optimize if INNER_DIV
+ is used in a TRUNC_MOD_EXPR with DIVISOR as second operand. */
+
+static bool
+optimize_successive_divisions_p (tree divisor, tree inner_div)
+{
+ if (!gimple_in_ssa_p (cfun))
+ return false;
+
+ imm_use_iterator imm_iter;
+ use_operand_p use_p;
+ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, inner_div)
+ {
+ gimple *use_stmt = USE_STMT (use_p);
+ if (!is_gimple_assign (use_stmt)
+ || gimple_assign_rhs_code (use_stmt) != TRUNC_MOD_EXPR
+ || !operand_equal_p (gimple_assign_rhs2 (use_stmt), divisor, 0))
+ continue;
+ return false;
+ }
+ return true;
+}