re PR middle-end/79665 (gcc's signed (x*x)/200 is slower than clang's)
PR middle-end/79665 * internal-fn.c (get_range_pos_neg): Moved to ... * tree.c (get_range_pos_neg): ... here. No longer static. * tree.h (get_range_pos_neg): New prototype. * expr.c (expand_expr_real_2) <case TRUNC_DIV_EXPR>: If both arguments are known to be in between 0 and signed maximum inclusive, try to expand both unsigned and signed divmod and use the cheaper one from those. From-SVN: r245676
This commit is contained in:
parent
18eb304e5f
commit
b607e75e25
|
@ -1,4 +1,15 @@
|
|||
2017-02-22 Jeff Law <law@redhat.com>
|
||||
2017-02-23 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR middle-end/79665
|
||||
* internal-fn.c (get_range_pos_neg): Moved to ...
|
||||
* tree.c (get_range_pos_neg): ... here. No longer static.
|
||||
* tree.h (get_range_pos_neg): New prototype.
|
||||
* expr.c (expand_expr_real_2) <case TRUNC_DIV_EXPR>: If both arguments
|
||||
are known to be in between 0 and signed maximum inclusive, try to
|
||||
expand both unsigned and signed divmod and use the cheaper one from
|
||||
those.
|
||||
|
||||
2017-02-22 Jeff Law <law@redhat.com>
|
||||
|
||||
PR tree-optimization/79578
|
||||
* tree-ssa-dse.c (clear_bytes_written_by): Use operand_equal_p
|
||||
|
|
28
gcc/expr.c
28
gcc/expr.c
|
@ -8809,6 +8809,34 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
|
|||
where some terms of the dividend have coeffs divisible by it. */
|
||||
expand_operands (treeop0, treeop1,
|
||||
subtarget, &op0, &op1, EXPAND_NORMAL);
|
||||
if (SCALAR_INT_MODE_P (mode)
|
||||
&& optimize >= 2
|
||||
&& get_range_pos_neg (treeop0) == 1
|
||||
&& get_range_pos_neg (treeop1) == 1)
|
||||
{
|
||||
/* If both arguments are known to be positive when interpreted
|
||||
as signed, we can expand it as both signed and unsigned
|
||||
division or modulo. Choose the cheaper sequence in that case. */
|
||||
bool speed_p = optimize_insn_for_speed_p ();
|
||||
do_pending_stack_adjust ();
|
||||
start_sequence ();
|
||||
rtx uns_ret = expand_divmod (0, code, mode, op0, op1, target, 1);
|
||||
rtx_insn *uns_insns = get_insns ();
|
||||
end_sequence ();
|
||||
start_sequence ();
|
||||
rtx sgn_ret = expand_divmod (0, code, mode, op0, op1, target, 0);
|
||||
rtx_insn *sgn_insns = get_insns ();
|
||||
end_sequence ();
|
||||
unsigned uns_cost = seq_cost (uns_insns, speed_p);
|
||||
unsigned sgn_cost = seq_cost (sgn_insns, speed_p);
|
||||
if (uns_cost < sgn_cost || (uns_cost == sgn_cost && unsignedp))
|
||||
{
|
||||
emit_insn (uns_insns);
|
||||
return uns_ret;
|
||||
}
|
||||
emit_insn (sgn_insns);
|
||||
return sgn_ret;
|
||||
}
|
||||
return expand_divmod (0, code, mode, op0, op1, target, unsignedp);
|
||||
|
||||
case RDIV_EXPR:
|
||||
|
|
|
@ -413,86 +413,6 @@ expand_FALLTHROUGH (internal_fn, gcall *call)
|
|||
"invalid use of attribute %<fallthrough%>");
|
||||
}
|
||||
|
||||
/* Helper function for expand_addsub_overflow. Return 1
|
||||
if ARG interpreted as signed in its precision is known to be always
|
||||
positive or 2 if ARG is known to be always negative, or 3 if ARG may
|
||||
be positive or negative. */
|
||||
|
||||
static int
|
||||
get_range_pos_neg (tree arg)
|
||||
{
|
||||
if (arg == error_mark_node)
|
||||
return 3;
|
||||
|
||||
int prec = TYPE_PRECISION (TREE_TYPE (arg));
|
||||
int cnt = 0;
|
||||
if (TREE_CODE (arg) == INTEGER_CST)
|
||||
{
|
||||
wide_int w = wi::sext (arg, prec);
|
||||
if (wi::neg_p (w))
|
||||
return 2;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
while (CONVERT_EXPR_P (arg)
|
||||
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (arg, 0)))
|
||||
&& TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg, 0))) <= prec)
|
||||
{
|
||||
arg = TREE_OPERAND (arg, 0);
|
||||
/* Narrower value zero extended into wider type
|
||||
will always result in positive values. */
|
||||
if (TYPE_UNSIGNED (TREE_TYPE (arg))
|
||||
&& TYPE_PRECISION (TREE_TYPE (arg)) < prec)
|
||||
return 1;
|
||||
prec = TYPE_PRECISION (TREE_TYPE (arg));
|
||||
if (++cnt > 30)
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (TREE_CODE (arg) != SSA_NAME)
|
||||
return 3;
|
||||
wide_int arg_min, arg_max;
|
||||
while (get_range_info (arg, &arg_min, &arg_max) != VR_RANGE)
|
||||
{
|
||||
gimple *g = SSA_NAME_DEF_STMT (arg);
|
||||
if (is_gimple_assign (g)
|
||||
&& CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (g)))
|
||||
{
|
||||
tree t = gimple_assign_rhs1 (g);
|
||||
if (INTEGRAL_TYPE_P (TREE_TYPE (t))
|
||||
&& TYPE_PRECISION (TREE_TYPE (t)) <= prec)
|
||||
{
|
||||
if (TYPE_UNSIGNED (TREE_TYPE (t))
|
||||
&& TYPE_PRECISION (TREE_TYPE (t)) < prec)
|
||||
return 1;
|
||||
prec = TYPE_PRECISION (TREE_TYPE (t));
|
||||
arg = t;
|
||||
if (++cnt > 30)
|
||||
return 3;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
if (TYPE_UNSIGNED (TREE_TYPE (arg)))
|
||||
{
|
||||
/* For unsigned values, the "positive" range comes
|
||||
below the "negative" range. */
|
||||
if (!wi::neg_p (wi::sext (arg_max, prec), SIGNED))
|
||||
return 1;
|
||||
if (wi::neg_p (wi::sext (arg_min, prec), SIGNED))
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!wi::neg_p (wi::sext (arg_min, prec), SIGNED))
|
||||
return 1;
|
||||
if (wi::neg_p (wi::sext (arg_max, prec), SIGNED))
|
||||
return 2;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
/* Return minimum precision needed to represent all values
|
||||
of ARG in SIGNed integral type. */
|
||||
|
||||
|
|
82
gcc/tree.c
82
gcc/tree.c
|
@ -14205,6 +14205,88 @@ verify_type (const_tree t)
|
|||
}
|
||||
|
||||
|
||||
/* Return 1 if ARG interpreted as signed in its precision is known to be
|
||||
always positive or 2 if ARG is known to be always negative, or 3 if
|
||||
ARG may be positive or negative. */
|
||||
|
||||
int
|
||||
get_range_pos_neg (tree arg)
|
||||
{
|
||||
if (arg == error_mark_node)
|
||||
return 3;
|
||||
|
||||
int prec = TYPE_PRECISION (TREE_TYPE (arg));
|
||||
int cnt = 0;
|
||||
if (TREE_CODE (arg) == INTEGER_CST)
|
||||
{
|
||||
wide_int w = wi::sext (arg, prec);
|
||||
if (wi::neg_p (w))
|
||||
return 2;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
while (CONVERT_EXPR_P (arg)
|
||||
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (arg, 0)))
|
||||
&& TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg, 0))) <= prec)
|
||||
{
|
||||
arg = TREE_OPERAND (arg, 0);
|
||||
/* Narrower value zero extended into wider type
|
||||
will always result in positive values. */
|
||||
if (TYPE_UNSIGNED (TREE_TYPE (arg))
|
||||
&& TYPE_PRECISION (TREE_TYPE (arg)) < prec)
|
||||
return 1;
|
||||
prec = TYPE_PRECISION (TREE_TYPE (arg));
|
||||
if (++cnt > 30)
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (TREE_CODE (arg) != SSA_NAME)
|
||||
return 3;
|
||||
wide_int arg_min, arg_max;
|
||||
while (get_range_info (arg, &arg_min, &arg_max) != VR_RANGE)
|
||||
{
|
||||
gimple *g = SSA_NAME_DEF_STMT (arg);
|
||||
if (is_gimple_assign (g)
|
||||
&& CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (g)))
|
||||
{
|
||||
tree t = gimple_assign_rhs1 (g);
|
||||
if (INTEGRAL_TYPE_P (TREE_TYPE (t))
|
||||
&& TYPE_PRECISION (TREE_TYPE (t)) <= prec)
|
||||
{
|
||||
if (TYPE_UNSIGNED (TREE_TYPE (t))
|
||||
&& TYPE_PRECISION (TREE_TYPE (t)) < prec)
|
||||
return 1;
|
||||
prec = TYPE_PRECISION (TREE_TYPE (t));
|
||||
arg = t;
|
||||
if (++cnt > 30)
|
||||
return 3;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
if (TYPE_UNSIGNED (TREE_TYPE (arg)))
|
||||
{
|
||||
/* For unsigned values, the "positive" range comes
|
||||
below the "negative" range. */
|
||||
if (!wi::neg_p (wi::sext (arg_max, prec), SIGNED))
|
||||
return 1;
|
||||
if (wi::neg_p (wi::sext (arg_min, prec), SIGNED))
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!wi::neg_p (wi::sext (arg_min, prec), SIGNED))
|
||||
return 1;
|
||||
if (wi::neg_p (wi::sext (arg_max, prec), SIGNED))
|
||||
return 2;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Return true if ARG is marked with the nonnull attribute in the
|
||||
current function signature. */
|
||||
|
||||
|
|
|
@ -4876,6 +4876,7 @@ extern bool gimple_canonical_types_compatible_p (const_tree, const_tree,
|
|||
bool trust_type_canonical = true);
|
||||
extern bool type_with_interoperable_signedness (const_tree);
|
||||
extern bitmap get_nonnull_args (const_tree);
|
||||
extern int get_range_pos_neg (tree);
|
||||
|
||||
/* Return simplified tree code of type that is used for canonical type
|
||||
merging. */
|
||||
|
|
Loading…
Reference in New Issue