static optab new_optab PARAMS ((void));
static inline optab init_optab PARAMS ((enum rtx_code));
static inline optab init_optabv PARAMS ((enum rtx_code));
+static inline int complex_part_zero_p PARAMS ((rtx, enum mode_class,
+ enum machine_mode));
static void init_libfuncs PARAMS ((optab, int, int, const char *, int));
static void init_integral_libfuncs PARAMS ((optab, const char *, int));
static void init_floating_libfuncs PARAMS ((optab, const char *, int));
return result;
}
\f
+/* Test whether either the real or imaginary part of a complex floating
+ point number is 0.0, so that it can be ignored (when compiling
+ with -funsafe-math-optimizations). */
+
+static inline int
+complex_part_zero_p (part, class, submode)
+ rtx part;
+ enum mode_class class;
+ enum machine_mode submode;
+{
+ return part == 0 ||
+ (flag_unsafe_math_optimizations
+ && class == MODE_COMPLEX_FLOAT
+ && part == CONST0_RTX (submode));
+}
+
/* Generate code to perform a straightforward complex divide. */
static int
if (divisor == 0)
return 0;
- if (imag0 == 0)
+ if (complex_part_zero_p (imag0, class, submode))
{
/* Mathematically, ((a)(c-id))/divisor. */
/* Computationally, (a+i0) / (c+id) = (ac/(cc+dd)) + i(-ad/(cc+dd)). */
/* Calculate dividend. */
- if (imag0 == 0)
+ if (complex_part_zero_p (imag0, class, submode))
{
real_t = real0;
/* Calculate dividend. */
- if (imag0 == 0)
+ if (complex_part_zero_p (imag0, class, submode))
{
/* Compute a / (c+id) as a(c/d) / (c(c/d)+d) + i (-a) / (c(c/d)+d). */
&& GET_MODE_SIZE (mode) >= 2 * UNITS_PER_WORD
&& binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
{
- int i;
+ unsigned int i;
optab otheroptab = binoptab == add_optab ? sub_optab : add_optab;
- unsigned int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
+ int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
rtx carry_in = NULL_RTX, carry_out = NULL_RTX;
- rtx xop0, xop1;
+ rtx xop0, xop1, xtarget;
/* We can handle either a 1 or -1 value for the carry. If STORE_FLAG
value is one of those, use it. Otherwise, use 1 since it is the
xop0 = force_reg (mode, op0);
xop1 = force_reg (mode, op1);
- if (target == 0 || GET_CODE (target) != REG
- || target == xop0 || target == xop1)
- target = gen_reg_rtx (mode);
+ xtarget = gen_reg_rtx (mode);
+
+ if (target == 0 || GET_CODE (target) != REG)
+ target = xtarget;
/* Indicate for flow that the entire target reg is being set. */
if (GET_CODE (target) == REG)
- emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
+ emit_insn (gen_rtx_CLOBBER (VOIDmode, xtarget));
/* Do the actual arithmetic. */
for (i = 0; i < nwords; i++)
{
int index = (WORDS_BIG_ENDIAN ? nwords - i - 1 : i);
- rtx target_piece = operand_subword (target, index, 1, mode);
+ rtx target_piece = operand_subword (xtarget, index, 1, mode);
rtx op0_piece = operand_subword_force (xop0, index, mode);
rtx op1_piece = operand_subword_force (xop1, index, mode);
rtx x;
carry_in = carry_out;
}
- if (i == GET_MODE_BITSIZE (mode) / BITS_PER_WORD)
+ if (i == GET_MODE_BITSIZE (mode) / (unsigned) BITS_PER_WORD)
{
if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
- rtx temp = emit_move_insn (target, target);
+ rtx temp = emit_move_insn (target, xtarget);
set_unique_reg_note (temp,
REG_EQUAL,
rtx temp = expand_binop (word_mode, binoptab, op0_low, op1_xhigh,
NULL_RTX, 0, OPTAB_DIRECT);
+ if (!REG_P (product_high))
+ product_high = force_reg (word_mode, product_high);
+
if (temp != 0)
temp = expand_binop (word_mode, add_optab, temp, product_high,
product_high, 0, next_methods);
if (temp != 0 && temp != product_high)
emit_move_insn (product_high, temp);
+ emit_move_insn (operand_subword (product, high, 1, mode), product_high);
+
if (temp != 0)
{
if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
else
real1 = op1;
- if (real0 == 0 || real1 == 0 || ! (imag0 != 0|| imag1 != 0))
+ if (real0 == 0 || real1 == 0 || ! (imag0 != 0 || imag1 != 0))
abort ();
switch (binoptab->code)
else if (res != realr)
emit_move_insn (realr, res);
- if (imag0 && imag1)
+ if (!complex_part_zero_p (imag0, class, submode)
+ && !complex_part_zero_p (imag1, class, submode))
res = expand_binop (submode, binoptab, imag0, imag1,
imagr, unsignedp, methods);
- else if (imag0)
+ else if (!complex_part_zero_p (imag0, class, submode))
res = imag0;
else if (binoptab->code == MINUS)
res = expand_unop (submode,
case MULT:
/* (a+ib) * (c+id) = (ac-bd) + i(ad+cb) */
- if (imag0 && imag1)
+ if (!complex_part_zero_p (imag0, class, submode)
+ && !complex_part_zero_p (imag1, class, submode))
{
rtx temp1, temp2;
else if (res != realr)
emit_move_insn (realr, res);
- if (imag0 != 0)
+ if (!complex_part_zero_p (imag0, class, submode))
res = expand_binop (submode, binoptab,
real1, imag0, imagr, unsignedp, methods);
else
case DIV:
/* (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd)) */
- if (imag1 == 0)
+ if (complex_part_zero_p (imag1, class, submode))
{
/* (a+ib) / (c+i0) = (a/c) + i(b/c) */
these from the list. */
for (insn = insns; insn; insn = next)
{
- rtx set = 0;
+ rtx set = 0, note;
int i;
next = NEXT_INSN (insn);
+ /* Some ports (cris) create an libcall regions at their own. We must
+ avoid any potential nesting of LIBCALLs. */
+ if ((note = find_reg_note (insn, REG_LIBCALL, NULL)) != NULL)
+ remove_note (insn, note);
+ if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL)
+ remove_note (insn, note);
+
if (GET_CODE (PATTERN (insn)) == SET || GET_CODE (PATTERN (insn)) == USE
|| GET_CODE (PATTERN (insn)) == CLOBBER)
set = PATTERN (insn);
for (insn = insns; insn; insn = next)
{
rtx set = single_set (insn);
+ rtx note;
+
+ /* Some ports (cris) create an libcall regions at their own. We must
+ avoid any potential nesting of LIBCALLs. */
+ if ((note = find_reg_note (insn, REG_LIBCALL, NULL)) != NULL)
+ remove_note (insn, note);
+ if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL)
+ remove_note (insn, note);
next = NEXT_INSN (insn);
int *punsignedp;
{
enum rtx_code comparison = *pcomparison;
+ rtx tmp;
rtx x = *px = protect_from_queue (*px, 0);
rtx y = *py = protect_from_queue (*py, 0);
enum machine_mode mode = GET_MODE (x);
case GT:
libfunc = gthf2_libfunc;
+ if (libfunc == NULL_RTX)
+ {
+ tmp = x; x = y; y = tmp;
+ *pcomparison = LT;
+ libfunc = lthf2_libfunc;
+ }
break;
case GE:
libfunc = gehf2_libfunc;
+ if (libfunc == NULL_RTX)
+ {
+ tmp = x; x = y; y = tmp;
+ *pcomparison = LE;
+ libfunc = lehf2_libfunc;
+ }
break;
case LT:
libfunc = lthf2_libfunc;
+ if (libfunc == NULL_RTX)
+ {
+ tmp = x; x = y; y = tmp;
+ *pcomparison = GT;
+ libfunc = gthf2_libfunc;
+ }
break;
case LE:
libfunc = lehf2_libfunc;
+ if (libfunc == NULL_RTX)
+ {
+ tmp = x; x = y; y = tmp;
+ *pcomparison = GE;
+ libfunc = gehf2_libfunc;
+ }
break;
case UNORDERED:
case GT:
libfunc = gtsf2_libfunc;
+ if (libfunc == NULL_RTX)
+ {
+ tmp = x; x = y; y = tmp;
+ *pcomparison = LT;
+ libfunc = ltsf2_libfunc;
+ }
break;
case GE:
libfunc = gesf2_libfunc;
+ if (libfunc == NULL_RTX)
+ {
+ tmp = x; x = y; y = tmp;
+ *pcomparison = LE;
+ libfunc = lesf2_libfunc;
+ }
break;
case LT:
libfunc = ltsf2_libfunc;
+ if (libfunc == NULL_RTX)
+ {
+ tmp = x; x = y; y = tmp;
+ *pcomparison = GT;
+ libfunc = gtsf2_libfunc;
+ }
break;
case LE:
libfunc = lesf2_libfunc;
+ if (libfunc == NULL_RTX)
+ {
+ tmp = x; x = y; y = tmp;
+ *pcomparison = GE;
+ libfunc = gesf2_libfunc;
+ }
break;
case UNORDERED:
case GT:
libfunc = gtdf2_libfunc;
+ if (libfunc == NULL_RTX)
+ {
+ tmp = x; x = y; y = tmp;
+ *pcomparison = LT;
+ libfunc = ltdf2_libfunc;
+ }
break;
case GE:
libfunc = gedf2_libfunc;
+ if (libfunc == NULL_RTX)
+ {
+ tmp = x; x = y; y = tmp;
+ *pcomparison = LE;
+ libfunc = ledf2_libfunc;
+ }
break;
case LT:
libfunc = ltdf2_libfunc;
+ if (libfunc == NULL_RTX)
+ {
+ tmp = x; x = y; y = tmp;
+ *pcomparison = GT;
+ libfunc = gtdf2_libfunc;
+ }
break;
case LE:
libfunc = ledf2_libfunc;
+ if (libfunc == NULL_RTX)
+ {
+ tmp = x; x = y; y = tmp;
+ *pcomparison = GE;
+ libfunc = gedf2_libfunc;
+ }
break;
case UNORDERED:
case GT:
libfunc = gtxf2_libfunc;
+ if (libfunc == NULL_RTX)
+ {
+ tmp = x; x = y; y = tmp;
+ *pcomparison = LT;
+ libfunc = ltxf2_libfunc;
+ }
break;
case GE:
libfunc = gexf2_libfunc;
+ if (libfunc == NULL_RTX)
+ {
+ tmp = x; x = y; y = tmp;
+ *pcomparison = LE;
+ libfunc = lexf2_libfunc;
+ }
break;
case LT:
libfunc = ltxf2_libfunc;
+ if (libfunc == NULL_RTX)
+ {
+ tmp = x; x = y; y = tmp;
+ *pcomparison = GT;
+ libfunc = gtxf2_libfunc;
+ }
break;
case LE:
libfunc = lexf2_libfunc;
+ if (libfunc == NULL_RTX)
+ {
+ tmp = x; x = y; y = tmp;
+ *pcomparison = GE;
+ libfunc = gexf2_libfunc;
+ }
break;
case UNORDERED:
case GT:
libfunc = gttf2_libfunc;
+ if (libfunc == NULL_RTX)
+ {
+ tmp = x; x = y; y = tmp;
+ *pcomparison = LT;
+ libfunc = lttf2_libfunc;
+ }
break;
case GE:
libfunc = getf2_libfunc;
+ if (libfunc == NULL_RTX)
+ {
+ tmp = x; x = y; y = tmp;
+ *pcomparison = LE;
+ libfunc = letf2_libfunc;
+ }
break;
case LT:
libfunc = lttf2_libfunc;
+ if (libfunc == NULL_RTX)
+ {
+ tmp = x; x = y; y = tmp;
+ *pcomparison = GT;
+ libfunc = gttf2_libfunc;
+ }
break;
case LE:
libfunc = letf2_libfunc;
+ if (libfunc == NULL_RTX)
+ {
+ tmp = x; x = y; y = tmp;
+ *pcomparison = GE;
+ libfunc = getf2_libfunc;
+ }
break;
case UNORDERED:
NULL_RTX, 0, OPTAB_LIB_WIDEN);
expand_fix (to, target, 0);
target = expand_binop (GET_MODE (to), xor_optab, to,
- GEN_INT (trunc_int_for_mode
- ((HOST_WIDE_INT) 1 << (bitsize - 1),
- GET_MODE (to))),
+ gen_int_mode
+ ((HOST_WIDE_INT) 1 << (bitsize - 1),
+ GET_MODE (to)),
to, 1, OPTAB_LIB_WIDEN);
if (target != to)
new_optab ()
{
int i;
- optab op = (optab) xmalloc (sizeof (struct optab));
+ optab op = (optab) ggc_alloc (sizeof (struct optab));
for (i = 0; i < NUM_MACHINE_MODES; i++)
{
op->handlers[i].insn_code = CODE_FOR_nothing;
init_one_libfunc (name)
const char *name;
{
- /* Create a FUNCTION_DECL that can be passed to ENCODE_SECTION_INFO. */
+ /* Create a FUNCTION_DECL that can be passed to
+ targetm.encode_section_info. */
/* ??? We don't have any type information except for this is
a function. Pretend this is "int foo()". */
tree decl = build_decl (FUNCTION_DECL, get_identifier (name),
return XEXP (DECL_RTL (decl), 0);
}
-/* Mark ARG (which is really an OPTAB *) for GC. */
-
-void
-mark_optab (arg)
- void *arg;
-{
- optab o = *(optab *) arg;
- int i;
-
- for (i = 0; i < NUM_MACHINE_MODES; ++i)
- ggc_mark_rtx (o->handlers[i].libfunc);
-}
-
/* Call this once to initialize the contents of the optabs
appropriately for the current target machine. */
truncxfdf2_libfunc = init_one_libfunc ("__truncxfdf2");
trunctfdf2_libfunc = init_one_libfunc ("__trunctfdf2");
+ abort_libfunc = init_one_libfunc ("abort");
memcpy_libfunc = init_one_libfunc ("memcpy");
memmove_libfunc = init_one_libfunc ("memmove");
bcopy_libfunc = init_one_libfunc ("bcopy");
/* Allow the target to add more libcalls or rename some, etc. */
INIT_TARGET_OPTABS;
#endif
-
- /* Add these GC roots. */
- ggc_add_root (optab_table, OTI_MAX, sizeof(optab), mark_optab);
- ggc_add_rtx_root (libfunc_table, LTI_MAX);
}
\f
+static GTY(()) rtx trap_rtx;
+
#ifdef HAVE_conditional_trap
/* The insn generating function can not take an rtx_code argument.
TRAP_RTX is used as an rtx argument. Its code is replaced with
the code to be used in the trap insn and all other fields are
ignored. */
-static rtx trap_rtx;
static void
init_traps ()
if (HAVE_conditional_trap)
{
trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX);
- ggc_add_rtx_root (&trap_rtx, 1);
}
}
#endif
return 0;
}
+
+#include "gt-optabs.h"