diff options
author | Paul Eggert <eggert@gnu.org> | 1993-03-18 21:28:43 +0000 |
---|---|---|
committer | Paul Eggert <eggert@gnu.org> | 1993-03-18 21:28:43 +0000 |
commit | c95c47f3e966ecff92e01cadb023976220b2b29a (patch) | |
tree | 438d0c17c50bfb92e65fa8fbbe055db48c213c2b | |
parent | 0cdd3dddaec089933fadb35754aeb93f16f2117b (diff) | |
download | gcc-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
-rw-r--r-- | gcc/optabs.c | 24 |
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); |