Commit 2d143ba8 by Richard Biener Committed by Richard Biener

re PR middle-end/80341 (gcc miscompiles division of signed char)

2017-04-07  Richard Biener  <rguenther@suse.de>

	PR middle-end/80341
	* tree.c (get_unwidened): Also handle ! for_type case for
	INTEGER_CSTs.
	* convert.c (do_narrow): Split out from ...
	(convert_to_integer_1): ... here.  Do not pass final truncation
	type to get_unwidened for TRUNC_DIV_EXPR.

	* gcc.dg/torture/pr80341.c: New testcase.

From-SVN: r246756
parent 5291ab73
2017-04-07 Richard Biener <rguenther@suse.de> 2017-04-07 Richard Biener <rguenther@suse.de>
PR middle-end/80341
* tree.c (get_unwidened): Also handle ! for_type case for
INTEGER_CSTs.
* convert.c (do_narrow): Split out from ...
(convert_to_integer_1): ... here. Do not pass final truncation
type to get_unwidened for TRUNC_DIV_EXPR.
2017-04-07 Richard Biener <rguenther@suse.de>
* tree-affine.c (wide_int_ext_for_comb): Take type rather * tree-affine.c (wide_int_ext_for_comb): Take type rather
than aff_tree. than aff_tree.
(aff_combination_const): Adjust. (aff_combination_const): Adjust.
......
...@@ -413,6 +413,83 @@ convert_to_real_maybe_fold (tree type, tree expr, bool dofold) ...@@ -413,6 +413,83 @@ convert_to_real_maybe_fold (tree type, tree expr, bool dofold)
return convert_to_real_1 (type, expr, dofold || CONSTANT_CLASS_P (expr)); return convert_to_real_1 (type, expr, dofold || CONSTANT_CLASS_P (expr));
} }
/* Try to narrow EX_FORM ARG0 ARG1 in narrowed arg types producing a
result in TYPE. */
static tree
do_narrow (location_t loc,
enum tree_code ex_form, tree type, tree arg0, tree arg1,
tree expr, unsigned inprec, unsigned outprec, bool dofold)
{
/* Do the arithmetic in type TYPEX,
then convert result to TYPE. */
tree typex = type;
/* Can't do arithmetic in enumeral types
so use an integer type that will hold the values. */
if (TREE_CODE (typex) == ENUMERAL_TYPE)
typex = lang_hooks.types.type_for_size (TYPE_PRECISION (typex),
TYPE_UNSIGNED (typex));
/* But now perhaps TYPEX is as wide as INPREC.
In that case, do nothing special here.
(Otherwise would recurse infinitely in convert. */
if (TYPE_PRECISION (typex) != inprec)
{
/* Don't do unsigned arithmetic where signed was wanted,
or vice versa.
Exception: if both of the original operands were
unsigned then we can safely do the work as unsigned.
Exception: shift operations take their type solely
from the first argument.
Exception: the LSHIFT_EXPR case above requires that
we perform this operation unsigned lest we produce
signed-overflow undefinedness.
And we may need to do it as unsigned
if we truncate to the original size. */
if (TYPE_UNSIGNED (TREE_TYPE (expr))
|| (TYPE_UNSIGNED (TREE_TYPE (arg0))
&& (TYPE_UNSIGNED (TREE_TYPE (arg1))
|| ex_form == LSHIFT_EXPR
|| ex_form == RSHIFT_EXPR
|| ex_form == LROTATE_EXPR
|| ex_form == RROTATE_EXPR))
|| ex_form == LSHIFT_EXPR
/* If we have !flag_wrapv, and either ARG0 or
ARG1 is of a signed type, we have to do
PLUS_EXPR, MINUS_EXPR or MULT_EXPR in an unsigned
type in case the operation in outprec precision
could overflow. Otherwise, we would introduce
signed-overflow undefinedness. */
|| ((!TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0))
|| !TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg1)))
&& ((TYPE_PRECISION (TREE_TYPE (arg0)) * 2u
> outprec)
|| (TYPE_PRECISION (TREE_TYPE (arg1)) * 2u
> outprec))
&& (ex_form == PLUS_EXPR
|| ex_form == MINUS_EXPR
|| ex_form == MULT_EXPR)))
{
if (!TYPE_UNSIGNED (typex))
typex = unsigned_type_for (typex);
}
else
{
if (TYPE_UNSIGNED (typex))
typex = signed_type_for (typex);
}
/* We should do away with all this once we have a proper
type promotion/demotion pass, see PR45397. */
expr = maybe_fold_build2_loc (dofold, loc, ex_form, typex,
convert (typex, arg0),
convert (typex, arg1));
return convert (type, expr);
}
return NULL_TREE;
}
/* Convert EXPR to some integer (or enum) type TYPE. /* Convert EXPR to some integer (or enum) type TYPE.
EXPR must be pointer, integer, discrete (enum, char, or bool), float, EXPR must be pointer, integer, discrete (enum, char, or bool), float,
...@@ -719,8 +796,8 @@ convert_to_integer_1 (tree type, tree expr, bool dofold) ...@@ -719,8 +796,8 @@ convert_to_integer_1 (tree type, tree expr, bool dofold)
case TRUNC_DIV_EXPR: case TRUNC_DIV_EXPR:
{ {
tree arg0 = get_unwidened (TREE_OPERAND (expr, 0), type); tree arg0 = get_unwidened (TREE_OPERAND (expr, 0), NULL_TREE);
tree arg1 = get_unwidened (TREE_OPERAND (expr, 1), type); tree arg1 = get_unwidened (TREE_OPERAND (expr, 1), NULL_TREE);
/* Don't distribute unless the output precision is at least as /* Don't distribute unless the output precision is at least as
big as the actual inputs and it has the same signedness. */ big as the actual inputs and it has the same signedness. */
...@@ -738,7 +815,12 @@ convert_to_integer_1 (tree type, tree expr, bool dofold) ...@@ -738,7 +815,12 @@ convert_to_integer_1 (tree type, tree expr, bool dofold)
&& (TYPE_UNSIGNED (TREE_TYPE (arg0)) && (TYPE_UNSIGNED (TREE_TYPE (arg0))
|| (TREE_CODE (arg1) == INTEGER_CST || (TREE_CODE (arg1) == INTEGER_CST
&& !integer_all_onesp (arg1)))) && !integer_all_onesp (arg1))))
goto trunc1; {
tree tem = do_narrow (loc, ex_form, type, arg0, arg1,
expr, inprec, outprec, dofold);
if (tem)
return tem;
}
break; break;
} }
...@@ -786,72 +868,10 @@ convert_to_integer_1 (tree type, tree expr, bool dofold) ...@@ -786,72 +868,10 @@ convert_to_integer_1 (tree type, tree expr, bool dofold)
|| inprec > TYPE_PRECISION (TREE_TYPE (arg0)) || inprec > TYPE_PRECISION (TREE_TYPE (arg0))
|| inprec > TYPE_PRECISION (TREE_TYPE (arg1))) || inprec > TYPE_PRECISION (TREE_TYPE (arg1)))
{ {
/* Do the arithmetic in type TYPEX, tree tem = do_narrow (loc, ex_form, type, arg0, arg1,
then convert result to TYPE. */ expr, inprec, outprec, dofold);
tree typex = type; if (tem)
return tem;
/* Can't do arithmetic in enumeral types
so use an integer type that will hold the values. */
if (TREE_CODE (typex) == ENUMERAL_TYPE)
typex
= lang_hooks.types.type_for_size (TYPE_PRECISION (typex),
TYPE_UNSIGNED (typex));
/* But now perhaps TYPEX is as wide as INPREC.
In that case, do nothing special here.
(Otherwise would recurse infinitely in convert. */
if (TYPE_PRECISION (typex) != inprec)
{
/* Don't do unsigned arithmetic where signed was wanted,
or vice versa.
Exception: if both of the original operands were
unsigned then we can safely do the work as unsigned.
Exception: shift operations take their type solely
from the first argument.
Exception: the LSHIFT_EXPR case above requires that
we perform this operation unsigned lest we produce
signed-overflow undefinedness.
And we may need to do it as unsigned
if we truncate to the original size. */
if (TYPE_UNSIGNED (TREE_TYPE (expr))
|| (TYPE_UNSIGNED (TREE_TYPE (arg0))
&& (TYPE_UNSIGNED (TREE_TYPE (arg1))
|| ex_form == LSHIFT_EXPR
|| ex_form == RSHIFT_EXPR
|| ex_form == LROTATE_EXPR
|| ex_form == RROTATE_EXPR))
|| ex_form == LSHIFT_EXPR
/* If we have !flag_wrapv, and either ARG0 or
ARG1 is of a signed type, we have to do
PLUS_EXPR, MINUS_EXPR or MULT_EXPR in an unsigned
type in case the operation in outprec precision
could overflow. Otherwise, we would introduce
signed-overflow undefinedness. */
|| ((!TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0))
|| !TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg1)))
&& ((TYPE_PRECISION (TREE_TYPE (arg0)) * 2u
> outprec)
|| (TYPE_PRECISION (TREE_TYPE (arg1)) * 2u
> outprec))
&& (ex_form == PLUS_EXPR
|| ex_form == MINUS_EXPR
|| ex_form == MULT_EXPR)))
{
if (!TYPE_UNSIGNED (typex))
typex = unsigned_type_for (typex);
}
else
{
if (TYPE_UNSIGNED (typex))
typex = signed_type_for (typex);
}
/* We should do away with all this once we have a proper
type promotion/demotion pass, see PR45397. */
expr = maybe_fold_build2_loc (dofold, loc, ex_form, typex,
convert (typex, arg0),
convert (typex, arg1));
return convert (type, expr);
}
} }
} }
break; break;
......
2017-04-07 Richard Biener <rguenther@suse.de>
PR middle-end/80341
* gcc.dg/torture/pr80341.c: New testcase.
2017-04-06 Jakub Jelinek <jakub@redhat.com> 2017-04-06 Jakub Jelinek <jakub@redhat.com>
PR debug/80234 PR debug/80234
......
/* { dg-do run } */
/* { dg-additional-options "-Wno-overflow" } */
const signed char c = -84;
signed char s;
void
foo ()
{
s = (unsigned short) c / -55;
}
int
main ()
{
foo ();
if (s != 90)
__builtin_abort ();
}
...@@ -9033,13 +9033,21 @@ get_unwidened (tree op, tree for_type) ...@@ -9033,13 +9033,21 @@ get_unwidened (tree op, tree for_type)
} }
} }
/* If we finally reach a constant see if it fits in for_type and /* If we finally reach a constant see if it fits in sth smaller and
in that case convert it. */ in that case convert it. */
if (for_type if (TREE_CODE (win) == INTEGER_CST)
&& TREE_CODE (win) == INTEGER_CST {
&& TREE_TYPE (win) != for_type tree wtype = TREE_TYPE (win);
&& int_fits_type_p (win, for_type)) unsigned prec = wi::min_precision (win, TYPE_SIGN (wtype));
win = fold_convert (for_type, win); if (for_type)
prec = MAX (prec, final_prec);
if (prec < TYPE_PRECISION (wtype))
{
tree t = lang_hooks.types.type_for_size (prec, TYPE_UNSIGNED (wtype));
if (t && TYPE_PRECISION (t) < TYPE_PRECISION (wtype))
win = fold_convert (t, win);
}
}
return win; return win;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment