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:
Jakub Jelinek 2017-02-23 08:49:06 +01:00
parent 18eb304e5f
commit b607e75e25
5 changed files with 123 additions and 81 deletions

View File

@ -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

View File

@ -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:

View File

@ -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. */

View File

@ -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. */

View File

@ -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. */