diff options
author | Richard Kenner <kenner@gcc.gnu.org> | 1994-05-30 10:33:41 -0400 |
---|---|---|
committer | Richard Kenner <kenner@gcc.gnu.org> | 1994-05-30 10:33:41 -0400 |
commit | a48fb61b5bbb8ae2f821875a07d0ac8ceb334e02 (patch) | |
tree | b790afda3ca6646caed60b65fd68a88b86616a76 /gcc/optabs.c | |
parent | 344a822046c08d2cb6a80eada0dbcbcf77cb6a44 (diff) | |
download | gcc-a48fb61b5bbb8ae2f821875a07d0ac8ceb334e02.zip gcc-a48fb61b5bbb8ae2f821875a07d0ac8ceb334e02.tar.gz gcc-a48fb61b5bbb8ae2f821875a07d0ac8ceb334e02.tar.bz2 |
(expand_float): Avoid double-rounding when float is is narrower than
int.
From-SVN: r7386
Diffstat (limited to 'gcc/optabs.c')
-rw-r--r-- | gcc/optabs.c | 47 |
1 files changed, 45 insertions, 2 deletions
diff --git a/gcc/optabs.c b/gcc/optabs.c index 7b263bc..b3b6ea9 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -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. */ |