aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorPaul Eggert <eggert@gnu.org>1993-03-18 21:28:43 +0000
committerPaul Eggert <eggert@gnu.org>1993-03-18 21:28:43 +0000
commitc95c47f3e966ecff92e01cadb023976220b2b29a (patch)
tree438d0c17c50bfb92e65fa8fbbe055db48c213c2b /gcc
parent0cdd3dddaec089933fadb35754aeb93f16f2117b (diff)
downloadgcc-c95c47f3e966ecff92e01cadb023976220b2b29a.zip
gcc-c95c47f3e966ecff92e01cadb023976220b2b29a.tar.gz
gcc-c95c47f3e966ecff92e01cadb023976220b2b29a.tar.bz2
(expand_float): When converting an unsigned type U to a smaller or equal-sized floating type F where there's no hardware support for unsigned-to-float conversion...
(expand_float): When converting an unsigned type U to a smaller or equal-sized floating type F where there's no hardware support for unsigned-to-float conversion, use a temporary floating type larger than F if possible, since this avoids rounding problems that are worst when U is just greater than the maximum signed integer of the same size. From-SVN: r3778
Diffstat (limited to 'gcc')
-rw-r--r--gcc/optabs.c24
1 files changed, 20 insertions, 4 deletions
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 81b5f69..95f1b21 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -3572,11 +3572,27 @@ expand_float (to, from, unsignedp)
if (flag_force_mem)
from = force_not_mem (from);
+ /* Look for a usable floating mode FMODE wider than the source and at
+ least as wide as the target. Using FMODE will avoid rounding woes
+ with unsigned values greater than the signed maximum value. */
+ for (fmode = GET_MODE (to); fmode != VOIDmode;
+ fmode = GET_MODE_WIDER_MODE (fmode))
+ 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. */
+ fmode = GET_MODE (to);
+ }
+
/* If we are about to do some arithmetic to correct for an
unsigned operand, do it in a pseudo-register. */
- if (GET_CODE (to) != REG || REGNO (to) <= LAST_VIRTUAL_REGISTER)
- target = gen_reg_rtx (GET_MODE (to));
+ if (GET_MODE (to) != fmode
+ || GET_CODE (to) != REG || REGNO (to) <= LAST_VIRTUAL_REGISTER)
+ target = gen_reg_rtx (fmode);
/* Convert as signed integer to floating. */
expand_float (target, from, 0);
@@ -3591,8 +3607,8 @@ expand_float (to, from, unsignedp)
Rather than setting up a dconst_dot_5, let's hope SCO
fixes the bug. */
offset = REAL_VALUE_LDEXP (dconst1, GET_MODE_BITSIZE (GET_MODE (from)));
- temp = expand_binop (GET_MODE (to), add_optab, target,
- immed_real_const_1 (offset, GET_MODE (to)),
+ temp = expand_binop (fmode, add_optab, target,
+ immed_real_const_1 (offset, fmode),
target, 0, OPTAB_LIB_WIDEN);
if (temp != target)
emit_move_insn (target, temp);