aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2007-09-04 16:03:31 +0200
committerJan Hubicka <hubicka@gcc.gnu.org>2007-09-04 14:03:31 +0000
commit8a33f10034d5c598395edc4ff0ae56e2bde7577e (patch)
treebc1e8971e3309ecdbd9ef277a0279ed5b1e1ce55
parent6977374226b230fe6e6d9b5ce2615bea094cb0f1 (diff)
downloadgcc-8a33f10034d5c598395edc4ff0ae56e2bde7577e.zip
gcc-8a33f10034d5c598395edc4ff0ae56e2bde7577e.tar.gz
gcc-8a33f10034d5c598395edc4ff0ae56e2bde7577e.tar.bz2
optabs.c (debug_optab_libfunc): Update; make available to gdb.
* optabs.c (debug_optab_libfunc): Update; make available to gdb. (libfunc_entry): New structure. (libfunc_hash): New hashtable. (hash_libfunc): New function. (eq_libfunc): New function. (convert_optab_libfunc): New function. (optab_libfunc): New function. (expand_binop, sign_expand_binop, expand_twoval_binop_libfunc, expand_unop, prepare_cmp_insn, prepare_float_insn, gen_add2_insn, expand_float, expand_fix, new_optab, new_convert_optab): Update for new libfunc API. (init_libfunc, init_integral_libfuncs, init_floating_libfuncs, init_interclass_conv_libfuncs init_intraclass_conv_libfuncs): Remove; reorganize all logic to: (gen_libfunc, gen_int_libfunc, gen_fp_libfunc, gen_int_fp_libfunc, gen_intv_fp_libfunc, gen_interclass_conv_libfunc, gen_int_to_fp_conv_libfunc, gen_ufloat_conv_libfunc, gen_int_to_fp_nondecimal_conv_libfunc, gen_fp_to_int_conv_libfunc, gen_intraclass_conv_libfunc, gen_trunc_conv_libfunc, gen_extend_conv_libfunc): New. (init_one_libfunc): Revamp for hashtables. (set_conv_libfunc): Likewise. (init_optabs): Initialize hashtable; use lazy initialization where possible. * optabs.h (optab_handlers): Move out of GGC. (optab, convert_optab): Move out of GGC; add lazy gen info. (code_to_optab, convert_optab_table, optab_table): Move out of GGC. (optab_libfunc, convert_optab_libfunc): New. * builtins.c (expand_builtin_powi): Update for new API. * expr.c (convert_move): Likewise. * expmed.c (expand_divmod): Likewise. From-SVN: r128083
-rw-r--r--gcc/ChangeLog33
-rw-r--r--gcc/builtins.c2
-rw-r--r--gcc/expmed.c4
-rw-r--r--gcc/expr.c2
-rw-r--r--gcc/optabs.c891
-rw-r--r--gcc/optabs.h24
6 files changed, 653 insertions, 303 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 1dd19c0..e37aa54 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,36 @@
+2007-09-04 Jan Hubicka <jh@suse.cz>
+
+ * optabs.c (debug_optab_libfunc): Update; make available to gdb.
+ (libfunc_entry): New structure.
+ (libfunc_hash): New hashtable.
+ (hash_libfunc): New function.
+ (eq_libfunc): New function.
+ (convert_optab_libfunc): New function.
+ (optab_libfunc): New function.
+ (expand_binop, sign_expand_binop, expand_twoval_binop_libfunc,
+ expand_unop, prepare_cmp_insn, prepare_float_insn, gen_add2_insn,
+ expand_float, expand_fix, new_optab, new_convert_optab):
+ Update for new libfunc API.
+ (init_libfunc, init_integral_libfuncs,
+ init_floating_libfuncs, init_interclass_conv_libfuncs
+ init_intraclass_conv_libfuncs): Remove; reorganize all logic to:
+ (gen_libfunc, gen_int_libfunc, gen_fp_libfunc, gen_int_fp_libfunc,
+ gen_intv_fp_libfunc, gen_interclass_conv_libfunc,
+ gen_int_to_fp_conv_libfunc, gen_ufloat_conv_libfunc,
+ gen_int_to_fp_nondecimal_conv_libfunc, gen_fp_to_int_conv_libfunc,
+ gen_intraclass_conv_libfunc, gen_trunc_conv_libfunc,
+ gen_extend_conv_libfunc): New.
+ (init_one_libfunc): Revamp for hashtables.
+ (set_conv_libfunc): Likewise.
+ (init_optabs): Initialize hashtable; use lazy initialization where possible.
+ * optabs.h (optab_handlers): Move out of GGC.
+ (optab, convert_optab): Move out of GGC; add lazy gen info.
+ (code_to_optab, convert_optab_table, optab_table): Move out of GGC.
+ (optab_libfunc, convert_optab_libfunc): New.
+ * builtins.c (expand_builtin_powi): Update for new API.
+ * expr.c (convert_move): Likewise.
+ * expmed.c (expand_divmod): Likewise.
+
2007-09-04 Daniel Jacobowitz <dan@codesourcery.com>
* config/rs6000/rs6000.c (rs6000_stack_info): Allocate space for the
diff --git a/gcc/builtins.c b/gcc/builtins.c
index e353e4d..fc16948 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -3060,7 +3060,7 @@ expand_builtin_powi (tree exp, rtx target, rtx subtarget)
if (GET_MODE (op1) != mode2)
op1 = convert_to_mode (mode2, op1, 0);
- target = emit_library_call_value (optab_handler (powi_optab, mode)->libfunc,
+ target = emit_library_call_value (optab_libfunc (powi_optab, mode),
target, LCT_CONST_MAKE_BLOCK, mode, 2,
op0, mode, op1, mode2);
diff --git a/gcc/expmed.c b/gcc/expmed.c
index 84a709a..09a58de 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -3886,8 +3886,8 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
if (compute_mode == VOIDmode)
for (compute_mode = mode; compute_mode != VOIDmode;
compute_mode = GET_MODE_WIDER_MODE (compute_mode))
- if (optab_handler (optab1, compute_mode)->libfunc
- || optab_handler (optab2, compute_mode)->libfunc)
+ if (optab_libfunc (optab1, compute_mode)
+ || optab_libfunc (optab2, compute_mode))
break;
/* If we still couldn't find a mode, use MODE, but expand_binop will
diff --git a/gcc/expr.c b/gcc/expr.c
index 9f321c8..13f447c 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -443,7 +443,7 @@ convert_move (rtx to, rtx from, int unsignedp)
}
/* Otherwise use a libcall. */
- libcall = convert_optab_handler (tab, to_mode, from_mode)->libfunc;
+ libcall = convert_optab_libfunc (tab, to_mode, from_mode);
/* Is this conversion implemented yet? */
gcc_assert (libcall);
diff --git a/gcc/optabs.c b/gcc/optabs.c
index f28393d..2501ce6 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -103,6 +103,9 @@ static rtx expand_unop_direct (enum machine_mode, optab, rtx, rtx, int);
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);
+
#ifndef HAVE_conditional_trap
#define HAVE_conditional_trap 0
#define gen_conditional_trap(a,b) (gcc_unreachable (), NULL_RTX)
@@ -114,6 +117,104 @@ static HOST_WIDE_INT libcall_id = 0;
#else
#define DECIMAL_PREFIX "dpd_"
#endif
+
+
+/* Info about libfunc. We use same hashtable for normal optabs and conversion
+ optab. In the first case mode2 is unused. */
+struct libfunc_entry GTY(())
+{
+ void * GTY((skip)) optab;
+ enum machine_mode mode1, mode2;
+ rtx libfunc;
+};
+
+/* Hash table used to convert declarations into nodes. */
+static GTY((param_is (struct libfunc_entry))) htab_t libfunc_hash;
+
+/* Used for attribute_hash. */
+
+static hashval_t
+hash_libfunc (const void *p)
+{
+ const struct libfunc_entry *const e = (const struct libfunc_entry *) p;
+
+ return (((int) e->mode1 + (int) e->mode2 * NUM_MACHINE_MODES)
+ ^ htab_hash_pointer (e->optab));
+}
+
+/* Used for optab_hash. */
+
+static int
+eq_libfunc (const void *p, const void *q)
+{
+ const struct libfunc_entry *const e1 = (const struct libfunc_entry *) p;
+ const struct libfunc_entry *const e2 = (const struct libfunc_entry *) q;
+
+ return (e1->optab == e2->optab
+ && e1->mode1 == e2->mode1
+ && e1->mode2 == e2->mode2);
+}
+
+/* Return libfunc corresponding operation defined by OPTAB converting
+ from MODE2 to MODE1. Trigger lazy initialization if needed, return NULL
+ if no libfunc is available. */
+rtx
+convert_optab_libfunc (convert_optab optab, enum machine_mode mode1,
+ enum machine_mode mode2)
+{
+ struct libfunc_entry e;
+ struct libfunc_entry **slot;
+
+ e.optab = optab;
+ e.mode1 = mode1;
+ e.mode2 = mode2;
+ slot = (struct libfunc_entry **) htab_find_slot (libfunc_hash, &e, NO_INSERT);
+ if (!slot)
+ {
+ if (optab->libcall_gen)
+ {
+ optab->libcall_gen (optab, optab->libcall_basename, mode1, mode2);
+ slot = (struct libfunc_entry **) htab_find_slot (libfunc_hash, &e, NO_INSERT);
+ if (slot)
+ return (*slot)->libfunc;
+ else
+ return NULL;
+ }
+ return NULL;
+ }
+ return (*slot)->libfunc;
+}
+
+/* Return libfunc corresponding operation defined by OPTAB in MODE.
+ Trigger lazy initialization if needed, return NULL if no libfunc is
+ available. */
+rtx
+optab_libfunc (optab optab, enum machine_mode mode)
+{
+ struct libfunc_entry e;
+ struct libfunc_entry **slot;
+
+ e.optab = optab;
+ e.mode1 = mode;
+ e.mode2 = VOIDmode;
+ slot = (struct libfunc_entry **) htab_find_slot (libfunc_hash, &e, NO_INSERT);
+ if (!slot)
+ {
+ if (optab->libcall_gen)
+ {
+ optab->libcall_gen (optab, optab->libcall_basename,
+ optab->libcall_suffix, mode);
+ slot = (struct libfunc_entry **) htab_find_slot (libfunc_hash,
+ &e, NO_INSERT);
+ if (slot)
+ return (*slot)->libfunc;
+ else
+ return NULL;
+ }
+ return NULL;
+ }
+ return (*slot)->libfunc;
+}
/* Add a REG_EQUAL note to the last insn in INSNS. TARGET is being set to
@@ -1419,6 +1520,7 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
? OPTAB_WIDEN : methods);
enum mode_class class;
enum machine_mode wider_mode;
+ rtx libfunc;
rtx temp;
rtx entry_last = get_last_insn ();
rtx last;
@@ -1989,7 +2091,8 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
/* It can't be open-coded in this mode.
Use a library call if one is available and caller says that's ok. */
- if (optab_handler (binoptab, mode)->libfunc
+ libfunc = optab_libfunc (binoptab, mode);
+ if (libfunc
&& (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN))
{
rtx insns;
@@ -2013,7 +2116,7 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
/* Pass 1 for NO_QUEUE so we don't lose any increments
if the libcall is cse'd or moved. */
- value = emit_library_call_value (optab_handler (binoptab, mode)->libfunc,
+ value = emit_library_call_value (libfunc,
NULL_RTX, LCT_CONST, mode, 2,
op0, mode, op1x, op1_mode);
@@ -2056,7 +2159,7 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
if ((optab_handler (binoptab, wider_mode)->insn_code
!= CODE_FOR_nothing)
|| (methods == OPTAB_LIB
- && optab_handler (binoptab, wider_mode)->libfunc))
+ && optab_libfunc (binoptab, wider_mode)))
{
rtx xop0 = op0, xop1 = op1;
int no_extend = 0;
@@ -2131,7 +2234,6 @@ sign_expand_binop (enum machine_mode mode, optab uoptab, optab soptab,
hides any signed insn for direct use. */
wide_soptab = *soptab;
optab_handler (&wide_soptab, mode)->insn_code = CODE_FOR_nothing;
- optab_handler (&wide_soptab, mode)->libfunc = 0;
temp = expand_binop (mode, &wide_soptab, op0, op1, target,
unsignedp, OPTAB_WIDEN);
@@ -2387,12 +2489,14 @@ expand_twoval_binop_libfunc (optab binoptab, rtx op0, rtx op1,
enum machine_mode libval_mode;
rtx libval;
rtx insns;
+ rtx libfunc;
/* Exactly one of TARG0 or TARG1 should be non-NULL. */
gcc_assert (!targ0 != !targ1);
mode = GET_MODE (op0);
- if (!optab_handler (binoptab, mode)->libfunc)
+ libfunc = optab_libfunc (binoptab, mode);
+ if (!libfunc)
return false;
/* The value returned by the library function will have twice as
@@ -2400,8 +2504,7 @@ expand_twoval_binop_libfunc (optab binoptab, rtx op0, rtx op1,
libval_mode = smallest_mode_for_size (2 * GET_MODE_BITSIZE (mode),
MODE_INT);
start_sequence ();
- libval = emit_library_call_value (optab_handler (binoptab, mode)->libfunc,
- NULL_RTX, LCT_CONST,
+ libval = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
libval_mode, 2,
op0, mode,
op1, mode);
@@ -2967,6 +3070,7 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
enum mode_class class = GET_MODE_CLASS (mode);
enum machine_mode wider_mode;
rtx temp;
+ rtx libfunc;
temp = expand_unop_direct (mode, unoptab, op0, target, unsignedp);
if (temp)
@@ -3135,7 +3239,8 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
try_libcall:
/* Now try a library call in this mode. */
- if (optab_handler (unoptab, mode)->libfunc)
+ libfunc = optab_libfunc (unoptab, mode);
+ if (libfunc)
{
rtx insns;
rtx value;
@@ -3152,8 +3257,7 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
/* Pass 1 for NO_QUEUE so we don't lose any increments
if the libcall is cse'd or moved. */
- value = emit_library_call_value (optab_handler (unoptab, mode)->libfunc,
- NULL_RTX, LCT_CONST, outmode,
+ value = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST, outmode,
1, op0, mode);
insns = get_insns ();
end_sequence ();
@@ -3175,7 +3279,7 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
{
if ((optab_handler (unoptab, wider_mode)->insn_code
!= CODE_FOR_nothing)
- || optab_handler (unoptab, wider_mode)->libfunc)
+ || optab_libfunc (unoptab, wider_mode))
{
rtx xop0 = op0;
rtx last = get_last_insn ();
@@ -4058,6 +4162,7 @@ prepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size,
enum machine_mode mode = *pmode;
rtx x = *px, y = *py;
int unsignedp = *punsignedp;
+ rtx libfunc;
/* If we are inside an appropriately-short loop and we are optimizing,
force expensive constants into a register. */
@@ -4162,15 +4267,20 @@ prepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size,
/* Handle a lib call just for the mode we are using. */
- if (optab_handler (cmp_optab, mode)->libfunc && !SCALAR_FLOAT_MODE_P (mode))
+ libfunc = optab_libfunc (cmp_optab, mode);
+ if (libfunc && !SCALAR_FLOAT_MODE_P (mode))
{
- rtx libfunc = optab_handler (cmp_optab, mode)->libfunc;
rtx result;
+ rtx ulibfunc;
/* If we want unsigned, and this mode has a distinct unsigned
comparison routine, use that. */
- if (unsignedp && optab_handler (ucmp_optab, mode)->libfunc)
- libfunc = optab_handler (ucmp_optab, mode)->libfunc;
+ if (unsignedp)
+ {
+ ulibfunc = optab_libfunc (ucmp_optab, mode);
+ }
+ if (unsignedp && ulibfunc)
+ libfunc = ulibfunc;
result = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST_MAKE_BLOCK,
targetm.libgcc_cmp_return_mode (),
@@ -4375,10 +4485,10 @@ prepare_float_lib_cmp (rtx *px, rtx *py, enum rtx_code *pcomparison,
mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
{
- if ((libfunc = optab_handler (code_to_optab[comparison], mode)->libfunc))
+ if ((libfunc = optab_libfunc (code_to_optab[comparison], mode)))
break;
- if ((libfunc = optab_handler (code_to_optab[swapped], mode)->libfunc))
+ if ((libfunc = optab_libfunc (code_to_optab[swapped] , mode)))
{
rtx tmp;
tmp = x; x = y; y = tmp;
@@ -4386,7 +4496,7 @@ prepare_float_lib_cmp (rtx *px, rtx *py, enum rtx_code *pcomparison,
break;
}
- if ((libfunc = optab_handler (code_to_optab[reversed], mode)->libfunc)
+ if ((libfunc = optab_libfunc (code_to_optab[reversed], mode))
&& FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, reversed))
{
comparison = reversed;
@@ -4755,6 +4865,7 @@ gen_add2_insn (rtx x, rtx y)
/* Generate and return an insn body to add r1 and c,
storing the result in r0. */
+
rtx
gen_add3_insn (rtx r0, rtx r1, rtx c)
{
@@ -4814,6 +4925,7 @@ gen_sub2_insn (rtx x, rtx y)
/* Generate and return an insn body to subtract r1 and c,
storing the result in r0. */
+
rtx
gen_sub3_insn (rtx r0, rtx r1, rtx c)
{
@@ -5124,8 +5236,7 @@ expand_float (rtx to, rtx from, int unsignedp)
if (GET_MODE_SIZE (GET_MODE (from)) < GET_MODE_SIZE (SImode))
from = convert_to_mode (SImode, from, unsignedp);
- libfunc = convert_optab_handler (tab, GET_MODE (to),
- GET_MODE (from))->libfunc;
+ libfunc = convert_optab_libfunc (tab, GET_MODE (to), GET_MODE (from));
gcc_assert (libfunc);
start_sequence ();
@@ -5305,8 +5416,7 @@ expand_fix (rtx to, rtx from, int unsignedp)
rtx libfunc;
convert_optab tab = unsignedp ? ufix_optab : sfix_optab;
- libfunc = convert_optab_handler (tab, GET_MODE (to),
- GET_MODE (from))->libfunc;
+ libfunc = convert_optab_libfunc (tab, GET_MODE (to), GET_MODE (from));
gcc_assert (libfunc);
start_sequence ();
@@ -5386,12 +5496,10 @@ static optab
new_optab (void)
{
int i;
- optab op = ggc_alloc (sizeof (struct optab));
+ optab op = xcalloc (sizeof (struct optab), 1);
+
for (i = 0; i < NUM_MACHINE_MODES; i++)
- {
- optab_handler (op, i)->insn_code = CODE_FOR_nothing;
- optab_handler (op, i)->libfunc = 0;
- }
+ optab_handler (op, i)->insn_code = CODE_FOR_nothing;
return op;
}
@@ -5400,13 +5508,12 @@ static convert_optab
new_convert_optab (void)
{
int i, j;
- convert_optab op = ggc_alloc (sizeof (struct convert_optab));
+ convert_optab op = xcalloc (sizeof (struct convert_optab), 1);
+
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;
- convert_optab_handler (op, i, j)->libfunc = 0;
- }
+ convert_optab_handler (op, i, j)->insn_code = CODE_FOR_nothing;
+
return op;
}
@@ -5448,80 +5555,105 @@ init_convert_optab (enum rtx_code code)
usually one of the characters '2', '3', or '4').
OPTABLE is the table in which libfunc fields are to be initialized.
- FIRST_MODE is the first machine mode index in the given optab to
- initialize.
- LAST_MODE is the last machine mode index in the given optab to
- initialize.
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
-init_libfuncs (optab optable, int first_mode, int last_mode,
- const char *opname, int suffix)
+gen_libfunc (optab optable, const char *opname, int suffix, enum machine_mode mode)
{
- int mode;
unsigned opname_len = strlen (opname);
+ const char *mname = GET_MODE_NAME (mode);
+ unsigned mname_len = strlen (mname);
+ char *libfunc_name = alloca (2 + opname_len + mname_len + 1 + 1);
+ char *p;
+ const char *q;
- for (mode = first_mode; (int) mode <= (int) last_mode;
- mode = (enum machine_mode) ((int) mode + 1))
- {
- const char *mname = GET_MODE_NAME (mode);
- unsigned mname_len = strlen (mname);
- char *libfunc_name = alloca (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';
-
- optab_handler (optable, mode)->libfunc
- = init_one_libfunc (ggc_alloc_string (libfunc_name, p - libfunc_name));
- }
+ 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));
}
-/* Initialize the libfunc fields of an entire group of entries in some
- optab which correspond to all integer mode operations. The parameters
- have the same meaning as similarly named ones for the `init_libfuncs'
- routine. (See above). */
+/* Like gen_libfunc, but verify that integer operation is involved. */
static void
-init_integral_libfuncs (optab optable, const char *opname, int suffix)
+gen_int_libfunc (optab optable, const char *opname, char suffix,
+ enum machine_mode mode)
{
- int maxsize = 2*BITS_PER_WORD;
+ 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;
- init_libfuncs (optable, word_mode,
- mode_for_size (maxsize, MODE_INT, 0),
- opname, suffix);
+ if (GET_MODE_CLASS (mode) != MODE_INT
+ || mode < word_mode || GET_MODE_BITSIZE (mode) > maxsize)
+ return;
+ gen_libfunc (optable, opname, suffix, mode);
}
-/* Initialize the libfunc fields of an entire group of entries in some
- optab which correspond to all real mode operations. The parameters
- have the same meaning as similarly named ones for the `init_libfuncs'
- routine. (See above). */
+/* 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 = alloca (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 FP or INT operation is involved. */
static void
-init_floating_libfuncs (optab optable, const char *opname, int suffix)
+gen_int_fp_libfunc (optab optable, const char *name, char suffix,
+ enum machine_mode mode)
{
- char *dec_opname = alloca (sizeof (DECIMAL_PREFIX) + strlen (opname));
+ 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);
+}
- /* 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);
+/* Like gen_libfunc, but verify that FP or INT operation is involved
+ and add 'v' suffix for integer operation. */
- init_libfuncs (optable, MIN_MODE_FLOAT, MAX_MODE_FLOAT, opname, suffix);
- init_libfuncs (optable, MIN_MODE_DECIMAL_FLOAT, MAX_MODE_DECIMAL_FLOAT,
- dec_opname, suffix);
+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 = alloca (len + 2);
+ strcpy (v_name, name);
+ v_name[len] = 'v';
+ v_name[len + 1] = 0;
+ gen_int_libfunc (optable, v_name, suffix, mode);
+ }
}
/* Initialize the libfunc fields of an entire group of entries of an
@@ -5529,17 +5661,16 @@ init_floating_libfuncs (optab optable, const char *opname, int suffix)
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
-init_interclass_conv_libfuncs (convert_optab tab, const char *opname,
- enum mode_class from_class,
- enum mode_class to_class)
+gen_interclass_conv_libfunc (convert_optab tab,
+ const char *opname,
+ enum machine_mode tmode,
+ enum machine_mode fmode)
{
- enum machine_mode first_from_mode = GET_CLASS_NARROWEST_MODE (from_class);
- enum machine_mode first_to_mode = GET_CLASS_NARROWEST_MODE (to_class);
size_t opname_len = strlen (opname);
- size_t max_mname_len = 0;
+ size_t mname_len = 0;
- enum machine_mode fmode, tmode;
const char *fname, *tname;
const char *q;
char *libfunc_name, *suffix;
@@ -5550,77 +5681,122 @@ init_interclass_conv_libfuncs (convert_optab tab, const char *opname,
depends on which underlying decimal floating point format is used. */
const size_t dec_len = sizeof (DECIMAL_PREFIX) - 1;
- for (fmode = first_from_mode;
- fmode != VOIDmode;
- fmode = GET_MODE_WIDER_MODE (fmode))
- max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (fmode)));
-
- for (tmode = first_to_mode;
- tmode != VOIDmode;
- tmode = GET_MODE_WIDER_MODE (tmode))
- max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (tmode)));
+ mname_len = strlen (GET_MODE_NAME (tmode)) + strlen (GET_MODE_NAME (fmode));
- nondec_name = alloca (2 + opname_len + 2*max_mname_len + 1 + 1);
+ nondec_name = alloca (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;
- dec_name = alloca (2 + dec_len + opname_len + 2*max_mname_len + 1 + 1);
+ dec_name = alloca (2 + dec_len + opname_len + mname_len + 1 + 1);
dec_name[0] = '_';
dec_name[1] = '_';
memcpy (&dec_name[2], DECIMAL_PREFIX, dec_len);
memcpy (&dec_name[2+dec_len], opname, opname_len);
dec_suffix = dec_name + dec_len + opname_len + 2;
- for (fmode = first_from_mode; fmode != VOIDmode;
- fmode = GET_MODE_WIDER_MODE (fmode))
- for (tmode = first_to_mode; tmode != VOIDmode;
- tmode = GET_MODE_WIDER_MODE (tmode))
- {
- fname = GET_MODE_NAME (fmode);
- tname = GET_MODE_NAME (tmode);
+ fname = GET_MODE_NAME (fmode);
+ tname = GET_MODE_NAME (tmode);
- if (DECIMAL_FLOAT_MODE_P(fmode) || DECIMAL_FLOAT_MODE_P(tmode))
- {
- libfunc_name = dec_name;
- suffix = dec_suffix;
- }
- else
- {
- libfunc_name = nondec_name;
- suffix = nondec_suffix;
- }
+ if (DECIMAL_FLOAT_MODE_P(fmode) || DECIMAL_FLOAT_MODE_P(tmode))
+ {
+ libfunc_name = dec_name;
+ suffix = dec_suffix;
+ }
+ else
+ {
+ libfunc_name = nondec_name;
+ suffix = nondec_suffix;
+ }
- p = suffix;
- for (q = fname; *q; p++, q++)
- *p = TOLOWER (*q);
- for (q = tname; *q; p++, q++)
- *p = TOLOWER (*q);
+ p = suffix;
+ for (q = fname; *q; p++, q++)
+ *p = TOLOWER (*q);
+ for (q = tname; *q; p++, q++)
+ *p = TOLOWER (*q);
- *p = '\0';
+ *p = '\0';
- convert_optab_handler (tab, tmode, fmode)->libfunc
- = init_one_libfunc (ggc_alloc_string (libfunc_name,
- p - libfunc_name));
- }
+ set_conv_libfunc (tab, tmode, fmode,
+ ggc_alloc_string (libfunc_name, p - libfunc_name));
}
-/* Initialize the libfunc fields of an entire group of entries of an
- intra-mode-class conversion optab. The string formation rules are
- similar to the ones for init_libfunc, above. WIDENING says whether
- the optab goes from narrow to wide modes or vice versa. These functions
- have two mode names _and_ an operand count. */
+/* Same as gen_interclass_conv_libfunc but verify that we are producing
+ int->fp conversion. */
+
+static void
+gen_int_to_fp_conv_libfunc (convert_optab tab,
+ const char *opname,
+ enum machine_mode tmode,
+ enum machine_mode fmode)
+{
+ if (GET_MODE_CLASS (fmode) != MODE_INT)
+ return;
+ if (GET_MODE_CLASS (tmode) != MODE_FLOAT && !DECIMAL_FLOAT_MODE_P (tmode))
+ return;
+ gen_interclass_conv_libfunc (tab, opname, tmode, fmode);
+}
+
+/* ufloat_optab is special by using floatun for FP and floatuns decimal fp
+ naming scheme. */
+
+static void
+gen_ufloat_conv_libfunc (convert_optab tab,
+ const char *opname ATTRIBUTE_UNUSED,
+ enum machine_mode tmode,
+ enum machine_mode fmode)
+{
+ if (DECIMAL_FLOAT_MODE_P (tmode))
+ gen_int_to_fp_conv_libfunc (tab, "floatuns", tmode, fmode);
+ else
+ gen_int_to_fp_conv_libfunc (tab, "floatun", tmode, fmode);
+}
+
+/* Same as gen_interclass_conv_libfunc but verify that we are producing
+ fp->int conversion. */
+
+static void
+gen_int_to_fp_nondecimal_conv_libfunc (convert_optab tab,
+ const char *opname,
+ enum machine_mode tmode,
+ enum machine_mode fmode)
+{
+ if (GET_MODE_CLASS (fmode) != MODE_INT)
+ return;
+ if (GET_MODE_CLASS (tmode) != MODE_FLOAT)
+ return;
+ gen_interclass_conv_libfunc (tab, opname, tmode, fmode);
+}
+
+/* Same as gen_interclass_conv_libfunc but verify that we are producing
+ fp->int conversion with no decimal floating point involved. */
+
static void
-init_intraclass_conv_libfuncs (convert_optab tab, const char *opname,
- enum mode_class class, bool widening)
+gen_fp_to_int_conv_libfunc (convert_optab tab,
+ const char *opname,
+ enum machine_mode tmode,
+ enum machine_mode fmode)
+{
+ if (GET_MODE_CLASS (fmode) != MODE_FLOAT && !DECIMAL_FLOAT_MODE_P (fmode))
+ return;
+ if (GET_MODE_CLASS (tmode) != MODE_INT)
+ return;
+ gen_interclass_conv_libfunc (tab, opname, tmode, fmode);
+}
+
+/* Initialize the libfunc fiels of an of an intra-mode-class conversion optab.
+ The string formation rules are
+ similar to the ones for init_libfunc, above. */
+
+static void
+gen_intraclass_conv_libfunc (convert_optab tab, const char *opname,
+ enum machine_mode tmode, enum machine_mode fmode)
{
- enum machine_mode first_mode = GET_CLASS_NARROWEST_MODE (class);
size_t opname_len = strlen (opname);
- size_t max_mname_len = 0;
+ size_t mname_len = 0;
- enum machine_mode nmode, wmode;
- const char *nname, *wname;
+ const char *fname, *tname;
const char *q;
char *nondec_name, *dec_name, *nondec_suffix, *dec_suffix;
char *libfunc_name, *suffix;
@@ -5630,58 +5806,105 @@ init_intraclass_conv_libfuncs (convert_optab tab, const char *opname,
depends on which underlying decimal floating point format is used. */
const size_t dec_len = sizeof (DECIMAL_PREFIX) - 1;
- for (nmode = first_mode; nmode != VOIDmode;
- nmode = GET_MODE_WIDER_MODE (nmode))
- max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (nmode)));
+ mname_len = strlen (GET_MODE_NAME (tmode)) + strlen (GET_MODE_NAME (fmode));
- nondec_name = alloca (2 + opname_len + 2*max_mname_len + 1 + 1);
+ nondec_name = alloca (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;
- dec_name = alloca (2 + dec_len + opname_len + 2*max_mname_len + 1 + 1);
+ dec_name = alloca (2 + dec_len + opname_len + mname_len + 1 + 1);
dec_name[0] = '_';
dec_name[1] = '_';
memcpy (&dec_name[2], DECIMAL_PREFIX, dec_len);
memcpy (&dec_name[2 + dec_len], opname, opname_len);
dec_suffix = dec_name + dec_len + opname_len + 2;
- for (nmode = first_mode; nmode != VOIDmode;
- nmode = GET_MODE_WIDER_MODE (nmode))
- for (wmode = GET_MODE_WIDER_MODE (nmode); wmode != VOIDmode;
- wmode = GET_MODE_WIDER_MODE (wmode))
- {
- nname = GET_MODE_NAME (nmode);
- wname = GET_MODE_NAME (wmode);
+ fname = GET_MODE_NAME (fmode);
+ tname = GET_MODE_NAME (tmode);
- if (DECIMAL_FLOAT_MODE_P(nmode) || DECIMAL_FLOAT_MODE_P(wmode))
- {
- libfunc_name = dec_name;
- suffix = dec_suffix;
- }
- else
- {
- libfunc_name = nondec_name;
- suffix = nondec_suffix;
- }
+ if (DECIMAL_FLOAT_MODE_P(fmode) || DECIMAL_FLOAT_MODE_P(tmode))
+ {
+ libfunc_name = dec_name;
+ suffix = dec_suffix;
+ }
+ else
+ {
+ libfunc_name = nondec_name;
+ suffix = nondec_suffix;
+ }
- p = suffix;
- for (q = widening ? nname : wname; *q; p++, q++)
- *p = TOLOWER (*q);
- for (q = widening ? wname : nname; *q; p++, q++)
- *p = TOLOWER (*q);
+ p = suffix;
+ for (q = fname; *q; p++, q++)
+ *p = TOLOWER (*q);
+ for (q = tname; *q; p++, q++)
+ *p = TOLOWER (*q);
- *p++ = '2';
- *p = '\0';
+ *p++ = '2';
+ *p = '\0';
- convert_optab_handler(tab, widening ? wmode : nmode,
- widening ? nmode : wmode)->libfunc
- = init_one_libfunc (ggc_alloc_string (libfunc_name,
- p - libfunc_name));
- }
+ set_conv_libfunc (tab, tmode, fmode,
+ ggc_alloc_string (libfunc_name, p - libfunc_name));
}
+/* Pick proper libcall for trunc_optab. We need to chose if we do
+ truncation or extension and interclass or intraclass. */
+
+static void
+gen_trunc_conv_libfunc (convert_optab tab,
+ const char *opname,
+ enum machine_mode tmode,
+ enum machine_mode fmode)
+{
+ if (GET_MODE_CLASS (tmode) != MODE_FLOAT && !DECIMAL_FLOAT_MODE_P (tmode))
+ return;
+ if (GET_MODE_CLASS (fmode) != MODE_FLOAT && !DECIMAL_FLOAT_MODE_P (fmode))
+ return;
+ if (tmode == fmode)
+ return;
+
+ if ((GET_MODE_CLASS (tmode) == MODE_FLOAT && DECIMAL_FLOAT_MODE_P (fmode))
+ || (GET_MODE_CLASS (fmode) == MODE_FLOAT && DECIMAL_FLOAT_MODE_P (tmode)))
+ gen_interclass_conv_libfunc (tab, opname, tmode, fmode);
+
+ if (GET_MODE_PRECISION (fmode) <= GET_MODE_PRECISION (tmode))
+ return;
+
+ if ((GET_MODE_CLASS (tmode) == MODE_FLOAT
+ && GET_MODE_CLASS (fmode) == MODE_FLOAT)
+ || (DECIMAL_FLOAT_MODE_P (fmode) && DECIMAL_FLOAT_MODE_P (tmode)))
+ gen_intraclass_conv_libfunc (tab, opname, tmode, fmode);
+}
+
+/* Pick proper libcall for extend_optab. We need to chose if we do
+ truncation or extension and interclass or intraclass. */
+
+static void
+gen_extend_conv_libfunc (convert_optab tab,
+ const char *opname ATTRIBUTE_UNUSED,
+ enum machine_mode tmode,
+ enum machine_mode fmode)
+{
+ if (GET_MODE_CLASS (tmode) != MODE_FLOAT && !DECIMAL_FLOAT_MODE_P (tmode))
+ return;
+ if (GET_MODE_CLASS (fmode) != MODE_FLOAT && !DECIMAL_FLOAT_MODE_P (fmode))
+ return;
+ if (tmode == fmode)
+ return;
+
+ if ((GET_MODE_CLASS (tmode) == MODE_FLOAT && DECIMAL_FLOAT_MODE_P (fmode))
+ || (GET_MODE_CLASS (fmode) == MODE_FLOAT && DECIMAL_FLOAT_MODE_P (tmode)))
+ gen_interclass_conv_libfunc (tab, opname, tmode, fmode);
+
+ if (GET_MODE_PRECISION (fmode) > GET_MODE_PRECISION (tmode))
+ return;
+
+ if ((GET_MODE_CLASS (tmode) == MODE_FLOAT
+ && GET_MODE_CLASS (fmode) == MODE_FLOAT)
+ || (DECIMAL_FLOAT_MODE_P (fmode) && DECIMAL_FLOAT_MODE_P (tmode)))
+ gen_intraclass_conv_libfunc (tab, opname, tmode, fmode);
+}
rtx
init_one_libfunc (const char *name)
@@ -5712,10 +5935,24 @@ init_one_libfunc (const char *name)
void
set_optab_libfunc (optab optable, enum machine_mode mode, const char *name)
{
+ rtx val;
+ struct libfunc_entry e;
+ struct libfunc_entry **slot;
+ e.optab = optable;
+ e.mode1 = mode;
+ e.mode2 = VOIDmode;
+
if (name)
- optab_handler (optable, mode)->libfunc = init_one_libfunc (name);
+ val = init_one_libfunc (name);
else
- optab_handler (optable, mode)->libfunc = 0;
+ val = 0;
+ slot = (struct libfunc_entry **) htab_find_slot (libfunc_hash, &e, INSERT);
+ if (*slot == NULL)
+ *slot = ggc_alloc (sizeof (struct libfunc_entry));
+ (*slot)->optab = optable;
+ (*slot)->mode1 = mode;
+ (*slot)->mode2 = VOIDmode;
+ (*slot)->libfunc = val;
}
/* Call this to reset the function entry for one conversion optab
@@ -5725,11 +5962,24 @@ void
set_conv_libfunc (convert_optab optable, enum machine_mode tmode,
enum machine_mode fmode, const char *name)
{
+ rtx val;
+ struct libfunc_entry e;
+ struct libfunc_entry **slot;
+ e.optab = optable;
+ e.mode1 = tmode;
+ e.mode2 = fmode;
+
if (name)
- convert_optab_handler (optable, tmode, fmode)->libfunc
- = init_one_libfunc (name);
+ val = init_one_libfunc (name);
else
- convert_optab_handler (optable, tmode, fmode)->libfunc = 0;
+ val = 0;
+ slot = (struct libfunc_entry **) htab_find_slot (libfunc_hash, &e, INSERT);
+ if (*slot == NULL)
+ *slot = ggc_alloc (sizeof (struct libfunc_entry));
+ (*slot)->optab = optable;
+ (*slot)->mode1 = tmode;
+ (*slot)->mode2 = fmode;
+ (*slot)->libfunc = val;
}
/* Call this to initialize the contents of the optabs
@@ -5741,6 +5991,7 @@ init_optabs (void)
unsigned int i;
enum machine_mode int_mode;
+ libfunc_hash = htab_create_ggc (10, hash_libfunc, eq_libfunc, NULL);
/* Start by initializing all tables to contain CODE_FOR_nothing. */
for (i = 0; i < NUM_RTX_CODE; i++)
@@ -5960,110 +6211,171 @@ init_optabs (void)
/* Fill in the optabs with the insns we support. */
init_all_optabs ();
- /* The ffs function operates on `int'. Fall back on it if we do not
- have a libgcc2 function for that width. */
- int_mode = mode_for_size (INT_TYPE_SIZE, MODE_INT, 0);
- optab_handler (ffs_optab, int_mode)->libfunc = init_one_libfunc ("ffs");
-
/* Initialize the optabs with the names of the library functions. */
- init_integral_libfuncs (add_optab, "add", '3');
- init_floating_libfuncs (add_optab, "add", '3');
- init_integral_libfuncs (addv_optab, "addv", '3');
- init_floating_libfuncs (addv_optab, "add", '3');
- init_integral_libfuncs (sub_optab, "sub", '3');
- init_floating_libfuncs (sub_optab, "sub", '3');
- init_integral_libfuncs (subv_optab, "subv", '3');
- init_floating_libfuncs (subv_optab, "sub", '3');
- init_integral_libfuncs (smul_optab, "mul", '3');
- init_floating_libfuncs (smul_optab, "mul", '3');
- init_integral_libfuncs (smulv_optab, "mulv", '3');
- init_floating_libfuncs (smulv_optab, "mul", '3');
- init_integral_libfuncs (sdiv_optab, "div", '3');
- init_floating_libfuncs (sdiv_optab, "div", '3');
- init_integral_libfuncs (sdivv_optab, "divv", '3');
- init_integral_libfuncs (udiv_optab, "udiv", '3');
- init_integral_libfuncs (sdivmod_optab, "divmod", '4');
- init_integral_libfuncs (udivmod_optab, "udivmod", '4');
- init_integral_libfuncs (smod_optab, "mod", '3');
- init_integral_libfuncs (umod_optab, "umod", '3');
- init_floating_libfuncs (ftrunc_optab, "ftrunc", '2');
- init_integral_libfuncs (and_optab, "and", '3');
- init_integral_libfuncs (ior_optab, "ior", '3');
- init_integral_libfuncs (xor_optab, "xor", '3');
- init_integral_libfuncs (ashl_optab, "ashl", '3');
- init_integral_libfuncs (ashr_optab, "ashr", '3');
- init_integral_libfuncs (lshr_optab, "lshr", '3');
- init_integral_libfuncs (smin_optab, "min", '3');
- init_floating_libfuncs (smin_optab, "min", '3');
- init_integral_libfuncs (smax_optab, "max", '3');
- init_floating_libfuncs (smax_optab, "max", '3');
- init_integral_libfuncs (umin_optab, "umin", '3');
- init_integral_libfuncs (umax_optab, "umax", '3');
- init_integral_libfuncs (neg_optab, "neg", '2');
- init_floating_libfuncs (neg_optab, "neg", '2');
- init_integral_libfuncs (negv_optab, "negv", '2');
- init_floating_libfuncs (negv_optab, "neg", '2');
- init_integral_libfuncs (one_cmpl_optab, "one_cmpl", '2');
- init_integral_libfuncs (ffs_optab, "ffs", '2');
- init_integral_libfuncs (clz_optab, "clz", '2');
- init_integral_libfuncs (ctz_optab, "ctz", '2');
- init_integral_libfuncs (popcount_optab, "popcount", '2');
- init_integral_libfuncs (parity_optab, "parity", '2');
+ add_optab->libcall_basename = "add";
+ add_optab->libcall_suffix = '3';
+ add_optab->libcall_gen = gen_int_fp_libfunc;
+ addv_optab->libcall_basename = "add";
+ addv_optab->libcall_suffix = '3';
+ addv_optab->libcall_gen = gen_intv_fp_libfunc;
+ sub_optab->libcall_basename = "sub";
+ sub_optab->libcall_suffix = '3';
+ sub_optab->libcall_gen = gen_int_fp_libfunc;
+ subv_optab->libcall_basename = "sub";
+ subv_optab->libcall_suffix = '3';
+ subv_optab->libcall_gen = gen_intv_fp_libfunc;
+ smul_optab->libcall_basename = "mul";
+ smul_optab->libcall_suffix = '3';
+ smul_optab->libcall_gen = gen_int_fp_libfunc;
+ smulv_optab->libcall_basename = "mul";
+ smulv_optab->libcall_suffix = '3';
+ smulv_optab->libcall_gen = gen_intv_fp_libfunc;
+ sdiv_optab->libcall_basename = "div";
+ sdiv_optab->libcall_suffix = '3';
+ sdiv_optab->libcall_gen = gen_int_fp_libfunc;
+ sdivv_optab->libcall_basename = "divv";
+ sdivv_optab->libcall_suffix = '3';
+ sdivv_optab->libcall_gen = gen_int_libfunc;
+ udiv_optab->libcall_basename = "udiv";
+ udiv_optab->libcall_suffix = '3';
+ udiv_optab->libcall_gen = gen_int_libfunc;
+ sdivmod_optab->libcall_basename = "divmod";
+ sdivmod_optab->libcall_suffix = '4';
+ sdivmod_optab->libcall_gen = gen_int_libfunc;
+ udivmod_optab->libcall_basename = "udivmod";
+ udivmod_optab->libcall_suffix = '4';
+ udivmod_optab->libcall_gen = gen_int_libfunc;
+ smod_optab->libcall_basename = "mod";
+ smod_optab->libcall_suffix = '3';
+ smod_optab->libcall_gen = gen_int_libfunc;
+ umod_optab->libcall_basename = "umod";
+ umod_optab->libcall_suffix = '3';
+ umod_optab->libcall_gen = gen_int_libfunc;
+ ftrunc_optab->libcall_basename = "ftrunc";
+ ftrunc_optab->libcall_suffix = '2';
+ ftrunc_optab->libcall_gen = gen_fp_libfunc;
+ and_optab->libcall_basename = "and";
+ and_optab->libcall_suffix = '3';
+ and_optab->libcall_gen = gen_int_libfunc;
+ ior_optab->libcall_basename = "ior";
+ ior_optab->libcall_suffix = '3';
+ ior_optab->libcall_gen = gen_int_libfunc;
+ xor_optab->libcall_basename = "xor";
+ xor_optab->libcall_suffix = '3';
+ xor_optab->libcall_gen = gen_int_libfunc;
+ ashl_optab->libcall_basename = "ashl";
+ ashl_optab->libcall_suffix = '3';
+ ashl_optab->libcall_gen = gen_int_libfunc;
+ ashr_optab->libcall_basename = "ashr";
+ ashr_optab->libcall_suffix = '3';
+ ashr_optab->libcall_gen = gen_int_libfunc;
+ lshr_optab->libcall_basename = "lshr";
+ lshr_optab->libcall_suffix = '3';
+ lshr_optab->libcall_gen = gen_int_libfunc;
+ smin_optab->libcall_basename = "min";
+ smin_optab->libcall_suffix = '3';
+ smin_optab->libcall_gen = gen_int_fp_libfunc;
+ smax_optab->libcall_basename = "max";
+ smax_optab->libcall_suffix = '3';
+ smax_optab->libcall_gen = gen_int_fp_libfunc;
+ umin_optab->libcall_basename = "umin";
+ umin_optab->libcall_suffix = '3';
+ umin_optab->libcall_gen = gen_int_libfunc;
+ umax_optab->libcall_basename = "umax";
+ umax_optab->libcall_suffix = '3';
+ 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;
+ negv_optab->libcall_basename = "neg";
+ negv_optab->libcall_suffix = '2';
+ negv_optab->libcall_gen = gen_intv_fp_libfunc;
+ one_cmpl_optab->libcall_basename = "one_cmpl";
+ one_cmpl_optab->libcall_suffix = '2';
+ one_cmpl_optab->libcall_gen = gen_int_libfunc;
+ ffs_optab->libcall_basename = "ffs";
+ ffs_optab->libcall_suffix = '2';
+ ffs_optab->libcall_gen = gen_int_libfunc;
+ clz_optab->libcall_basename = "clz";
+ clz_optab->libcall_suffix = '2';
+ clz_optab->libcall_gen = gen_int_libfunc;
+ ctz_optab->libcall_basename = "ctz";
+ ctz_optab->libcall_suffix = '2';
+ ctz_optab->libcall_gen = gen_int_libfunc;
+ popcount_optab->libcall_basename = "popcount";
+ popcount_optab->libcall_suffix = '2';
+ popcount_optab->libcall_gen = gen_int_libfunc;
+ parity_optab->libcall_basename = "parity";
+ parity_optab->libcall_suffix = '2';
+ parity_optab->libcall_gen = gen_int_libfunc;
/* Comparison libcalls for integers MUST come in pairs,
signed/unsigned. */
- init_integral_libfuncs (cmp_optab, "cmp", '2');
- init_integral_libfuncs (ucmp_optab, "ucmp", '2');
- init_floating_libfuncs (cmp_optab, "cmp", '2');
+ cmp_optab->libcall_basename = "cmp";
+ cmp_optab->libcall_suffix = '2';
+ cmp_optab->libcall_gen = gen_int_fp_libfunc;
+ ucmp_optab->libcall_basename = "ucmp";
+ ucmp_optab->libcall_suffix = '2';
+ ucmp_optab->libcall_gen = gen_int_libfunc;
/* EQ etc are floating point only. */
- init_floating_libfuncs (eq_optab, "eq", '2');
- init_floating_libfuncs (ne_optab, "ne", '2');
- init_floating_libfuncs (gt_optab, "gt", '2');
- init_floating_libfuncs (ge_optab, "ge", '2');
- init_floating_libfuncs (lt_optab, "lt", '2');
- init_floating_libfuncs (le_optab, "le", '2');
- init_floating_libfuncs (unord_optab, "unord", '2');
-
- init_floating_libfuncs (powi_optab, "powi", '2');
+ eq_optab->libcall_basename = "eq";
+ eq_optab->libcall_suffix = '2';
+ eq_optab->libcall_gen = gen_fp_libfunc;
+ ne_optab->libcall_basename = "ne";
+ ne_optab->libcall_suffix = '2';
+ ne_optab->libcall_gen = gen_fp_libfunc;
+ gt_optab->libcall_basename = "gt";
+ gt_optab->libcall_suffix = '2';
+ gt_optab->libcall_gen = gen_fp_libfunc;
+ ge_optab->libcall_basename = "ge";
+ ge_optab->libcall_suffix = '2';
+ ge_optab->libcall_gen = gen_fp_libfunc;
+ lt_optab->libcall_basename = "lt";
+ lt_optab->libcall_suffix = '2';
+ lt_optab->libcall_gen = gen_fp_libfunc;
+ le_optab->libcall_basename = "le";
+ le_optab->libcall_suffix = '2';
+ le_optab->libcall_gen = gen_fp_libfunc;
+ unord_optab->libcall_basename = "unord";
+ unord_optab->libcall_suffix = '2';
+ unord_optab->libcall_gen = gen_fp_libfunc;
+
+ powi_optab->libcall_basename = "powi";
+ powi_optab->libcall_suffix = '2';
+ powi_optab->libcall_gen = gen_fp_libfunc;
/* Conversions. */
- init_interclass_conv_libfuncs (sfloat_optab, "float",
- MODE_INT, MODE_FLOAT);
- init_interclass_conv_libfuncs (sfloat_optab, "float",
- MODE_INT, MODE_DECIMAL_FLOAT);
- init_interclass_conv_libfuncs (ufloat_optab, "floatun",
- MODE_INT, MODE_FLOAT);
- init_interclass_conv_libfuncs (ufloat_optab, "floatun",
- MODE_INT, MODE_DECIMAL_FLOAT);
- init_interclass_conv_libfuncs (sfix_optab, "fix",
- MODE_FLOAT, MODE_INT);
- init_interclass_conv_libfuncs (sfix_optab, "fix",
- MODE_DECIMAL_FLOAT, MODE_INT);
- init_interclass_conv_libfuncs (ufix_optab, "fixuns",
- MODE_FLOAT, MODE_INT);
- init_interclass_conv_libfuncs (ufix_optab, "fixuns",
- MODE_DECIMAL_FLOAT, MODE_INT);
- init_interclass_conv_libfuncs (ufloat_optab, "floatuns",
- MODE_INT, MODE_DECIMAL_FLOAT);
- init_interclass_conv_libfuncs (lrint_optab, "lrint",
- MODE_INT, MODE_FLOAT);
- init_interclass_conv_libfuncs (lround_optab, "lround",
- MODE_INT, MODE_FLOAT);
- init_interclass_conv_libfuncs (lfloor_optab, "lfloor",
- MODE_INT, MODE_FLOAT);
- init_interclass_conv_libfuncs (lceil_optab, "lceil",
- MODE_INT, MODE_FLOAT);
-
- /* sext_optab is also used for FLOAT_EXTEND. */
- init_intraclass_conv_libfuncs (sext_optab, "extend", MODE_FLOAT, true);
- init_intraclass_conv_libfuncs (sext_optab, "extend", MODE_DECIMAL_FLOAT, true);
- init_interclass_conv_libfuncs (sext_optab, "extend", MODE_FLOAT, MODE_DECIMAL_FLOAT);
- init_interclass_conv_libfuncs (sext_optab, "extend", MODE_DECIMAL_FLOAT, MODE_FLOAT);
- init_intraclass_conv_libfuncs (trunc_optab, "trunc", MODE_FLOAT, false);
- init_intraclass_conv_libfuncs (trunc_optab, "trunc", MODE_DECIMAL_FLOAT, false);
- init_interclass_conv_libfuncs (trunc_optab, "trunc", MODE_FLOAT, MODE_DECIMAL_FLOAT);
- init_interclass_conv_libfuncs (trunc_optab, "trunc", MODE_DECIMAL_FLOAT, MODE_FLOAT);
+ sfloat_optab->libcall_basename = "float";
+ sfloat_optab->libcall_gen = gen_int_to_fp_conv_libfunc;
+ ufloat_optab->libcall_gen = gen_ufloat_conv_libfunc;
+ sfix_optab->libcall_basename = "fix";
+ sfix_optab->libcall_gen = gen_fp_to_int_conv_libfunc;
+ ufix_optab->libcall_basename = "fixuns";
+ ufix_optab->libcall_gen = gen_fp_to_int_conv_libfunc;
+ lrint_optab->libcall_basename = "lrint";
+ lrint_optab->libcall_gen = gen_int_to_fp_nondecimal_conv_libfunc;
+ lround_optab->libcall_basename = "lround";
+ lround_optab->libcall_gen = gen_int_to_fp_nondecimal_conv_libfunc;
+ lfloor_optab->libcall_basename = "lfloor";
+ lfloor_optab->libcall_gen = gen_int_to_fp_nondecimal_conv_libfunc;
+ lceil_optab->libcall_basename = "lceil";
+ lceil_optab->libcall_gen = gen_int_to_fp_nondecimal_conv_libfunc;
+
+ /* trunc_optab is also used for FLOAT_EXTEND. */
+ sext_optab->libcall_basename = "extend";
+ sext_optab->libcall_gen = gen_extend_conv_libfunc;
+ trunc_optab->libcall_basename = "trunc";
+ trunc_optab->libcall_gen = gen_trunc_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)
+ {
+ int_mode = mode_for_size (INT_TYPE_SIZE, MODE_INT, 0);
+ set_optab_libfunc (ffs_optab, mode_for_size (INT_TYPE_SIZE, MODE_INT, 0),
+ "ffs");
+ }
/* Explicitly initialize the bswap libfuncs since we need them to be
valid for things other than word_mode. */
@@ -6073,8 +6385,7 @@ init_optabs (void)
/* Use cabs for double complex abs, since systems generally have cabs.
Don't define any libcall for float complex, so that cabs will be used. */
if (complex_double_type_node)
- optab_handler (abs_optab, TYPE_MODE (complex_double_type_node))->libfunc
- = init_one_libfunc ("cabs");
+ set_optab_libfunc (abs_optab, TYPE_MODE (complex_double_type_node), "cabs");
abort_libfunc = init_one_libfunc ("abort");
memcpy_libfunc = init_one_libfunc ("memcpy");
@@ -6109,12 +6420,10 @@ init_optabs (void)
targetm.init_libfuncs ();
}
-#ifdef DEBUG
-
/* Print information about the current contents of the optabs on
STDERR. */
-static void
+void
debug_optab_libfuncs (void)
{
int i;
@@ -6126,17 +6435,17 @@ debug_optab_libfuncs (void)
for (j = 0; j < NUM_MACHINE_MODES; ++j)
{
optab o;
- struct optab_handlers *h;
+ rtx l;
o = optab_table[i];
- h = optab_handler (o, j);
- if (h->libfunc)
+ l = optab_libfunc (optab_table[i], j);
+ if (l)
{
- gcc_assert (GET_CODE (h->libfunc) == SYMBOL_REF);
+ gcc_assert (GET_CODE (l) == SYMBOL_REF);
fprintf (stderr, "%s\t%s:\t%s\n",
GET_RTX_NAME (o->code),
GET_MODE_NAME (j),
- XSTR (h->libfunc, 0));
+ XSTR (l, 0));
}
}
@@ -6146,24 +6455,22 @@ debug_optab_libfuncs (void)
for (k = 0; k < NUM_MACHINE_MODES; ++k)
{
convert_optab o;
- struct optab_handlers *h;
+ rtx l;
- o = &convert_optab_table[i];
- h = convert_optab_handler(o, j, k);
- if (h->libfunc)
+ o = convert_optab_table[i];
+ l = convert_optab_libfunc (o, j, k);
+ if (l)
{
- gcc_assert (GET_CODE (h->libfunc) == SYMBOL_REF);
+ gcc_assert (GET_CODE (l) == SYMBOL_REF);
fprintf (stderr, "%s\t%s\t%s:\t%s\n",
GET_RTX_NAME (o->code),
GET_MODE_NAME (j),
GET_MODE_NAME (k),
- XSTR (h->libfunc, 0));
+ XSTR (l, 0));
}
}
}
-#endif /* DEBUG */
-
/* Generate insns to trap with code TCODE if OP1 and OP2 satisfy condition
CODE. Return 0 on failure. */
diff --git a/gcc/optabs.h b/gcc/optabs.h
index c5b4a3d..a85b3f3 100644
--- a/gcc/optabs.h
+++ b/gcc/optabs.h
@@ -39,15 +39,17 @@ along with GCC; see the file COPYING3. If not see
A few optabs, such as move_optab and cmp_optab, are used
by special code. */
-struct optab_handlers GTY(())
+struct optab_handlers
{
enum insn_code insn_code;
- rtx libfunc;
};
-struct optab GTY(())
+struct optab
{
enum rtx_code code;
+ const char *libcall_basename;
+ char libcall_suffix;
+ void (*libcall_gen)(struct optab *, const char *name, char suffix, enum machine_mode);
struct optab_handlers handlers[NUM_MACHINE_MODES];
};
typedef struct optab * optab;
@@ -55,9 +57,13 @@ typedef struct optab * optab;
/* A convert_optab is for some sort of conversion operation between
modes. The first array index is the destination mode, the second
is the source mode. */
-struct convert_optab GTY(())
+struct convert_optab
{
enum rtx_code code;
+ const char *libcall_basename;
+ void (*libcall_gen)(struct convert_optab *, const char *name,
+ enum machine_mode,
+ enum machine_mode);
struct optab_handlers handlers[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
};
typedef struct convert_optab *convert_optab;
@@ -324,7 +330,7 @@ enum optab_index
OTI_MAX
};
-extern GTY(()) optab optab_table[OTI_MAX];
+extern optab optab_table[OTI_MAX];
#define add_optab (optab_table[OTI_add])
#define sub_optab (optab_table[OTI_sub])
@@ -498,7 +504,7 @@ enum convert_optab_index
COI_MAX
};
-extern GTY(()) convert_optab convert_optab_table[COI_MAX];
+extern convert_optab convert_optab_table[COI_MAX];
#define sext_optab (convert_optab_table[COI_sext])
#define zext_optab (convert_optab_table[COI_zext])
@@ -521,7 +527,7 @@ extern enum insn_code reload_in_optab[NUM_MACHINE_MODES];
extern enum insn_code reload_out_optab[NUM_MACHINE_MODES];
/* Contains the optab used for each rtx code. */
-extern GTY(()) optab code_to_optab[NUM_RTX_CODE + 1];
+extern optab code_to_optab[NUM_RTX_CODE + 1];
typedef rtx (*rtxfun) (rtx);
@@ -709,4 +715,8 @@ extern rtx expand_vec_shift_expr (tree, rtx);
#define convert_optab_handler(optab,mode,mode2) \
(&(optab)->handlers[(int) (mode)][(int) (mode2)])
+extern rtx optab_libfunc (optab optab, enum machine_mode mode);
+extern rtx optab_libfunc (optab optab, enum machine_mode mode);
+extern rtx convert_optab_libfunc (convert_optab optab, enum machine_mode mode1,
+ enum machine_mode mode2);
#endif /* GCC_OPTABS_H */