diff options
author | kenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4> | 1994-05-30 14:33:41 +0000 |
---|---|---|
committer | kenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4> | 1994-05-30 14:33:41 +0000 |
commit | 144a41c27d85a610d201daf722108ba0496c5845 (patch) | |
tree | b790afda3ca6646caed60b65fd68a88b86616a76 /gcc/optabs.c | |
parent | 94ff816da7084242e7e20c85d30442ee94b71c70 (diff) | |
download | ppe42-gcc-144a41c27d85a610d201daf722108ba0496c5845.tar.gz ppe42-gcc-144a41c27d85a610d201daf722108ba0496c5845.zip |
(expand_float): Avoid double-rounding when float is is narrower than
int.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@7386 138bc75d-0d04-0410-961f-82ee72b054a4
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 7b263bcab1e..b3b6ea96928 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. */ |