* [PATCH] Fix PR80341
@ 2017-04-06 13:59 Richard Biener
0 siblings, 0 replies; only message in thread
From: Richard Biener @ 2017-04-06 13:59 UTC (permalink / raw)
To: gcc-patches
This fixes an old bug I introduced. We may not pass in the final
truncation type to get_unwidened for divisions but need to preserve
the original values. That means the INTEGER_CST handling needs
extension for the !for_type case as well. And some refactoring.
(as much as I hate working on this premature folding code...)
Bootstrap and regtest running on x86_64-unknown-linux-gnu.
Richard.
2017-04-06 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.
Index: gcc/tree.c
===================================================================
*** gcc/tree.c (revision 246728)
--- gcc/tree.c (working copy)
*************** get_unwidened (tree op, tree for_type)
*** 9033,9045 ****
}
}
! /* If we finally reach a constant see if it fits in for_type and
in that case convert it. */
! if (for_type
! && TREE_CODE (win) == INTEGER_CST
! && TREE_TYPE (win) != for_type
! && int_fits_type_p (win, for_type))
! win = fold_convert (for_type, win);
return win;
}
--- 9033,9053 ----
}
}
! /* If we finally reach a constant see if it fits in sth smaller and
in that case convert it. */
! if (TREE_CODE (win) == INTEGER_CST)
! {
! tree wtype = TREE_TYPE (win);
! unsigned prec = wi::min_precision (win, TYPE_SIGN (wtype));
! 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;
}
Index: gcc/convert.c
===================================================================
*** gcc/convert.c (revision 246728)
--- gcc/convert.c (working copy)
*************** convert_to_real_maybe_fold (tree type, t
*** 413,418 ****
--- 413,495 ----
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.
EXPR must be pointer, integer, discrete (enum, char, or bool), float,
*************** convert_to_integer_1 (tree type, tree ex
*** 719,726 ****
case TRUNC_DIV_EXPR:
{
! tree arg0 = get_unwidened (TREE_OPERAND (expr, 0), type);
! tree arg1 = get_unwidened (TREE_OPERAND (expr, 1), type);
/* Don't distribute unless the output precision is at least as
big as the actual inputs and it has the same signedness. */
--- 796,803 ----
case TRUNC_DIV_EXPR:
{
! tree arg0 = get_unwidened (TREE_OPERAND (expr, 0), NULL_TREE);
! tree arg1 = get_unwidened (TREE_OPERAND (expr, 1), NULL_TREE);
/* Don't distribute unless the output precision is at least as
big as the actual inputs and it has the same signedness. */
*************** convert_to_integer_1 (tree type, tree ex
*** 738,744 ****
&& (TYPE_UNSIGNED (TREE_TYPE (arg0))
|| (TREE_CODE (arg1) == INTEGER_CST
&& !integer_all_onesp (arg1))))
! goto trunc1;
break;
}
--- 815,826 ----
&& (TYPE_UNSIGNED (TREE_TYPE (arg0))
|| (TREE_CODE (arg1) == INTEGER_CST
&& !integer_all_onesp (arg1))))
! {
! tree tem = do_narrow (loc, ex_form, type, arg0, arg1,
! expr, inprec, outprec, dofold);
! if (tem)
! return tem;
! }
break;
}
*************** convert_to_integer_1 (tree type, tree ex
*** 786,857 ****
|| inprec > TYPE_PRECISION (TREE_TYPE (arg0))
|| inprec > TYPE_PRECISION (TREE_TYPE (arg1)))
{
! /* 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);
! }
}
}
break;
--- 868,877 ----
|| inprec > TYPE_PRECISION (TREE_TYPE (arg0))
|| inprec > TYPE_PRECISION (TREE_TYPE (arg1)))
{
! tree tem = do_narrow (loc, ex_form, type, arg0, arg1,
! expr, inprec, outprec, dofold);
! if (tem)
! return tem;
}
}
break;
Index: gcc/testsuite/gcc.dg/torture/pr80341.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/pr80341.c (nonexistent)
--- gcc/testsuite/gcc.dg/torture/pr80341.c (working copy)
***************
*** 0 ****
--- 1,18 ----
+ /* { dg-do run } */
+
+ const signed char c = -84;
+ signed char s;
+
+ void
+ foo ()
+ {
+ s = (unsigned short) c / -55;
+ }
+
+ int
+ main ()
+ {
+ foo ();
+ if (s != 90)
+ __builtin_abort ();
+ }
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2017-04-06 13:59 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-04-06 13:59 [PATCH] Fix PR80341 Richard Biener
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).