This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFA: fix PR tree-optimization/28144/27394


As Andrew has clarified that the Java frontend handles the two-step conversion for
floating point -> narrow integers, the remaining problem for PR28144 was that the
comment in fold-const.c was wrong.
In order to allow people to debug their programs meaningfully at -O0, I've broken
out the code that determines what mode to use to do a run-time conversion from
floating point to integer, and made fold-const.c use it to determine the type that
the conversion is done in.
I've put the expand_fix_1 prototype in rtl.h rather than optabs.h to avoid a gratuitous
dependency of fold-const.c on optabs.h.


:ADDPATCH tree-optimization:

regression tested on i686-pc-linux-gnu native and X sh-elf in Revision 115417
2006-07-16  J"orn Rennecke <joern.rennecke@st.com>

gcc:
	PR tree-optimization/28144/27394
	* rtl.h (expand_fix_1): Declare.
	* optabs.c (expand_fix_1): New function, broken out of:
	(expand_fix).
	* fold-const.c (fold_convert_const_int_from_real): Fix comment
	wrt. implementing Java conversions.
	Perform conversion in same mode as optabs.c would do it.
testsuite:
	PR tree-optimization/27394
	gcc.c-torture/execute/pr27394.c: New test.

Index: optabs.c
===================================================================
/usr/bin/diff -p -d -F^( -u -L optabs.c	(revision 115417) -L optabs.c	(working copy) .svn/text-base/optabs.c.svn-base optabs.c
--- optabs.c	(revision 115417)
+++ optabs.c	(working copy)
@@ -4684,6 +4684,18 @@ expand_float (rtx to, rtx from, int unsi
 void
 expand_fix (rtx to, rtx from, int unsignedp)
 {
+  expand_fix_1 (to, GET_MODE (to), from, GET_MODE (from), &unsignedp);
+}
+
+/* As above, but don't actually emit any code if FROM and TO are NULL_RTX.
+   Return the mode that is actuallyu the target of the floating
+   point -> integer conversion.  Reset *UNSIGNEDPP if we use a widened
+   signed conversion to implement an unsigned conversion.  */
+enum machine_mode
+expand_fix_1 (rtx to, enum machine_mode to_mode, rtx from,
+	      enum machine_mode from_mode, int *unsignedpp)
+{
+  int unsignedp = *unsignedpp;
   enum insn_code icode;
   rtx target = to;
   enum machine_mode fmode, imode;
@@ -4694,37 +4706,37 @@ expand_fix (rtx to, rtx from, int unsign
      this conversion.  If the integer mode is wider than the mode of TO,
      we can do the conversion either signed or unsigned.  */
 
-  for (fmode = GET_MODE (from); fmode != VOIDmode;
+  for (fmode = from_mode; fmode != VOIDmode;
        fmode = GET_MODE_WIDER_MODE (fmode))
-    for (imode = GET_MODE (to); imode != VOIDmode;
+    for (imode = to_mode; imode != VOIDmode;
 	 imode = GET_MODE_WIDER_MODE (imode))
       {
-	int doing_unsigned = unsignedp;
-
 	icode = can_fix_p (imode, fmode, unsignedp, &must_trunc);
-	if (icode == CODE_FOR_nothing && imode != GET_MODE (to) && unsignedp)
-	  icode = can_fix_p (imode, fmode, 0, &must_trunc), doing_unsigned = 0;
+	if (icode == CODE_FOR_nothing && imode != to_mode && unsignedp)
+	  icode = can_fix_p (imode, fmode, 0, &must_trunc), *unsignedpp = 0;
 
 	if (icode != CODE_FOR_nothing)
 	  {
-	    if (fmode != GET_MODE (from))
+	    if (!to)
+	      return imode;
+
+	    if (fmode != from_mode)
 	      from = convert_to_mode (fmode, from, 0);
 
 	    if (must_trunc)
 	      {
-		rtx temp = gen_reg_rtx (GET_MODE (from));
-		from = expand_unop (GET_MODE (from), ftrunc_optab, from,
-				    temp, 0);
+		rtx temp = gen_reg_rtx (fmode);
+		from = expand_unop (fmode, ftrunc_optab, from, temp, 0);
 	      }
 
 	    if (imode != GET_MODE (to))
 	      target = gen_reg_rtx (imode);
 
 	    emit_unop_insn (icode, target, from,
-			    doing_unsigned ? UNSIGNED_FIX : FIX);
+			    *unsignedpp ? UNSIGNED_FIX : FIX);
 	    if (target != to)
 	      convert_move (to, target, unsignedp);
-	    return;
+	    return imode;
 	  }
       }
 
@@ -4750,29 +4762,31 @@ expand_fix (rtx to, rtx from, int unsign
      2^63.  The subtraction of 2^63 should not generate any rounding as it
      simply clears out that bit.  The rest is trivial.  */
 
-  if (unsignedp && GET_MODE_BITSIZE (GET_MODE (to)) <= HOST_BITS_PER_WIDE_INT)
-    for (fmode = GET_MODE (from); fmode != VOIDmode;
+  if (unsignedp && GET_MODE_BITSIZE (to_mode) <= HOST_BITS_PER_WIDE_INT)
+    for (fmode = from_mode; fmode != VOIDmode;
 	 fmode = GET_MODE_WIDER_MODE (fmode))
-      if (CODE_FOR_nothing != can_fix_p (GET_MODE (to), fmode, 0,
-					 &must_trunc))
+      if (CODE_FOR_nothing != can_fix_p (to_mode, fmode, 0, &must_trunc))
 	{
 	  int bitsize;
 	  REAL_VALUE_TYPE offset;
 	  rtx limit, lab1, lab2, insn;
 
+	  /* The net effect will still be an unsigned conversion to TO_MODE.  */
+	  if (!to)
+	    return to_mode;
+
 	  bitsize = GET_MODE_BITSIZE (GET_MODE (to));
 	  real_2expN (&offset, bitsize - 1);
 	  limit = CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode);
 	  lab1 = gen_label_rtx ();
 	  lab2 = gen_label_rtx ();
 
-	  if (fmode != GET_MODE (from))
+	  if (fmode != from_mode)
 	    from = convert_to_mode (fmode, from, 0);
 
 	  /* See if we need to do the subtraction.  */
 	  do_pending_stack_adjust ();
-	  emit_cmp_and_jump_insns (from, limit, GE, NULL_RTX, GET_MODE (from),
-				   0, lab1);
+	  emit_cmp_and_jump_insns (from, limit, GE, NULL_RTX, fmode, 0, lab1);
 
 	  /* If not, do the signed "fix" and branch around fixup code.  */
 	  expand_fix (to, from, 0);
@@ -4783,13 +4797,12 @@ expand_fix (rtx to, rtx from, int unsign
 	     then add 2**(N-1).  Do the addition using XOR since this
 	     will often generate better code.  */
 	  emit_label (lab1);
-	  target = expand_binop (GET_MODE (from), sub_optab, from, limit,
+	  target = expand_binop (fmode, sub_optab, from, limit,
 				 NULL_RTX, 0, OPTAB_LIB_WIDEN);
 	  expand_fix (to, target, 0);
-	  target = expand_binop (GET_MODE (to), xor_optab, to,
+	  target = expand_binop (to_mode, xor_optab, to,
 				 gen_int_mode
-				 ((HOST_WIDE_INT) 1 << (bitsize - 1),
-				  GET_MODE (to)),
+				 ((HOST_WIDE_INT) 1 << (bitsize - 1), to_mode),
 				 to, 1, OPTAB_LIB_WIDEN);
 
 	  if (target != to)
@@ -4809,15 +4822,19 @@ expand_fix (rtx to, rtx from, int unsign
 						  copy_rtx (from)));
 	    }
 
-	  return;
+	  return to_mode;
 	}
 
   /* We can't do it with an insn, so use a library call.  But first ensure
      that the mode of TO is at least as wide as SImode, since those are the
      only library calls we know about.  */
 
-  if (GET_MODE_SIZE (GET_MODE (to)) < GET_MODE_SIZE (SImode))
+  if (GET_MODE_SIZE (to_mode) < GET_MODE_SIZE (SImode))
     {
+      imode = SImode;
+      if (!to)
+	return imode;
+
       target = gen_reg_rtx (SImode);
 
       expand_fix (target, from, unsignedp);
@@ -4827,31 +4844,36 @@ expand_fix (rtx to, rtx from, int unsign
       rtx insns;
       rtx value;
       rtx libfunc;
+      convert_optab tab;
 
-      convert_optab tab = unsignedp ? ufix_optab : sfix_optab;
-      libfunc = tab->handlers[GET_MODE (to)][GET_MODE (from)].libfunc;
+      imode = to_mode;
+      if (!to)
+	return imode;
+
+      tab = unsignedp ? ufix_optab : sfix_optab;
+      libfunc = tab->handlers[GET_MODE (to)][from_mode].libfunc;
       gcc_assert (libfunc);
 
       start_sequence ();
 
       value = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
-				       GET_MODE (to), 1, from,
-				       GET_MODE (from));
+				       to_mode, 1, from, from_mode);
       insns = get_insns ();
       end_sequence ();
 
       emit_libcall_block (insns, target, value,
 			  gen_rtx_fmt_e (unsignedp ? UNSIGNED_FIX : FIX,
-					 GET_MODE (to), from));
+					 to_mode, from));
     }
 
   if (target != to)
     {
-      if (GET_MODE (to) == GET_MODE (target))
+      if (to_mode == GET_MODE (target))
         emit_move_insn (to, target);
       else
         convert_move (to, target, 0);
     }
+  return imode;
 }
 
 /* Report whether we have an instruction to perform the operation
Index: fold-const.c
===================================================================
/usr/bin/diff -p -d -F^( -u -L fold-const.c	(revision 115417) -L fold-const.c	(working copy) .svn/text-base/fold-const.c.svn-base fold-const.c
--- fold-const.c	(revision 115417)
+++ fold-const.c	(working copy)
@@ -1836,11 +1836,16 @@ fold_convert_const_int_from_real (enum t
      INT_MAX are mapped to INT_MAX, and values less than INT_MIN
      are mapped to INT_MIN.  These semantics are allowed by the
      C and C++ standards that simply state that the behavior of
-     FP-to-integer conversion is unspecified upon overflow.  */
+     FP-to-integer conversion is unspecified upon overflow.
+     The Java two-step conversion from floating point to byte / char /
+     short is handled in the front end.  */
 
   HOST_WIDE_INT high, low;
   REAL_VALUE_TYPE r;
   REAL_VALUE_TYPE x = TREE_REAL_CST (arg1);
+  enum machine_mode fix_mode;
+  tree fix_type;
+  int unsignedp = TYPE_UNSIGNED (type);
 
   switch (code)
     {
@@ -1872,12 +1877,25 @@ fold_convert_const_int_from_real (enum t
       low = 0;
     }
 
+  /* Getting different results for different optimization levels makes
+     debugging of faulty programs harder.  Therefore, use the same logic
+     as optabs.c:expand_fix to determine what the target mode of the
+     conversion will be, to avoid gratuitous differences between
+     compile-time and run-time conversions.  */
+  fix_mode = expand_fix_1 (NULL_RTX, TYPE_MODE (type), NULL_RTX,
+			   TYPE_MODE (TREE_TYPE (arg1)), &unsignedp);
+  fix_type = NULL_TREE;
+  if (fix_mode != TYPE_MODE (type))
+    fix_type = lang_hooks.types.type_for_mode (fix_mode, unsignedp);
+  if (!fix_type)
+    fix_type = type;
+
   /* See if R is less than the lower bound or greater than the
      upper bound.  */
 
   if (! overflow)
     {
-      tree lt = TYPE_MIN_VALUE (type);
+      tree lt = TYPE_MIN_VALUE (fix_type);
       REAL_VALUE_TYPE l = real_value_from_int_cst (NULL_TREE, lt);
       if (REAL_VALUES_LESS (r, l))
 	{
@@ -1889,7 +1907,7 @@ fold_convert_const_int_from_real (enum t
 
   if (! overflow)
     {
-      tree ut = TYPE_MAX_VALUE (type);
+      tree ut = TYPE_MAX_VALUE (fix_type);
       if (ut)
 	{
 	  REAL_VALUE_TYPE u = real_value_from_int_cst (NULL_TREE, ut);
Index: rtl.h
===================================================================
/usr/bin/diff -p -d -F^( -u -L rtl.h	(revision 115417) -L rtl.h	(working copy) .svn/text-base/rtl.h.svn-base rtl.h
--- rtl.h	(revision 115417)
+++ rtl.h	(working copy)
@@ -2263,6 +2263,9 @@ extern unsigned int variable_tracking_ma
 /* In stor-layout.c.  */
 extern void get_mode_bounds (enum machine_mode, int, enum machine_mode,
 			     rtx *, rtx *);
+/* In optabs.c  */
+extern enum machine_mode expand_fix_1 (rtx, enum machine_mode, rtx,
+				       enum machine_mode, int *);
 
 /* In loop-unswitch.c  */
 extern rtx reversed_condition (rtx);
Index: testsuite/gcc.c-torture/execute/pr27394.c
===================================================================
/usr/bin/diff -p -d -F^( -u -L testsuite/gcc.c-torture/execute/pr27394.c	(revision 0) -L testsuite/gcc.c-torture/execute/pr27394.c	(revision 0) testsuite/gcc.c-torture/execute/.svn/empty-file testsuite/gcc.c-torture/execute/pr27394.c
--- testsuite/gcc.c-torture/execute/pr27394.c	(revision 0)
+++ testsuite/gcc.c-torture/execute/pr27394.c	(revision 0)
@@ -0,0 +1,18 @@
+char __attribute__ ((noinline))
+d2c (double d)
+{
+  return d;
+}
+
+char d2c_const (void)
+{
+  return 300.;
+}
+
+int
+main ()
+{
+  if (d2c (300.) != d2c_const ())
+    abort ();
+  exit (0);
+}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]