]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
(expand_float): Avoid double-rounding when float is is narrower than
authorRichard Kenner <kenner@gcc.gnu.org>
Mon, 30 May 1994 14:33:41 +0000 (10:33 -0400)
committerRichard Kenner <kenner@gcc.gnu.org>
Mon, 30 May 1994 14:33:41 +0000 (10:33 -0400)
int.

From-SVN: r7386

gcc/optabs.c

index 7b263bcab1e7c54deb72e56475ba06e1e662e64d..b3b6ea96928ce176d682c1c352160b1c9859d4e7 100644 (file)
@@ -3070,11 +3070,51 @@ expand_float (to, from, unsignedp)
        if (GET_MODE_BITSIZE (GET_MODE (from)) < GET_MODE_BITSIZE (fmode)
            && can_float_p (fmode, GET_MODE (from), 0) != CODE_FOR_nothing)
          break;
+
       if (fmode == VOIDmode)
        {
-         /* There is no such mode.  Pretend the target is wide enough.
-            This may cause rounding problems, unfortunately.  */
+         /* There is no such mode.  Pretend the target is wide enough.  */
          fmode = GET_MODE (to);
+
+         /* Avoid double-rounding when TO is narrower than FROM. */
+         if ((significand_size (fmode) + 1)
+             < GET_MODE_BITSIZE (GET_MODE (from)))
+           {
+             rtx temp1;
+             rtx neglabel = gen_label_rtx ();
+
+             imode = GET_MODE (from);
+             do_pending_stack_adjust ();
+
+             /* Test whether the sign bit is set.  */
+             emit_cmp_insn (from, const0_rtx, GE, NULL_RTX, imode, 0, 0);
+             emit_jump_insn (gen_blt (neglabel));
+
+             /* The sign bit is not set.  Convert as signed.  */
+             expand_float (target, from, 0);
+             emit_jump_insn (gen_jump (label));
+
+             /* The sign bit is set.
+                Convert to a usable (positive signed) value by shifting right
+                one bit, while remembering if a nonzero bit was shifted
+                out; i.e., compute  (from & 1) | (from >> 1).  */
+
+             emit_label (neglabel);
+             temp = expand_binop (imode, and_optab, from, const1_rtx,
+                                   0, 1, 0);
+             temp1 = expand_binop (imode, lshr_optab, from, const1_rtx,
+                                  from, 1, 0);
+             temp = expand_binop (imode, ior_optab, temp, temp1,
+                                  temp, 1, 0);
+             expand_float (target, temp, 0);
+
+             /* Multiply by 2 to undo the shift above.  */
+             target = expand_binop (fmode, add_optab, target, target,
+                                  target, 0, 0);
+             do_pending_stack_adjust ();
+             emit_label (label);
+             goto done;
+           }
        }
 
       /* If we are about to do some arithmetic to correct for an
@@ -3102,6 +3142,7 @@ expand_float (to, from, unsignedp)
                           target, 0, OPTAB_LIB_WIDEN);
       if (temp != target)
        emit_move_insn (target, temp);
+
       do_pending_stack_adjust ();
       emit_label (label);
     }
@@ -3183,6 +3224,8 @@ expand_float (to, from, unsignedp)
                          gen_rtx (FLOAT, GET_MODE (to), from));
     }
 
+ done:
+
   /* Copy result to requested destination
      if we have been computing in a temp location.  */