/* Expand the basic unary and binary arithmetic operations, for GNU compiler.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
This file is part of GCC.
See expr.h for documentation of these optabs. */
-optab optab_table[OTI_MAX];
+#if GCC_VERSION >= 4000
+__extension__ struct optab optab_table[OTI_MAX]
+ = { [0 ... OTI_MAX - 1].handlers[0 ... NUM_MACHINE_MODES - 1].insn_code
+ = CODE_FOR_nothing };
+#else
+/* init_insn_codes will do runtime initialization otherwise. */
+struct optab optab_table[OTI_MAX];
+#endif
rtx libfunc_table[LTI_MAX];
/* Tables of patterns for converting one mode to another. */
-convert_optab convert_optab_table[COI_MAX];
+#if GCC_VERSION >= 4000
+__extension__ struct convert_optab convert_optab_table[COI_MAX]
+ = { [0 ... COI_MAX - 1].handlers[0 ... NUM_MACHINE_MODES - 1]
+ [0 ... NUM_MACHINE_MODES - 1].insn_code
+ = CODE_FOR_nothing };
+#else
+/* init_convert_optab will do runtime initialization otherwise. */
+struct convert_optab convert_optab_table[COI_MAX];
+#endif
/* Contains the optab used for each rtx code. */
optab code_to_optab[NUM_RTX_CODE + 1];
enum machine_mode *, int *);
static rtx expand_unop_direct (enum machine_mode, optab, rtx, rtx, int);
-/* Current libcall id. It doesn't matter what these are, as long
- as they are unique to each libcall that is emitted. */
-static HOST_WIDE_INT libcall_id = 0;
-
/* Debug facility for use in GDB. */
void debug_optab_libfuncs (void);
struct libfunc_entry e;
struct libfunc_entry **slot;
- e.optab = (size_t) (convert_optab_table[0] - optab);
+ e.optab = (size_t) (optab - &convert_optab_table[0]);
e.mode1 = mode1;
e.mode2 = mode2;
slot = (struct libfunc_entry **) htab_find_slot (libfunc_hash, &e, NO_INSERT);
struct libfunc_entry e;
struct libfunc_entry **slot;
- e.optab = (size_t) (optab_table[0] - optab);
+ e.optab = (size_t) (optab - &optab_table[0]);
e.mode1 = mode;
e.mode2 = VOIDmode;
slot = (struct libfunc_entry **) htab_find_slot (libfunc_hash, &e, NO_INSERT);
case FLOOR_DIV_EXPR:
case ROUND_DIV_EXPR:
case EXACT_DIV_EXPR:
+ if (TYPE_SATURATING(type))
+ return TYPE_UNSIGNED(type) ? usdiv_optab : ssdiv_optab;
return TYPE_UNSIGNED (type) ? udiv_optab : sdiv_optab;
case LSHIFT_EXPR:
+ if (TYPE_SATURATING(type))
+ return TYPE_UNSIGNED(type) ? usashl_optab : ssashl_optab;
return ashl_optab;
case RSHIFT_EXPR:
{
case POINTER_PLUS_EXPR:
case PLUS_EXPR:
+ if (TYPE_SATURATING(type))
+ return TYPE_UNSIGNED(type) ? usadd_optab : ssadd_optab;
return trapv ? addv_optab : add_optab;
case MINUS_EXPR:
+ if (TYPE_SATURATING(type))
+ return TYPE_UNSIGNED(type) ? ussub_optab : sssub_optab;
return trapv ? subv_optab : sub_optab;
case MULT_EXPR:
+ if (TYPE_SATURATING(type))
+ return TYPE_UNSIGNED(type) ? usmul_optab : ssmul_optab;
return trapv ? smulv_optab : smul_optab;
case NEGATE_EXPR:
+ if (TYPE_SATURATING(type))
+ return TYPE_UNSIGNED(type) ? usneg_optab : ssneg_optab;
return trapv ? negv_optab : neg_optab;
case ABS_EXPR:
switch (binoptab->code)
{
case ASHIFT:
+ case SS_ASHIFT:
+ case US_ASHIFT:
case ASHIFTRT:
case LSHIFTRT:
case ROTATE:
avoid_expensive_constant (enum machine_mode mode, optab binoptab,
rtx x, bool unsignedp)
{
- if (optimize
+ if (mode != VOIDmode
+ && optimize
&& CONSTANT_P (x)
&& rtx_cost (x, binoptab->code) > COSTS_N_INSNS (1))
{
hides any signed insn for direct use. */
wide_soptab = *soptab;
optab_handler (&wide_soptab, mode)->insn_code = CODE_FOR_nothing;
+ /* We don't want to generate new hash table entries from this fake
+ optab. */
+ wide_soptab.libcall_gen = NULL;
temp = expand_binop (mode, &wide_soptab, op0, op1, target,
unsignedp, OPTAB_WIDEN);
{
rtx insns;
rtx value;
+ rtx eq_value;
enum machine_mode outmode = mode;
/* All of these functions return small values. Thus we choose to
end_sequence ();
target = gen_reg_rtx (outmode);
- emit_libcall_block (insns, target, value,
- gen_rtx_fmt_e (unoptab->code, outmode, op0));
+ eq_value = gen_rtx_fmt_e (unoptab->code, mode, op0);
+ if (GET_MODE_SIZE (outmode) < GET_MODE_SIZE (mode))
+ eq_value = simplify_gen_unary (TRUNCATE, outmode, eq_value, mode);
+ else if (GET_MODE_SIZE (outmode) > GET_MODE_SIZE (mode))
+ eq_value = simplify_gen_unary (ZERO_EXTEND, outmode, eq_value, mode);
+ emit_libcall_block (insns, target, value, eq_value);
return target;
}
REG_NOTES (first));
REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first,
REG_NOTES (last));
- next = NEXT_INSN (last);
- for (insn = first; insn != next; insn = NEXT_INSN (insn))
- REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_LIBCALL_ID,
- GEN_INT (libcall_id),
- REG_NOTES (insn));
- libcall_id++;
}
}
}
remove_note (insn, note);
if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL)
remove_note (insn, note);
- if ((note = find_reg_note (insn, REG_LIBCALL_ID, NULL)) != NULL)
- remove_note (insn, note);
data.target = target;
data.first = insns;
remove_note (insn, note);
if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL)
remove_note (insn, note);
- if ((note = find_reg_note (insn, REG_LIBCALL_ID, NULL)) != NULL)
- remove_note (insn, note);
next = NEXT_INSN (insn);
if (libfunc && !SCALAR_FLOAT_MODE_P (mode))
{
rtx result;
- rtx ulibfunc;
/* If we want unsigned, and this mode has a distinct unsigned
comparison routine, use that. */
if (unsignedp)
{
- ulibfunc = optab_libfunc (ucmp_optab, mode);
+ rtx ulibfunc = optab_libfunc (ucmp_optab, mode);
+ if (ulibfunc)
+ libfunc = ulibfunc;
}
- if (unsignedp && ulibfunc)
- libfunc = ulibfunc;
result = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST_MAKE_BLOCK,
targetm.libgcc_cmp_return_mode (),
}
/* Unsigned integer, and no way to convert directly. Convert as signed,
- then unconditionally adjust the result. For decimal float values we
- do this only if we have already determined that a signed conversion
- provides sufficient accuracy. */
- if (unsignedp && (can_do_signed || !DECIMAL_FLOAT_MODE_P (GET_MODE (to))))
+ then unconditionally adjust the result. */
+ if (unsignedp && can_do_signed)
{
rtx label = gen_label_rtx ();
rtx temp;
}
}
+/* Generate code to convert FROM or TO a fixed-point.
+ If UINTP is true, either TO or FROM is an unsigned integer.
+ If SATP is true, we need to saturate the result. */
+
+void
+expand_fixed_convert (rtx to, rtx from, int uintp, int satp)
+{
+ enum machine_mode to_mode = GET_MODE (to);
+ enum machine_mode from_mode = GET_MODE (from);
+ convert_optab tab;
+ enum rtx_code this_code;
+ enum insn_code code;
+ rtx insns, value;
+ rtx libfunc;
+
+ if (to_mode == from_mode)
+ {
+ emit_move_insn (to, from);
+ return;
+ }
+
+ if (uintp)
+ {
+ tab = satp ? satfractuns_optab : fractuns_optab;
+ this_code = satp ? UNSIGNED_SAT_FRACT : UNSIGNED_FRACT_CONVERT;
+ }
+ else
+ {
+ tab = satp ? satfract_optab : fract_optab;
+ this_code = satp ? SAT_FRACT : FRACT_CONVERT;
+ }
+ code = tab->handlers[to_mode][from_mode].insn_code;
+ if (code != CODE_FOR_nothing)
+ {
+ emit_unop_insn (code, to, from, this_code);
+ return;
+ }
+
+ libfunc = convert_optab_libfunc (tab, to_mode, from_mode);
+ gcc_assert (libfunc);
+
+ start_sequence ();
+ value = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST, to_mode,
+ 1, from, from_mode);
+ insns = get_insns ();
+ end_sequence ();
+
+ emit_libcall_block (insns, to, value,
+ gen_rtx_fmt_e (tab->code, to_mode, from));
+}
+
/* Generate code to convert FROM to fixed point and store in TO. FROM
must be floating point, TO must be signed. Use the conversion optab
TAB to do the conversion. */
!= CODE_FOR_nothing));
}
-/* Create a blank optab. */
-static optab
-new_optab (void)
-{
- int i;
- optab op = xcalloc (sizeof (struct optab), 1);
+/* Set all insn_code fields to CODE_FOR_nothing. */
- for (i = 0; i < NUM_MACHINE_MODES; i++)
- optab_handler (op, i)->insn_code = CODE_FOR_nothing;
-
- return op;
-}
-
-static convert_optab
-new_convert_optab (void)
+static void
+init_insn_codes (void)
{
- int i, j;
- convert_optab op = xcalloc (sizeof (struct convert_optab), 1);
+ unsigned int i;
- for (i = 0; i < NUM_MACHINE_MODES; i++)
- for (j = 0; j < NUM_MACHINE_MODES; j++)
- convert_optab_handler (op, i, j)->insn_code = CODE_FOR_nothing;
+ for (i = 0; i < (unsigned int) OTI_MAX; i++)
+ {
+ unsigned int j;
+ optab op;
- return op;
+ op = &optab_table[i];
+ for (j = 0; j < NUM_MACHINE_MODES; j++)
+ optab_handler (op, j)->insn_code = CODE_FOR_nothing;
+ }
+ for (i = 0; i < (unsigned int) COI_MAX; i++)
+ {
+ unsigned int j, k;
+ convert_optab op;
+
+ op = &convert_optab_table[i];
+ for (j = 0; j < NUM_MACHINE_MODES; j++)
+ for (k = 0; k < NUM_MACHINE_MODES; k++)
+ convert_optab_handler (op, j, k)->insn_code = CODE_FOR_nothing;
+ }
}
-/* Same, but fill in its code as CODE, and write it into the
- code_to_optab table. */
-static inline optab
-init_optab (enum rtx_code code)
+/* Initialize OP's code to CODE, and write it into the code_to_optab table. */
+static inline void
+init_optab (optab op, enum rtx_code code)
{
- optab op = new_optab ();
op->code = code;
code_to_optab[(int) code] = op;
- return op;
}
/* Same, but fill in its code as CODE, and do _not_ write it into
the code_to_optab table. */
-static inline optab
-init_optabv (enum rtx_code code)
+static inline void
+init_optabv (optab op, enum rtx_code code)
{
- optab op = new_optab ();
op->code = code;
- return op;
}
/* Conversion optabs never go in the code_to_optab table. */
-static inline convert_optab
-init_convert_optab (enum rtx_code code)
+static void
+init_convert_optab (convert_optab op, enum rtx_code code)
{
- convert_optab op = new_convert_optab ();
op->code = code;
- return op;
}
/* Initialize the libfunc fields of an entire group of entries in some
}
}
+/* Like gen_libfunc, but verify that fixed-point operation is involved. */
+
+static void
+gen_fixed_libfunc (optab optable, const char *opname, char suffix,
+ enum machine_mode mode)
+{
+ if (!ALL_FIXED_POINT_MODE_P (mode))
+ return;
+ gen_libfunc (optable, opname, suffix, mode);
+}
+
+/* Like gen_libfunc, but verify that signed fixed-point operation is
+ involved. */
+
+static void
+gen_signed_fixed_libfunc (optab optable, const char *opname, char suffix,
+ enum machine_mode mode)
+{
+ if (!SIGNED_FIXED_POINT_MODE_P (mode))
+ return;
+ gen_libfunc (optable, opname, suffix, mode);
+}
+
+/* Like gen_libfunc, but verify that unsigned fixed-point operation is
+ involved. */
+
+static void
+gen_unsigned_fixed_libfunc (optab optable, const char *opname, char suffix,
+ enum machine_mode mode)
+{
+ if (!UNSIGNED_FIXED_POINT_MODE_P (mode))
+ return;
+ gen_libfunc (optable, opname, suffix, mode);
+}
+
/* Like gen_libfunc, but verify that FP or INT operation is involved. */
static void
}
}
+/* Like gen_libfunc, but verify that FP or INT or FIXED operation is
+ involved. */
+
+static void
+gen_int_fp_fixed_libfunc (optab optable, const char *name, char suffix,
+ enum machine_mode mode)
+{
+ if (DECIMAL_FLOAT_MODE_P (mode) || GET_MODE_CLASS (mode) == MODE_FLOAT)
+ gen_fp_libfunc (optable, name, suffix, mode);
+ if (INTEGRAL_MODE_P (mode))
+ gen_int_libfunc (optable, name, suffix, mode);
+ if (ALL_FIXED_POINT_MODE_P (mode))
+ gen_fixed_libfunc (optable, name, suffix, mode);
+}
+
+/* Like gen_libfunc, but verify that FP or INT or signed FIXED operation is
+ involved. */
+
+static void
+gen_int_fp_signed_fixed_libfunc (optab optable, const char *name, char suffix,
+ enum machine_mode mode)
+{
+ if (DECIMAL_FLOAT_MODE_P (mode) || GET_MODE_CLASS (mode) == MODE_FLOAT)
+ gen_fp_libfunc (optable, name, suffix, mode);
+ if (INTEGRAL_MODE_P (mode))
+ gen_int_libfunc (optable, name, suffix, mode);
+ if (SIGNED_FIXED_POINT_MODE_P (mode))
+ gen_signed_fixed_libfunc (optable, name, suffix, mode);
+}
+
+/* Like gen_libfunc, but verify that INT or FIXED operation is
+ involved. */
+
+static void
+gen_int_fixed_libfunc (optab optable, const char *name, char suffix,
+ enum machine_mode mode)
+{
+ if (INTEGRAL_MODE_P (mode))
+ gen_int_libfunc (optable, name, suffix, mode);
+ if (ALL_FIXED_POINT_MODE_P (mode))
+ gen_fixed_libfunc (optable, name, suffix, mode);
+}
+
+/* Like gen_libfunc, but verify that INT or signed FIXED operation is
+ involved. */
+
+static void
+gen_int_signed_fixed_libfunc (optab optable, const char *name, char suffix,
+ enum machine_mode mode)
+{
+ if (INTEGRAL_MODE_P (mode))
+ gen_int_libfunc (optable, name, suffix, mode);
+ if (SIGNED_FIXED_POINT_MODE_P (mode))
+ gen_signed_fixed_libfunc (optable, name, suffix, mode);
+}
+
+/* Like gen_libfunc, but verify that INT or unsigned FIXED operation is
+ involved. */
+
+static void
+gen_int_unsigned_fixed_libfunc (optab optable, const char *name, char suffix,
+ enum machine_mode mode)
+{
+ if (INTEGRAL_MODE_P (mode))
+ gen_int_libfunc (optable, name, suffix, mode);
+ if (UNSIGNED_FIXED_POINT_MODE_P (mode))
+ gen_unsigned_fixed_libfunc (optable, name, suffix, mode);
+}
+
/* Initialize the libfunc fields of an entire group of entries of an
inter-mode-class conversion optab. The string formation rules are
similar to the ones for init_libfuncs, above, but instead of having
gen_intraclass_conv_libfunc (tab, opname, tmode, fmode);
}
+/* Pick proper libcall for fract_optab. We need to chose if we do
+ interclass or intraclass. */
+
+static void
+gen_fract_conv_libfunc (convert_optab tab,
+ const char *opname,
+ enum machine_mode tmode,
+ enum machine_mode fmode)
+{
+ if (tmode == fmode)
+ return;
+ if (!(ALL_FIXED_POINT_MODE_P (tmode) || ALL_FIXED_POINT_MODE_P (fmode)))
+ return;
+
+ if (GET_MODE_CLASS (tmode) == GET_MODE_CLASS (fmode))
+ gen_intraclass_conv_libfunc (tab, opname, tmode, fmode);
+ else
+ gen_interclass_conv_libfunc (tab, opname, tmode, fmode);
+}
+
+/* Pick proper libcall for fractuns_optab. */
+
+static void
+gen_fractuns_conv_libfunc (convert_optab tab,
+ const char *opname,
+ enum machine_mode tmode,
+ enum machine_mode fmode)
+{
+ if (tmode == fmode)
+ return;
+ /* One mode must be a fixed-point mode, and the other must be an integer
+ mode. */
+ if (!((ALL_FIXED_POINT_MODE_P (tmode) && GET_MODE_CLASS (fmode) == MODE_INT)
+ || (ALL_FIXED_POINT_MODE_P (fmode)
+ && GET_MODE_CLASS (tmode) == MODE_INT)))
+ return;
+
+ gen_interclass_conv_libfunc (tab, opname, tmode, fmode);
+}
+
+/* Pick proper libcall for satfract_optab. We need to chose if we do
+ interclass or intraclass. */
+
+static void
+gen_satfract_conv_libfunc (convert_optab tab,
+ const char *opname,
+ enum machine_mode tmode,
+ enum machine_mode fmode)
+{
+ if (tmode == fmode)
+ return;
+ /* TMODE must be a fixed-point mode. */
+ if (!ALL_FIXED_POINT_MODE_P (tmode))
+ return;
+
+ if (GET_MODE_CLASS (tmode) == GET_MODE_CLASS (fmode))
+ gen_intraclass_conv_libfunc (tab, opname, tmode, fmode);
+ else
+ gen_interclass_conv_libfunc (tab, opname, tmode, fmode);
+}
+
+/* Pick proper libcall for satfractuns_optab. */
+
+static void
+gen_satfractuns_conv_libfunc (convert_optab tab,
+ const char *opname,
+ enum machine_mode tmode,
+ enum machine_mode fmode)
+{
+ if (tmode == fmode)
+ return;
+ /* TMODE must be a fixed-point mode, and FMODE must be an integer mode. */
+ if (!(ALL_FIXED_POINT_MODE_P (tmode) && GET_MODE_CLASS (fmode) == MODE_INT))
+ return;
+
+ gen_interclass_conv_libfunc (tab, opname, tmode, fmode);
+}
+
rtx
init_one_libfunc (const char *name)
{
rtx val;
struct libfunc_entry e;
struct libfunc_entry **slot;
- e.optab = (size_t) (optab_table[0] - optable);
+ e.optab = (size_t) (optable - &optab_table[0]);
e.mode1 = mode;
e.mode2 = VOIDmode;
slot = (struct libfunc_entry **) htab_find_slot (libfunc_hash, &e, INSERT);
if (*slot == NULL)
*slot = ggc_alloc (sizeof (struct libfunc_entry));
- (*slot)->optab = (size_t) (optab_table[0] - optable);
+ (*slot)->optab = (size_t) (optable - &optab_table[0]);
(*slot)->mode1 = mode;
(*slot)->mode2 = VOIDmode;
(*slot)->libfunc = val;
rtx val;
struct libfunc_entry e;
struct libfunc_entry **slot;
- e.optab = (size_t) (convert_optab_table[0] - optable);
+ e.optab = (size_t) (optable - &convert_optab_table[0]);
e.mode1 = tmode;
e.mode2 = fmode;
slot = (struct libfunc_entry **) htab_find_slot (libfunc_hash, &e, INSERT);
if (*slot == NULL)
*slot = ggc_alloc (sizeof (struct libfunc_entry));
- (*slot)->optab = (size_t) (convert_optab_table[0] - optable);
+ (*slot)->optab = (size_t) (optable - &convert_optab_table[0]);
(*slot)->mode1 = tmode;
(*slot)->mode2 = fmode;
(*slot)->libfunc = val;
{
unsigned int i;
enum machine_mode int_mode;
+ static bool reinit;
libfunc_hash = htab_create_ggc (10, hash_libfunc, eq_libfunc, NULL);
/* Start by initializing all tables to contain CODE_FOR_nothing. */
vcondu_gen_code[i] = CODE_FOR_nothing;
}
- add_optab = init_optab (PLUS);
- addv_optab = init_optabv (PLUS);
- sub_optab = init_optab (MINUS);
- subv_optab = init_optabv (MINUS);
- smul_optab = init_optab (MULT);
- smulv_optab = init_optabv (MULT);
- smul_highpart_optab = init_optab (UNKNOWN);
- umul_highpart_optab = init_optab (UNKNOWN);
- smul_widen_optab = init_optab (UNKNOWN);
- umul_widen_optab = init_optab (UNKNOWN);
- usmul_widen_optab = init_optab (UNKNOWN);
- smadd_widen_optab = init_optab (UNKNOWN);
- umadd_widen_optab = init_optab (UNKNOWN);
- smsub_widen_optab = init_optab (UNKNOWN);
- umsub_widen_optab = init_optab (UNKNOWN);
- sdiv_optab = init_optab (DIV);
- sdivv_optab = init_optabv (DIV);
- sdivmod_optab = init_optab (UNKNOWN);
- udiv_optab = init_optab (UDIV);
- udivmod_optab = init_optab (UNKNOWN);
- smod_optab = init_optab (MOD);
- umod_optab = init_optab (UMOD);
- fmod_optab = init_optab (UNKNOWN);
- remainder_optab = init_optab (UNKNOWN);
- ftrunc_optab = init_optab (UNKNOWN);
- and_optab = init_optab (AND);
- ior_optab = init_optab (IOR);
- xor_optab = init_optab (XOR);
- ashl_optab = init_optab (ASHIFT);
- ashr_optab = init_optab (ASHIFTRT);
- lshr_optab = init_optab (LSHIFTRT);
- rotl_optab = init_optab (ROTATE);
- rotr_optab = init_optab (ROTATERT);
- smin_optab = init_optab (SMIN);
- smax_optab = init_optab (SMAX);
- umin_optab = init_optab (UMIN);
- umax_optab = init_optab (UMAX);
- pow_optab = init_optab (UNKNOWN);
- atan2_optab = init_optab (UNKNOWN);
+#if GCC_VERSION >= 4000
+ /* We statically initialize the insn_codes with CODE_FOR_nothing. */
+ if (reinit)
+ init_insn_codes ();
+#else
+ init_insn_codes ();
+#endif
+
+ init_optab (add_optab, PLUS);
+ init_optabv (addv_optab, PLUS);
+ init_optab (sub_optab, MINUS);
+ init_optabv (subv_optab, MINUS);
+ init_optab (ssadd_optab, SS_PLUS);
+ init_optab (usadd_optab, US_PLUS);
+ init_optab (sssub_optab, SS_MINUS);
+ init_optab (ussub_optab, US_MINUS);
+ init_optab (smul_optab, MULT);
+ init_optab (ssmul_optab, SS_MULT);
+ init_optab (usmul_optab, US_MULT);
+ init_optabv (smulv_optab, MULT);
+ init_optab (smul_highpart_optab, UNKNOWN);
+ init_optab (umul_highpart_optab, UNKNOWN);
+ init_optab (smul_widen_optab, UNKNOWN);
+ init_optab (umul_widen_optab, UNKNOWN);
+ init_optab (usmul_widen_optab, UNKNOWN);
+ init_optab (smadd_widen_optab, UNKNOWN);
+ init_optab (umadd_widen_optab, UNKNOWN);
+ init_optab (ssmadd_widen_optab, UNKNOWN);
+ init_optab (usmadd_widen_optab, UNKNOWN);
+ init_optab (smsub_widen_optab, UNKNOWN);
+ init_optab (umsub_widen_optab, UNKNOWN);
+ init_optab (ssmsub_widen_optab, UNKNOWN);
+ init_optab (usmsub_widen_optab, UNKNOWN);
+ init_optab (sdiv_optab, DIV);
+ init_optab (ssdiv_optab, SS_DIV);
+ init_optab (usdiv_optab, US_DIV);
+ init_optabv (sdivv_optab, DIV);
+ init_optab (sdivmod_optab, UNKNOWN);
+ init_optab (udiv_optab, UDIV);
+ init_optab (udivmod_optab, UNKNOWN);
+ init_optab (smod_optab, MOD);
+ init_optab (umod_optab, UMOD);
+ init_optab (fmod_optab, UNKNOWN);
+ init_optab (remainder_optab, UNKNOWN);
+ init_optab (ftrunc_optab, UNKNOWN);
+ init_optab (and_optab, AND);
+ init_optab (ior_optab, IOR);
+ init_optab (xor_optab, XOR);
+ init_optab (ashl_optab, ASHIFT);
+ init_optab (ssashl_optab, SS_ASHIFT);
+ init_optab (usashl_optab, US_ASHIFT);
+ init_optab (ashr_optab, ASHIFTRT);
+ init_optab (lshr_optab, LSHIFTRT);
+ init_optab (rotl_optab, ROTATE);
+ init_optab (rotr_optab, ROTATERT);
+ init_optab (smin_optab, SMIN);
+ init_optab (smax_optab, SMAX);
+ init_optab (umin_optab, UMIN);
+ init_optab (umax_optab, UMAX);
+ init_optab (pow_optab, UNKNOWN);
+ init_optab (atan2_optab, UNKNOWN);
/* These three have codes assigned exclusively for the sake of
have_insn_for. */
- mov_optab = init_optab (SET);
- movstrict_optab = init_optab (STRICT_LOW_PART);
- cmp_optab = init_optab (COMPARE);
-
- storent_optab = init_optab (UNKNOWN);
-
- ucmp_optab = init_optab (UNKNOWN);
- tst_optab = init_optab (UNKNOWN);
-
- eq_optab = init_optab (EQ);
- ne_optab = init_optab (NE);
- gt_optab = init_optab (GT);
- ge_optab = init_optab (GE);
- lt_optab = init_optab (LT);
- le_optab = init_optab (LE);
- unord_optab = init_optab (UNORDERED);
-
- neg_optab = init_optab (NEG);
- negv_optab = init_optabv (NEG);
- abs_optab = init_optab (ABS);
- absv_optab = init_optabv (ABS);
- addcc_optab = init_optab (UNKNOWN);
- one_cmpl_optab = init_optab (NOT);
- bswap_optab = init_optab (BSWAP);
- ffs_optab = init_optab (FFS);
- clz_optab = init_optab (CLZ);
- ctz_optab = init_optab (CTZ);
- popcount_optab = init_optab (POPCOUNT);
- parity_optab = init_optab (PARITY);
- sqrt_optab = init_optab (SQRT);
- floor_optab = init_optab (UNKNOWN);
- ceil_optab = init_optab (UNKNOWN);
- round_optab = init_optab (UNKNOWN);
- btrunc_optab = init_optab (UNKNOWN);
- nearbyint_optab = init_optab (UNKNOWN);
- rint_optab = init_optab (UNKNOWN);
- sincos_optab = init_optab (UNKNOWN);
- sin_optab = init_optab (UNKNOWN);
- asin_optab = init_optab (UNKNOWN);
- cos_optab = init_optab (UNKNOWN);
- acos_optab = init_optab (UNKNOWN);
- exp_optab = init_optab (UNKNOWN);
- exp10_optab = init_optab (UNKNOWN);
- exp2_optab = init_optab (UNKNOWN);
- expm1_optab = init_optab (UNKNOWN);
- ldexp_optab = init_optab (UNKNOWN);
- scalb_optab = init_optab (UNKNOWN);
- logb_optab = init_optab (UNKNOWN);
- ilogb_optab = init_optab (UNKNOWN);
- log_optab = init_optab (UNKNOWN);
- log10_optab = init_optab (UNKNOWN);
- log2_optab = init_optab (UNKNOWN);
- log1p_optab = init_optab (UNKNOWN);
- tan_optab = init_optab (UNKNOWN);
- atan_optab = init_optab (UNKNOWN);
- copysign_optab = init_optab (UNKNOWN);
- signbit_optab = init_optab (UNKNOWN);
-
- isinf_optab = init_optab (UNKNOWN);
-
- strlen_optab = init_optab (UNKNOWN);
- cbranch_optab = init_optab (UNKNOWN);
- cmov_optab = init_optab (UNKNOWN);
- cstore_optab = init_optab (UNKNOWN);
- push_optab = init_optab (UNKNOWN);
-
- reduc_smax_optab = init_optab (UNKNOWN);
- reduc_umax_optab = init_optab (UNKNOWN);
- reduc_smin_optab = init_optab (UNKNOWN);
- reduc_umin_optab = init_optab (UNKNOWN);
- reduc_splus_optab = init_optab (UNKNOWN);
- reduc_uplus_optab = init_optab (UNKNOWN);
-
- ssum_widen_optab = init_optab (UNKNOWN);
- usum_widen_optab = init_optab (UNKNOWN);
- sdot_prod_optab = init_optab (UNKNOWN);
- udot_prod_optab = init_optab (UNKNOWN);
-
- vec_extract_optab = init_optab (UNKNOWN);
- vec_extract_even_optab = init_optab (UNKNOWN);
- vec_extract_odd_optab = init_optab (UNKNOWN);
- vec_interleave_high_optab = init_optab (UNKNOWN);
- vec_interleave_low_optab = init_optab (UNKNOWN);
- vec_set_optab = init_optab (UNKNOWN);
- vec_init_optab = init_optab (UNKNOWN);
- vec_shl_optab = init_optab (UNKNOWN);
- vec_shr_optab = init_optab (UNKNOWN);
- vec_realign_load_optab = init_optab (UNKNOWN);
- movmisalign_optab = init_optab (UNKNOWN);
- vec_widen_umult_hi_optab = init_optab (UNKNOWN);
- vec_widen_umult_lo_optab = init_optab (UNKNOWN);
- vec_widen_smult_hi_optab = init_optab (UNKNOWN);
- vec_widen_smult_lo_optab = init_optab (UNKNOWN);
- vec_unpacks_hi_optab = init_optab (UNKNOWN);
- vec_unpacks_lo_optab = init_optab (UNKNOWN);
- vec_unpacku_hi_optab = init_optab (UNKNOWN);
- vec_unpacku_lo_optab = init_optab (UNKNOWN);
- vec_unpacks_float_hi_optab = init_optab (UNKNOWN);
- vec_unpacks_float_lo_optab = init_optab (UNKNOWN);
- vec_unpacku_float_hi_optab = init_optab (UNKNOWN);
- vec_unpacku_float_lo_optab = init_optab (UNKNOWN);
- vec_pack_trunc_optab = init_optab (UNKNOWN);
- vec_pack_usat_optab = init_optab (UNKNOWN);
- vec_pack_ssat_optab = init_optab (UNKNOWN);
- vec_pack_ufix_trunc_optab = init_optab (UNKNOWN);
- vec_pack_sfix_trunc_optab = init_optab (UNKNOWN);
-
- powi_optab = init_optab (UNKNOWN);
+ init_optab (mov_optab, SET);
+ init_optab (movstrict_optab, STRICT_LOW_PART);
+ init_optab (cmp_optab, COMPARE);
+
+ init_optab (storent_optab, UNKNOWN);
+
+ init_optab (ucmp_optab, UNKNOWN);
+ init_optab (tst_optab, UNKNOWN);
+
+ init_optab (eq_optab, EQ);
+ init_optab (ne_optab, NE);
+ init_optab (gt_optab, GT);
+ init_optab (ge_optab, GE);
+ init_optab (lt_optab, LT);
+ init_optab (le_optab, LE);
+ init_optab (unord_optab, UNORDERED);
+
+ init_optab (neg_optab, NEG);
+ init_optab (ssneg_optab, SS_NEG);
+ init_optab (usneg_optab, US_NEG);
+ init_optabv (negv_optab, NEG);
+ init_optab (abs_optab, ABS);
+ init_optabv (absv_optab, ABS);
+ init_optab (addcc_optab, UNKNOWN);
+ init_optab (one_cmpl_optab, NOT);
+ init_optab (bswap_optab, BSWAP);
+ init_optab (ffs_optab, FFS);
+ init_optab (clz_optab, CLZ);
+ init_optab (ctz_optab, CTZ);
+ init_optab (popcount_optab, POPCOUNT);
+ init_optab (parity_optab, PARITY);
+ init_optab (sqrt_optab, SQRT);
+ init_optab (floor_optab, UNKNOWN);
+ init_optab (ceil_optab, UNKNOWN);
+ init_optab (round_optab, UNKNOWN);
+ init_optab (btrunc_optab, UNKNOWN);
+ init_optab (nearbyint_optab, UNKNOWN);
+ init_optab (rint_optab, UNKNOWN);
+ init_optab (sincos_optab, UNKNOWN);
+ init_optab (sin_optab, UNKNOWN);
+ init_optab (asin_optab, UNKNOWN);
+ init_optab (cos_optab, UNKNOWN);
+ init_optab (acos_optab, UNKNOWN);
+ init_optab (exp_optab, UNKNOWN);
+ init_optab (exp10_optab, UNKNOWN);
+ init_optab (exp2_optab, UNKNOWN);
+ init_optab (expm1_optab, UNKNOWN);
+ init_optab (ldexp_optab, UNKNOWN);
+ init_optab (scalb_optab, UNKNOWN);
+ init_optab (logb_optab, UNKNOWN);
+ init_optab (ilogb_optab, UNKNOWN);
+ init_optab (log_optab, UNKNOWN);
+ init_optab (log10_optab, UNKNOWN);
+ init_optab (log2_optab, UNKNOWN);
+ init_optab (log1p_optab, UNKNOWN);
+ init_optab (tan_optab, UNKNOWN);
+ init_optab (atan_optab, UNKNOWN);
+ init_optab (copysign_optab, UNKNOWN);
+ init_optab (signbit_optab, UNKNOWN);
+
+ init_optab (isinf_optab, UNKNOWN);
+
+ init_optab (strlen_optab, UNKNOWN);
+ init_optab (cbranch_optab, UNKNOWN);
+ init_optab (cmov_optab, UNKNOWN);
+ init_optab (cstore_optab, UNKNOWN);
+ init_optab (push_optab, UNKNOWN);
+
+ init_optab (reduc_smax_optab, UNKNOWN);
+ init_optab (reduc_umax_optab, UNKNOWN);
+ init_optab (reduc_smin_optab, UNKNOWN);
+ init_optab (reduc_umin_optab, UNKNOWN);
+ init_optab (reduc_splus_optab, UNKNOWN);
+ init_optab (reduc_uplus_optab, UNKNOWN);
+
+ init_optab (ssum_widen_optab, UNKNOWN);
+ init_optab (usum_widen_optab, UNKNOWN);
+ init_optab (sdot_prod_optab, UNKNOWN);
+ init_optab (udot_prod_optab, UNKNOWN);
+
+ init_optab (vec_extract_optab, UNKNOWN);
+ init_optab (vec_extract_even_optab, UNKNOWN);
+ init_optab (vec_extract_odd_optab, UNKNOWN);
+ init_optab (vec_interleave_high_optab, UNKNOWN);
+ init_optab (vec_interleave_low_optab, UNKNOWN);
+ init_optab (vec_set_optab, UNKNOWN);
+ init_optab (vec_init_optab, UNKNOWN);
+ init_optab (vec_shl_optab, UNKNOWN);
+ init_optab (vec_shr_optab, UNKNOWN);
+ init_optab (vec_realign_load_optab, UNKNOWN);
+ init_optab (movmisalign_optab, UNKNOWN);
+ init_optab (vec_widen_umult_hi_optab, UNKNOWN);
+ init_optab (vec_widen_umult_lo_optab, UNKNOWN);
+ init_optab (vec_widen_smult_hi_optab, UNKNOWN);
+ init_optab (vec_widen_smult_lo_optab, UNKNOWN);
+ init_optab (vec_unpacks_hi_optab, UNKNOWN);
+ init_optab (vec_unpacks_lo_optab, UNKNOWN);
+ init_optab (vec_unpacku_hi_optab, UNKNOWN);
+ init_optab (vec_unpacku_lo_optab, UNKNOWN);
+ init_optab (vec_unpacks_float_hi_optab, UNKNOWN);
+ init_optab (vec_unpacks_float_lo_optab, UNKNOWN);
+ init_optab (vec_unpacku_float_hi_optab, UNKNOWN);
+ init_optab (vec_unpacku_float_lo_optab, UNKNOWN);
+ init_optab (vec_pack_trunc_optab, UNKNOWN);
+ init_optab (vec_pack_usat_optab, UNKNOWN);
+ init_optab (vec_pack_ssat_optab, UNKNOWN);
+ init_optab (vec_pack_ufix_trunc_optab, UNKNOWN);
+ init_optab (vec_pack_sfix_trunc_optab, UNKNOWN);
+
+ init_optab (powi_optab, UNKNOWN);
/* Conversions. */
- sext_optab = init_convert_optab (SIGN_EXTEND);
- zext_optab = init_convert_optab (ZERO_EXTEND);
- trunc_optab = init_convert_optab (TRUNCATE);
- sfix_optab = init_convert_optab (FIX);
- ufix_optab = init_convert_optab (UNSIGNED_FIX);
- sfixtrunc_optab = init_convert_optab (UNKNOWN);
- ufixtrunc_optab = init_convert_optab (UNKNOWN);
- sfloat_optab = init_convert_optab (FLOAT);
- ufloat_optab = init_convert_optab (UNSIGNED_FLOAT);
- lrint_optab = init_convert_optab (UNKNOWN);
- lround_optab = init_convert_optab (UNKNOWN);
- lfloor_optab = init_convert_optab (UNKNOWN);
- lceil_optab = init_convert_optab (UNKNOWN);
+ init_convert_optab (sext_optab, SIGN_EXTEND);
+ init_convert_optab (zext_optab, ZERO_EXTEND);
+ init_convert_optab (trunc_optab, TRUNCATE);
+ init_convert_optab (sfix_optab, FIX);
+ init_convert_optab (ufix_optab, UNSIGNED_FIX);
+ init_convert_optab (sfixtrunc_optab, UNKNOWN);
+ init_convert_optab (ufixtrunc_optab, UNKNOWN);
+ init_convert_optab (sfloat_optab, FLOAT);
+ init_convert_optab (ufloat_optab, UNSIGNED_FLOAT);
+ init_convert_optab (lrint_optab, UNKNOWN);
+ init_convert_optab (lround_optab, UNKNOWN);
+ init_convert_optab (lfloor_optab, UNKNOWN);
+ init_convert_optab (lceil_optab, UNKNOWN);
+
+ init_convert_optab (fract_optab, FRACT_CONVERT);
+ init_convert_optab (fractuns_optab, UNSIGNED_FRACT_CONVERT);
+ init_convert_optab (satfract_optab, SAT_FRACT);
+ init_convert_optab (satfractuns_optab, UNSIGNED_SAT_FRACT);
for (i = 0; i < NUM_MACHINE_MODES; i++)
{
/* Initialize the optabs with the names of the library functions. */
add_optab->libcall_basename = "add";
add_optab->libcall_suffix = '3';
- add_optab->libcall_gen = gen_int_fp_libfunc;
+ add_optab->libcall_gen = gen_int_fp_fixed_libfunc;
addv_optab->libcall_basename = "add";
addv_optab->libcall_suffix = '3';
addv_optab->libcall_gen = gen_intv_fp_libfunc;
+ ssadd_optab->libcall_basename = "ssadd";
+ ssadd_optab->libcall_suffix = '3';
+ ssadd_optab->libcall_gen = gen_signed_fixed_libfunc;
+ usadd_optab->libcall_basename = "usadd";
+ usadd_optab->libcall_suffix = '3';
+ usadd_optab->libcall_gen = gen_unsigned_fixed_libfunc;
sub_optab->libcall_basename = "sub";
sub_optab->libcall_suffix = '3';
- sub_optab->libcall_gen = gen_int_fp_libfunc;
+ sub_optab->libcall_gen = gen_int_fp_fixed_libfunc;
subv_optab->libcall_basename = "sub";
subv_optab->libcall_suffix = '3';
subv_optab->libcall_gen = gen_intv_fp_libfunc;
+ sssub_optab->libcall_basename = "sssub";
+ sssub_optab->libcall_suffix = '3';
+ sssub_optab->libcall_gen = gen_signed_fixed_libfunc;
+ ussub_optab->libcall_basename = "ussub";
+ ussub_optab->libcall_suffix = '3';
+ ussub_optab->libcall_gen = gen_unsigned_fixed_libfunc;
smul_optab->libcall_basename = "mul";
smul_optab->libcall_suffix = '3';
- smul_optab->libcall_gen = gen_int_fp_libfunc;
+ smul_optab->libcall_gen = gen_int_fp_fixed_libfunc;
smulv_optab->libcall_basename = "mul";
smulv_optab->libcall_suffix = '3';
smulv_optab->libcall_gen = gen_intv_fp_libfunc;
+ ssmul_optab->libcall_basename = "ssmul";
+ ssmul_optab->libcall_suffix = '3';
+ ssmul_optab->libcall_gen = gen_signed_fixed_libfunc;
+ usmul_optab->libcall_basename = "usmul";
+ usmul_optab->libcall_suffix = '3';
+ usmul_optab->libcall_gen = gen_unsigned_fixed_libfunc;
sdiv_optab->libcall_basename = "div";
sdiv_optab->libcall_suffix = '3';
- sdiv_optab->libcall_gen = gen_int_fp_libfunc;
+ sdiv_optab->libcall_gen = gen_int_fp_signed_fixed_libfunc;
sdivv_optab->libcall_basename = "divv";
sdivv_optab->libcall_suffix = '3';
sdivv_optab->libcall_gen = gen_int_libfunc;
+ ssdiv_optab->libcall_basename = "ssdiv";
+ ssdiv_optab->libcall_suffix = '3';
+ ssdiv_optab->libcall_gen = gen_signed_fixed_libfunc;
udiv_optab->libcall_basename = "udiv";
udiv_optab->libcall_suffix = '3';
- udiv_optab->libcall_gen = gen_int_libfunc;
+ udiv_optab->libcall_gen = gen_int_unsigned_fixed_libfunc;
+ usdiv_optab->libcall_basename = "usdiv";
+ usdiv_optab->libcall_suffix = '3';
+ usdiv_optab->libcall_gen = gen_unsigned_fixed_libfunc;
sdivmod_optab->libcall_basename = "divmod";
sdivmod_optab->libcall_suffix = '4';
sdivmod_optab->libcall_gen = gen_int_libfunc;
xor_optab->libcall_gen = gen_int_libfunc;
ashl_optab->libcall_basename = "ashl";
ashl_optab->libcall_suffix = '3';
- ashl_optab->libcall_gen = gen_int_libfunc;
+ ashl_optab->libcall_gen = gen_int_fixed_libfunc;
+ ssashl_optab->libcall_basename = "ssashl";
+ ssashl_optab->libcall_suffix = '3';
+ ssashl_optab->libcall_gen = gen_signed_fixed_libfunc;
+ usashl_optab->libcall_basename = "usashl";
+ usashl_optab->libcall_suffix = '3';
+ usashl_optab->libcall_gen = gen_unsigned_fixed_libfunc;
ashr_optab->libcall_basename = "ashr";
ashr_optab->libcall_suffix = '3';
- ashr_optab->libcall_gen = gen_int_libfunc;
+ ashr_optab->libcall_gen = gen_int_signed_fixed_libfunc;
lshr_optab->libcall_basename = "lshr";
lshr_optab->libcall_suffix = '3';
- lshr_optab->libcall_gen = gen_int_libfunc;
+ lshr_optab->libcall_gen = gen_int_unsigned_fixed_libfunc;
smin_optab->libcall_basename = "min";
smin_optab->libcall_suffix = '3';
smin_optab->libcall_gen = gen_int_fp_libfunc;
umax_optab->libcall_gen = gen_int_libfunc;
neg_optab->libcall_basename = "neg";
neg_optab->libcall_suffix = '2';
- neg_optab->libcall_gen = gen_int_fp_libfunc;
+ neg_optab->libcall_gen = gen_int_fp_fixed_libfunc;
+ ssneg_optab->libcall_basename = "ssneg";
+ ssneg_optab->libcall_suffix = '2';
+ ssneg_optab->libcall_gen = gen_signed_fixed_libfunc;
+ usneg_optab->libcall_basename = "usneg";
+ usneg_optab->libcall_suffix = '2';
+ usneg_optab->libcall_gen = gen_unsigned_fixed_libfunc;
negv_optab->libcall_basename = "neg";
negv_optab->libcall_suffix = '2';
negv_optab->libcall_gen = gen_intv_fp_libfunc;
signed/unsigned. */
cmp_optab->libcall_basename = "cmp";
cmp_optab->libcall_suffix = '2';
- cmp_optab->libcall_gen = gen_int_fp_libfunc;
+ cmp_optab->libcall_gen = gen_int_fp_fixed_libfunc;
ucmp_optab->libcall_basename = "ucmp";
ucmp_optab->libcall_suffix = '2';
ucmp_optab->libcall_gen = gen_int_libfunc;
trunc_optab->libcall_basename = "trunc";
trunc_optab->libcall_gen = gen_trunc_conv_libfunc;
+ /* Conversions for fixed-point modes and other modes. */
+ fract_optab->libcall_basename = "fract";
+ fract_optab->libcall_gen = gen_fract_conv_libfunc;
+ satfract_optab->libcall_basename = "satfract";
+ satfract_optab->libcall_gen = gen_satfract_conv_libfunc;
+ fractuns_optab->libcall_basename = "fractuns";
+ fractuns_optab->libcall_gen = gen_fractuns_conv_libfunc;
+ satfractuns_optab->libcall_basename = "satfractuns";
+ satfractuns_optab->libcall_gen = gen_satfractuns_conv_libfunc;
+
/* The ffs function operates on `int'. Fall back on it if we do not
have a libgcc2 function for that width. */
if (INT_TYPE_SIZE < BITS_PER_WORD)
/* Allow the target to add more libcalls or rename some, etc. */
targetm.init_libfuncs ();
+
+ reinit = true;
}
/* Print information about the current contents of the optabs on
optab o;
rtx l;
- o = optab_table[i];
- l = optab_libfunc (optab_table[i], j);
+ o = &optab_table[i];
+ l = optab_libfunc (o, j);
if (l)
{
gcc_assert (GET_CODE (l) == SYMBOL_REF);
convert_optab o;
rtx l;
- o = convert_optab_table[i];
+ o = &convert_optab_table[i];
l = convert_optab_libfunc (o, j, k);
if (l)
{
case MINUS:
icode = sync_sub_optab[mode];
- if (icode == CODE_FOR_nothing)
+ if (icode == CODE_FOR_nothing || CONST_INT_P (val))
{
icode = sync_add_optab[mode];
if (icode != CODE_FOR_nothing)
case MINUS:
old_code = sync_old_sub_optab[mode];
new_code = sync_new_sub_optab[mode];
- if (old_code == CODE_FOR_nothing && new_code == CODE_FOR_nothing)
+ if ((old_code == CODE_FOR_nothing && new_code == CODE_FOR_nothing)
+ || CONST_INT_P (val))
{
old_code = sync_old_add_optab[mode];
new_code = sync_new_add_optab[mode];