OSDN Git Service

gcc/
[pf3gnuchains/gcc-fork.git] / gcc / config / mips / mips.c
index 8a2ba16..f153d13 100644 (file)
@@ -1,6 +1,6 @@
 /* Subroutines used for MIPS code generation.
    Copyright (C) 1989, 1990, 1991, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
    Contributed by A. Lichnewsky, lich@inria.inria.fr.
    Changes by Michael Meissner, meissner@osf.org.
@@ -148,6 +148,13 @@ enum mips_address_type {
   ADDRESS_SYMBOLIC
 };
 
+/* Enumerates the setting of the -mr10k-cache-barrier option.  */
+enum mips_r10k_cache_barrier_setting {
+  R10K_CACHE_BARRIER_NONE,
+  R10K_CACHE_BARRIER_STORE,
+  R10K_CACHE_BARRIER_LOAD_STORE
+};
+
 /* Macros to create an enumeration identifier for a function prototype.  */
 #define MIPS_FTYPE_NAME1(A, B) MIPS_##A##_FTYPE_##B
 #define MIPS_FTYPE_NAME2(A, B, C) MIPS_##A##_FTYPE_##B##_##C
@@ -285,7 +292,8 @@ struct machine_function GTY(()) {
   /* The current frame information, calculated by mips_compute_frame_info.  */
   struct mips_frame_info frame;
 
-  /* The register to use as the function's global pointer.  */
+  /* The register to use as the function's global pointer, or INVALID_REGNUM
+     if the function doesn't need one.  */
   unsigned int global_pointer;
 
   /* True if mips_adjust_insn_length should ignore an instruction's
@@ -445,7 +453,6 @@ static int mips_base_target_flags;
 bool mips_base_mips16;
 
 /* The ambient values of other global variables.  */
-static int mips_base_delayed_branch; /* flag_delayed_branch */
 static int mips_base_schedule_insns; /* flag_schedule_insns */
 static int mips_base_reorder_blocks_and_partition; /* flag_reorder... */
 static int mips_base_move_loop_invariants; /* flag_move_loop_invariants */
@@ -456,6 +463,9 @@ static int mips_base_align_functions; /* align_functions */
 /* The -mcode-readable setting.  */
 enum mips_code_readable_setting mips_code_readable = CODE_READABLE_YES;
 
+/* The -mr10k-cache-barrier setting.  */
+static enum mips_r10k_cache_barrier_setting mips_r10k_cache_barrier;
+
 /* Index [M][R] is true if register R is allowed to hold a value of mode M.  */
 bool mips_hard_regno_mode_ok[(int) MAX_MACHINE_MODE][FIRST_PSEUDO_REGISTER];
 
@@ -502,7 +512,7 @@ const enum reg_class mips_regno_to_class[FIRST_PSEUDO_REGISTER] = {
   MD0_REG,     MD1_REG,        NO_REGS,        ST_REGS,
   ST_REGS,     ST_REGS,        ST_REGS,        ST_REGS,
   ST_REGS,     ST_REGS,        ST_REGS,        NO_REGS,
-  NO_REGS,     ALL_REGS,       ALL_REGS,       NO_REGS,
+  NO_REGS,     FRAME_REGS,     FRAME_REGS,     NO_REGS,
   COP0_REGS,   COP0_REGS,      COP0_REGS,      COP0_REGS,
   COP0_REGS,   COP0_REGS,      COP0_REGS,      COP0_REGS,
   COP0_REGS,   COP0_REGS,      COP0_REGS,      COP0_REGS,
@@ -597,6 +607,10 @@ static const struct mips_cpu_info mips_cpu_info_table[] = {
 
   /* MIPS IV processors. */
   { "r8000", PROCESSOR_R8000, 4, 0 },
+  { "r10000", PROCESSOR_R10000, 4, 0 },
+  { "r12000", PROCESSOR_R10000, 4, 0 },
+  { "r14000", PROCESSOR_R10000, 4, 0 },
+  { "r16000", PROCESSOR_R10000, 4, 0 },
   { "vr5000", PROCESSOR_R5000, 4, 0 },
   { "vr5400", PROCESSOR_R5400, 4, 0 },
   { "vr5500", PROCESSOR_R5500, 4, PTF_AVOID_BRANCHLIKELY },
@@ -1005,6 +1019,19 @@ static const struct mips_rtx_cost_data mips_rtx_cost_data[PROCESSOR_MAX] = {
                     1,           /* branch_cost */
                     4            /* memory_latency */
   },
+  { /* R1x000 */
+    COSTS_N_INSNS (2),            /* fp_add */
+    COSTS_N_INSNS (2),            /* fp_mult_sf */
+    COSTS_N_INSNS (2),            /* fp_mult_df */
+    COSTS_N_INSNS (12),           /* fp_div_sf */
+    COSTS_N_INSNS (19),           /* fp_div_df */
+    COSTS_N_INSNS (5),            /* int_mult_si */
+    COSTS_N_INSNS (9),            /* int_mult_di */
+    COSTS_N_INSNS (34),           /* int_div_si */
+    COSTS_N_INSNS (66),           /* int_div_di */
+                    1,           /* branch_cost */
+                    4            /* memory_latency */
+  },
   { /* SB1 */
     /* These costs are the same as the SB-1A below.  */
     COSTS_N_INSNS (4),            /* fp_add */
@@ -3225,8 +3252,8 @@ mips_binary_cost (rtx x, int single_cost, int double_cost)
   else
     cost = single_cost;
   return (cost
-         + rtx_cost (XEXP (x, 0), 0)
-         + rtx_cost (XEXP (x, 1), GET_CODE (x)));
+         + rtx_cost (XEXP (x, 0), 0, !optimize_size)
+         + rtx_cost (XEXP (x, 1), GET_CODE (x), !optimize_size));
 }
 
 /* Return the cost of floating-point multiplications of mode MODE.  */
@@ -3296,7 +3323,8 @@ mips_zero_extend_cost (enum machine_mode mode, rtx op)
 /* Implement TARGET_RTX_COSTS.  */
 
 static bool
-mips_rtx_costs (rtx x, int code, int outer_code, int *total)
+mips_rtx_costs (rtx x, int code, int outer_code, int *total,
+               bool speed)
 {
   enum machine_mode mode = GET_MODE (x);
   bool float_mode_p = FLOAT_MODE_P (mode);
@@ -3443,7 +3471,7 @@ mips_rtx_costs (rtx x, int code, int outer_code, int *total)
          && UINTVAL (XEXP (x, 1)) == 0xffffffff)
        {
          *total = (mips_zero_extend_cost (mode, XEXP (x, 0))
-                   + rtx_cost (XEXP (x, 0), 0));
+                   + rtx_cost (XEXP (x, 0), 0, speed));
          return true;
        }
       /* Fall through.  */
@@ -3475,7 +3503,7 @@ mips_rtx_costs (rtx x, int code, int outer_code, int *total)
     case LO_SUM:
       /* Low-part immediates need an extended MIPS16 instruction.  */
       *total = (COSTS_N_INSNS (TARGET_MIPS16 ? 2 : 1)
-               + rtx_cost (XEXP (x, 0), 0));
+               + rtx_cost (XEXP (x, 0), 0, speed));
       return true;
 
     case LT:
@@ -3515,17 +3543,17 @@ mips_rtx_costs (rtx x, int code, int outer_code, int *total)
          if (GET_CODE (op0) == MULT && GET_CODE (XEXP (op0, 0)) == NEG)
            {
              *total = (mips_fp_mult_cost (mode)
-                       + rtx_cost (XEXP (XEXP (op0, 0), 0), 0)
-                       + rtx_cost (XEXP (op0, 1), 0)
-                       + rtx_cost (op1, 0));
+                       + rtx_cost (XEXP (XEXP (op0, 0), 0), 0, speed)
+                       + rtx_cost (XEXP (op0, 1), 0, speed)
+                       + rtx_cost (op1, 0, speed));
              return true;
            }
          if (GET_CODE (op1) == MULT)
            {
              *total = (mips_fp_mult_cost (mode)
-                       + rtx_cost (op0, 0)
-                       + rtx_cost (XEXP (op1, 0), 0)
-                       + rtx_cost (XEXP (op1, 1), 0));
+                       + rtx_cost (op0, 0, speed)
+                       + rtx_cost (XEXP (op1, 0), 0, speed)
+                       + rtx_cost (XEXP (op1, 1), 0, speed));
              return true;
            }
        }
@@ -3566,9 +3594,9 @@ mips_rtx_costs (rtx x, int code, int outer_code, int *total)
              && GET_CODE (XEXP (op, 0)) == MULT)
            {
              *total = (mips_fp_mult_cost (mode)
-                       + rtx_cost (XEXP (XEXP (op, 0), 0), 0)
-                       + rtx_cost (XEXP (XEXP (op, 0), 1), 0)
-                       + rtx_cost (XEXP (op, 1), 0));
+                       + rtx_cost (XEXP (XEXP (op, 0), 0), 0, speed)
+                       + rtx_cost (XEXP (XEXP (op, 0), 1), 0, speed)
+                       + rtx_cost (XEXP (op, 1), 0, speed));
              return true;
            }
        }
@@ -3606,9 +3634,9 @@ mips_rtx_costs (rtx x, int code, int outer_code, int *total)
          if (outer_code == SQRT || GET_CODE (XEXP (x, 1)) == SQRT)
            /* An rsqrt<mode>a or rsqrt<mode>b pattern.  Count the
               division as being free.  */
-           *total = rtx_cost (XEXP (x, 1), 0);
+           *total = rtx_cost (XEXP (x, 1), 0, speed);
          else
-           *total = mips_fp_div_cost (mode) + rtx_cost (XEXP (x, 1), 0);
+           *total = mips_fp_div_cost (mode) + rtx_cost (XEXP (x, 1), 0, speed);
          return true;
        }
       /* Fall through.  */
@@ -3636,7 +3664,7 @@ mips_rtx_costs (rtx x, int code, int outer_code, int *total)
              && CONST_INT_P (XEXP (x, 1))
              && exact_log2 (INTVAL (XEXP (x, 1))) >= 0)
            {
-             *total = COSTS_N_INSNS (2) + rtx_cost (XEXP (x, 0), 0);
+             *total = COSTS_N_INSNS (2) + rtx_cost (XEXP (x, 0), 0, speed);
              return true;
            }
          *total = COSTS_N_INSNS (mips_idiv_insns ());
@@ -3671,7 +3699,7 @@ mips_rtx_costs (rtx x, int code, int outer_code, int *total)
 /* Implement TARGET_ADDRESS_COST.  */
 
 static int
-mips_address_cost (rtx addr)
+mips_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED)
 {
   return mips_address_insns (addr, SImode, false);
 }
@@ -4221,8 +4249,14 @@ mips_expand_scc (enum rtx_code code, rtx target)
 
   if (code == EQ || code == NE)
     {
-      rtx zie = mips_zero_if_equal (cmp_operands[0], cmp_operands[1]);
-      mips_emit_binary (code, target, zie, const0_rtx);
+      if (ISA_HAS_SEQ_SNE
+         && reg_imm10_operand (cmp_operands[1], GET_MODE (cmp_operands[1])))
+       mips_emit_binary (code, target, cmp_operands[0], cmp_operands[1]);
+      else
+       {
+         rtx zie = mips_zero_if_equal (cmp_operands[0], cmp_operands[1]);
+         mips_emit_binary (code, target, zie, const0_rtx);
+       }
     }
   else
     mips_emit_int_order_test (code, 0, target,
@@ -5258,10 +5292,10 @@ mips_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
       if (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_FLOAT
          && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_FPVALUE)
        {
-         top = build3 (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop,
-                       NULL_TREE);
-         off = build3 (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff,
-                       NULL_TREE);
+         top = build3 (COMPONENT_REF, TREE_TYPE (f_ftop),
+                       unshare_expr (valist), f_ftop, NULL_TREE);
+         off = build3 (COMPONENT_REF, TREE_TYPE (f_foff),
+                       unshare_expr (valist), f_foff, NULL_TREE);
 
          /* When va_start saves FPR arguments to the stack, each slot
             takes up UNITS_PER_HWFPVALUE bytes, regardless of the
@@ -5288,17 +5322,17 @@ mips_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
        }
       else
        {
-         top = build3 (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop,
-                       NULL_TREE);
-         off = build3 (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff,
-                       NULL_TREE);
+         top = build3 (COMPONENT_REF, TREE_TYPE (f_gtop),
+                       unshare_expr (valist), f_gtop, NULL_TREE);
+         off = build3 (COMPONENT_REF, TREE_TYPE (f_goff),
+                       unshare_expr (valist), f_goff, NULL_TREE);
          rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
          if (rsize > UNITS_PER_WORD)
            {
              /* [1] Emit code for: off &= -rsize.      */
-             t = build2 (BIT_AND_EXPR, TREE_TYPE (off), off,
-                         build_int_cst (NULL_TREE, -rsize));
-             gimplify_assign (off, t, pre_p);
+             t = build2 (BIT_AND_EXPR, TREE_TYPE (off), unshare_expr (off),
+                         build_int_cst (TREE_TYPE (off), -rsize));
+             gimplify_assign (unshare_expr (off), t, pre_p);
            }
          osize = rsize;
        }
@@ -5329,12 +5363,14 @@ mips_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
        {
          /* [9] Emit: ovfl = ((intptr_t) ovfl + osize - 1) & -osize.  */
          u = size_int (osize - 1);
-         t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (ovfl), ovfl, u);
+         t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (ovfl),
+                     unshare_expr (ovfl), u);
          t = fold_convert (sizetype, t);
          u = size_int (-osize);
          t = build2 (BIT_AND_EXPR, sizetype, t, u);
          t = fold_convert (TREE_TYPE (ovfl), t);
-         align = build2 (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t);
+         align = build2 (MODIFY_EXPR, TREE_TYPE (ovfl),
+                         unshare_expr (ovfl), t);
        }
       else
        align = NULL;
@@ -6156,7 +6192,8 @@ mips_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
      because there is no direct "jx" instruction equivalent to "jalx" to
      switch the ISA mode.  We only care about cases where the sibling
      and normal calls would both be direct.  */
-  if (mips_use_mips16_mode_p (decl)
+  if (decl
+      && mips_use_mips16_mode_p (decl)
       && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
     return false;
 
@@ -6365,8 +6402,10 @@ mips_expand_synci_loop (rtx begin, rtx end)
   rtx inc, label, cmp, cmp_result;
 
   /* Load INC with the cache line size (rdhwr INC,$1).  */
-  inc = gen_reg_rtx (SImode);
-  emit_insn (gen_rdhwr (inc, const1_rtx));
+  inc = gen_reg_rtx (Pmode);
+  emit_insn (Pmode == SImode
+            ? gen_rdhwr_synci_step_si (inc)
+            : gen_rdhwr_synci_step_di (inc));
 
   /* Loop back to here.  */
   label = gen_label_rtx ();
@@ -6658,6 +6697,32 @@ mips_use_ins_ext_p (rtx op, HOST_WIDE_INT width, HOST_WIDE_INT bitpos)
 
   return true;
 }
+
+/* Check if MASK and SHIFT are valid in mask-low-and-shift-left
+   operation if MAXLEN is the maxium length of consecutive bits that
+   can make up MASK.  MODE is the mode of the operation.  See
+   mask_low_and_shift_len for the actual definition.  */
+
+bool
+mask_low_and_shift_p (enum machine_mode mode, rtx mask, rtx shift, int maxlen)
+{
+  return IN_RANGE (mask_low_and_shift_len (mode, mask, shift), 1, maxlen);
+}
+
+/* The canonical form of a mask-low-and-shift-left operation is
+   (and (ashift X SHIFT) MASK) where MASK has the lower SHIFT number of bits
+   cleared.  Thus we need to shift MASK to the right before checking if it
+   is a valid mask value.  MODE is the mode of the operation.  If true
+   return the length of the mask, otherwise return -1.  */
+
+int
+mask_low_and_shift_len (enum machine_mode mode, rtx mask, rtx shift)
+{
+  HOST_WIDE_INT shval;
+
+  shval = INTVAL (shift) & (GET_MODE_BITSIZE (mode) - 1);
+  return exact_log2 ((UINTVAL (mask) >> shval) + 1);
+}
 \f
 /* Return true if -msplit-addresses is selected and should be honored.
 
@@ -6848,6 +6913,7 @@ mips_print_operand_reloc (FILE *file, rtx op, enum mips_symbol_context context,
    '#' Print a nop if in a ".set noreorder" block.
    '/' Like '#', but do nothing within a delayed-branch sequence.
    '?' Print "l" if mips_branch_likely is true
+   '~' Print a nop if mips_branch_likely is true
    '.' Print the name of the register with a hard-wired zero (zero or $0).
    '@' Print the name of the assembler temporary register (at or $1).
    '^' Print the name of the pic call-through register (t9 or $25).
@@ -6922,6 +6988,11 @@ mips_print_operand_punctuation (FILE *file, int ch)
        putc ('l', file);
       break;
 
+    case '~':
+      if (mips_branch_likely)
+       fputs ("\n\tnop", file);
+      break;
+
     case '.':
       fputs (reg_names[GP_REG_FIRST + 0], file);
       break;
@@ -6965,7 +7036,7 @@ mips_init_print_operand_punct (void)
 {
   const char *p;
 
-  for (p = "()[]<>*#/?.@^+$|-"; *p; p++)
+  for (p = "()[]<>*#/?~.@^+$|-"; *p; p++)
     mips_print_operand_punct[(unsigned char) *p] = true;
 }
 
@@ -7025,6 +7096,7 @@ mips_print_float_branch_condition (FILE *file, enum rtx_code code, int letter)
    'X' Print CONST_INT OP in hexadecimal format.
    'x' Print the low 16 bits of CONST_INT OP in hexadecimal format.
    'd' Print CONST_INT OP in decimal.
+   'm' Print one less than CONST_INT OP in decimal.
    'h' Print the high-part relocation associated with OP, after stripping
          any outermost HIGH.
    'R' Print the low-part relocation associated with OP.
@@ -7080,6 +7152,13 @@ mips_print_operand (FILE *file, rtx op, int letter)
        output_operand_lossage ("invalid use of '%%%c'", letter);
       break;
 
+    case 'm':
+      if (GET_CODE (op) == CONST_INT)
+       fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (op) - 1);
+      else
+       output_operand_lossage ("invalid use of '%%%c'", letter);
+      break;
+
     case 'h':
       if (code == HIGH)
        op = XEXP (op, 0);
@@ -7703,7 +7782,7 @@ mips_mdebug_abi_name (void)
     case ABI_N32:
       return "abiN32";
     case ABI_64:
-      return "abiN64";
+      return "abi64";
     case ABI_EABI:
       return TARGET_64BIT ? "eabi64" : "eabi32";
     default:
@@ -8283,8 +8362,8 @@ mips16_cfun_returns_in_fpr_p (void)
 }
 
 /* Return the register that should be used as the global pointer
-   within this function.  Return 0 if the function doesn't need
-   a global pointer.  */
+   within this function.  Return INVALID_REGNUM if the function
+   doesn't need a global pointer.  */
 
 static unsigned int
 mips_global_pointer (void)
@@ -8319,7 +8398,7 @@ mips_global_pointer (void)
         -call_nonpic code, no new uses will be introduced during or after
         reload.  */
       if (TARGET_ABICALLS_PIC0)
-       return 0;
+       return INVALID_REGNUM;
 
       /* We need to handle the following implicit gp references:
 
@@ -8341,7 +8420,7 @@ mips_global_pointer (void)
           external libgcc routine.  */
       if (!crtl->uses_const_pool
          && !mips16_cfun_returns_in_fpr_p ())
-       return 0;
+       return INVALID_REGNUM;
     }
 
   /* We need a global pointer, but perhaps we can use a call-clobbered
@@ -8357,48 +8436,85 @@ mips_global_pointer (void)
   return GLOBAL_POINTER_REGNUM;
 }
 
-/* Return true if the current function must save register REGNO.  */
+/* Return true if the current function should treat register REGNO
+   as call-saved.  */
 
 static bool
-mips_save_reg_p (unsigned int regno)
+mips_cfun_call_saved_reg_p (unsigned int regno)
+{
+  /* call_insns preserve $28 unless they explicitly say otherwise,
+     so call_really_used_regs[] treats $28 as call-saved.  However,
+     we want the ABI property rather than the default call_insn
+     property here.  */
+  return (regno == GLOBAL_POINTER_REGNUM
+         ? TARGET_CALL_SAVED_GP
+         : !call_really_used_regs[regno]);
+}
+
+/* Return true if the function body might clobber register REGNO.
+   We know that REGNO is call-saved.  */
+
+static bool
+mips_cfun_might_clobber_call_saved_reg_p (unsigned int regno)
 {
-  /* We need to save $gp if TARGET_CALL_SAVED_GP and if we have not
-     chosen a call-clobbered substitute.  */
-  if (TARGET_CALL_SAVED_GP
-      && regno == GLOBAL_POINTER_REGNUM
-      && cfun->machine->global_pointer == regno)
+  /* Some functions should be treated as clobbering all call-saved
+     registers.  */
+  if (crtl->saves_all_registers)
     return true;
 
-  /* Check call-saved registers.  */
-  if ((crtl->saves_all_registers || df_regs_ever_live_p (regno))
-      && !call_really_used_regs[regno])
+  /* DF handles cases where a register is explicitly referenced in
+     the rtl.  Incoming values are passed in call-clobbered registers,
+     so we can assume that any live call-saved register is set within
+     the function.  */
+  if (df_regs_ever_live_p (regno))
     return true;
 
-  /* Save both registers in an FPR pair if either one is used.  This is
-     needed for the case when MIN_FPRS_PER_FMT == 1, which allows the odd
-     register to be used without the even register.  */
-  if (FP_REG_P (regno)
-      && MAX_FPRS_PER_FMT == 2
-      && df_regs_ever_live_p (regno + 1)
-      && !call_really_used_regs[regno + 1])
+  /* Check for registers that are clobbered by FUNCTION_PROFILER.
+     These clobbers are not explicit in the rtl.  */
+  if (crtl->profile && MIPS_SAVE_REG_FOR_PROFILING_P (regno))
     return true;
 
-  /* We need to save the old frame pointer before setting up a new one.  */
+  /* If we're using a call-saved global pointer, the function's
+     prologue will need to set it up.  */
+  if (cfun->machine->global_pointer == regno)
+    return true;
+
+  /* The function's prologue will need to set the frame pointer if
+     frame_pointer_needed.  */
   if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
     return true;
 
-  /* Check for registers that must be saved for FUNCTION_PROFILER.  */
-  if (crtl->profile && MIPS_SAVE_REG_FOR_PROFILING_P (regno))
+  /* If a MIPS16 function returns a value in FPRs, its epilogue
+     will need to call an external libgcc routine.  This yet-to-be
+     generated call_insn will clobber $31.  */
+  if (regno == GP_REG_FIRST + 31 && mips16_cfun_returns_in_fpr_p ())
     return true;
 
-  /* We need to save the incoming return address if it is ever clobbered
-     within the function, if __builtin_eh_return is being used to set a
-     different return address, or if a stub is being used to return a
-     value in FPRs.  */
-  if (regno == GP_REG_FIRST + 31
-      && (df_regs_ever_live_p (regno)
-         || crtl->calls_eh_return
-         || mips16_cfun_returns_in_fpr_p ()))
+  return false;
+}
+
+/* Return true if the current function must save register REGNO.  */
+
+static bool
+mips_save_reg_p (unsigned int regno)
+{
+  if (mips_cfun_call_saved_reg_p (regno))
+    {
+      if (mips_cfun_might_clobber_call_saved_reg_p (regno))
+       return true;
+
+      /* Save both registers in an FPR pair if either one is used.  This is
+        needed for the case when MIN_FPRS_PER_FMT == 1, which allows the odd
+        register to be used without the even register.  */
+      if (FP_REG_P (regno)
+         && MAX_FPRS_PER_FMT == 2
+         && mips_cfun_might_clobber_call_saved_reg_p (regno + 1))
+       return true;
+    }
+
+  /* We need to save the incoming return address if __builtin_eh_return
+     is being used to set a different return address.  */
+  if (regno == GP_REG_FIRST + 31 && crtl->calls_eh_return)
     return true;
 
   return false;
@@ -8584,7 +8700,7 @@ mips_compute_frame_info (void)
 enum mips_loadgp_style
 mips_current_loadgp_style (void)
 {
-  if (!TARGET_USE_GOT || cfun->machine->global_pointer == 0)
+  if (!TARGET_USE_GOT || cfun->machine->global_pointer == INVALID_REGNUM)
     return LOADGP_NONE;
 
   if (TARGET_RTP_PIC)
@@ -8734,7 +8850,7 @@ mips_restore_gp (rtx temp)
 {
   gcc_assert (TARGET_ABICALLS && TARGET_OLDABI);
 
-  if (cfun->machine->global_pointer == 0)
+  if (cfun->machine->global_pointer == INVALID_REGNUM)
     return;
 
   if (TARGET_MIPS16)
@@ -8811,7 +8927,7 @@ static void
 mips_output_cplocal (void)
 {
   if (!TARGET_EXPLICIT_RELOCS
-      && cfun->machine->global_pointer > 0
+      && cfun->machine->global_pointer != INVALID_REGNUM
       && cfun->machine->global_pointer != GLOBAL_POINTER_REGNUM)
     output_asm_insn (".cplocal %+", 0);
 }
@@ -9047,7 +9163,7 @@ mips_expand_prologue (void)
   unsigned int nargs;
   rtx insn;
 
-  if (cfun->machine->global_pointer > 0)
+  if (cfun->machine->global_pointer != INVALID_REGNUM)
     SET_REGNO (pic_offset_table_rtx, cfun->machine->global_pointer);
 
   frame = &cfun->machine->frame;
@@ -9165,7 +9281,7 @@ mips_expand_prologue (void)
 
   /* Initialize the $gp save slot.  */
   if (frame->cprestore_size > 0
-      && cfun->machine->global_pointer != 0)
+      && cfun->machine->global_pointer != INVALID_REGNUM)
     {
       if (TARGET_MIPS16)
        mips_emit_move (mips_cprestore_slot (MIPS_PROLOGUE_TEMP (Pmode)),
@@ -9620,62 +9736,165 @@ mips_preferred_reload_class (rtx x, enum reg_class rclass)
   return rclass;
 }
 
-/* Implement REGISTER_MOVE_COST.  */
+/* RCLASS is a class involved in a REGISTER_MOVE_COST calculation.
+   Return a "canonical" class to represent it in later calculations.  */
 
-int
-mips_register_move_cost (enum machine_mode mode,
-                        enum reg_class to, enum reg_class from)
+static enum reg_class
+mips_canonicalize_move_class (enum reg_class rclass)
 {
-  if (TARGET_MIPS16)
+  /* All moves involving accumulator registers have the same cost.  */
+  if (reg_class_subset_p (rclass, ACC_REGS))
+    rclass = ACC_REGS;
+
+  /* Likewise promote subclasses of general registers to the most
+     interesting containing class.  */
+  if (TARGET_MIPS16 && reg_class_subset_p (rclass, M16_REGS))
+    rclass = M16_REGS;
+  else if (reg_class_subset_p (rclass, GENERAL_REGS))
+    rclass = GENERAL_REGS;
+
+  return rclass;
+}
+
+/* Return the cost of moving a value of mode MODE from a register of
+   class FROM to a GPR.  Return 0 for classes that are unions of other
+   classes handled by this function.  */
+
+static int
+mips_move_to_gpr_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
+                      enum reg_class from)
+{
+  switch (from)
     {
-      /* ??? We cannot move general registers into HI and LO because
-        MIPS16 has no MTHI and MTLO instructions.  Make the cost of
-        moves in the opposite direction just as high, which stops the
-        register allocators from using HI and LO for pseudos.  */
-      if (reg_class_subset_p (from, GENERAL_REGS)
-         && reg_class_subset_p (to, GENERAL_REGS))
-       {
-         if (reg_class_subset_p (from, M16_REGS)
-             || reg_class_subset_p (to, M16_REGS))
-           return 2;
-         /* Two MOVEs.  */
-         return 4;
-       }
+    case GENERAL_REGS:
+      /* A MIPS16 MOVE instruction, or a non-MIPS16 MOVE macro.  */
+      return 2;
+
+    case ACC_REGS:
+      /* MFLO and MFHI.  */
+      return 6;
+
+    case FP_REGS:
+      /* MFC1, etc.  */
+      return 4;
+
+    case ST_REGS:
+      /* LUI followed by MOVF.  */
+      return 4;
+
+    case COP0_REGS:
+    case COP2_REGS:
+    case COP3_REGS:
+      /* This choice of value is historical.  */
+      return 5;
+
+    default:
+      return 0;
     }
-  else if (reg_class_subset_p (from, GENERAL_REGS))
+}
+
+/* Return the cost of moving a value of mode MODE from a GPR to a
+   register of class TO.  Return 0 for classes that are unions of
+   other classes handled by this function.  */
+
+static int
+mips_move_from_gpr_cost (enum machine_mode mode, enum reg_class to)
+{
+  switch (to)
     {
-      if (reg_class_subset_p (to, GENERAL_REGS))
-       return 2;
-      if (reg_class_subset_p (to, FP_REGS))
-       return 4;
-      if (reg_class_subset_p (to, ALL_COP_AND_GR_REGS))
-       return 5;
-      if (reg_class_subset_p (to, ACC_REGS))
-       return 6;
+    case GENERAL_REGS:
+      /* A MIPS16 MOVE instruction, or a non-MIPS16 MOVE macro.  */
+      return 2;
+
+    case ACC_REGS:
+      /* MTLO and MTHI.  */
+      return 6;
+
+    case FP_REGS:
+      /* MTC1, etc.  */
+      return 4;
+
+    case ST_REGS:
+      /* A secondary reload through an FPR scratch.  */
+      return (mips_register_move_cost (mode, GENERAL_REGS, FP_REGS)
+             + mips_register_move_cost (mode, FP_REGS, ST_REGS));
+
+    case COP0_REGS:
+    case COP2_REGS:
+    case COP3_REGS:
+      /* This choice of value is historical.  */
+      return 5;
+
+    default:
+      return 0;
     }
-  else if (reg_class_subset_p (to, GENERAL_REGS))
+}
+
+/* Implement REGISTER_MOVE_COST.  Return 0 for classes that are the
+   maximum of the move costs for subclasses; regclass will work out
+   the maximum for us.  */
+
+int
+mips_register_move_cost (enum machine_mode mode,
+                        enum reg_class from, enum reg_class to)
+{
+  enum reg_class dregs;
+  int cost1, cost2;
+
+  from = mips_canonicalize_move_class (from);
+  to = mips_canonicalize_move_class (to);
+
+  /* Handle moves that can be done without using general-purpose registers.  */
+  if (from == FP_REGS)
     {
-      if (reg_class_subset_p (from, FP_REGS))
-       return 4;
-      if (reg_class_subset_p (from, ST_REGS))
-       /* LUI followed by MOVF.  */
+      if (to == FP_REGS && mips_mode_ok_for_mov_fmt_p (mode))
+       /* MOV.FMT.  */
        return 4;
-      if (reg_class_subset_p (from, ALL_COP_AND_GR_REGS))
-       return 5;
-      if (reg_class_subset_p (from, ACC_REGS))
-       return 6;
+      if (to == ST_REGS)
+       /* The sequence generated by mips_expand_fcc_reload.  */
+       return 8;
     }
-  else if (reg_class_subset_p (from, FP_REGS))
+
+  /* Handle cases in which only one class deviates from the ideal.  */
+  dregs = TARGET_MIPS16 ? M16_REGS : GENERAL_REGS;
+  if (from == dregs)
+    return mips_move_from_gpr_cost (mode, to);
+  if (to == dregs)
+    return mips_move_to_gpr_cost (mode, from);
+
+  /* Handles cases that require a GPR temporary.  */
+  cost1 = mips_move_to_gpr_cost (mode, from);
+  if (cost1 != 0)
     {
-      if (reg_class_subset_p (to, FP_REGS)
-         && mips_mode_ok_for_mov_fmt_p (mode))
-       return 4;
-      if (reg_class_subset_p (to, ST_REGS))
-       /* An expensive sequence.  */
-       return 8;
+      cost2 = mips_move_from_gpr_cost (mode, to);
+      if (cost2 != 0)
+       return cost1 + cost2;
     }
 
-  return 12;
+  return 0;
+}
+
+/* Implement TARGET_IRA_COVER_CLASSES.  */
+
+static const enum reg_class *
+mips_ira_cover_classes (void)
+{
+  static const enum reg_class acc_classes[] = {
+    GR_AND_ACC_REGS, FP_REGS, COP0_REGS, COP2_REGS, COP3_REGS,
+    ST_REGS, LIM_REG_CLASSES
+  };
+  static const enum reg_class no_acc_classes[] = {
+    GR_REGS, FP_REGS, COP0_REGS, COP2_REGS, COP3_REGS,
+    ST_REGS, LIM_REG_CLASSES
+  };
+
+  /* Don't allow the register allocators to use LO and HI in MIPS16 mode,
+     which has no MTLO or MTHI instructions.  Also, using GR_AND_ACC_REGS
+     as a cover class only works well when we keep per-register costs.
+     Using it when not optimizing can cause us to think accumulators
+     have the same cost as GPRs in cases where GPRs are actually much
+     cheaper.  */
+  return TARGET_MIPS16 || !optimize ? no_acc_classes : acc_classes;
 }
 
 /* Return the register class required for a secondary register when
@@ -9702,10 +9921,6 @@ mips_secondary_reload_class (enum reg_class rclass,
       if (!reg_class_subset_p (rclass, M16_REGS) && !M16_REG_P (regno))
        return M16_REGS;
 
-      /* We can't really copy to HI or LO at all in MIPS16 mode.  */
-      if (in_p ? reg_classes_intersect_p (rclass, ACC_REGS) : ACC_REG_P (regno))
-       return M16_REGS;
-
       return NO_REGS;
     }
 
@@ -9978,6 +10193,8 @@ mips_output_conditional_branch (rtx insn, rtx *operands,
   unsigned int length;
   rtx taken, not_taken;
 
+  gcc_assert (LABEL_P (operands[1]));  
+
   length = get_attr_length (insn);
   if (length <= 8)
     {
@@ -10086,6 +10303,17 @@ mips_output_order_conditional_branch (rtx insn, rtx *operands, bool inverted_p)
   return mips_output_conditional_branch (insn, operands, branch[1], branch[0]);
 }
 \f
+/* Return the assembly code for __sync_*() loop LOOP.  The loop should support
+   both normal and likely branches, using %? and %~ where appropriate.  */
+
+const char *
+mips_output_sync_loop (const char *loop)
+{
+  /* Use branch-likely instructions to work around the LL/SC R10000 errata.  */
+  mips_branch_likely = TARGET_FIX_R10000;
+  return loop;
+}
+\f
 /* Return the assembly code for DIV or DDIV instruction DIVISION, which has
    the operands given by OPERANDS.  Add in a divide-by-zero check if needed.
 
@@ -10317,7 +10545,10 @@ mips_issue_rate (void)
         but in reality only a maximum of 3 insns can be issued as
         floating-point loads and stores also require a slot in the
         AGEN pipe.  */
-     return 4;
+    case PROCESSOR_R10000:
+      /* All R10K Processors are quad-issue (being the first MIPS
+         processors to support this feature). */
+      return 4;
 
     case PROCESSOR_20KC:
     case PROCESSOR_R4130:
@@ -10325,6 +10556,7 @@ mips_issue_rate (void)
     case PROCESSOR_R5500:
     case PROCESSOR_R7000:
     case PROCESSOR_R9000:
+    case PROCESSOR_OCTEON:
       return 2;
 
     case PROCESSOR_SB1:
@@ -10466,6 +10698,9 @@ mips_multipass_dfa_lookahead (void)
   if (TUNE_LOONGSON_2EF)
     return 4;
 
+  if (TUNE_OCTEON)
+    return 2;
+
   return 0;
 }
 \f
@@ -10881,6 +11116,7 @@ AVAIL_NON_MIPS16 (dspr2, TARGET_DSPR2)
 AVAIL_NON_MIPS16 (dsp_32, !TARGET_64BIT && TARGET_DSP)
 AVAIL_NON_MIPS16 (dspr2_32, !TARGET_64BIT && TARGET_DSPR2)
 AVAIL_NON_MIPS16 (loongson, TARGET_LOONGSON_VECTORS)
+AVAIL_NON_MIPS16 (cache, TARGET_CACHE_BUILTIN)
 
 /* Construct a mips_builtin_description from the given arguments.
 
@@ -11019,7 +11255,6 @@ AVAIL_NON_MIPS16 (loongson, TARGET_LOONGSON_VECTORS)
 #define CODE_FOR_loongson_pminub CODE_FOR_uminv8qi3
 #define CODE_FOR_loongson_pmulhuh CODE_FOR_umulv4hi3_highpart
 #define CODE_FOR_loongson_pmulhh CODE_FOR_smulv4hi3_highpart
-#define CODE_FOR_loongson_biadd CODE_FOR_reduc_uplus_v8qi
 #define CODE_FOR_loongson_psubw CODE_FOR_subv2si3
 #define CODE_FOR_loongson_psubh CODE_FOR_subv4hi3
 #define CODE_FOR_loongson_psubb CODE_FOR_subv8qi3
@@ -11311,7 +11546,10 @@ static const struct mips_builtin_description mips_builtins[] = {
   LOONGSON_BUILTIN_SUFFIX (punpcklwd, u, MIPS_UV2SI_FTYPE_UV2SI_UV2SI),
   LOONGSON_BUILTIN_SUFFIX (punpcklbh, s, MIPS_V8QI_FTYPE_V8QI_V8QI),
   LOONGSON_BUILTIN_SUFFIX (punpcklhw, s, MIPS_V4HI_FTYPE_V4HI_V4HI),
-  LOONGSON_BUILTIN_SUFFIX (punpcklwd, s, MIPS_V2SI_FTYPE_V2SI_V2SI)
+  LOONGSON_BUILTIN_SUFFIX (punpcklwd, s, MIPS_V2SI_FTYPE_V2SI_V2SI),
+
+  /* Sundry other built-in functions.  */
+  DIRECT_NO_TARGET_BUILTIN (cache, MIPS_VOID_FTYPE_SI_CVPOINTER, cache)
 };
 
 /* MODE is a vector mode whose elements have type TYPE.  Return the type
@@ -11333,10 +11571,25 @@ mips_builtin_vector_type (tree type, enum machine_mode mode)
   return types[mode_index];
 }
 
+/* Return a type for 'const volatile void *'.  */
+
+static tree
+mips_build_cvpointer_type (void)
+{
+  static tree cache;
+
+  if (cache == NULL_TREE)
+    cache = build_pointer_type (build_qualified_type
+                               (void_type_node,
+                                TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE));
+  return cache;
+}
+
 /* Source-level argument types.  */
 #define MIPS_ATYPE_VOID void_type_node
 #define MIPS_ATYPE_INT integer_type_node
 #define MIPS_ATYPE_POINTER ptr_type_node
+#define MIPS_ATYPE_CVPOINTER mips_build_cvpointer_type ()
 
 /* Standard mode-based argument types.  */
 #define MIPS_ATYPE_UQI unsigned_intQI_type_node
@@ -11429,14 +11682,24 @@ static rtx
 mips_prepare_builtin_arg (enum insn_code icode,
                          unsigned int opno, tree exp, unsigned int argno)
 {
+  tree arg;
   rtx value;
   enum machine_mode mode;
 
-  value = expand_normal (CALL_EXPR_ARG (exp, argno));
+  arg = CALL_EXPR_ARG (exp, argno);
+  value = expand_normal (arg);
   mode = insn_data[icode].operand[opno].mode;
   if (!insn_data[icode].operand[opno].predicate (value, mode))
     {
-      value = copy_to_mode_reg (mode, value);
+      /* We need to get the mode from ARG for two reasons:
+
+          - to cope with address operands, where MODE is the mode of the
+            memory, rather than of VALUE itself.
+
+          - to cope with special predicates like pmode_register_operand,
+            where MODE is VOIDmode.  */
+      value = copy_to_mode_reg (TYPE_MODE (TREE_TYPE (arg)), value);
+
       /* Check the predicate again.  */
       if (!insn_data[icode].operand[opno].predicate (value, mode))
        {
@@ -11479,7 +11742,8 @@ mips_expand_builtin_direct (enum insn_code icode, rtx target, tree exp,
   opno = 0;
   if (has_target_p)
     {
-      ops[opno] = mips_prepare_builtin_target (icode, opno, target);
+      target = mips_prepare_builtin_target (icode, opno, target);
+      ops[opno] = target;
       opno++;
     }
 
@@ -11666,8 +11930,7 @@ mips_expand_builtin_bposge (enum mips_builtin_type builtin_type, rtx target)
 
 static rtx
 mips_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
-                    enum machine_mode mode ATTRIBUTE_UNUSED,
-                    int ignore ATTRIBUTE_UNUSED)
+                    enum machine_mode mode, int ignore)
 {
   tree fndecl;
   unsigned int fcode, avail;
@@ -11683,7 +11946,7 @@ mips_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
     {
       error ("built-in function %qs not supported for MIPS16",
             IDENTIFIER_POINTER (DECL_NAME (fndecl)));
-      return const0_rtx;
+      return ignore ? const0_rtx : CONST0_RTX (mode);
     }
   switch (d->builtin_type)
     {
@@ -11983,6 +12246,378 @@ mips16_lay_out_constants (void)
   mips16_emit_constants (pool.first, get_last_insn ());
 }
 \f
+/* Return true if it is worth r10k_simplify_address's while replacing
+   an address with X.  We are looking for constants, and for addresses
+   at a known offset from the incoming stack pointer.  */
+
+static bool
+r10k_simplified_address_p (rtx x)
+{
+  if (GET_CODE (x) == PLUS && CONST_INT_P (XEXP (x, 1)))
+    x = XEXP (x, 0);
+  return x == virtual_incoming_args_rtx || CONSTANT_P (x);
+}
+
+/* X is an expression that appears in INSN.  Try to use the UD chains
+   to simplify it, returning the simplified form on success and the
+   original form otherwise.  Replace the incoming value of $sp with
+   virtual_incoming_args_rtx (which should never occur in X otherwise).  */
+
+static rtx
+r10k_simplify_address (rtx x, rtx insn)
+{
+  rtx newx, op0, op1, set, def_insn, note;
+  df_ref use, def;
+  struct df_link *defs;
+
+  newx = NULL_RTX;
+  if (UNARY_P (x))
+    {
+      op0 = r10k_simplify_address (XEXP (x, 0), insn);
+      if (op0 != XEXP (x, 0))
+       newx = simplify_gen_unary (GET_CODE (x), GET_MODE (x),
+                                  op0, GET_MODE (XEXP (x, 0)));
+    }
+  else if (BINARY_P (x))
+    {
+      op0 = r10k_simplify_address (XEXP (x, 0), insn);
+      op1 = r10k_simplify_address (XEXP (x, 1), insn);
+      if (op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
+       newx = simplify_gen_binary (GET_CODE (x), GET_MODE (x), op0, op1);
+    }
+  else if (GET_CODE (x) == LO_SUM)
+    {
+      /* LO_SUMs can be offset from HIGHs, if we know they won't
+        overflow.  See mips_classify_address for the rationale behind
+        the lax check.  */
+      op0 = r10k_simplify_address (XEXP (x, 0), insn);
+      if (GET_CODE (op0) == HIGH)
+       newx = XEXP (x, 1);
+    }
+  else if (REG_P (x))
+    {
+      /* Uses are recorded by regno_reg_rtx, not X itself.  */
+      use = df_find_use (insn, regno_reg_rtx[REGNO (x)]);
+      gcc_assert (use);
+      defs = DF_REF_CHAIN (use);
+
+      /* Require a single definition.  */
+      if (defs && defs->next == NULL)
+       {
+         def = defs->ref;
+         if (DF_REF_IS_ARTIFICIAL (def))
+           {
+             /* Replace the incoming value of $sp with
+                virtual_incoming_args_rtx.  */
+             if (x == stack_pointer_rtx
+                 && DF_REF_BB (def) == ENTRY_BLOCK_PTR)
+               newx = virtual_incoming_args_rtx;
+           }
+         else if (dominated_by_p (CDI_DOMINATORS, DF_REF_BB (use),
+                                  DF_REF_BB (def)))
+           {
+             /* Make sure that DEF_INSN is a single set of REG.  */
+             def_insn = DF_REF_INSN (def);
+             if (NONJUMP_INSN_P (def_insn))
+               {
+                 set = single_set (def_insn);
+                 if (set && rtx_equal_p (SET_DEST (set), x))
+                   {
+                     /* Prefer to use notes, since the def-use chains
+                        are often shorter.  */
+                     note = find_reg_equal_equiv_note (def_insn);
+                     if (note)
+                       newx = XEXP (note, 0);
+                     else
+                       newx = SET_SRC (set);
+                     newx = r10k_simplify_address (newx, def_insn);
+                   }
+               }
+           }
+       }
+    }
+  if (newx && r10k_simplified_address_p (newx))
+    return newx;
+  return x;
+}
+
+/* Return true if ADDRESS is known to be an uncached address
+   on R10K systems.  */
+
+static bool
+r10k_uncached_address_p (unsigned HOST_WIDE_INT address)
+{
+  unsigned HOST_WIDE_INT upper;
+
+  /* Check for KSEG1.  */
+  if (address + 0x60000000 < 0x20000000)
+    return true;
+
+  /* Check for uncached XKPHYS addresses.  */
+  if (Pmode == DImode)
+    {
+      upper = (address >> 40) & 0xf9ffff;
+      if (upper == 0x900000 || upper == 0xb80000)
+       return true;
+    }
+  return false;
+}
+
+/* Return true if we can prove that an access to address X in instruction
+   INSN would be safe from R10K speculation.  This X is a general
+   expression; it might not be a legitimate address.  */
+
+static bool
+r10k_safe_address_p (rtx x, rtx insn)
+{
+  rtx base, offset;
+  HOST_WIDE_INT offset_val;
+
+  x = r10k_simplify_address (x, insn);
+
+  /* Check for references to the stack frame.  It doesn't really matter
+     how much of the frame has been allocated at INSN; -mr10k-cache-barrier
+     allows us to assume that accesses to any part of the eventual frame
+     is safe from speculation at any point in the function.  */
+  mips_split_plus (x, &base, &offset_val);
+  if (base == virtual_incoming_args_rtx
+      && offset_val >= -cfun->machine->frame.total_size
+      && offset_val < cfun->machine->frame.args_size)
+    return true;
+
+  /* Check for uncached addresses.  */
+  if (CONST_INT_P (x))
+    return r10k_uncached_address_p (INTVAL (x));
+
+  /* Check for accesses to a static object.  */
+  split_const (x, &base, &offset);
+  return offset_within_block_p (base, INTVAL (offset));
+}
+
+/* Return true if a MEM with MEM_EXPR EXPR and MEM_OFFSET OFFSET is
+   an in-range access to an automatic variable, or to an object with
+   a link-time-constant address.  */
+
+static bool
+r10k_safe_mem_expr_p (tree expr, rtx offset)
+{
+  if (expr == NULL_TREE
+      || offset == NULL_RTX
+      || !CONST_INT_P (offset)
+      || INTVAL (offset) < 0
+      || INTVAL (offset) >= int_size_in_bytes (TREE_TYPE (expr)))
+    return false;
+
+  while (TREE_CODE (expr) == COMPONENT_REF)
+    {
+      expr = TREE_OPERAND (expr, 0);
+      if (expr == NULL_TREE)
+       return false;
+    }
+
+  return DECL_P (expr);
+}
+
+/* A for_each_rtx callback for which DATA points to the instruction
+   containing *X.  Stop the search if we find a MEM that is not safe
+   from R10K speculation.  */
+
+static int
+r10k_needs_protection_p_1 (rtx *loc, void *data)
+{
+  rtx mem;
+
+  mem = *loc;
+  if (!MEM_P (mem))
+    return 0;
+
+  if (r10k_safe_mem_expr_p (MEM_EXPR (mem), MEM_OFFSET (mem)))
+    return -1;
+
+  if (r10k_safe_address_p (XEXP (mem, 0), (rtx) data))
+    return -1;
+
+  return 1;
+}
+
+/* A note_stores callback for which DATA points to an instruction pointer.
+   If *DATA is nonnull, make it null if it X contains a MEM that is not
+   safe from R10K speculation.  */
+
+static void
+r10k_needs_protection_p_store (rtx x, const_rtx pat ATTRIBUTE_UNUSED,
+                              void *data)
+{
+  rtx *insn_ptr;
+
+  insn_ptr = (rtx *) data;
+  if (*insn_ptr && for_each_rtx (&x, r10k_needs_protection_p_1, *insn_ptr))
+    *insn_ptr = NULL_RTX;
+}
+
+/* A for_each_rtx callback that iterates over the pattern of a CALL_INSN.
+   Return nonzero if the call is not to a declared function.  */
+
+static int
+r10k_needs_protection_p_call (rtx *loc, void *data ATTRIBUTE_UNUSED)
+{
+  rtx x;
+
+  x = *loc;
+  if (!MEM_P (x))
+    return 0;
+
+  x = XEXP (x, 0);
+  if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_DECL (x))
+    return -1;
+
+  return 1;
+}
+
+/* Return true if instruction INSN needs to be protected by an R10K
+   cache barrier.  */
+
+static bool
+r10k_needs_protection_p (rtx insn)
+{
+  if (CALL_P (insn))
+    return for_each_rtx (&PATTERN (insn), r10k_needs_protection_p_call, NULL);
+
+  if (mips_r10k_cache_barrier == R10K_CACHE_BARRIER_STORE)
+    {
+      note_stores (PATTERN (insn), r10k_needs_protection_p_store, &insn);
+      return insn == NULL_RTX;
+    }
+
+  return for_each_rtx (&PATTERN (insn), r10k_needs_protection_p_1, insn);
+}
+
+/* Return true if BB is only reached by blocks in PROTECTED_BBS and if every
+   edge is unconditional.  */
+
+static bool
+r10k_protected_bb_p (basic_block bb, sbitmap protected_bbs)
+{
+  edge_iterator ei;
+  edge e;
+
+  FOR_EACH_EDGE (e, ei, bb->preds)
+    if (!single_succ_p (e->src)
+       || !TEST_BIT (protected_bbs, e->src->index)
+       || (e->flags & EDGE_COMPLEX) != 0)
+      return false;
+  return true;
+}
+
+/* Implement -mr10k-cache-barrier= for the current function.  */
+
+static void
+r10k_insert_cache_barriers (void)
+{
+  int *rev_post_order;
+  unsigned int i, n;
+  basic_block bb;
+  sbitmap protected_bbs;
+  rtx insn, end, unprotected_region;
+
+  if (TARGET_MIPS16)
+    {
+      sorry ("%qs does not support MIPS16 code", "-mr10k-cache-barrier");
+      return;
+    }
+
+  /* Restore the BLOCK_FOR_INSN pointers, which are needed by DF.  */
+  compute_bb_for_insn ();
+
+  /* Create def-use chains.  */
+  df_set_flags (DF_EQ_NOTES);
+  df_chain_add_problem (DF_UD_CHAIN);
+  df_analyze ();
+
+  /* Calculate dominators.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+
+  /* Bit X of PROTECTED_BBS is set if the last operation in basic block
+     X is protected by a cache barrier.  */
+  protected_bbs = sbitmap_alloc (last_basic_block);
+  sbitmap_zero (protected_bbs);
+
+  /* Iterate over the basic blocks in reverse post-order.  */
+  rev_post_order = XNEWVEC (int, last_basic_block);
+  n = pre_and_rev_post_order_compute (NULL, rev_post_order, false);
+  for (i = 0; i < n; i++)
+    {
+      bb = BASIC_BLOCK (rev_post_order[i]);
+
+      /* If this block is only reached by unconditional edges, and if the
+        source of every edge is protected, the beginning of the block is
+        also protected.  */
+      if (r10k_protected_bb_p (bb, protected_bbs))
+       unprotected_region = NULL_RTX;
+      else
+       unprotected_region = pc_rtx;
+      end = NEXT_INSN (BB_END (bb));
+
+      /* UNPROTECTED_REGION is:
+
+        - null if we are processing a protected region,
+        - pc_rtx if we are processing an unprotected region but have
+          not yet found the first instruction in it
+        - the first instruction in an unprotected region otherwise.  */
+      for (insn = BB_HEAD (bb); insn != end; insn = NEXT_INSN (insn))
+       {
+         if (unprotected_region && INSN_P (insn))
+           {
+             if (recog_memoized (insn) == CODE_FOR_mips_cache)
+               /* This CACHE instruction protects the following code.  */
+               unprotected_region = NULL_RTX;
+             else
+               {
+                 /* See if INSN is the first instruction in this
+                    unprotected region.  */
+                 if (unprotected_region == pc_rtx)
+                   unprotected_region = insn;
+
+                 /* See if INSN needs to be protected.  If so,
+                    we must insert a cache barrier somewhere between
+                    PREV_INSN (UNPROTECTED_REGION) and INSN.  It isn't
+                    clear which position is better performance-wise,
+                    but as a tie-breaker, we assume that it is better
+                    to allow delay slots to be back-filled where
+                    possible, and that it is better not to insert
+                    barriers in the middle of already-scheduled code.
+                    We therefore insert the barrier at the beginning
+                    of the region.  */
+                 if (r10k_needs_protection_p (insn))
+                   {
+                     emit_insn_before (gen_r10k_cache_barrier (),
+                                       unprotected_region);
+                     unprotected_region = NULL_RTX;
+                   }
+               }
+           }
+
+         if (CALL_P (insn))
+           /* The called function is not required to protect the exit path.
+              The code that follows a call is therefore unprotected.  */
+           unprotected_region = pc_rtx;
+       }
+
+      /* Record whether the end of this block is protected.  */
+      if (unprotected_region == NULL_RTX)
+       SET_BIT (protected_bbs, bb->index);
+    }
+  XDELETEVEC (rev_post_order);
+
+  sbitmap_free (protected_bbs);
+
+  free_dominance_info (CDI_DOMINATORS);
+
+  df_finish_pass (false);
+
+  free_bb_for_insn ();
+}
+\f
 /* A temporary variable used by for_each_rtx callbacks, etc.  */
 static rtx mips_sim_insn;
 
@@ -12634,6 +13269,13 @@ mips_reorg_process_insns (void)
                 orphaned high-part relocation.  */
              if (mips_orphaned_high_part_p (htab, insn))
                delete_insn (insn);
+             /* Also delete cache barriers if the last instruction
+                was an annulled branch.  INSN will not be speculatively
+                executed.  */
+             else if (recog_memoized (insn) == CODE_FOR_r10k_cache_barrier
+                      && last_insn
+                      && INSN_ANNULLED_BRANCH_P (SEQ_BEGIN (last_insn)))
+               delete_insn (insn);
              else
                {
                  mips_avoid_hazard (last_insn, insn, &hilo_delay,
@@ -12653,7 +13295,9 @@ static void
 mips_reorg (void)
 {
   mips16_lay_out_constants ();
-  if (mips_base_delayed_branch)
+  if (mips_r10k_cache_barrier != R10K_CACHE_BARRIER_NONE)
+    r10k_insert_cache_barriers ();
+  if (optimize > 0 && flag_delayed_branch)
     dbr_schedule (get_insns ());
   mips_reorg_process_insns ();
   if (!TARGET_MIPS16
@@ -13082,6 +13726,17 @@ mips_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
        return false;
       return true;
 
+    case OPT_mr10k_cache_barrier_:
+      if (strcmp (arg, "load-store") == 0)
+       mips_r10k_cache_barrier = R10K_CACHE_BARRIER_LOAD_STORE;
+      else if (strcmp (arg, "store") == 0)
+       mips_r10k_cache_barrier = R10K_CACHE_BARRIER_STORE;
+      else if (strcmp (arg, "none") == 0)
+       mips_r10k_cache_barrier = R10K_CACHE_BARRIER_NONE;
+      else
+       return false;
+      return true;
+
     default:
       return true;
     }
@@ -13317,10 +13972,39 @@ mips_override_options (void)
     warning (0, "the %qs architecture does not support paired-single"
             " instructions", mips_arch_info->name);
 
+  if (mips_r10k_cache_barrier != R10K_CACHE_BARRIER_NONE
+      && !TARGET_CACHE_BUILTIN)
+    {
+      error ("%qs requires a target that provides the %qs instruction",
+            "-mr10k-cache-barrier", "cache");
+      mips_r10k_cache_barrier = R10K_CACHE_BARRIER_NONE;
+    }
+
   /* If TARGET_DSPR2, enable MASK_DSP.  */
   if (TARGET_DSPR2)
     target_flags |= MASK_DSP;
 
+  /* .eh_frame addresses should be the same width as a C pointer.
+     Most MIPS ABIs support only one pointer size, so the assembler
+     will usually know exactly how big an .eh_frame address is.
+
+     Unfortunately, this is not true of the 64-bit EABI.  The ABI was
+     originally defined to use 64-bit pointers (i.e. it is LP64), and
+     this is still the default mode.  However, we also support an n32-like
+     ILP32 mode, which is selected by -mlong32.  The problem is that the
+     assembler has traditionally not had an -mlong option, so it has
+     traditionally not known whether we're using the ILP32 or LP64 form.
+
+     As it happens, gas versions up to and including 2.19 use _32-bit_
+     addresses for EABI64 .cfi_* directives.  This is wrong for the
+     default LP64 mode, so we can't use the directives by default.
+     Moreover, since gas's current behavior is at odds with gcc's
+     default behavior, it seems unwise to rely on future versions
+     of gas behaving the same way.  We therefore avoid using .cfi
+     directives for -mlong32 as well.  */
+  if (mips_abi == ABI_EABI && TARGET_64BIT)
+    flag_dwarf2_cfi_asm = 0;
+
   mips_init_print_operand_punct ();
 
   /* Set up array to map GCC register number to debug register number.
@@ -13375,9 +14059,26 @@ mips_override_options (void)
       && mips_matching_cpu_name_p (mips_arch_info->name, "r4400"))
     target_flags |= MASK_FIX_R4400;
 
+  /* Default to working around R10000 errata only if the processor
+     was selected explicitly.  */
+  if ((target_flags_explicit & MASK_FIX_R10000) == 0
+      && mips_matching_cpu_name_p (mips_arch_info->name, "r10000"))
+    target_flags |= MASK_FIX_R10000;
+
+  /* Make sure that branch-likely instructions available when using
+     -mfix-r10000.  The instructions are not available if either:
+
+       1. -mno-branch-likely was passed.
+       2. The selected ISA does not support branch-likely and
+          the command line does not include -mbranch-likely.  */
+  if (TARGET_FIX_R10000
+      && ((target_flags_explicit & MASK_BRANCHLIKELY) == 0
+          ? !ISA_HAS_BRANCHLIKELY
+          : !TARGET_BRANCHLIKELY))
+    sorry ("%qs requires branch-likely instructions", "-mfix-r10000");
+
   /* Save base state of options.  */
   mips_base_target_flags = target_flags;
-  mips_base_delayed_branch = flag_delayed_branch;
   mips_base_schedule_insns = flag_schedule_insns;
   mips_base_reorder_blocks_and_partition = flag_reorder_blocks_and_partition;
   mips_base_move_loop_invariants = flag_move_loop_invariants;
@@ -13390,9 +14091,6 @@ mips_override_options (void)
      Do all CPP-sensitive stuff in non-MIPS16 mode; we'll switch to
      MIPS16 mode afterwards if need be.  */
   mips_set_mips16_mode (false);
-
-  /* We call dbr_schedule from within mips_reorg.  */
-  flag_delayed_branch = 0;
 }
 
 /* Swap the register information for registers I and I + 1, which
@@ -13423,7 +14121,14 @@ mips_swap_registers (unsigned int i)
 void
 mips_conditional_register_usage (void)
 {
-  if (!ISA_HAS_DSP)
+
+  if (ISA_HAS_DSP)
+    {
+      /* These DSP control register fields are global.  */
+      global_regs[CCDSP_PO_REGNUM] = 1;
+      global_regs[CCDSP_SC_REGNUM] = 1;
+    }
+  else 
     {
       int regno;
 
@@ -13702,6 +14407,9 @@ mips_order_regs_for_local_alloc (void)
 #undef TARGET_DWARF_REGISTER_SPAN
 #define TARGET_DWARF_REGISTER_SPAN mips_dwarf_register_span
 
+#undef TARGET_IRA_COVER_CLASSES
+#define TARGET_IRA_COVER_CLASSES mips_ira_cover_classes
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 #include "gt-mips.h"