From 8a33f10034d5c598395edc4ff0ae56e2bde7577e Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Tue, 4 Sep 2007 16:03:31 +0200 Subject: 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 --- gcc/ChangeLog | 33 +++ gcc/builtins.c | 2 +- gcc/expmed.c | 4 +- gcc/expr.c | 2 +- gcc/optabs.c | 891 ++++++++++++++++++++++++++++++++++++++------------------- gcc/optabs.h | 24 +- 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 + + * 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 * 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 */ -- cgit v1.1