summaryrefslogtreecommitdiff
path: root/gcc/optabs.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/optabs.c')
-rw-r--r--gcc/optabs.c73
1 files changed, 73 insertions, 0 deletions
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 9da95e1de72..9aa2e4ae3f8 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -22,6 +22,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "toplev.h"
/* Include insn-config.h before expr.h so that HAVE_conditional_move
@@ -2514,6 +2516,39 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
return target;
}
+ /* Try negating floating point values by flipping the sign bit. */
+ if (unoptab->code == NEG && class == MODE_FLOAT
+ && GET_MODE_BITSIZE (mode) <= 2 * HOST_BITS_PER_WIDE_INT)
+ {
+ const struct real_format *fmt = real_format_for_mode[mode - QFmode];
+ enum machine_mode imode = int_mode_for_mode (mode);
+ int bitpos = (fmt != 0) ? fmt->signbit : -1;
+
+ if (imode != BLKmode && bitpos >= 0 && fmt->has_signed_zero)
+ {
+ HOST_WIDE_INT hi, lo;
+ rtx last = get_last_insn ();
+
+ if (bitpos < HOST_BITS_PER_WIDE_INT)
+ {
+ hi = 0;
+ lo = (HOST_WIDE_INT) 1 << bitpos;
+ }
+ else
+ {
+ hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT);
+ lo = 0;
+ }
+ temp = expand_binop (imode, xor_optab,
+ gen_lowpart (imode, op0),
+ immed_double_const (lo, hi, imode),
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ if (temp != 0)
+ return gen_lowpart (mode, temp);
+ delete_insns_since (last);
+ }
+ }
+
/* Now try a library call in this mode. */
if (unoptab->handlers[(int) mode].libfunc)
{
@@ -2626,6 +2661,39 @@ expand_abs (mode, op0, target, result_unsignedp, safe)
if (temp != 0)
return temp;
+ /* For floating point modes, try clearing the sign bit. */
+ if (GET_MODE_CLASS (mode) == MODE_FLOAT
+ && GET_MODE_BITSIZE (mode) <= 2 * HOST_BITS_PER_WIDE_INT)
+ {
+ const struct real_format *fmt = real_format_for_mode[mode - QFmode];
+ enum machine_mode imode = int_mode_for_mode (mode);
+ int bitpos = (fmt != 0) ? fmt->signbit : -1;
+
+ if (imode != BLKmode && bitpos >= 0)
+ {
+ HOST_WIDE_INT hi, lo;
+ rtx last = get_last_insn ();
+
+ if (bitpos < HOST_BITS_PER_WIDE_INT)
+ {
+ hi = 0;
+ lo = (HOST_WIDE_INT) 1 << bitpos;
+ }
+ else
+ {
+ hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT);
+ lo = 0;
+ }
+ temp = expand_binop (imode, and_optab,
+ gen_lowpart (imode, op0),
+ immed_double_const (~lo, ~hi, imode),
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ if (temp != 0)
+ return gen_lowpart (mode, temp);
+ delete_insns_since (last);
+ }
+ }
+
/* If we have a MAX insn, we can do this as MAX (x, -x). */
if (smax_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
@@ -5164,6 +5232,11 @@ init_optabs ()
one_cmpl_optab = init_optab (NOT);
ffs_optab = init_optab (FFS);
sqrt_optab = init_optab (SQRT);
+ floor_optab = init_optab (UNKNOWN);
+ ceil_optab = init_optab (UNKNOWN);
+ round_optab = init_optab (UNKNOWN);
+ trunc_optab = init_optab (UNKNOWN);
+ nearbyint_optab = init_optab (UNKNOWN);
sin_optab = init_optab (UNKNOWN);
cos_optab = init_optab (UNKNOWN);
exp_optab = init_optab (UNKNOWN);