public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [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).