OSDN Git Service

* config/rs6000/rs6000.c (output_toc): Make "offset" HOST_WIDE_INT.
[pf3gnuchains/gcc-fork.git] / gcc / config / rs6000 / rs6000.c
index 577bbfb..8d51003 100644 (file)
@@ -584,7 +584,6 @@ static unsigned toc_hash_function (const void *);
 static int toc_hash_eq (const void *, const void *);
 static int constant_pool_expr_1 (rtx, int *, int *);
 static bool constant_pool_expr_p (rtx);
-static bool legitimate_small_data_p (enum machine_mode, rtx);
 static bool legitimate_indexed_address_p (rtx, int);
 static bool legitimate_lo_sum_address_p (enum machine_mode, rtx, int);
 static struct machine_function * rs6000_init_machine_status (void);
@@ -1981,7 +1980,7 @@ num_insns_constant (rtx op, enum machine_mode mode)
     case CONST_INT:
 #if HOST_BITS_PER_WIDE_INT == 64
       if ((INTVAL (op) >> 31) != 0 && (INTVAL (op) >> 31) != -1
-         && mask_operand (op, mode))
+         && mask64_operand (op, mode))
        return 2;
       else
 #endif
@@ -2023,7 +2022,7 @@ num_insns_constant (rtx op, enum machine_mode mode)
                || (high == -1 && low < 0))
              return num_insns_constant_wide (low);
 
-           else if (mask_operand (op, mode))
+           else if (mask64_operand (op, mode))
              return 2;
 
            else if (low == 0)
@@ -2261,7 +2260,7 @@ rs6000_expand_vector_init (rtx target, rtx vals)
     {
       rtx copy = copy_rtx (vals);
 
-      /* Load constant part of vector, substititute neighboring value for
+      /* Load constant part of vector, substitute neighboring value for
         varying element.  */
       XVECEXP (copy, 0, one_var) = XVECEXP (vals, 0, (one_var + 1) % n_elts);
       rs6000_expand_vector_init (target, copy);
@@ -2347,61 +2346,6 @@ rs6000_expand_vector_extract (rtx target, rtx vec, int elt)
   emit_move_insn (target, adjust_address_nv (mem, inner_mode, 0));
 }
 
-int
-mask64_1or2_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED,
-                      bool allow_one)
-{
-  if (GET_CODE (op) == CONST_INT)
-    {
-      HOST_WIDE_INT c, lsb;
-      bool one_ok;
-
-      c = INTVAL (op);
-
-      /* Disallow all zeros.  */
-      if (c == 0)
-       return 0;
-
-      /* We can use a single rlwinm insn if no upper bits of C are set
-         AND there are zero, one or two transitions in the _whole_ of
-         C.  */
-      one_ok = !(c & ~(HOST_WIDE_INT)0xffffffff);
-
-      /* We don't change the number of transitions by inverting,
-        so make sure we start with the LS bit zero.  */
-      if (c & 1)
-       c = ~c;
-
-      /* Find the first transition.  */
-      lsb = c & -c;
-
-      /* Invert to look for a second transition.  */
-      c = ~c;
-
-      /* Erase first transition.  */
-      c &= -lsb;
-
-      /* Find the second transition.  */
-      lsb = c & -c;
-
-      /* Invert to look for a third transition.  */
-      c = ~c;
-
-      /* Erase second transition.  */
-      c &= -lsb;
-
-      if (one_ok && !(allow_one || c))
-       return 0;
-
-      /* Find the third transition (if any).  */
-      lsb = c & -c;
-
-      /* Match if all the bits above are 1's (or c is zero).  */
-      return c == -lsb;
-    }
-  return 0;
-}
-
 /* Generates shifts and masks for a pair of rldicl or rldicr insns to
    implement ANDing by the mask IN.  */
 void
@@ -2631,8 +2575,8 @@ legitimate_constant_pool_address_p (rtx x)
          && constant_pool_expr_p (XEXP (x, 1)));
 }
 
-static bool
-legitimate_small_data_p (enum machine_mode mode, rtx x)
+bool
+rs6000_legitimate_small_data_p (enum machine_mode mode, rtx x)
 {
   return (DEFAULT_ABI == ABI_V4
          && !flag_pic && !TARGET_TOC
@@ -3034,8 +2978,13 @@ rs6000_legitimize_tls_address (rtx addr, enum tls_model model)
     {
       rtx r3, got, tga, tmp1, tmp2, eqv;
 
+      /* We currently use relocations like @got@tlsgd for tls, which
+        means the linker will handle allocation of tls entries, placing
+        them in the .got section.  So use a pointer to the .got section,
+        not one to secondary TOC sections used by 64-bit -mminimal-toc,
+        or to secondary GOT sections used by 32-bit -fPIC.  */
       if (TARGET_64BIT)
-       got = gen_rtx_REG (Pmode, TOC_REGISTER);
+       got = gen_rtx_REG (Pmode, 2);
       else
        {
          if (flag_pic == 1)
@@ -3301,16 +3250,21 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
       return x;
     }
 
-#if TARGET_MACHO
   if (GET_CODE (x) == SYMBOL_REF
-      && DEFAULT_ABI == ABI_DARWIN
       && !ALTIVEC_VECTOR_MODE (mode)
+#if TARGET_MACHO
+      && DEFAULT_ABI == ABI_DARWIN
       && (flag_pic || MACHO_DYNAMIC_NO_PIC_P)
+#else
+      && DEFAULT_ABI == ABI_V4
+      && !flag_pic
+#endif
       /* Don't do this for TFmode, since the result isn't offsettable.
         The same goes for DImode without 64-bit gprs.  */
       && mode != TFmode
       && (mode != DImode || TARGET_POWERPC64))
     {
+#if TARGET_MACHO
       if (flag_pic)
        {
          rtx offset = gen_rtx_CONST (Pmode,
@@ -3321,6 +3275,7 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
                  gen_rtx_HIGH (Pmode, offset)), offset);
        }
       else
+#endif
        x = gen_rtx_LO_SUM (GET_MODE (x),
              gen_rtx_HIGH (Pmode, x), x);
 
@@ -3330,7 +3285,23 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
       *win = 1;
       return x;
     }
-#endif
+
+  /* Reload an offset address wrapped by an AND that represents the
+     masking of the lower bits.  Strip the outer AND and let reload
+     convert the offset address into an indirect address.  */
+  if (TARGET_ALTIVEC
+      && ALTIVEC_VECTOR_MODE (mode)
+      && GET_CODE (x) == AND
+      && GET_CODE (XEXP (x, 0)) == PLUS
+      && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
+      && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
+      && GET_CODE (XEXP (x, 1)) == CONST_INT
+      && INTVAL (XEXP (x, 1)) == -16)
+    {
+      x = XEXP (x, 0);
+      *win = 1;
+      return x;
+    }
 
   if (TARGET_TOC
       && constant_pool_expr_p (x)
@@ -3384,7 +3355,7 @@ rs6000_legitimate_address (enum machine_mode mode, rtx x, int reg_ok_strict)
       && TARGET_UPDATE
       && legitimate_indirect_address_p (XEXP (x, 0), reg_ok_strict))
     return 1;
-  if (legitimate_small_data_p (mode, x))
+  if (rs6000_legitimate_small_data_p (mode, x))
     return 1;
   if (legitimate_constant_pool_address_p (x))
     return 1;
@@ -4980,9 +4951,10 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
   if (mode == VOIDmode)
     {
       if (abi == ABI_V4
-         && cum->nargs_prototype < 0
          && (cum->call_cookie & CALL_LIBCALL) == 0
-         && (cum->prototype || TARGET_NO_PROTOTYPE))
+         && (cum->stdarg
+             || (cum->nargs_prototype < 0
+                 && (cum->prototype || TARGET_NO_PROTOTYPE))))
        {
          /* For the SPE, we need to crxor CR6 always.  */
          if (TARGET_SPE_ABI)
@@ -5497,7 +5469,8 @@ setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
 
       mem = gen_rtx_MEM (BLKmode,
                         plus_constant (save_area,
-                                       first_reg_offset * reg_size)),
+                                       first_reg_offset * reg_size));
+      MEM_NOTRAP_P (mem) = 1;
       set_mem_alias_set (mem, set);
       set_mem_align (mem, BITS_PER_WORD);
 
@@ -5532,6 +5505,7 @@ setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
           fregno++, off += UNITS_PER_FP_WORD, nregs++)
        {
          mem = gen_rtx_MEM (DFmode, plus_constant (save_area, off));
+         MEM_NOTRAP_P (mem) = 1;
          set_mem_alias_set (mem, set);
          set_mem_align (mem, GET_MODE_ALIGNMENT (DFmode));
          emit_move_insn (mem, gen_rtx_REG (DFmode, fregno));
@@ -9116,7 +9090,7 @@ expand_block_clear (rtx operands[])
          clear_bytes = 4;
          mode = SImode;
        }
-      else if (bytes == 2 && (align >= 16 || !STRICT_ALIGNMENT))
+      else if (bytes >= 2 && (align >= 16 || !STRICT_ALIGNMENT))
        {                       /* move 2 bytes */
          clear_bytes = 2;
          mode = HImode;
@@ -9252,7 +9226,7 @@ expand_block_move (rtx operands[])
          mode = SImode;
          gen_func.mov = gen_movsi;
        }
-      else if (bytes == 2 && (align >= 16 || !STRICT_ALIGNMENT))
+      else if (bytes >= 2 && (align >= 16 || !STRICT_ALIGNMENT))
        {                       /* move 2 bytes */
          move_bytes = 2;
          mode = HImode;
@@ -10362,7 +10336,7 @@ print_operand (FILE *file, rtx x, int code)
       /* PowerPC64 mask position.  All 0's is excluded.
         CONST_INT 32-bit mask is considered sign-extended so any
         transition must occur within the CONST_INT, not on the boundary.  */
-      if (! mask_operand (x, DImode))
+      if (! mask64_operand (x, DImode))
        output_operand_lossage ("invalid %%S value");
 
       uval = INT_LOWPART (x);
@@ -12287,16 +12261,14 @@ rs6000_split_multireg_move (rtx dst, rtx src)
              emit_insn (TARGET_32BIT
                         ? gen_addsi3 (breg, breg, delta_rtx)
                         : gen_adddi3 (breg, breg, delta_rtx));
-             src = gen_rtx_MEM (mode, breg);
+             src = replace_equiv_address (src, breg);
            }
          else if (! offsettable_memref_p (src))
            {
-             rtx newsrc, basereg;
+             rtx basereg;
              basereg = gen_rtx_REG (Pmode, reg);
              emit_insn (gen_rtx_SET (VOIDmode, basereg, XEXP (src, 0)));
-             newsrc = gen_rtx_MEM (GET_MODE (src), basereg);
-             MEM_COPY_ATTRIBUTES (newsrc, src);
-             src = newsrc;
+             src = replace_equiv_address (src, basereg);
            }
 
          breg = XEXP (src, 0);
@@ -12341,7 +12313,7 @@ rs6000_split_multireg_move (rtx dst, rtx src)
                emit_insn (TARGET_32BIT
                           ? gen_addsi3 (breg, breg, delta_rtx)
                           : gen_adddi3 (breg, breg, delta_rtx));
-             dst = gen_rtx_MEM (mode, breg);
+             dst = replace_equiv_address (dst, breg);
            }
          else
            gcc_assert (offsettable_memref_p (dst));
@@ -13406,7 +13378,10 @@ rs6000_emit_eh_reg_restore (rtx source, rtx scratch)
          || current_function_calls_alloca
          || info->total_size > 32767)
        {
-         emit_move_insn (operands[1], gen_rtx_MEM (Pmode, frame_rtx));
+         tmp = gen_rtx_MEM (Pmode, frame_rtx);
+         MEM_NOTRAP_P (tmp) = 1;
+         set_mem_alias_set (tmp, rs6000_sr_alias_set);
+         emit_move_insn (operands[1], tmp);
          frame_rtx = operands[1];
        }
       else if (info->push_p)
@@ -13414,6 +13389,8 @@ rs6000_emit_eh_reg_restore (rtx source, rtx scratch)
 
       tmp = plus_constant (frame_rtx, info->lr_save_offset + sp_offset);
       tmp = gen_rtx_MEM (Pmode, tmp);
+      MEM_NOTRAP_P (tmp) = 1;
+      set_mem_alias_set (tmp, rs6000_sr_alias_set);
       emit_move_insn (tmp, operands[0]);
     }
   else
@@ -13486,12 +13463,12 @@ rs6000_aix_emit_builtin_unwind_init (void)
   rtx tocompare = gen_reg_rtx (SImode);
   rtx no_toc_save_needed = gen_label_rtx ();
 
-  mem = gen_rtx_MEM (Pmode, hard_frame_pointer_rtx);
+  mem = gen_frame_mem (Pmode, hard_frame_pointer_rtx);
   emit_move_insn (stack_top, mem);
 
-  mem = gen_rtx_MEM (Pmode,
-                    gen_rtx_PLUS (Pmode, stack_top,
-                                  GEN_INT (2 * GET_MODE_SIZE (Pmode))));
+  mem = gen_frame_mem (Pmode,
+                      gen_rtx_PLUS (Pmode, stack_top,
+                                    GEN_INT (2 * GET_MODE_SIZE (Pmode))));
   emit_move_insn (opcode_addr, mem);
   emit_move_insn (opcode, gen_rtx_MEM (SImode, opcode_addr));
   emit_move_insn (tocompare, gen_int_mode (TARGET_32BIT ? 0x80410014
@@ -13501,9 +13478,9 @@ rs6000_aix_emit_builtin_unwind_init (void)
                           SImode, NULL_RTX, NULL_RTX,
                           no_toc_save_needed);
 
-  mem = gen_rtx_MEM (Pmode,
-                    gen_rtx_PLUS (Pmode, stack_top,
-                                  GEN_INT (5 * GET_MODE_SIZE (Pmode))));
+  mem = gen_frame_mem (Pmode,
+                      gen_rtx_PLUS (Pmode, stack_top,
+                                    GEN_INT (5 * GET_MODE_SIZE (Pmode))));
   emit_move_insn (mem, gen_rtx_REG (Pmode, 2));
   emit_label (no_toc_save_needed);
 }
@@ -15611,7 +15588,7 @@ output_toc (FILE *file, rtx x, int labelno, enum machine_mode mode)
   const char *name = buf;
   const char *real_name;
   rtx base = x;
-  int offset = 0;
+  HOST_WIDE_INT offset = 0;
 
   gcc_assert (!TARGET_NO_TOC);
 
@@ -15878,9 +15855,9 @@ output_toc (FILE *file, rtx x, int labelno, enum machine_mode mode)
       fprintf (file, "\t.tc %s", real_name);
 
       if (offset < 0)
-       fprintf (file, ".N%d", - offset);
+       fprintf (file, ".N" HOST_WIDE_INT_PRINT_UNSIGNED, - offset);
       else if (offset)
-       fprintf (file, ".P%d", offset);
+       fprintf (file, ".P" HOST_WIDE_INT_PRINT_UNSIGNED, offset);
 
       fputs ("[TC],", file);
     }
@@ -15895,9 +15872,9 @@ output_toc (FILE *file, rtx x, int labelno, enum machine_mode mode)
     {
       RS6000_OUTPUT_BASENAME (file, name);
       if (offset < 0)
-       fprintf (file, "%d", offset);
+       fprintf (file, HOST_WIDE_INT_PRINT_DEC, offset);
       else if (offset > 0)
-       fprintf (file, "+%d", offset);
+       fprintf (file, "+" HOST_WIDE_INT_PRINT_DEC, offset);
     }
   else
     output_addr_const (file, x);
@@ -16660,26 +16637,24 @@ rs6000_is_costly_dependence (rtx insn, rtx next, rtx link, int cost,
 static rtx
 get_next_active_insn (rtx insn, rtx tail)
 {
-  rtx next_insn;
-
-  if (!insn || insn == tail)
+  if (insn == NULL_RTX || insn == tail)
     return NULL_RTX;
 
-  next_insn = NEXT_INSN (insn);
-
-  while (next_insn
-        && next_insn != tail
-        && (GET_CODE (next_insn) == NOTE
-            || GET_CODE (PATTERN (next_insn)) == USE
-            || GET_CODE (PATTERN (next_insn)) == CLOBBER))
+  while (1)
     {
-      next_insn = NEXT_INSN (next_insn);
-    }
-
-  if (!next_insn || next_insn == tail)
-    return NULL_RTX;
+      insn = NEXT_INSN (insn);
+      if (insn == NULL_RTX || insn == tail)
+       return NULL_RTX;
 
-  return next_insn;
+      if (CALL_P (insn)
+         || JUMP_P (insn)
+         || (NONJUMP_INSN_P (insn)
+             && GET_CODE (PATTERN (insn)) != USE
+             && GET_CODE (PATTERN (insn)) != CLOBBER
+             && INSN_CODE (insn) != CODE_FOR_stack_tie))
+       break;
+    }
+  return insn;
 }
 
 /* Return whether the presence of INSN causes a dispatch group termination
@@ -18218,7 +18193,9 @@ rs6000_rtx_costs (rtx x, int code, int outer_code, int *total)
              && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'K')
                  || (CONST_OK_FOR_LETTER_P (INTVAL (x),
                                             mode == SImode ? 'L' : 'J'))
-                 || mask_operand (x, VOIDmode)))
+                 || mask_operand (x, mode)
+                 || (mode == DImode
+                     && mask64_operand (x, DImode))))
          || ((outer_code == IOR || outer_code == XOR)
              && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'K')
                  || (CONST_OK_FOR_LETTER_P (INTVAL (x),
@@ -18270,7 +18247,8 @@ rs6000_rtx_costs (rtx x, int code, int outer_code, int *total)
          && ((outer_code == AND
               && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'K')
                   || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L')
-                  || mask_operand (x, DImode)))
+                  || mask_operand (x, DImode)
+                  || mask64_operand (x, DImode)))
              || ((outer_code == IOR || outer_code == XOR)
                  && CONST_DOUBLE_HIGH (x) == 0
                  && (CONST_DOUBLE_LOW (x)
@@ -18326,12 +18304,6 @@ rs6000_rtx_costs (rtx x, int code, int outer_code, int *total)
          else
            *total = rs6000_cost->fp;
        }
-      else if (GET_CODE (XEXP (x, 0)) == MULT)
-       {
-         /* The rs6000 doesn't have shift-and-add instructions.  */
-         rs6000_rtx_costs (XEXP (x, 0), MULT, PLUS, total);
-         *total += COSTS_N_INSNS (1);
-       }
       else
        *total = COSTS_N_INSNS (1);
       return false;
@@ -18358,12 +18330,6 @@ rs6000_rtx_costs (rtx x, int code, int outer_code, int *total)
          else
            *total = rs6000_cost->fp;
        }
-      else if (GET_CODE (XEXP (x, 0)) == MULT)
-       {
-         /* The rs6000 doesn't have shift-and-sub instructions.  */
-         rs6000_rtx_costs (XEXP (x, 0), MULT, MINUS, total);
-         *total += COSTS_N_INSNS (1);
-       }
       else
        *total = COSTS_N_INSNS (1);
       return false;
@@ -18813,7 +18779,26 @@ rs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
                                                   GP_ARG_RETURN + 1),
                                      GEN_INT (4))));
     }
-
+  if (TARGET_32BIT && TARGET_POWERPC64 && TYPE_MODE (valtype) == DCmode)
+    {
+      return gen_rtx_PARALLEL (DCmode,
+       gen_rtvec (4,
+                  gen_rtx_EXPR_LIST (VOIDmode,
+                                     gen_rtx_REG (SImode, GP_ARG_RETURN),
+                                     const0_rtx),
+                  gen_rtx_EXPR_LIST (VOIDmode,
+                                     gen_rtx_REG (SImode,
+                                                  GP_ARG_RETURN + 1),
+                                     GEN_INT (4)),
+                  gen_rtx_EXPR_LIST (VOIDmode,
+                                     gen_rtx_REG (SImode,
+                                                  GP_ARG_RETURN + 2),
+                                     GEN_INT (8)),
+                  gen_rtx_EXPR_LIST (VOIDmode,
+                                     gen_rtx_REG (SImode,
+                                                  GP_ARG_RETURN + 3),
+                                     GEN_INT (12))));
+    }
   if ((INTEGRAL_TYPE_P (valtype)
        && TYPE_PRECISION (valtype) < BITS_PER_WORD)
       || POINTER_TYPE_P (valtype))