public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Lazy construction of libcalls
@ 2007-08-21 17:13 Jan Hubicka
  2007-08-24 13:44 ` Richard Sandiford
  0 siblings, 1 reply; 13+ messages in thread
From: Jan Hubicka @ 2007-08-21 17:13 UTC (permalink / raw)
  To: gcc-patches

Hi,
at startup we build about 500 libcalls to initialize our optabs, each
with DECL node, RTL representation and pretty sparse array.  This patch
moves libcalls into separate hashtable and initialize them lazily on
demand.  This save most of the DECLs and RTLs and additionally reduces
optables themselves to half and moves them out of GGC memory (the
pointers to generation functions don't need to be there).
Instead of 4.3MB at startup of GGC memory, we now need 1.2MB.
Since clearing up the optab tables actually show up in the profiles, I
expect startup to be also faster, but I accidentally removed original
binary making it dificult to test.

I would also expect it to be easier to move to into RTL in per-functions
obstacks now since optabs can be reinitialized for every functions
easilly too.

While comparing the tables produced by new and old code, I noticed that
"ffs" for SI used to be called "ffssi3" but now it is "ffs".
I believe it was inteded to be called ffs because of:
  optab_handler (ffs_optab, int_mode)->libfunc = init_one_libfunc ("ffs");
that however later get overwriten by initialization code.
Other oddity is that "floatun" is "floatuns" when mode is DECIMAL_FLOAT.
But I guess for comatibility, we don't want to rename it.

If time allows, I would like to now move logic of setting up optabs from
genoptab and optabs.c into single place (optabs.def) and then reorganize
the optab datastructure itself, but I would expect less compile
time/memory benefits from that change than from this one.  On the ohter
hand if we continue to grow in number of machine modes, we should do
this anyway and having def file is nice cleanup.

Bootstrapped/regtested i686-linux, I am also testing PPC and ia64 since
this patch is somewhat architecture specific, OK?

Honza

:ADDPATCH middle-end:

	* 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.
Index: optabs.c
===================================================================
*** optabs.c	(revision 127649)
--- optabs.c	(working copy)
*************** static convert_optab new_convert_optab (
*** 109,121 ****
  static inline optab init_optab (enum rtx_code);
  static inline optab init_optabv (enum rtx_code);
  static inline convert_optab init_convert_optab (enum rtx_code);
- static void init_libfuncs (optab, int, int, const char *, int);
- static void init_integral_libfuncs (optab, const char *, int);
- static void init_floating_libfuncs (optab, const char *, int);
- static void init_interclass_conv_libfuncs (convert_optab, const char *,
- 					   enum mode_class, enum mode_class);
- static void init_intraclass_conv_libfuncs (convert_optab, const char *,
- 					   enum mode_class, bool);
  static void emit_cmp_and_jump_insn_1 (rtx, rtx, enum machine_mode,
  				      enum rtx_code, int, rtx);
  static void prepare_float_lib_cmp (rtx *, rtx *, enum rtx_code *,
--- 109,114 ----
*************** static rtx vector_compare_rtx (tree, boo
*** 131,136 ****
--- 124,132 ----
     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)
*************** static HOST_WIDE_INT libcall_id = 0;
*** 142,147 ****
--- 138,241 ----
  #else
  #define DECIMAL_PREFIX "dpd_"
  #endif
+ \f
+ 
+ /* 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;
+ }
  
  \f
  /* Add a REG_EQUAL note to the last insn in INSNS.  TARGET is being set to
*************** expand_binop (enum machine_mode mode, op
*** 1375,1380 ****
--- 1469,1475 ----
    enum mode_class class;
    enum machine_mode wider_mode;
    rtx temp;
+   rtx libfunc;
    int commutative_op = 0;
    int shift_op = (binoptab->code == ASHIFT
  		  || binoptab->code == ASHIFTRT
*************** expand_binop (enum machine_mode mode, op
*** 1970,1976 ****
    /* 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
        && (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN))
      {
        rtx insns;
--- 2065,2072 ----
    /* It can't be open-coded in this mode.
       Use a library call if one is available and caller says that's ok.  */
  
!   libfunc = optab_libfunc (binoptab, mode);
!   if (libfunc
        && (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN))
      {
        rtx insns;
*************** expand_binop (enum machine_mode mode, op
*** 1994,2000 ****
  
        /* 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,
  				       NULL_RTX, LCT_CONST, mode, 2,
  				       op0, mode, op1x, op1_mode);
  
--- 2090,2096 ----
  
        /* 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 (libfunc,
  				       NULL_RTX, LCT_CONST, mode, 2,
  				       op0, mode, op1x, op1_mode);
  
*************** expand_binop (enum machine_mode mode, op
*** 2037,2043 ****
  	  if ((optab_handler (binoptab, wider_mode)->insn_code
  	       != CODE_FOR_nothing)
  	      || (methods == OPTAB_LIB
! 		  && optab_handler (binoptab, wider_mode)->libfunc))
  	    {
  	      rtx xop0 = op0, xop1 = op1;
  	      int no_extend = 0;
--- 2133,2139 ----
  	  if ((optab_handler (binoptab, wider_mode)->insn_code
  	       != CODE_FOR_nothing)
  	      || (methods == OPTAB_LIB
! 		  && optab_libfunc (binoptab, wider_mode)))
  	    {
  	      rtx xop0 = op0, xop1 = op1;
  	      int no_extend = 0;
*************** sign_expand_binop (enum machine_mode mod
*** 2112,2118 ****
       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);
--- 2208,2214 ----
       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);
*************** expand_twoval_binop_libfunc (optab binop
*** 2374,2385 ****
    enum machine_mode libval_mode;
    rtx libval;
    rtx insns;
  
    /* Exactly one of TARG0 or TARG1 should be non-NULL.  */
    gcc_assert (!targ0 != !targ1);
  
    mode = GET_MODE (op0);
!   if (!optab_handler (binoptab, mode)->libfunc)
      return false;
  
    /* The value returned by the library function will have twice as
--- 2470,2483 ----
    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);
!   libfunc = optab_libfunc (binoptab, mode);
!   if (!libfunc)
      return false;
  
    /* The value returned by the library function will have twice as
*************** expand_twoval_binop_libfunc (optab binop
*** 2387,2394 ****
    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_mode, 2,
  				    op0, mode,
  				    op1, mode);
--- 2485,2491 ----
    libval_mode = smallest_mode_for_size (2 * GET_MODE_BITSIZE (mode),
  					MODE_INT);
    start_sequence ();
!   libval = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
  				    libval_mode, 2,
  				    op0, mode,
  				    op1, mode);
*************** expand_unop (enum machine_mode mode, opt
*** 2770,2775 ****
--- 2867,2873 ----
    rtx temp;
    rtx last = get_last_insn ();
    rtx pat;
+   rtx libfunc;
  
    class = GET_MODE_CLASS (mode);
  
*************** expand_unop (enum machine_mode mode, opt
*** 2968,2974 ****
  
   try_libcall:
    /* Now try a library call in this mode.  */
!   if (optab_handler (unoptab, mode)->libfunc)
      {
        rtx insns;
        rtx value;
--- 3066,3073 ----
  
   try_libcall:
    /* Now try a library call in this mode.  */
!   libfunc = optab_libfunc (unoptab, mode);
!   if (libfunc)
      {
        rtx insns;
        rtx value;
*************** expand_unop (enum machine_mode mode, opt
*** 2985,2992 ****
  
        /* 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,
  				       1, op0, mode);
        insns = get_insns ();
        end_sequence ();
--- 3084,3090 ----
  
        /* 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 (libfunc, NULL_RTX, LCT_CONST, outmode,
  				       1, op0, mode);
        insns = get_insns ();
        end_sequence ();
*************** expand_unop (enum machine_mode mode, opt
*** 3008,3014 ****
  	{
  	  if ((optab_handler (unoptab, wider_mode)->insn_code
  	       != CODE_FOR_nothing)
! 	      || optab_handler (unoptab, wider_mode)->libfunc)
  	    {
  	      rtx xop0 = op0;
  
--- 3106,3112 ----
  	{
  	  if ((optab_handler (unoptab, wider_mode)->insn_code
  	       != CODE_FOR_nothing)
! 	      || optab_libfunc (unoptab, wider_mode))
  	    {
  	      rtx xop0 = op0;
  
*************** prepare_cmp_insn (rtx *px, rtx *py, enum
*** 3890,3895 ****
--- 3988,3994 ----
    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.  */
*************** prepare_cmp_insn (rtx *px, rtx *py, enum
*** 3994,4008 ****
  
    /* Handle a lib call just for the mode we are using.  */
  
!   if (optab_handler (cmp_optab, mode)->libfunc && !SCALAR_FLOAT_MODE_P (mode))
      {
-       rtx libfunc = optab_handler (cmp_optab, mode)->libfunc;
        rtx result;
  
        /* 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;
  
        result = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST_MAKE_BLOCK,
  					targetm.libgcc_cmp_return_mode (),
--- 4093,4112 ----
  
    /* Handle a lib call just for the mode we are using.  */
  
!   libfunc = optab_libfunc (cmp_optab, mode);
!   if (libfunc && !SCALAR_FLOAT_MODE_P (mode))
      {
        rtx result;
+       rtx ulibfunc;
  
        /* If we want unsigned, and this mode has a distinct unsigned
  	 comparison routine, use that.  */
!       if (unsignedp)
! 	{
! 	  ulibfunc = optab_libfunc (ucmp_optab, mode);
! 	}
!       if (unsignedp && ulibfunc)
! 	libfunc = ulibfunc;
  
        result = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST_MAKE_BLOCK,
  					targetm.libgcc_cmp_return_mode (),
*************** prepare_float_lib_cmp (rtx *px, rtx *py,
*** 4206,4215 ****
         mode != VOIDmode;
         mode = GET_MODE_WIDER_MODE (mode))
      {
!       if ((libfunc = optab_handler (code_to_optab[comparison], mode)->libfunc))
  	break;
  
!       if ((libfunc = optab_handler (code_to_optab[swapped], mode)->libfunc))
  	{
  	  rtx tmp;
  	  tmp = x; x = y; y = tmp;
--- 4310,4319 ----
         mode != VOIDmode;
         mode = GET_MODE_WIDER_MODE (mode))
      {
!       if ((libfunc = optab_libfunc (code_to_optab[comparison], mode)))
  	break;
  
!       if ((libfunc = optab_libfunc (code_to_optab[swapped] , mode)))
  	{
  	  rtx tmp;
  	  tmp = x; x = y; y = tmp;
*************** prepare_float_lib_cmp (rtx *px, rtx *py,
*** 4217,4223 ****
  	  break;
  	}
  
!       if ((libfunc = optab_handler (code_to_optab[reversed], mode)->libfunc)
  	  && FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, reversed))
  	{
  	  comparison = reversed;
--- 4321,4327 ----
  	  break;
  	}
  
!       if ((libfunc = optab_libfunc (code_to_optab[reversed], mode))
  	  && FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, reversed))
  	{
  	  comparison = reversed;
*************** gen_add2_insn (rtx x, rtx y)
*** 4586,4591 ****
--- 4690,4696 ----
  
  /* 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)
  {
*************** gen_sub2_insn (rtx x, rtx y)
*** 4645,4650 ****
--- 4750,4756 ----
  
  /* 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)
  {
*************** expand_float (rtx to, rtx from, int unsi
*** 4955,4962 ****
        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;
        gcc_assert (libfunc);
  
        start_sequence ();
--- 5061,5067 ----
        if (GET_MODE_SIZE (GET_MODE (from)) < GET_MODE_SIZE (SImode))
  	from = convert_to_mode (SImode, from, unsignedp);
  
!       libfunc = convert_optab_libfunc (tab, GET_MODE (to), GET_MODE (from));
        gcc_assert (libfunc);
  
        start_sequence ();
*************** expand_fix (rtx to, rtx from, int unsign
*** 5136,5143 ****
        rtx libfunc;
  
        convert_optab tab = unsignedp ? ufix_optab : sfix_optab;
!       libfunc = convert_optab_handler (tab, GET_MODE (to),
! 				       GET_MODE (from))->libfunc;
        gcc_assert (libfunc);
  
        start_sequence ();
--- 5241,5247 ----
        rtx libfunc;
  
        convert_optab tab = unsignedp ? ufix_optab : sfix_optab;
!       libfunc = convert_optab_libfunc (tab, GET_MODE (to), GET_MODE (from));
        gcc_assert (libfunc);
  
        start_sequence ();
*************** static optab
*** 5217,5228 ****
  new_optab (void)
  {
    int i;
!   optab op = ggc_alloc (sizeof (struct optab));
    for (i = 0; i < NUM_MACHINE_MODES; i++)
!     {
!       optab_handler (op, i)->insn_code = CODE_FOR_nothing;
!       optab_handler (op, i)->libfunc = 0;
!     }
  
    return op;
  }
--- 5321,5330 ----
  new_optab (void)
  {
    int i;
!   optab op = xcalloc (sizeof (struct optab), 1);
! 
    for (i = 0; i < NUM_MACHINE_MODES; i++)
!     optab_handler (op, i)->insn_code = CODE_FOR_nothing;
  
    return op;
  }
*************** static convert_optab
*** 5231,5243 ****
  new_convert_optab (void)
  {
    int i, j;
!   convert_optab op = ggc_alloc (sizeof (struct convert_optab));
    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;
!       }
    return op;
  }
  
--- 5333,5344 ----
  new_convert_optab (void)
  {
    int i, j;
!   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;
! 
    return op;
  }
  
*************** init_convert_optab (enum rtx_code code)
*** 5279,5358 ****
     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.
  */
  
  static void
! init_libfuncs (optab optable, int first_mode, int last_mode,
! 	       const char *opname, int suffix)
  {
-   int mode;
    unsigned opname_len = strlen (opname);
  
!   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));
!     }
  }
  
! /* 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).  */
  
  static void
! init_integral_libfuncs (optab optable, const char *opname, int suffix)
  {
!   int maxsize = 2*BITS_PER_WORD;
    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);
  }
  
! /* 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).  */
  
  static void
! init_floating_libfuncs (optab optable, const char *opname, int suffix)
  {
!   char *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);
! 
!   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);
  }
  
  /* Initialize the libfunc fields of an entire group of entries of an
--- 5380,5484 ----
     usually one of the characters '2', '3', or '4').
  
     OPTABLE is the table in which libfunc fields are to be initialized.
     OPNAME is the generic (string) name of the operation.
     SUFFIX is the character which specifies the number of operands for
       the given generic operation.
+    MODE is the mode to generate for.
  */
  
  static void
! gen_libfunc (optab optable, const char *opname, int suffix, enum machine_mode mode)
  {
    unsigned opname_len = strlen (opname);
+   const char *mname = GET_MODE_NAME (mode);
+   unsigned mname_len = strlen (mname);
+   char *libfunc_name = 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';
  
!   set_optab_libfunc (optable, mode,
! 		     ggc_alloc_string (libfunc_name, p - libfunc_name));
  }
  
! /* Like gen_libfunc, but verify that integer operation is involved.  */
  
  static void
! gen_int_libfunc (optab optable, const char *opname, char suffix,
! 		 enum machine_mode mode)
  {
!   int maxsize = 2 * BITS_PER_WORD;
! 
!   if (GET_MODE_CLASS (mode) != MODE_INT)
!     return;
    if (maxsize < LONG_LONG_TYPE_SIZE)
      maxsize = LONG_LONG_TYPE_SIZE;
!   if (GET_MODE_CLASS (mode) != MODE_INT
!       || mode < word_mode || GET_MODE_BITSIZE (mode) > maxsize)
!     return;
!   gen_libfunc (optable, opname, suffix, mode);
  }
  
! /* Like gen_libfunc, but verify that FP and set decimal prefix if needed.  */
  
  static void
! gen_fp_libfunc (optab optable, const char *opname, char suffix,
! 		enum machine_mode mode)
  {
!   char *dec_opname;
  
!   if (GET_MODE_CLASS (mode) == MODE_FLOAT)
!     gen_libfunc (optable, opname, suffix, mode);
!   if (DECIMAL_FLOAT_MODE_P (mode))
!     {
!       dec_opname = 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
! gen_int_fp_libfunc (optab optable, const char *name, char suffix,
! 		    enum machine_mode mode)
! {
!   if (DECIMAL_FLOAT_MODE_P (mode) || GET_MODE_CLASS (mode) == MODE_FLOAT)
!     gen_fp_libfunc (optable, name, suffix, mode);
!   if (INTEGRAL_MODE_P (mode))
!     gen_int_libfunc (optable, name, suffix, mode);
! }
! 
! /* Like gen_libfunc, but verify that FP or INT operation is involved
!    and add 'v' suffix for integer operation.  */
! 
! static void
! gen_intv_fp_libfunc (optab optable, const char *name, char suffix,
! 		     enum machine_mode mode)
! {
!   if (DECIMAL_FLOAT_MODE_P (mode) || GET_MODE_CLASS (mode) == MODE_FLOAT)
!     gen_fp_libfunc (optable, name, suffix, mode);
!   if (GET_MODE_CLASS (mode) == MODE_INT)
!     {
!       int len = strlen (name);
!       char *v_name = 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
*************** init_floating_libfuncs (optab optable, c
*** 5360,5376 ****
     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)
  {
-   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;
  
-   enum machine_mode fmode, tmode;
    const char *fname, *tname;
    const char *q;
    char *libfunc_name, *suffix;
--- 5486,5501 ----
     similar to the ones for init_libfuncs, above, but instead of having
     a mode name and an operand count these functions have two mode names
     and no operand count.  */
+ 
  static void
! gen_interclass_conv_libfunc (convert_optab tab,
! 			     const char *opname,
! 			     enum machine_mode tmode,
! 			     enum machine_mode fmode)
  {
    size_t opname_len = strlen (opname);
!   size_t mname_len = 0;
  
    const char *fname, *tname;
    const char *q;
    char *libfunc_name, *suffix;
*************** init_interclass_conv_libfuncs (convert_o
*** 5381,5457 ****
       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)));
  
!   nondec_name = alloca (2 + opname_len + 2*max_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[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);
  
! 	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 = '\0';
! 
! 	convert_optab_handler (tab, tmode, fmode)->libfunc
! 	  = init_one_libfunc (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.  */
  static void
! init_intraclass_conv_libfuncs (convert_optab tab, const char *opname,
! 			       enum mode_class class, bool widening)
  {
-   enum machine_mode first_mode = GET_CLASS_NARROWEST_MODE (class);
    size_t opname_len = strlen (opname);
!   size_t max_mname_len = 0;
  
!   enum machine_mode nmode, wmode;
!   const char *nname, *wname;
    const char *q;
    char *nondec_name, *dec_name, *nondec_suffix, *dec_suffix;
    char *libfunc_name, *suffix;
--- 5506,5627 ----
       depends on which underlying decimal floating point format is used.  */
    const size_t dec_len = sizeof (DECIMAL_PREFIX) - 1;
  
!   mname_len = strlen (GET_MODE_NAME (tmode)) + strlen (GET_MODE_NAME (fmode));
  
!   nondec_name = 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 + 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;
  
!   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;
!     }
  
!   p = suffix;
!   for (q = fname; *q; p++, q++)
!     *p = TOLOWER (*q);
!   for (q = tname; *q; p++, q++)
!     *p = TOLOWER (*q);
! 
!   *p = '\0';
! 
!   set_conv_libfunc (tab, tmode, fmode,
! 		    ggc_alloc_string (libfunc_name, p - libfunc_name));
  }
  
! /* 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
! 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)
  {
    size_t opname_len = strlen (opname);
!   size_t mname_len = 0;
  
!   const char *fname, *tname;
    const char *q;
    char *nondec_name, *dec_name, *nondec_suffix, *dec_suffix;
    char *libfunc_name, *suffix;
*************** init_intraclass_conv_libfuncs (convert_o
*** 5461,5518 ****
       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)));
  
!   nondec_name = alloca (2 + opname_len + 2*max_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[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);
  
! 	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;
! 	  }
  
! 	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++ = '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));
!       }
  }
  
  
  rtx
  init_one_libfunc (const char *name)
--- 5631,5735 ----
       depends on which underlying decimal floating point format is used.  */
    const size_t dec_len = sizeof (DECIMAL_PREFIX) - 1;
  
!   mname_len = strlen (GET_MODE_NAME (tmode)) + strlen (GET_MODE_NAME (fmode));
  
!   nondec_name = 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 + 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;
  
!   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;
!     }
  
!   p = suffix;
!   for (q = fname; *q; p++, q++)
!     *p = TOLOWER (*q);
!   for (q = tname; *q; p++, q++)
!     *p = TOLOWER (*q);
! 
!   *p++ = '2';
!   *p = '\0';
! 
!   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)
*************** init_one_libfunc (const char *name)
*** 5543,5552 ****
  void
  set_optab_libfunc (optab optable, enum machine_mode mode, const char *name)
  {
    if (name)
!     optab_handler (optable, mode)->libfunc = init_one_libfunc (name);
    else
!     optab_handler (optable, mode)->libfunc = 0;
  }
  
  /* Call this to reset the function entry for one conversion optab
--- 5760,5783 ----
  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)
!     val = init_one_libfunc (name);
    else
!     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
*************** void
*** 5556,5566 ****
  set_conv_libfunc (convert_optab optable, enum machine_mode tmode,
  		  enum machine_mode fmode, const char *name)
  {
    if (name)
!     convert_optab_handler (optable, tmode, fmode)->libfunc
!       = init_one_libfunc (name);
    else
!     convert_optab_handler (optable, tmode, fmode)->libfunc = 0;
  }
  
  /* Call this once to initialize the contents of the optabs
--- 5787,5810 ----
  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)
!     val = init_one_libfunc (name);
    else
!     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 once to initialize the contents of the optabs
*************** init_optabs (void)
*** 5572,5577 ****
--- 5816,5822 ----
    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++)
*************** init_optabs (void)
*** 5794,5900 ****
    /* 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');
  
    /* 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');
  
    /* 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');
  
    /* 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);
  
    /* Explicitly initialize the bswap libfuncs since we need them to be
       valid for things other than word_mode.  */
--- 6039,6203 ----
    /* 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);
!   set_optab_libfunc (ffs_optab, mode_for_size (INT_TYPE_SIZE, MODE_INT, 0),
! 		     "ffs");
  
    /* Initialize the optabs with the names of the library functions.  */
!   add_optab->libcall_basename = "add";
!   add_optab->libcall_suffix = '3';
!   add_optab->libcall_gen = gen_int_fp_libfunc;
!   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.  */
!   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.  */
!   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.  */
!   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;
  
    /* Explicitly initialize the bswap libfuncs since we need them to be
       valid for things other than word_mode.  */
*************** init_optabs (void)
*** 5904,5911 ****
    /* 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");
  
    abort_libfunc = init_one_libfunc ("abort");
    memcpy_libfunc = init_one_libfunc ("memcpy");
--- 6207,6213 ----
    /* 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)
!     set_optab_libfunc (abs_optab, TYPE_MODE (complex_double_type_node), "cabs");
  
    abort_libfunc = init_one_libfunc ("abort");
    memcpy_libfunc = init_one_libfunc ("memcpy");
*************** init_optabs (void)
*** 5940,5951 ****
    targetm.init_libfuncs ();
  }
  
- #ifdef DEBUG
- 
  /* Print information about the current contents of the optabs on
     STDERR.  */
  
! static void
  debug_optab_libfuncs (void)
  {
    int i;
--- 6242,6251 ----
    targetm.init_libfuncs ();
  }
  
  /* Print information about the current contents of the optabs on
     STDERR.  */
  
! void
  debug_optab_libfuncs (void)
  {
    int i;
*************** debug_optab_libfuncs (void)
*** 5957,5973 ****
      for (j = 0; j < NUM_MACHINE_MODES; ++j)
        {
  	optab o;
! 	struct optab_handlers *h;
  
  	o = optab_table[i];
! 	h = optab_handler (o, j);
! 	if (h->libfunc)
  	  {
! 	    gcc_assert (GET_CODE (h->libfunc) == SYMBOL_REF);
  	    fprintf (stderr, "%s\t%s:\t%s\n",
  		     GET_RTX_NAME (o->code),
  		     GET_MODE_NAME (j),
! 		     XSTR (h->libfunc, 0));
  	  }
        }
  
--- 6257,6273 ----
      for (j = 0; j < NUM_MACHINE_MODES; ++j)
        {
  	optab o;
! 	rtx l;
  
  	o = optab_table[i];
! 	l = optab_libfunc (optab_table[i], j);
! 	if (l)
  	  {
! 	    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 (l, 0));
  	  }
        }
  
*************** debug_optab_libfuncs (void)
*** 5977,6000 ****
        for (k = 0; k < NUM_MACHINE_MODES; ++k)
  	{
  	  convert_optab o;
! 	  struct optab_handlers *h;
  
! 	  o = &convert_optab_table[i];
! 	  h = convert_optab_handler(o, j, k);
! 	  if (h->libfunc)
  	    {
! 	      gcc_assert (GET_CODE (h->libfunc) == 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));
  	    }
  	}
  }
  
- #endif /* DEBUG */
- 
  \f
  /* Generate insns to trap with code TCODE if OP1 and OP2 satisfy condition
     CODE.  Return 0 on failure.  */
--- 6277,6298 ----
        for (k = 0; k < NUM_MACHINE_MODES; ++k)
  	{
  	  convert_optab o;
! 	  rtx l;
  
! 	  o = convert_optab_table[i];
! 	  l = convert_optab_libfunc (o, j, k);
! 	  if (l)
  	    {
! 	      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 (l, 0));
  	    }
  	}
  }
  
  \f
  /* Generate insns to trap with code TCODE if OP1 and OP2 satisfy condition
     CODE.  Return 0 on failure.  */
Index: optabs.h
===================================================================
*** optabs.h	(revision 127649)
--- optabs.h	(working copy)
*************** along with GCC; see the file COPYING3.  
*** 39,53 ****
     A few optabs, such as move_optab and cmp_optab, are used
     by special code.  */
  
! struct optab_handlers GTY(())
  {
    enum insn_code insn_code;
-   rtx libfunc;
  };
  
! struct optab GTY(())
  {
    enum rtx_code code;
    struct optab_handlers handlers[NUM_MACHINE_MODES];
  };
  typedef struct optab * optab;
--- 39,55 ----
     A few optabs, such as move_optab and cmp_optab, are used
     by special code.  */
  
! struct optab_handlers
  {
    enum insn_code insn_code;
  };
  
! 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;
*************** typedef struct optab * optab;
*** 55,63 ****
  /* 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(())
  {
    enum rtx_code code;
    struct optab_handlers handlers[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
  };
  typedef struct convert_optab *convert_optab;
--- 57,69 ----
  /* 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
  {
    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;
*************** enum optab_index
*** 324,330 ****
    OTI_MAX
  };
  
! extern GTY(()) optab optab_table[OTI_MAX];
  
  #define add_optab (optab_table[OTI_add])
  #define sub_optab (optab_table[OTI_sub])
--- 330,336 ----
    OTI_MAX
  };
  
! extern optab optab_table[OTI_MAX];
  
  #define add_optab (optab_table[OTI_add])
  #define sub_optab (optab_table[OTI_sub])
*************** enum convert_optab_index
*** 498,504 ****
    COI_MAX
  };
  
! extern GTY(()) convert_optab convert_optab_table[COI_MAX];
  
  #define sext_optab (convert_optab_table[COI_sext])
  #define zext_optab (convert_optab_table[COI_zext])
--- 504,510 ----
    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])
*************** extern enum insn_code reload_in_optab[NU
*** 521,527 ****
  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];
  
  \f
  typedef rtx (*rtxfun) (rtx);
--- 527,533 ----
  extern enum insn_code reload_out_optab[NUM_MACHINE_MODES];
  
  /* Contains the optab used for each rtx code.  */
! extern optab code_to_optab[NUM_RTX_CODE + 1];
  
  \f
  typedef rtx (*rtxfun) (rtx);
*************** extern rtx expand_vec_shift_expr (tree, 
*** 709,712 ****
--- 715,722 ----
  #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 */
Index: builtins.c
===================================================================
*** builtins.c	(revision 127649)
--- builtins.c	(working copy)
*************** expand_builtin_powi (tree exp, rtx targe
*** 3100,3106 ****
    if (GET_MODE (op1) != mode2)
      op1 = convert_to_mode (mode2, op1, 0);
  
!   target = emit_library_call_value (optab_handler (powi_optab, mode)->libfunc,
  				    target, LCT_CONST_MAKE_BLOCK, mode, 2,
  				    op0, mode, op1, mode2);
  
--- 3100,3106 ----
    if (GET_MODE (op1) != mode2)
      op1 = convert_to_mode (mode2, op1, 0);
  
!   target = emit_library_call_value (optab_libfunc (powi_optab, mode),
  				    target, LCT_CONST_MAKE_BLOCK, mode, 2,
  				    op0, mode, op1, mode2);
  
Index: expr.c
===================================================================
*** expr.c	(revision 127649)
--- expr.c	(working copy)
*************** convert_move (rtx to, rtx from, int unsi
*** 435,441 ****
  	}
  
        /* Otherwise use a libcall.  */
!       libcall = convert_optab_handler (tab, to_mode, from_mode)->libfunc;
  
        /* Is this conversion implemented yet?  */
        gcc_assert (libcall);
--- 435,441 ----
  	}
  
        /* Otherwise use a libcall.  */
!       libcall = convert_optab_libfunc (tab, to_mode, from_mode);
  
        /* Is this conversion implemented yet?  */
        gcc_assert (libcall);
Index: expmed.c
===================================================================
*** expmed.c	(revision 127649)
--- expmed.c	(working copy)
*************** expand_divmod (int rem_flag, enum tree_c
*** 3886,3893 ****
    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)
  	break;
  
    /* If we still couldn't find a mode, use MODE, but expand_binop will
--- 3886,3893 ----
    if (compute_mode == VOIDmode)
      for (compute_mode = mode; compute_mode != VOIDmode;
  	 compute_mode = GET_MODE_WIDER_MODE (compute_mode))
!       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

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Lazy construction of libcalls
  2007-08-21 17:13 Lazy construction of libcalls Jan Hubicka
@ 2007-08-24 13:44 ` Richard Sandiford
  2007-08-24 14:23   ` Jan Hubicka
  2007-08-24 14:43   ` Jan Hubicka
  0 siblings, 2 replies; 13+ messages in thread
From: Richard Sandiford @ 2007-08-24 13:44 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: gcc-patches

Jan Hubicka <jh@suse.cz> writes:
> While comparing the tables produced by new and old code, I noticed that
> "ffs" for SI used to be called "ffssi3" but now it is "ffs".
> I believe it was inteded to be called ffs because of:
>   optab_handler (ffs_optab, int_mode)->libfunc = init_one_libfunc ("ffs");
> that however later get overwriten by initialization code.

Actually, this was deliberate.  All libgccs have word and doubleword
ffs functions, but not all C libraries have "ffs".  So we wanted the
libgcc versions to take precedence over the C library fallback.  See:

    http://gcc.gnu.org/ml/gcc-patches/2007-04/msg01165.html

for details.

Richard

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Lazy construction of libcalls
  2007-08-24 13:44 ` Richard Sandiford
@ 2007-08-24 14:23   ` Jan Hubicka
  2007-08-24 14:46     ` Richard Sandiford
  2007-08-24 14:43   ` Jan Hubicka
  1 sibling, 1 reply; 13+ messages in thread
From: Jan Hubicka @ 2007-08-24 14:23 UTC (permalink / raw)
  To: Jan Hubicka, gcc-patches, richard

> Jan Hubicka <jh@suse.cz> writes:
> > While comparing the tables produced by new and old code, I noticed that
> > "ffs" for SI used to be called "ffssi3" but now it is "ffs".
> > I believe it was inteded to be called ffs because of:
> >   optab_handler (ffs_optab, int_mode)->libfunc = init_one_libfunc ("ffs");
> > that however later get overwriten by initialization code.
> 
> Actually, this was deliberate.  All libgccs have word and doubleword
> ffs functions, but not all C libraries have "ffs".  So we wanted the
> libgcc versions to take precedence over the C library fallback.  See:
> 
>     http://gcc.gnu.org/ml/gcc-patches/2007-04/msg01165.html
> 
> for details.

OK, so the initialization of libgcc always overwrite the ffs
initialization, so simply removing the line above would work?
Why it was kept around at first place?

Honza
> 
> Richard

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Lazy construction of libcalls
  2007-08-24 13:44 ` Richard Sandiford
  2007-08-24 14:23   ` Jan Hubicka
@ 2007-08-24 14:43   ` Jan Hubicka
  1 sibling, 0 replies; 13+ messages in thread
From: Jan Hubicka @ 2007-08-24 14:43 UTC (permalink / raw)
  To: Jan Hubicka, gcc-patches, richard

Hi,
also I should add that I've benchmarked the patch now.  100 compilations
of empty function comes from 5.2s to 4.1s.  I am rather surprised by the
savings, especially by fact that they come from kernel time in oprofile.
Perhaps it is because our mmap strategy on GGC memory is not too
effective when GGC pool is small?  I will look into this later, just
wanted to mention.

Honza

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Lazy construction of libcalls
  2007-08-24 14:23   ` Jan Hubicka
@ 2007-08-24 14:46     ` Richard Sandiford
  2007-09-04  8:16       ` Jan Hubicka
  0 siblings, 1 reply; 13+ messages in thread
From: Richard Sandiford @ 2007-08-24 14:46 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: gcc-patches

Jan Hubicka <jh@suse.cz> writes:
>> Jan Hubicka <jh@suse.cz> writes:
>> > While comparing the tables produced by new and old code, I noticed that
>> > "ffs" for SI used to be called "ffssi3" but now it is "ffs".
>> > I believe it was inteded to be called ffs because of:
>> >   optab_handler (ffs_optab, int_mode)->libfunc = init_one_libfunc ("ffs");
>> > that however later get overwriten by initialization code.
>> 
>> Actually, this was deliberate.  All libgccs have word and doubleword
>> ffs functions, but not all C libraries have "ffs".  So we wanted the
>> libgcc versions to take precedence over the C library fallback.  See:
>> 
>>     http://gcc.gnu.org/ml/gcc-patches/2007-04/msg01165.html
>> 
>> for details.
>
> OK, so the initialization of libgcc always overwrite the ffs
> initialization, so simply removing the line above would work?

Not for 64-bit targets with a 32-bit int, since __builtin_ffs() takes
an int argument.  We could of course add an SImode libgcc function for
those targets, but the patch above was just supposed to make better
use of what we already had.

Richard

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Lazy construction of libcalls
  2007-08-24 14:46     ` Richard Sandiford
@ 2007-09-04  8:16       ` Jan Hubicka
  2007-09-04  8:28         ` Richard Guenther
  2007-09-08 12:44         ` Lazy construction of libcalls Andrew Haley
  0 siblings, 2 replies; 13+ messages in thread
From: Jan Hubicka @ 2007-09-04  8:16 UTC (permalink / raw)
  To: Jan Hubicka, gcc-patches, richard

> Jan Hubicka <jh@suse.cz> writes:
> >> Jan Hubicka <jh@suse.cz> writes:
> >> > While comparing the tables produced by new and old code, I noticed that
> >> > "ffs" for SI used to be called "ffssi3" but now it is "ffs".
> >> > I believe it was inteded to be called ffs because of:
> >> >   optab_handler (ffs_optab, int_mode)->libfunc = init_one_libfunc ("ffs");
> >> > that however later get overwriten by initialization code.
> >> 
> >> Actually, this was deliberate.  All libgccs have word and doubleword
> >> ffs functions, but not all C libraries have "ffs".  So we wanted the
> >> libgcc versions to take precedence over the C library fallback.  See:
> >> 
> >>     http://gcc.gnu.org/ml/gcc-patches/2007-04/msg01165.html
> >> 
> >> for details.
> >
> > OK, so the initialization of libgcc always overwrite the ffs
> > initialization, so simply removing the line above would work?
> 
> Not for 64-bit targets with a 32-bit int, since __builtin_ffs() takes
> an int argument.  We could of course add an SImode libgcc function for
> those targets, but the patch above was just supposed to make better
> use of what we already had.

Thanks for explanation - I've now added a guard 
if (INT_TYPE_SIZE < BITS_PER_WORD)
into my local copy that should do what described again. I am re-testing now,
OK with that change?

Honza
> 
> Richard

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Lazy construction of libcalls
  2007-09-04  8:16       ` Jan Hubicka
@ 2007-09-04  8:28         ` Richard Guenther
  2007-09-19  6:50           ` Kaveh R. GHAZI
  2007-09-08 12:44         ` Lazy construction of libcalls Andrew Haley
  1 sibling, 1 reply; 13+ messages in thread
From: Richard Guenther @ 2007-09-04  8:28 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: Jan Hubicka, gcc-patches, richard

On 9/4/07, Jan Hubicka <hubicka@ucw.cz> wrote:
> > Jan Hubicka <jh@suse.cz> writes:
> > >> Jan Hubicka <jh@suse.cz> writes:
> > >> > While comparing the tables produced by new and old code, I noticed that
> > >> > "ffs" for SI used to be called "ffssi3" but now it is "ffs".
> > >> > I believe it was inteded to be called ffs because of:
> > >> >   optab_handler (ffs_optab, int_mode)->libfunc = init_one_libfunc ("ffs");
> > >> > that however later get overwriten by initialization code.
> > >>
> > >> Actually, this was deliberate.  All libgccs have word and doubleword
> > >> ffs functions, but not all C libraries have "ffs".  So we wanted the
> > >> libgcc versions to take precedence over the C library fallback.  See:
> > >>
> > >>     http://gcc.gnu.org/ml/gcc-patches/2007-04/msg01165.html
> > >>
> > >> for details.
> > >
> > > OK, so the initialization of libgcc always overwrite the ffs
> > > initialization, so simply removing the line above would work?
> >
> > Not for 64-bit targets with a 32-bit int, since __builtin_ffs() takes
> > an int argument.  We could of course add an SImode libgcc function for
> > those targets, but the patch above was just supposed to make better
> > use of what we already had.
>
> Thanks for explanation - I've now added a guard
> if (INT_TYPE_SIZE < BITS_PER_WORD)
> into my local copy that should do what described again. I am re-testing now,
> OK with that change?

Ok.

Thanks,
Richard.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Lazy construction of libcalls
  2007-09-04  8:16       ` Jan Hubicka
  2007-09-04  8:28         ` Richard Guenther
@ 2007-09-08 12:44         ` Andrew Haley
  2007-09-08 16:28           ` Jan Hubicka
  1 sibling, 1 reply; 13+ messages in thread
From: Andrew Haley @ 2007-09-08 12:44 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: Jan Hubicka, gcc-patches, richard

Jan Hubicka writes:
 > > Jan Hubicka <jh@suse.cz> writes:
 > > >> Jan Hubicka <jh@suse.cz> writes:
 > > >> > While comparing the tables produced by new and old code, I noticed that
 > > >> > "ffs" for SI used to be called "ffssi3" but now it is "ffs".
 > > >> > I believe it was inteded to be called ffs because of:
 > > >> >   optab_handler (ffs_optab, int_mode)->libfunc = init_one_libfunc ("ffs");
 > > >> > that however later get overwriten by initialization code.
 > > >> 
 > > >> Actually, this was deliberate.  All libgccs have word and doubleword
 > > >> ffs functions, but not all C libraries have "ffs".  So we wanted the
 > > >> libgcc versions to take precedence over the C library fallback.  See:
 > > >> 
 > > >>     http://gcc.gnu.org/ml/gcc-patches/2007-04/msg01165.html
 > > >> 
 > > >> for details.
 > > >
 > > > OK, so the initialization of libgcc always overwrite the ffs
 > > > initialization, so simply removing the line above would work?
 > > 
 > > Not for 64-bit targets with a 32-bit int, since __builtin_ffs() takes
 > > an int argument.  We could of course add an SImode libgcc function for
 > > those targets, but the patch above was just supposed to make better
 > > use of what we already had.
 > 
 > Thanks for explanation - I've now added a guard 
 > if (INT_TYPE_SIZE < BITS_PER_WORD)
 > into my local copy that should do what described again. I am re-testing now,
 > OK with that change?

This breaks ARM EABI.  The symptom is that we generate signed instead
of unsigned libcalls for a % b where a and b are usigned ints.

The problem is here in sign_expand_binop(), where we generate a fake
optab:

  /* Try widening to a signed int.  Make a fake signed optab that
     hides any signed insn for direct use.  */
  wide_soptab = *soptab;
  optab_handler (&wide_soptab, mode)->insn_code = CODE_FOR_nothing;
 
We later call expand_binop (mode, &wide_soptab ...  which in turn
calls optab_libfunc (binoptab, mode) which calls optab->libcall_gen()
and inserts the fake optab into the hash table.  This means that the
hash table ->optab points into the stack.  We don't want to do this,
I'm sure.

I suspect the easiest way to fix this is by setting libcall_gen to
NULL in the fake optab.

Andrew.


2007-09-08  Andrew Haley  <aph@redhat.com>

        * optabs.c (sign_expand_binop): Set libcall_gen = NULL in the fake
        signed optab.

Index: gcc/optabs.c
===================================================================
--- gcc/optabs.c        (revision 128099)
+++ gcc/optabs.c        (working copy)
@@ -2234,6 +2234,9 @@
      hides any signed insn for direct use.  */
   wide_soptab = *soptab;
   optab_handler (&wide_soptab, mode)->insn_code = CODE_FOR_nothing;
+  /* We don't want to generate new hash table entries from this fake
+     optab.  */
+  wide_soptab.libcall_gen = NULL;
 
   temp = expand_binop (mode, &wide_soptab, op0, op1, target,
                       unsignedp, OPTAB_WIDEN);

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Lazy construction of libcalls
  2007-09-08 12:44         ` Lazy construction of libcalls Andrew Haley
@ 2007-09-08 16:28           ` Jan Hubicka
  0 siblings, 0 replies; 13+ messages in thread
From: Jan Hubicka @ 2007-09-08 16:28 UTC (permalink / raw)
  To: Andrew Haley; +Cc: Jan Hubicka, Jan Hubicka, gcc-patches, richard

> Jan Hubicka writes:
>  > > Jan Hubicka <jh@suse.cz> writes:
>  > > >> Jan Hubicka <jh@suse.cz> writes:
>  > > >> > While comparing the tables produced by new and old code, I noticed that
>  > > >> > "ffs" for SI used to be called "ffssi3" but now it is "ffs".
>  > > >> > I believe it was inteded to be called ffs because of:
>  > > >> >   optab_handler (ffs_optab, int_mode)->libfunc = init_one_libfunc ("ffs");
>  > > >> > that however later get overwriten by initialization code.
>  > > >> 
>  > > >> Actually, this was deliberate.  All libgccs have word and doubleword
>  > > >> ffs functions, but not all C libraries have "ffs".  So we wanted the
>  > > >> libgcc versions to take precedence over the C library fallback.  See:
>  > > >> 
>  > > >>     http://gcc.gnu.org/ml/gcc-patches/2007-04/msg01165.html
>  > > >> 
>  > > >> for details.
>  > > >
>  > > > OK, so the initialization of libgcc always overwrite the ffs
>  > > > initialization, so simply removing the line above would work?
>  > > 
>  > > Not for 64-bit targets with a 32-bit int, since __builtin_ffs() takes
>  > > an int argument.  We could of course add an SImode libgcc function for
>  > > those targets, but the patch above was just supposed to make better
>  > > use of what we already had.
>  > 
>  > Thanks for explanation - I've now added a guard 
>  > if (INT_TYPE_SIZE < BITS_PER_WORD)
>  > into my local copy that should do what described again. I am re-testing now,
>  > OK with that change?
> 
> This breaks ARM EABI.  The symptom is that we generate signed instead
> of unsigned libcalls for a % b where a and b are usigned ints.
> 
> The problem is here in sign_expand_binop(), where we generate a fake
> optab:
> 
>   /* Try widening to a signed int.  Make a fake signed optab that
>      hides any signed insn for direct use.  */
>   wide_soptab = *soptab;
>   optab_handler (&wide_soptab, mode)->insn_code = CODE_FOR_nothing;
>  
> We later call expand_binop (mode, &wide_soptab ...  which in turn
> calls optab_libfunc (binoptab, mode) which calls optab->libcall_gen()
> and inserts the fake optab into the hash table.  This means that the
> hash table ->optab points into the stack.  We don't want to do this,
> I'm sure.

Uh, sure...
> 
> I suspect the easiest way to fix this is by setting libcall_gen to
> NULL in the fake optab.

Thanks, that seems like correct fix to me.

Honza

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Lazy construction of libcalls
  2007-09-04  8:28         ` Richard Guenther
@ 2007-09-19  6:50           ` Kaveh R. GHAZI
  2007-09-28  5:48             ` [PING]: fix breakage in c4x ports Kaveh R. GHAZI
  0 siblings, 1 reply; 13+ messages in thread
From: Kaveh R. GHAZI @ 2007-09-19  6:50 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Jan Hubicka, Jan Hubicka, gcc-patches, richard

On Tue, 4 Sep 2007, Richard Guenther wrote:

> > Thanks for explanation - I've now added a guard
> > if (INT_TYPE_SIZE < BITS_PER_WORD)
> > into my local copy that should do what described again. I am re-testing now,
> > OK with that change?
>
> Ok.
> Richard.

Hi Jan - I believe this patch breaks c4x targets:

config/c4x/c4x.md: In function `gen_mulqi3':
config/c4x/c4x.md:2088: error: structure has no member named `libfunc'
config/c4x/c4x.md: In function `gen_mulhi3':
config/c4x/c4x.md:7160: error: structure has no member named `libfunc'
make[2]: *** [insn-emit.o] Error 1

While c4x may be on the obsolete list, as long as it's in our sources IMHO
we shouldn't break it (a la treelang).  Does the patch below look correct
to you?

Tested via "make cc1" cross-targetted to c4x-unknown-elf and
c4x-unknown-rtems.  (I don't have any sim setup or testsuite results, I
just make cross-targets once in a while to check for breakage.)

Ok for mainline?

		Thanks,
		--Kaveh


2007-09-18  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>

	* config/c4x/c4x.md (mulqi3, mulhi3): Use optab_libfunc.

diff -rup orig/egcc-SVN20070917/gcc/config/c4x/c4x.md egcc-SVN20070917/gcc/config/c4x/c4x.md
--- orig/egcc-SVN20070917/gcc/config/c4x/c4x.md	2007-08-02 10:20:24.000000000 -0400
+++ egcc-SVN20070917/gcc/config/c4x/c4x.md	2007-09-18 23:42:20.351116062 -0400
@@ -2085,7 +2085,7 @@
                                           operands[2]));
             DONE;
          }
-       c4x_emit_libcall3 (smul_optab->handlers[(int) QImode].libfunc,
+       c4x_emit_libcall3 (optab_libfunc (smul_optab, QImode),
 			  MULT, QImode, operands);
        DONE;
      }
@@ -7157,7 +7157,7 @@
                             (match_operand:HI 2 "src_operand" "")))
               (clobber (reg:CC 21))])]
   ""
-  "c4x_emit_libcall3 (smul_optab->handlers[(int) HImode].libfunc,
+  "c4x_emit_libcall3 (optab_libfunc (smul_optab, HImode),
 		      MULT, HImode, operands);
    DONE;")

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PING]: fix breakage in c4x ports
  2007-09-19  6:50           ` Kaveh R. GHAZI
@ 2007-09-28  5:48             ` Kaveh R. GHAZI
  2007-10-12 13:15               ` [PING x 2]: " Kaveh R. GHAZI
  0 siblings, 1 reply; 13+ messages in thread
From: Kaveh R. GHAZI @ 2007-09-28  5:48 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Jan Hubicka, Jan Hubicka, gcc-patches, richard

Ping?

http://gcc.gnu.org/ml/gcc-patches/2007-09/msg01511.html

		Thanks,
		--Kaveh
--
Kaveh R. Ghazi			ghazi@caip.rutgers.edu

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PING x 2]: fix breakage in c4x ports
  2007-09-28  5:48             ` [PING]: fix breakage in c4x ports Kaveh R. GHAZI
@ 2007-10-12 13:15               ` Kaveh R. GHAZI
  2007-10-12 13:16                 ` Richard Guenther
  0 siblings, 1 reply; 13+ messages in thread
From: Kaveh R. GHAZI @ 2007-10-12 13:15 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Jan Hubicka, Jan Hubicka, gcc-patches, richard


Ping x 2 ?
http://gcc.gnu.org/ml/gcc-patches/2007-09/msg02002.html

		Thanks,
		--Kaveh
--
Kaveh R. Ghazi			ghazi@caip.rutgers.edu

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PING x 2]: fix breakage in c4x ports
  2007-10-12 13:15               ` [PING x 2]: " Kaveh R. GHAZI
@ 2007-10-12 13:16                 ` Richard Guenther
  0 siblings, 0 replies; 13+ messages in thread
From: Richard Guenther @ 2007-10-12 13:16 UTC (permalink / raw)
  To: Kaveh R. GHAZI; +Cc: Jan Hubicka, Jan Hubicka, gcc-patches, richard

On 10/12/07, Kaveh R. GHAZI <ghazi@caip.rutgers.edu> wrote:
>
> Ping x 2 ?
> http://gcc.gnu.org/ml/gcc-patches/2007-09/msg02002.html

Ok.

Richard.

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2007-10-12 13:16 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-08-21 17:13 Lazy construction of libcalls Jan Hubicka
2007-08-24 13:44 ` Richard Sandiford
2007-08-24 14:23   ` Jan Hubicka
2007-08-24 14:46     ` Richard Sandiford
2007-09-04  8:16       ` Jan Hubicka
2007-09-04  8:28         ` Richard Guenther
2007-09-19  6:50           ` Kaveh R. GHAZI
2007-09-28  5:48             ` [PING]: fix breakage in c4x ports Kaveh R. GHAZI
2007-10-12 13:15               ` [PING x 2]: " Kaveh R. GHAZI
2007-10-12 13:16                 ` Richard Guenther
2007-09-08 12:44         ` Lazy construction of libcalls Andrew Haley
2007-09-08 16:28           ` Jan Hubicka
2007-08-24 14:43   ` Jan Hubicka

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).