+ if (imode != GET_MODE (to))
+ target = gen_reg_rtx (imode);
+
+ if (!maybe_emit_unop_insn (icode, target, from, UNKNOWN))
+ {
+ delete_insns_since (last);
+ continue;
+ }
+ if (target != to)
+ convert_move (to, target, 0);
+ return true;
+ }
+ }
+
+ return false;
+}
+\f
+/* Report whether we have an instruction to perform the operation
+ specified by CODE on operands of mode MODE. */
+int
+have_insn_for (enum rtx_code code, enum machine_mode mode)
+{
+ return (code_to_optab[(int) code] != 0
+ && (optab_handler (code_to_optab[(int) code], mode)->insn_code
+ != CODE_FOR_nothing));
+}
+
+/* Set all insn_code fields to CODE_FOR_nothing. */
+
+static void
+init_insn_codes (void)
+{
+ unsigned int i;
+
+ for (i = 0; i < (unsigned int) OTI_MAX; i++)
+ {
+ unsigned int j;
+ optab 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;
+ }
+}
+
+/* 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)
+{
+ op->code = code;
+ code_to_optab[(int) code] = op;
+}
+
+/* Same, but fill in its code as CODE, and do _not_ write it into
+ the code_to_optab table. */
+static inline void
+init_optabv (optab op, enum rtx_code code)
+{
+ op->code = code;
+}
+
+/* Conversion optabs never go in the code_to_optab table. */
+static void
+init_convert_optab (convert_optab op, enum rtx_code code)
+{
+ op->code = code;
+}
+
+/* Initialize the libfunc fields of an entire group of entries in some
+ optab. Each entry is set equal to a string consisting of a leading
+ pair of underscores followed by a generic operation name followed by
+ a mode name (downshifted to lowercase) followed by a single character
+ representing the number of operands for the given operation (which is
+ usually one of the characters '2', '3', or '4').
+
+ OPTABLE is the table in which libfunc fields are to be initialized.
+ OPNAME is the generic (string) name of the operation.
+ SUFFIX is the character which specifies the number of operands for
+ the given generic operation.
+ MODE is the mode to generate for.
+*/
+
+static void
+gen_libfunc (optab optable, const char *opname, int suffix, enum machine_mode mode)
+{
+ unsigned opname_len = strlen (opname);
+ const char *mname = GET_MODE_NAME (mode);
+ unsigned mname_len = strlen (mname);
+ char *libfunc_name = XALLOCAVEC (char, 2 + opname_len + mname_len + 1 + 1);
+ char *p;
+ const char *q;
+
+ p = libfunc_name;
+ *p++ = '_';
+ *p++ = '_';
+ for (q = opname; *q; )
+ *p++ = *q++;
+ for (q = mname; *q; q++)
+ *p++ = TOLOWER (*q);
+ *p++ = suffix;
+ *p = '\0';
+
+ set_optab_libfunc (optable, mode,
+ ggc_alloc_string (libfunc_name, p - libfunc_name));
+}
+
+/* Like gen_libfunc, but verify that integer operation is involved. */
+
+static void
+gen_int_libfunc (optab optable, const char *opname, char suffix,
+ enum machine_mode mode)
+{
+ int maxsize = 2 * BITS_PER_WORD;
+
+ if (GET_MODE_CLASS (mode) != MODE_INT)
+ return;
+ if (maxsize < LONG_LONG_TYPE_SIZE)
+ maxsize = LONG_LONG_TYPE_SIZE;
+ if (GET_MODE_CLASS (mode) != MODE_INT
+ || mode < word_mode || GET_MODE_BITSIZE (mode) > maxsize)
+ return;
+ gen_libfunc (optable, opname, suffix, mode);
+}
+
+/* Like gen_libfunc, but verify that FP and set decimal prefix if needed. */
+
+static void
+gen_fp_libfunc (optab optable, const char *opname, char suffix,
+ enum machine_mode mode)
+{
+ char *dec_opname;
+
+ if (GET_MODE_CLASS (mode) == MODE_FLOAT)
+ gen_libfunc (optable, opname, suffix, mode);
+ if (DECIMAL_FLOAT_MODE_P (mode))
+ {
+ dec_opname = XALLOCAVEC (char, sizeof (DECIMAL_PREFIX) + strlen (opname));
+ /* For BID support, change the name to have either a bid_ or dpd_ prefix
+ depending on the low level floating format used. */
+ memcpy (dec_opname, DECIMAL_PREFIX, sizeof (DECIMAL_PREFIX) - 1);
+ strcpy (dec_opname + sizeof (DECIMAL_PREFIX) - 1, opname);
+ gen_libfunc (optable, dec_opname, suffix, mode);
+ }
+}
+
+/* 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
+gen_int_fp_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);
+}
+
+/* Like gen_libfunc, but verify that FP or INT operation is involved
+ and add 'v' suffix for integer operation. */
+
+static void
+gen_intv_fp_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 (GET_MODE_CLASS (mode) == MODE_INT)
+ {
+ int len = strlen (name);
+ char *v_name = XALLOCAVEC (char, len + 2);
+ strcpy (v_name, name);
+ v_name[len] = 'v';
+ v_name[len + 1] = 0;
+ gen_int_libfunc (optable, v_name, suffix, mode);
+ }
+}
+
+/* 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
+ a mode name and an operand count these functions have two mode names
+ and no operand count. */
+
+static void
+gen_interclass_conv_libfunc (convert_optab tab,
+ const char *opname,
+ enum machine_mode tmode,
+ enum machine_mode fmode)
+{
+ size_t opname_len = strlen (opname);
+ size_t mname_len = 0;
+
+ const char *fname, *tname;
+ const char *q;
+ char *libfunc_name, *suffix;
+ char *nondec_name, *dec_name, *nondec_suffix, *dec_suffix;
+ char *p;
+
+ /* If this is a decimal conversion, add the current BID vs. DPD prefix that
+ depends on which underlying decimal floating point format is used. */
+ const size_t dec_len = sizeof (DECIMAL_PREFIX) - 1;
+
+ mname_len = strlen (GET_MODE_NAME (tmode)) + strlen (GET_MODE_NAME (fmode));
+
+ nondec_name = XALLOCAVEC (char, 2 + opname_len + mname_len + 1 + 1);
+ nondec_name[0] = '_';
+ nondec_name[1] = '_';
+ memcpy (&nondec_name[2], opname, opname_len);
+ nondec_suffix = nondec_name + opname_len + 2;