OSDN Git Service

* config/rs6000/darwin-ldouble.c: Build file for SOFT_FLOAT.
[pf3gnuchains/gcc-fork.git] / gcc / config / rs6000 / rs6000.c
index a773483..ce17814 100644 (file)
@@ -1,6 +1,6 @@
 /* Subroutines used for code generation on IBM RS/6000.
    Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005, 2006
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
    Free Software Foundation, Inc.
    Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
 
@@ -1446,9 +1446,6 @@ rs6000_override_options (const char *default_cpu)
 
   if (TARGET_E500)
     {
-      if (TARGET_ALTIVEC)
-       error ("AltiVec and E500 instructions cannot coexist");
-
       /* The e500 does not have string instructions, and we set
         MASK_STRING above when optimizing for size.  */
       if ((target_flags & MASK_STRING) != 0)
@@ -1471,6 +1468,9 @@ rs6000_override_options (const char *default_cpu)
        rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
     }
 
+  /* Detect invalid option combinations with E500.  */
+  CHECK_E500_OPTIONS;
+
   rs6000_always_hint = (rs6000_cpu != PROCESSOR_POWER4
                        && rs6000_cpu != PROCESSOR_POWER5
                         && rs6000_cpu != PROCESSOR_POWER6
@@ -3363,8 +3363,7 @@ rs6000_legitimize_tls_address (rtx addr, enum tls_model model)
                  emit_move_insn (tmp2, mem);
                  emit_insn (gen_addsi3 (tmp3, tmp1, tmp2));
                  last = emit_move_insn (got, tmp3);
-                 REG_NOTES (last) = gen_rtx_EXPR_LIST (REG_EQUAL, gsym,
-                                                       REG_NOTES (last));
+                 set_unique_reg_note (last, REG_EQUAL, gsym);
                  REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
                                                         REG_NOTES (first));
                  REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first,
@@ -3936,11 +3935,11 @@ rs6000_emit_set_const (rtx dest, enum machine_mode mode,
     case SImode:
       result = no_new_pseudos ? dest : gen_reg_rtx (SImode);
 
-      emit_insn (gen_rtx_SET (VOIDmode, result,
+      emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (result),
                              GEN_INT (INTVAL (source)
                                       & (~ (HOST_WIDE_INT) 0xffff))));
       emit_insn (gen_rtx_SET (VOIDmode, dest,
-                             gen_rtx_IOR (SImode, result,
+                             gen_rtx_IOR (SImode, copy_rtx (result),
                                           GEN_INT (INTVAL (source) & 0xffff))));
       result = dest;
       break;
@@ -3995,7 +3994,7 @@ rs6000_emit_set_long_const (rtx dest, HOST_WIDE_INT c1, HOST_WIDE_INT c2)
 
       operand1 = operand_subword_force (dest, WORDS_BIG_ENDIAN == 0,
                                        DImode);
-      operand2 = operand_subword_force (dest, WORDS_BIG_ENDIAN != 0,
+      operand2 = operand_subword_force (copy_rtx (dest), WORDS_BIG_ENDIAN != 0,
                                        DImode);
       emit_move_insn (operand1, GEN_INT (c1));
       emit_move_insn (operand2, GEN_INT (c2));
@@ -4030,7 +4029,9 @@ rs6000_emit_set_long_const (rtx dest, HOST_WIDE_INT c1, HOST_WIDE_INT c2)
          else
            emit_move_insn (dest, GEN_INT (ud2 << 16));
          if (ud1 != 0)
-           emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud1)));
+           emit_move_insn (copy_rtx (dest),
+                           gen_rtx_IOR (DImode, copy_rtx (dest),
+                                        GEN_INT (ud1)));
        }
       else if ((ud4 == 0xffff && (ud3 & 0x8000))
               || (ud4 == 0 && ! (ud3 & 0x8000)))
@@ -4042,10 +4043,16 @@ rs6000_emit_set_long_const (rtx dest, HOST_WIDE_INT c1, HOST_WIDE_INT c2)
            emit_move_insn (dest, GEN_INT (ud3 << 16));
 
          if (ud2 != 0)
-           emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud2)));
-         emit_move_insn (dest, gen_rtx_ASHIFT (DImode, dest, GEN_INT (16)));
+           emit_move_insn (copy_rtx (dest),
+                           gen_rtx_IOR (DImode, copy_rtx (dest),
+                                        GEN_INT (ud2)));
+         emit_move_insn (copy_rtx (dest),
+                         gen_rtx_ASHIFT (DImode, copy_rtx (dest),
+                                         GEN_INT (16)));
          if (ud1 != 0)
-           emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud1)));
+           emit_move_insn (copy_rtx (dest),
+                           gen_rtx_IOR (DImode, copy_rtx (dest),
+                                        GEN_INT (ud1)));
        }
       else
        {
@@ -4056,14 +4063,20 @@ rs6000_emit_set_long_const (rtx dest, HOST_WIDE_INT c1, HOST_WIDE_INT c2)
            emit_move_insn (dest, GEN_INT (ud4 << 16));
 
          if (ud3 != 0)
-           emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud3)));
+           emit_move_insn (copy_rtx (dest),
+                           gen_rtx_IOR (DImode, copy_rtx (dest),
+                                        GEN_INT (ud3)));
 
-         emit_move_insn (dest, gen_rtx_ASHIFT (DImode, dest, GEN_INT (32)));
+         emit_move_insn (copy_rtx (dest),
+                         gen_rtx_ASHIFT (DImode, copy_rtx (dest),
+                                         GEN_INT (32)));
          if (ud2 != 0)
-           emit_move_insn (dest, gen_rtx_IOR (DImode, dest,
-                                              GEN_INT (ud2 << 16)));
+           emit_move_insn (copy_rtx (dest),
+                           gen_rtx_IOR (DImode, copy_rtx (dest),
+                                        GEN_INT (ud2 << 16)));
          if (ud1 != 0)
-           emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud1)));
+           emit_move_insn (copy_rtx (dest),
+                           gen_rtx_IOR (DImode, copy_rtx (dest), GEN_INT (ud1)));
        }
     }
   return dest;
@@ -4134,8 +4147,8 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
     {
       emit_move_insn (adjust_address (operands[0], SImode, 0),
                      adjust_address (operands[1], SImode, 0));
-      emit_move_insn (adjust_address (operands[0], SImode, 4),
-                     adjust_address (operands[1], SImode, 4));
+      emit_move_insn (adjust_address (copy_rtx (operands[0]), SImode, 4),
+                     adjust_address (copy_rtx (operands[1]), SImode, 4));
       return;
     }
 
@@ -4162,7 +4175,8 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
       if (FP_REGNO_P (regnum) || regnum >= FIRST_PSEUDO_REGISTER)
        {
          rtx newreg;
-         newreg = (no_new_pseudos ? operands[1] : gen_reg_rtx (mode));
+         newreg = (no_new_pseudos ? copy_rtx (operands[1])
+                   : gen_reg_rtx (mode));
          emit_insn (gen_aux_truncdfsf2 (newreg, operands[1]));
          operands[1] = newreg;
        }
@@ -8787,9 +8801,8 @@ altivec_init_builtins (void)
       decl = add_builtin_function ("__builtin_altivec_mask_for_load",
                                   v16qi_ftype_long_pcvoid,
                                   ALTIVEC_BUILTIN_MASK_FOR_LOAD,
-                                  BUILT_IN_MD, NULL,
-                                  tree_cons (get_identifier ("const"),
-                                             NULL_TREE, NULL_TREE));
+                                  BUILT_IN_MD, NULL, NULL_TREE);
+      TREE_READONLY (decl) = 1;
       /* Record the decl. Will be used by rs6000_builtin_mask_for_load.  */
       altivec_builtin_mask_for_load = decl;
     }
@@ -9388,9 +9401,6 @@ rs6000_common_init_builtins (void)
 static void
 rs6000_init_libfuncs (void)
 {
-  if (!TARGET_HARD_FLOAT)
-    return;
-
   if (DEFAULT_ABI != ABI_V4 && TARGET_XCOFF
       && !TARGET_POWER2 && !TARGET_POWERPC)
     {
@@ -9409,6 +9419,27 @@ rs6000_init_libfuncs (void)
        set_optab_libfunc (sub_optab, TFmode, "__gcc_qsub");
        set_optab_libfunc (smul_optab, TFmode, "__gcc_qmul");
        set_optab_libfunc (sdiv_optab, TFmode, "__gcc_qdiv");
+
+       if (TARGET_SOFT_FLOAT)
+         {
+           set_optab_libfunc (neg_optab, TFmode, "__gcc_qneg");
+           set_optab_libfunc (eq_optab, TFmode, "__gcc_qeq");
+           set_optab_libfunc (ne_optab, TFmode, "__gcc_qne");
+           set_optab_libfunc (gt_optab, TFmode, "__gcc_qgt");
+           set_optab_libfunc (ge_optab, TFmode, "__gcc_qge");
+           set_optab_libfunc (lt_optab, TFmode, "__gcc_qlt");
+           set_optab_libfunc (le_optab, TFmode, "__gcc_qle");
+           set_optab_libfunc (unord_optab, TFmode, "__gcc_qunord");
+
+           set_conv_libfunc (sext_optab, TFmode, SFmode, "__gcc_stoq");
+           set_conv_libfunc (sext_optab, TFmode, DFmode, "__gcc_dtoq");
+           set_conv_libfunc (trunc_optab, SFmode, TFmode, "__gcc_qtos");
+           set_conv_libfunc (trunc_optab, DFmode, TFmode, "__gcc_qtod");
+           set_conv_libfunc (sfix_optab, SImode, TFmode, "__gcc_qtoi");
+           set_conv_libfunc (ufix_optab, SImode, TFmode, "__gcc_qtou");
+           set_conv_libfunc (sfloat_optab, TFmode, SImode, "__gcc_itoq");
+           set_conv_libfunc (ufloat_optab, TFmode, SImode, "__gcc_utoq");
+         }
       }
     else
       {
@@ -11002,7 +11033,8 @@ print_operand (FILE *file, rtx x, int code)
        tmp = XEXP (x, 0);
 
        /* Ugly hack because %y is overloaded.  */
-       if (TARGET_E500 && GET_MODE_SIZE (GET_MODE (x)) == 8)
+       if ((TARGET_SPE || TARGET_E500_DOUBLE)
+           && GET_MODE_SIZE (GET_MODE (x)) == 8)
          {
            /* Handle [reg].  */
            if (GET_CODE (tmp) == REG)
@@ -11301,7 +11333,7 @@ rs6000_generate_compare (enum rtx_code code)
   compare_result = gen_reg_rtx (comp_mode);
 
   /* E500 FP compare instructions on the GPRs.  Yuck!  */
-  if ((TARGET_E500 && !TARGET_FPRS && TARGET_HARD_FLOAT)
+  if ((!TARGET_FPRS && TARGET_HARD_FLOAT)
       && rs6000_compare_fp_p)
     {
       rtx cmp, or_result, compare_result2;
@@ -11494,7 +11526,7 @@ rs6000_generate_compare (enum rtx_code code)
      under flag_finite_math_only we don't bother.  */
   if (rs6000_compare_fp_p
       && !flag_finite_math_only
-      && !(TARGET_HARD_FLOAT && TARGET_E500 && !TARGET_FPRS)
+      && !(TARGET_HARD_FLOAT && !TARGET_FPRS)
       && (code == LE || code == GE
          || code == UNEQ || code == LTGT
          || code == UNGT || code == UNLT))
@@ -11544,7 +11576,7 @@ rs6000_emit_sCOND (enum rtx_code code, rtx result)
   condition_rtx = rs6000_generate_compare (code);
   cond_code = GET_CODE (condition_rtx);
 
-  if (TARGET_E500 && rs6000_compare_fp_p
+  if (rs6000_compare_fp_p
       && !TARGET_FPRS && TARGET_HARD_FLOAT)
     {
       rtx t;
@@ -11651,7 +11683,7 @@ output_cbranch (rtx op, const char *label, int reversed, rtx insn)
        code = reverse_condition (code);
     }
 
-  if ((TARGET_E500 && !TARGET_FPRS && TARGET_HARD_FLOAT) && mode == CCFPmode)
+  if ((!TARGET_FPRS && TARGET_HARD_FLOAT) && mode == CCFPmode)
     {
       /* The efscmp/tst* instructions twiddle bit 2, which maps nicely
         to the GT bit.  */
@@ -12067,7 +12099,7 @@ rs6000_emit_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
        return rs6000_emit_int_cmove (dest, op, true_cond, false_cond);
       return 0;
     }
-  else if (TARGET_E500 && TARGET_HARD_FLOAT && !TARGET_FPRS
+  else if (TARGET_HARD_FLOAT && !TARGET_FPRS
           && SCALAR_FLOAT_MODE_P (compare_mode))
     return 0;
 
@@ -19724,11 +19756,12 @@ rs6000_rtx_costs (rtx x, int code, int outer_code, int *total)
     case MINUS:
       if (mode == DFmode)
        {
-         if (GET_CODE (XEXP (x, 0)) == MULT)
+         if (GET_CODE (XEXP (x, 0)) == MULT
+             || GET_CODE (XEXP (x, 1)) == MULT)
            {
              /* FNMA accounted in outer NEG.  */
              if (outer_code == NEG)
-               *total = 0;
+               *total = rs6000_cost->dmul - rs6000_cost->fp;
              else
                *total = rs6000_cost->dmul;
            }