OSDN Git Service

* c-decl.c (c_init_decl_processing): Clear input_file_name
[pf3gnuchains/gcc-fork.git] / gcc / optabs.c
index d8c058e..c693e80 100644 (file)
@@ -1,6 +1,6 @@
 /* Expand the basic unary and binary arithmetic operations, for GNU compiler.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -126,6 +126,8 @@ static rtx expand_vector_binop PARAMS ((enum machine_mode, optab,
                                        enum optab_methods));
 static rtx expand_vector_unop PARAMS ((enum machine_mode, optab, rtx, rtx,
                                       int));
+static rtx widen_clz PARAMS ((enum machine_mode, rtx, rtx));
+static rtx expand_parity PARAMS ((enum machine_mode, rtx, rtx));
 \f
 /* Add a REG_EQUAL note to the last insn in INSNS.  TARGET is being set to
    the result of operation CODE applied to OP0 (and OP1 if it is a binary
@@ -169,11 +171,9 @@ add_equal_note (insns, target, code, op0, op1)
     return 1;
 
   if (! rtx_equal_p (SET_DEST (set), target)
-      /* For a STRICT_LOW_PART, the REG_NOTE applies to what is inside the
-        SUBREG.  */
+      /* For a STRICT_LOW_PART, the REG_NOTE applies to what is inside it.  */
       && (GET_CODE (SET_DEST (set)) != STRICT_LOW_PART
-         || ! rtx_equal_p (SUBREG_REG (XEXP (SET_DEST (set), 0)),
-                           target)))
+         || ! rtx_equal_p (XEXP (SET_DEST (set), 0), target)))
     return 1;
 
   /* If TARGET is in OP0 or OP1, check if anything in SEQ sets TARGET
@@ -700,8 +700,17 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
 
   if (flag_force_mem)
     {
-      op0 = force_not_mem (op0);
-      op1 = force_not_mem (op1);
+      /* Load duplicate non-volatile operands once.  */
+      if (rtx_equal_p (op0, op1) && ! volatile_refs_p (op0))
+       {
+         op0 = force_not_mem (op0);
+         op1 = op0;
+       }
+      else
+       {
+         op0 = force_not_mem (op0);
+         op1 = force_not_mem (op1);
+       }
     }
 
   /* If subtracting an integer constant, convert this into an addition of
@@ -1299,7 +1308,8 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
 
       if (i == GET_MODE_BITSIZE (mode) / (unsigned) BITS_PER_WORD)
        {
-         if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+         if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing
+             || ! rtx_equal_p (target, xtarget))
            {
              rtx temp = emit_move_insn (target, xtarget);
 
@@ -1309,6 +1319,8 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
                                                   copy_rtx (xop0),
                                                   copy_rtx (xop1)));
            }
+         else
+           target = xtarget;
 
          return target;
        }
@@ -1635,8 +1647,13 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
              temp1 = expand_binop (submode, binoptab, real0, imag1,
                                    NULL_RTX, unsignedp, methods);
 
-             temp2 = expand_binop (submode, binoptab, real1, imag0,
-                                   NULL_RTX, unsignedp, methods);
+             /* Avoid expanding redundant multiplication for the common
+                case of squaring a complex number.  */
+             if (rtx_equal_p (real0, real1) && rtx_equal_p (imag0, imag1))
+               temp2 = temp1;
+             else
+               temp2 = expand_binop (submode, binoptab, real1, imag0,
+                                     NULL_RTX, unsignedp, methods);
 
              if (temp1 == 0 || temp2 == 0)
                break;
@@ -2323,6 +2340,89 @@ expand_simple_unop (mode, code, op0, target, unsignedp)
   return expand_unop (mode, unop, op0, target, unsignedp);
 }
 
+/* Try calculating
+       (clz:narrow x)
+   as
+       (clz:wide (zero_extend:wide x)) - ((width wide) - (width narrow)).  */
+static rtx
+widen_clz (mode, op0, target)
+     enum machine_mode mode;
+     rtx op0;
+     rtx target;
+{
+  enum mode_class class = GET_MODE_CLASS (mode);
+  if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
+    {
+      enum machine_mode wider_mode;
+      for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
+          wider_mode = GET_MODE_WIDER_MODE (wider_mode))
+       {
+         if (clz_optab->handlers[(int) wider_mode].insn_code
+             != CODE_FOR_nothing)
+           {
+             rtx xop0, temp, last;
+
+             last = get_last_insn ();
+
+             if (target == 0)
+               target = gen_reg_rtx (mode);
+             xop0 = widen_operand (op0, wider_mode, mode, true, false);
+             temp = expand_unop (wider_mode, clz_optab, xop0, NULL_RTX, true);
+             if (temp != 0)
+               temp = expand_binop (wider_mode, sub_optab, temp,
+                                    GEN_INT (GET_MODE_BITSIZE (wider_mode)
+                                             - GET_MODE_BITSIZE (mode)),
+                                    target, true, OPTAB_DIRECT);
+             if (temp == 0)
+               delete_insns_since (last);
+
+             return temp;
+           }
+       }
+    }
+  return 0;
+}
+
+/* Try calculating (parity x) as (and (popcount x) 1), where
+   popcount can also be done in a wider mode.  */
+static rtx
+expand_parity (mode, op0, target)
+     enum machine_mode mode;
+     rtx op0;
+     rtx target;
+{
+  enum mode_class class = GET_MODE_CLASS (mode);
+  if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
+    {
+      enum machine_mode wider_mode;
+      for (wider_mode = mode; wider_mode != VOIDmode;
+          wider_mode = GET_MODE_WIDER_MODE (wider_mode))
+       {
+         if (popcount_optab->handlers[(int) wider_mode].insn_code
+             != CODE_FOR_nothing)
+           {
+             rtx xop0, temp, last;
+
+             last = get_last_insn ();
+
+             if (target == 0)
+               target = gen_reg_rtx (mode);
+             xop0 = widen_operand (op0, wider_mode, mode, true, false);
+             temp = expand_unop (wider_mode, popcount_optab, xop0, NULL_RTX,
+                                 true);
+             if (temp != 0)
+               temp = expand_binop (wider_mode, and_optab, temp, GEN_INT (1),
+                                    target, true, OPTAB_DIRECT);
+             if (temp == 0)
+               delete_insns_since (last);
+
+             return temp;
+           }
+       }
+    }
+  return 0;
+}
+
 /* Generate code to perform an operation specified by UNOPTAB
    on operand OP0, with result having machine-mode MODE.
 
@@ -2403,6 +2503,16 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
 
   /* It can't be done in this mode.  Can we open-code it in a wider mode?  */
 
+  /* Widening clz needs special treatment.  */
+  if (unoptab == clz_optab)
+    {
+      temp = widen_clz (mode, op0, target);
+      if (temp)
+       return temp;
+      else
+       goto try_libcall;
+    }
+
   if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
     for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
         wider_mode = GET_MODE_WIDER_MODE (wider_mode))
@@ -2530,6 +2640,14 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
          HOST_WIDE_INT hi, lo;
          rtx last = get_last_insn ();
 
+         /* Handle targets with different FP word orders.  */
+         if (FLOAT_WORDS_BIG_ENDIAN != WORDS_BIG_ENDIAN)
+           {
+             int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
+             int word = nwords - (bitpos / BITS_PER_WORD) - 1;
+             bitpos = word * BITS_PER_WORD + bitpos % BITS_PER_WORD;
+           }
+
          if (bitpos < HOST_BITS_PER_WIDE_INT)
            {
              hi = 0;
@@ -2550,22 +2668,39 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
         }
     }
 
+  /* Try calculating parity (x) as popcount (x) % 2.  */
+  if (unoptab == parity_optab)
+    {
+      temp = expand_parity (mode, op0, target);
+      if (temp)
+       return temp;
+    }
+
+ try_libcall:
   /* Now try a library call in this mode.  */
   if (unoptab->handlers[(int) mode].libfunc)
     {
       rtx insns;
       rtx value;
+      enum machine_mode outmode = mode;
+
+      /* All of these functions return small values.  Thus we choose to
+        have them return something that isn't a double-word.  */
+      if (unoptab == ffs_optab || unoptab == clz_optab || unoptab == ctz_optab
+         || unoptab == popcount_optab || unoptab == parity_optab)
+       outmode = TYPE_MODE (integer_type_node);
 
       start_sequence ();
 
       /* 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 (unoptab->handlers[(int) mode].libfunc,
-                                      NULL_RTX, LCT_CONST, mode, 1, op0, mode);
+                                      NULL_RTX, LCT_CONST, outmode,
+                                      1, op0, mode);
       insns = get_insns ();
       end_sequence ();
 
-      target = gen_reg_rtx (mode);
+      target = gen_reg_rtx (outmode);
       emit_libcall_block (insns, target, value,
                          gen_rtx_fmt_e (unoptab->code, mode, op0));
 
@@ -2600,6 +2735,14 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
              temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX,
                                  unsignedp);
 
+             /* If we are generating clz using wider mode, adjust the
+                result.  */
+             if (unoptab == clz_optab && temp != 0)
+               temp = expand_binop (wider_mode, sub_optab, temp,
+                                    GEN_INT (GET_MODE_BITSIZE (wider_mode)
+                                             - GET_MODE_BITSIZE (mode)),
+                                    target, true, OPTAB_DIRECT);
+
              if (temp)
                {
                  if (class != MODE_INT)
@@ -2644,14 +2787,13 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
  */
 
 rtx
-expand_abs (mode, op0, target, result_unsignedp, safe)
+expand_abs_nojump (mode, op0, target, result_unsignedp)
      enum machine_mode mode;
      rtx op0;
      rtx target;
      int result_unsignedp;
-     int safe;
 {
-  rtx temp, op1;
+  rtx temp;
 
   if (! flag_trapv)
     result_unsignedp = 1;
@@ -2675,6 +2817,14 @@ expand_abs (mode, op0, target, result_unsignedp, safe)
          HOST_WIDE_INT hi, lo;
          rtx last = get_last_insn ();
 
+         /* Handle targets with different FP word orders.  */
+         if (FLOAT_WORDS_BIG_ENDIAN != WORDS_BIG_ENDIAN)
+           {
+             int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
+             int word = nwords - (bitpos / BITS_PER_WORD) - 1;
+             bitpos = word * BITS_PER_WORD + bitpos % BITS_PER_WORD;
+           }
+
          if (bitpos < HOST_BITS_PER_WIDE_INT)
            {
              hi = 0;
@@ -2731,6 +2881,23 @@ expand_abs (mode, op0, target, result_unsignedp, safe)
        return temp;
     }
 
+  return NULL_RTX;
+}
+
+rtx
+expand_abs (mode, op0, target, result_unsignedp, safe)
+     enum machine_mode mode;
+     rtx op0;
+     rtx target;
+     int result_unsignedp;
+     int safe;
+{
+  rtx temp, op1;
+
+  temp = expand_abs_nojump (mode, op0, target, result_unsignedp);
+  if (temp != 0)
+    return temp;
+
   /* If that does not win, use conditional jump and negate.  */
 
   /* It is safe to use the target if it is the same
@@ -3434,8 +3601,17 @@ prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, purpose)
 
   if (mode != BLKmode && flag_force_mem)
     {
-      x = force_not_mem (x);
-      y = force_not_mem (y);
+      /* Load duplicate non-volatile operands once.  */
+      if (rtx_equal_p (x, y) && ! volatile_refs_p (x))
+       {
+         x = force_not_mem (x);
+         y = x;
+       }
+      else
+       {
+         x = force_not_mem (x);
+         y = force_not_mem (y);
+       }
     }
 
   /* If we are inside an appropriately-short loop and one operand is an
@@ -4376,8 +4552,9 @@ emit_conditional_add (target, code, op0, op1, cmode, op2, op3, mode,
   return target;
 }
 \f
-/* These functions generate an insn body and return it
-   rather than emitting the insn.
+/* These functions attempt to generate an insn body, rather than
+   emitting the insn, but if the gen function already emits them, we
+   make no attempt to turn them back into naked patterns.
 
    They do not protect from queued increments,
    because they may be used 1) in protect_from_queue itself
@@ -4518,69 +4695,8 @@ rtx
 gen_move_insn (x, y)
      rtx x, y;
 {
-  enum machine_mode mode = GET_MODE (x);
-  enum insn_code insn_code;
   rtx seq;
 
-  if (mode == VOIDmode)
-    mode = GET_MODE (y); 
-
-  insn_code = mov_optab->handlers[(int) mode].insn_code;
-
-  /* Handle MODE_CC modes:  If we don't have a special move insn for this mode,
-     find a mode to do it in.  If we have a movcc, use it.  Otherwise,
-     find the MODE_INT mode of the same width.  */
-
-  if (GET_MODE_CLASS (mode) == MODE_CC && insn_code == CODE_FOR_nothing)
-    {
-      enum machine_mode tmode = VOIDmode;
-      rtx x1 = x, y1 = y;
-
-      if (mode != CCmode
-         && mov_optab->handlers[(int) CCmode].insn_code != CODE_FOR_nothing)
-       tmode = CCmode;
-      else
-       for (tmode = QImode; tmode != VOIDmode;
-            tmode = GET_MODE_WIDER_MODE (tmode))
-         if (GET_MODE_SIZE (tmode) == GET_MODE_SIZE (mode))
-           break;
-
-      if (tmode == VOIDmode)
-       abort ();
-
-      /* Get X and Y in TMODE.  We can't use gen_lowpart here because it
-        may call change_address which is not appropriate if we were
-        called when a reload was in progress.  We don't have to worry
-        about changing the address since the size in bytes is supposed to
-        be the same.  Copy the MEM to change the mode and move any
-        substitutions from the old MEM to the new one.  */
-
-      if (reload_in_progress)
-       {
-         x = gen_lowpart_common (tmode, x1);
-         if (x == 0 && GET_CODE (x1) == MEM)
-           {
-             x = adjust_address_nv (x1, tmode, 0);
-             copy_replacements (x1, x);
-           }
-
-         y = gen_lowpart_common (tmode, y1);
-         if (y == 0 && GET_CODE (y1) == MEM)
-           {
-             y = adjust_address_nv (y1, tmode, 0);
-             copy_replacements (y1, y);
-           }
-       }
-      else
-       {
-         x = gen_lowpart (tmode, x);
-         y = gen_lowpart (tmode, y);
-       }
-         
-      insn_code = mov_optab->handlers[(int) tmode].insn_code;
-      return (GEN_FCN (insn_code) (x, y));
-    }
-
   start_sequence ();
   emit_move_insn_1 (x, y);
   seq = get_insns ();
@@ -4677,10 +4793,10 @@ expand_float (to, from, unsignedp)
      wider mode.  If the integer mode is wider than the mode of FROM,
      we can do the conversion signed even if the input is unsigned.  */
 
-  for (imode = GET_MODE (from); imode != VOIDmode;
-       imode = GET_MODE_WIDER_MODE (imode))
-    for (fmode = GET_MODE (to); fmode != VOIDmode;
-        fmode = GET_MODE_WIDER_MODE (fmode))
+  for (fmode = GET_MODE (to); fmode != VOIDmode;
+       fmode = GET_MODE_WIDER_MODE (fmode))
+    for (imode = GET_MODE (from); imode != VOIDmode;
+        imode = GET_MODE_WIDER_MODE (imode))
       {
        int doing_unsigned = unsignedp;
 
@@ -4981,15 +5097,26 @@ expand_fix (to, from, unsignedp)
      one plus the highest signed number, convert, and add it back.
 
      We only need to check all real modes, since we know we didn't find
-     anything with a wider integer mode.  */
+     anything with a wider integer mode.  
+
+     This code used to extend FP value into mode wider than the destination.
+     This is not needed.  Consider, for instance conversion from SFmode
+     into DImode.
+
+     The hot path trought the code is dealing with inputs smaller than 2^63
+     and doing just the conversion, so there is no bits to lose.
+
+     In the other path we know the value is positive in the range 2^63..2^64-1
+     inclusive.  (as for other imput overflow happens and result is undefined)
+     So we know that the most important bit set in mantisa corresponds to
+     2^63.  The subtraction of 2^63 should not generate any rounding as it
+     simply clears out that bit.  The rest is trivial.  */
 
   if (unsignedp && GET_MODE_BITSIZE (GET_MODE (to)) <= HOST_BITS_PER_WIDE_INT)
     for (fmode = GET_MODE (from); fmode != VOIDmode;
         fmode = GET_MODE_WIDER_MODE (fmode))
-      /* Make sure we won't lose significant bits doing this.  */
-      if (GET_MODE_BITSIZE (fmode) > GET_MODE_BITSIZE (GET_MODE (to))
-         && CODE_FOR_nothing != can_fix_p (GET_MODE (to), fmode, 0,
-                                           &must_trunc))
+      if (CODE_FOR_nothing != can_fix_p (GET_MODE (to), fmode, 0,
+                                        &must_trunc))
        {
          int bitsize;
          REAL_VALUE_TYPE offset;
@@ -5242,8 +5369,7 @@ init_libfuncs (optable, first_mode, last_mode, opname, suffix)
       *p = '\0';
 
       optable->handlers[(int) mode].libfunc
-       = gen_rtx_SYMBOL_REF (Pmode, ggc_alloc_string (libfunc_name,
-                                                      p - libfunc_name));
+       = init_one_libfunc (ggc_alloc_string (libfunc_name, p - libfunc_name));
     }
 }
 
@@ -5258,7 +5384,12 @@ init_integral_libfuncs (optable, opname, suffix)
      const char *opname;
      int suffix;
 {
-  init_libfuncs (optable, SImode, TImode, opname, 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
@@ -5272,13 +5403,26 @@ init_floating_libfuncs (optable, opname, suffix)
      const char *opname;
      int suffix;
 {
-  init_libfuncs (optable, SFmode, TFmode, opname, suffix);
+  enum machine_mode fmode, dmode, lmode;
+
+  fmode = float_type_node ? TYPE_MODE (float_type_node) : VOIDmode;
+  dmode = double_type_node ? TYPE_MODE (double_type_node) : VOIDmode;
+  lmode = long_double_type_node ? TYPE_MODE (long_double_type_node) : VOIDmode;
+
+  if (fmode != VOIDmode)
+    init_libfuncs (optable, fmode, fmode, opname, suffix);
+  if (dmode != fmode && dmode != VOIDmode)
+    init_libfuncs (optable, dmode, dmode, opname, suffix);
+  if (lmode != dmode && lmode != VOIDmode)
+    init_libfuncs (optable, lmode, lmode, opname, suffix);
 }
 
 rtx
 init_one_libfunc (name)
      const char *name;
 {
+  rtx symbol;
+
   /* Create a FUNCTION_DECL that can be passed to
      targetm.encode_section_info.  */
   /* ??? We don't have any type information except for this is
@@ -5289,8 +5433,13 @@ init_one_libfunc (name)
   DECL_EXTERNAL (decl) = 1;
   TREE_PUBLIC (decl) = 1;
 
-  /* Return the symbol_ref from the mem rtx.  */
-  return XEXP (DECL_RTL (decl), 0);
+  symbol = XEXP (DECL_RTL (decl), 0);
+
+  /* Zap the nonsensical SYMBOL_REF_DECL for this.  What we're left with
+     are the flags assigned by targetm.encode_section_info.  */
+  SYMBOL_REF_DECL (symbol) = 0;
+
+  return symbol;
 }
 
 /* Call this once to initialize the contents of the optabs
@@ -5361,6 +5510,8 @@ init_optabs ()
   smax_optab = init_optab (SMAX);
   umin_optab = init_optab (UMIN);
   umax_optab = init_optab (UMAX);
+  pow_optab = init_optab (UNKNOWN);
+  atan2_optab = init_optab (UNKNOWN);
 
   /* These three have codes assigned exclusively for the sake of
      have_insn_for.  */
@@ -5377,6 +5528,10 @@ init_optabs ()
   addcc_optab = init_optab (UNKNOWN);
   one_cmpl_optab = init_optab (NOT);
   ffs_optab = init_optab (FFS);
+  clz_optab = init_optab (CLZ);
+  ctz_optab = init_optab (CTZ);
+  popcount_optab = init_optab (POPCOUNT);
+  parity_optab = init_optab (PARITY);
   sqrt_optab = init_optab (SQRT);
   floor_optab = init_optab (UNKNOWN);
   ceil_optab = init_optab (UNKNOWN);
@@ -5454,6 +5609,10 @@ init_optabs ()
   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');
@@ -5534,6 +5693,7 @@ init_optabs ()
   bcmp_libfunc = init_one_libfunc ("__gcc_bcmp");
   memset_libfunc = init_one_libfunc ("memset");
   bzero_libfunc = init_one_libfunc ("bzero");
+  setbits_libfunc = init_one_libfunc ("__setbits");
 
   unwind_resume_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS
                                            ? "_Unwind_SjLj_Resume"
@@ -5643,6 +5803,9 @@ init_optabs ()
   profile_function_exit_libfunc
     = init_one_libfunc ("__cyg_profile_func_exit");
 
+  gcov_flush_libfunc = init_one_libfunc ("__gcov_flush");
+  gcov_init_libfunc = init_one_libfunc ("__gcov_init");
+
 #ifdef HAVE_conditional_trap
   init_traps ();
 #endif