OSDN Git Service

2009-04-02 Chao-ying Fu <fu@mips.com>
[pf3gnuchains/gcc-fork.git] / gcc / config / mips / mips.h
index 815a529..fbcfdca 100644 (file)
@@ -1,6 +1,6 @@
 /* Definitions of target machine for GNU compiler.  MIPS version.
    Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009
    Free Software Foundation, Inc.
    Contributed by A. Lichnewsky (lich@inria.inria.fr).
    Changed by Michael Meissner (meissner@osf.org).
@@ -50,6 +50,7 @@ enum processor_type {
   PROCESSOR_LOONGSON_2E,
   PROCESSOR_LOONGSON_2F,
   PROCESSOR_M4K,
+  PROCESSOR_OCTEON,
   PROCESSOR_R3900,
   PROCESSOR_R6000,
   PROCESSOR_R4000,
@@ -66,6 +67,7 @@ enum processor_type {
   PROCESSOR_R7000,
   PROCESSOR_R8000,
   PROCESSOR_R9000,
+  PROCESSOR_R10000,
   PROCESSOR_SB1,
   PROCESSOR_SB1A,
   PROCESSOR_SR71000,
@@ -148,6 +150,15 @@ enum mips_code_readable_setting {
 /* True if we are generating position-independent VxWorks RTP code.  */
 #define TARGET_RTP_PIC (TARGET_VXWORKS_RTP && flag_pic)
 
+/* True if the output file is marked as ".abicalls; .option pic0"
+   (-call_nonpic).  */
+#define TARGET_ABICALLS_PIC0 \
+  (TARGET_ABSOLUTE_ABICALLS && TARGET_PLT)
+
+/* True if the output file is marked as ".abicalls; .option pic2" (-KPIC).  */
+#define TARGET_ABICALLS_PIC2 \
+  (TARGET_ABICALLS && !TARGET_ABICALLS_PIC0)
+
 /* True if the call patterns should be split into a jalr followed by
    an instruction to restore $gp.  It is only safe to split the load
    from the call when every use of $gp is explicit.  */
@@ -200,7 +211,10 @@ enum mips_code_readable_setting {
    Although GAS does understand .gpdword, the SGI linker mishandles
    the relocations GAS generates (R_MIPS_GPREL32 followed by R_MIPS_64).
    We therefore disable GP-relative switch tables for n64 on IRIX targets.  */
-#define TARGET_GPWORD (TARGET_ABICALLS && !(mips_abi == ABI_64 && TARGET_IRIX))
+#define TARGET_GPWORD                          \
+  (TARGET_ABICALLS                             \
+   && !TARGET_ABSOLUTE_ABICALLS                        \
+   && !(mips_abi == ABI_64 && TARGET_IRIX))
 
 /* Generate mips16 code */
 #define TARGET_MIPS16          ((target_flags & MASK_MIPS16) != 0)
@@ -241,6 +255,7 @@ enum mips_code_readable_setting {
 #define TARGET_MIPS5500             (mips_arch == PROCESSOR_R5500)
 #define TARGET_MIPS7000             (mips_arch == PROCESSOR_R7000)
 #define TARGET_MIPS9000             (mips_arch == PROCESSOR_R9000)
+#define TARGET_OCTEON              (mips_arch == PROCESSOR_OCTEON)
 #define TARGET_SB1                  (mips_arch == PROCESSOR_SB1                \
                                     || mips_arch == PROCESSOR_SB1A)
 #define TARGET_SR71K                (mips_arch == PROCESSOR_SR71000)
@@ -267,6 +282,7 @@ enum mips_code_readable_setting {
 #define TUNE_MIPS6000               (mips_tune == PROCESSOR_R6000)
 #define TUNE_MIPS7000               (mips_tune == PROCESSOR_R7000)
 #define TUNE_MIPS9000               (mips_tune == PROCESSOR_R9000)
+#define TUNE_OCTEON                (mips_tune == PROCESSOR_OCTEON)
 #define TUNE_SB1                    (mips_tune == PROCESSOR_SB1                \
                                     || mips_tune == PROCESSOR_SB1A)
 
@@ -513,10 +529,19 @@ enum mips_code_readable_setting {
          builtin_define ("_MIPSEL");                                   \
        }                                                               \
                                                                         \
+      /* Whether calls should go through $25.  The separate __PIC__    \
+        macro indicates whether abicalls code might use a GOT.  */     \
+      if (TARGET_ABICALLS)                                             \
+       builtin_define ("__mips_abicalls");                             \
+                                                                       \
       /* Whether Loongson vector modes are enabled.  */                 \
       if (TARGET_LOONGSON_VECTORS)                                     \
         builtin_define ("__mips_loongson_vector_rev");                  \
                                                                        \
+      /* Historical Octeon macro.  */                                  \
+      if (TARGET_OCTEON)                                               \
+       builtin_define ("__OCTEON__");                                  \
+                                                                       \
       /* Macros dependent on the C dialect.  */                                \
       if (preprocessing_asm_p ())                                      \
        {                                                               \
@@ -545,6 +570,9 @@ enum mips_code_readable_setting {
                                                                        \
       if (mips_abi == ABI_EABI)                                                \
        builtin_define ("__mips_eabi");                                 \
+                                                                       \
+      if (TARGET_CACHE_BUILTIN)                                                \
+       builtin_define ("__GCC_HAVE_BUILTIN_MIPS_CACHE");               \
     }                                                                  \
   while (0)
 
@@ -676,12 +704,13 @@ enum mips_code_readable_setting {
      %{march=mips1|march=r2000|march=r3000|march=r3900:-mips1} \
      %{march=mips2|march=r6000:-mips2} \
      %{march=mips3|march=r4*|march=vr4*|march=orion|march=loongson2*:-mips3} \
-     %{march=mips4|march=r8000|march=vr5*|march=rm7000|march=rm9000:-mips4} \
+     %{march=mips4|march=r8000|march=vr5*|march=rm7000|march=rm9000 \
+       |march=r10000|march=r12000|march=r14000|march=r16000:-mips4} \
      %{march=mips32|march=4kc|march=4km|march=4kp|march=4ksc:-mips32} \
      %{march=mips32r2|march=m4k|march=4ke*|march=4ksd|march=24k* \
        |march=34k*|march=74k*: -mips32r2} \
      %{march=mips64|march=5k*|march=20k*|march=sb1*|march=sr71000: -mips64} \
-     %{march=mips64r2: -mips64r2} \
+     %{march=mips64r2|march=octeon: -mips64r2} \
      %{!march=*: -" MULTILIB_ISA_DEFAULT "}}"
 
 /* A spec that infers a -mhard-float or -msoft-float setting from an
@@ -691,7 +720,7 @@ enum mips_code_readable_setting {
 #define MIPS_ARCH_FLOAT_SPEC \
   "%{mhard-float|msoft-float|march=mips*:; \
      march=vr41*|march=m4k|march=4k*|march=24kc|march=24kec \
-     |march=34kc|march=74kc|march=5kc: -msoft-float; \
+     |march=34kc|march=74kc|march=5kc|march=octeon: -msoft-float; \
      march=*: -mhard-float}"
 
 /* A spec condition that matches 32-bit options.  It only works if
@@ -715,8 +744,15 @@ enum mips_code_readable_setting {
   {"abi", "%{!mabi=*:-mabi=%(VALUE)}" }, \
   {"float", "%{!msoft-float:%{!mhard-float:-m%(VALUE)-float}}" }, \
   {"divide", "%{!mdivide-traps:%{!mdivide-breaks:-mdivide-%(VALUE)}}" }, \
-  {"llsc", "%{!mllsc:%{!mno-llsc:-m%(VALUE)}}" }
+  {"llsc", "%{!mllsc:%{!mno-llsc:-m%(VALUE)}}" }, \
+  {"mips-plt", "%{!mplt:%{!mno-plt:-m%(VALUE)}}" }
+
+
+/* A spec that infers the -mdsp setting from an -march argument.  */
+#define BASE_DRIVER_SELF_SPECS \
+  "%{!mno-dsp:%{march=24ke*|march=34k*|march=74k*: -mdsp}}"
 
+#define DRIVER_SELF_SPECS BASE_DRIVER_SELF_SPECS
 
 #define GENERATE_DIVIDE_TRAPS (TARGET_DIVIDE_TRAPS \
                                && ISA_HAS_COND_TRAP)
@@ -731,9 +767,15 @@ enum mips_code_readable_setting {
 /* Likewise for 32-bit regs.  */
 #define ABI_NEEDS_32BIT_REGS   (mips_abi == ABI_32)
 
-/* True if symbols are 64 bits wide.  At present, n64 is the only
-   ABI for which this is true.  */
-#define ABI_HAS_64BIT_SYMBOLS  (mips_abi == ABI_64 && !TARGET_SYM32)
+/* True if the file format uses 64-bit symbols.  At present, this is
+   only true for n64, which uses 64-bit ELF.  */
+#define FILE_HAS_64BIT_SYMBOLS (mips_abi == ABI_64)
+
+/* True if symbols are 64 bits wide.  This is usually determined by
+   the ABI's file format, but it can be overridden by -msym32.  Note that
+   overriding the size with -msym32 changes the ABI of relocatable objects,
+   although it doesn't change the ABI of a fully-linked object.  */
+#define ABI_HAS_64BIT_SYMBOLS  (FILE_HAS_64BIT_SYMBOLS && !TARGET_SYM32)
 
 /* ISA has instructions for managing 64-bit fp and gp regs (e.g. mips3).  */
 #define ISA_HAS_64BIT_REGS     (ISA_MIPS3                              \
@@ -759,6 +801,11 @@ enum mips_code_readable_setting {
                                  || ISA_MIPS64R2)                      \
                                 && !TARGET_MIPS16)
 
+/* ISA has a three-operand multiplication instruction.  */
+#define ISA_HAS_DMUL3          (TARGET_64BIT                           \
+                                && TARGET_OCTEON                       \
+                                && !TARGET_MIPS16)
+
 /* ISA has the floating-point conditional move instructions introduced
    in mips4.  */
 #define ISA_HAS_FP_CONDMOVE    ((ISA_MIPS4                             \
@@ -884,6 +931,7 @@ enum mips_code_readable_setting {
 
 /* ISA has data prefetch instructions.  This controls use of 'pref'.  */
 #define ISA_HAS_PREFETCH       ((ISA_MIPS4                             \
+                                 || TARGET_LOONGSON_2EF                \
                                  || ISA_MIPS32                         \
                                  || ISA_MIPS32R2                       \
                                  || ISA_MIPS64                         \
@@ -983,6 +1031,30 @@ enum mips_code_readable_setting {
   (target_flags_explicit & MASK_LLSC   \
    ? TARGET_LLSC && !TARGET_MIPS16     \
    : ISA_HAS_LL_SC)
+
+/* ISA includes the baddu instruction.  */
+#define ISA_HAS_BADDU          (TARGET_OCTEON && !TARGET_MIPS16)
+
+/* ISA includes the bbit* instructions.  */
+#define ISA_HAS_BBIT           (TARGET_OCTEON && !TARGET_MIPS16)
+
+/* ISA includes the cins instruction.  */
+#define ISA_HAS_CINS           (TARGET_OCTEON && !TARGET_MIPS16)
+
+/* ISA includes the exts instruction.  */
+#define ISA_HAS_EXTS           (TARGET_OCTEON && !TARGET_MIPS16)
+
+/* ISA includes the seq and sne instructions.  */
+#define ISA_HAS_SEQ_SNE                (TARGET_OCTEON && !TARGET_MIPS16)
+
+/* ISA includes the pop instruction.  */
+#define ISA_HAS_POP            (TARGET_OCTEON && !TARGET_MIPS16)
+
+/* The CACHE instruction is available in non-MIPS16 code.  */
+#define TARGET_CACHE_BUILTIN (mips_isa >= 3)
+
+/* The CACHE instruction is available.  */
+#define ISA_HAS_CACHE (TARGET_CACHE_BUILTIN && !TARGET_MIPS16)
 \f
 /* Add -G xx support.  */
 
@@ -1074,7 +1146,7 @@ enum mips_code_readable_setting {
 %{mfix-vr4120} %{mfix-vr4130} \
 %(subtarget_asm_optimizing_spec) \
 %(subtarget_asm_debugging_spec) \
-%{mabi=*} %{!mabi*: %(asm_abi_default_spec)} \
+%{mabi=*} %{!mabi=*: %(asm_abi_default_spec)} \
 %{mgp32} %{mgp64} %{march=*} %{mxgot:-xgot} \
 %{mfp32} %{mfp64} \
 %{mshared} %{mno-shared} \
@@ -1152,7 +1224,14 @@ enum mips_code_readable_setting {
 #define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
 #endif
 
-#define DWARF2_ADDR_SIZE (ABI_HAS_64BIT_SYMBOLS ? 8 : 4)
+/* The size of DWARF addresses should be the same as the size of symbols
+   in the target file format.  They shouldn't depend on things like -msym32,
+   because many DWARF consumers do not allow the mixture of address sizes
+   that one would then get from linking -msym32 code with -msym64 code.
+
+   Note that the default POINTER_SIZE test is not appropriate for MIPS.
+   EABI64 has 64-bit pointers but uses 32-bit ELF.  */
+#define DWARF2_ADDR_SIZE (FILE_HAS_64BIT_SYMBOLS ? 8 : 4)
 
 /* By default, turn on GDB extensions.  */
 #define DEFAULT_GDB_EXTENSIONS 1
@@ -1543,6 +1622,9 @@ enum mips_code_readable_setting {
 #define GP_REG_LAST  31
 #define GP_REG_NUM   (GP_REG_LAST - GP_REG_FIRST + 1)
 #define GP_DBX_FIRST 0
+#define K0_REG_NUM   (GP_REG_FIRST + 26)
+#define K1_REG_NUM   (GP_REG_FIRST + 27)
+#define KERNEL_REG_P(REGNO)    (IN_RANGE (REGNO, K0_REG_NUM, K1_REG_NUM))
 
 #define FP_REG_FIRST 32
 #define FP_REG_LAST  63
@@ -1570,6 +1652,10 @@ enum mips_code_readable_setting {
 #define COP0_REG_LAST 111
 #define COP0_REG_NUM (COP0_REG_LAST - COP0_REG_FIRST + 1)
 
+#define COP0_STATUS_REG_NUM    (COP0_REG_FIRST + 12)
+#define COP0_CAUSE_REG_NUM     (COP0_REG_FIRST + 13)
+#define COP0_EPC_REG_NUM       (COP0_REG_FIRST + 14)
+
 #define COP2_REG_FIRST 112
 #define COP2_REG_LAST 143
 #define COP2_REG_NUM (COP2_REG_LAST - COP2_REG_FIRST + 1)
@@ -1588,6 +1674,17 @@ enum mips_code_readable_setting {
 #define HI_REGNUM      (TARGET_BIG_ENDIAN ? MD_REG_FIRST : MD_REG_FIRST + 1)
 #define LO_REGNUM      (TARGET_BIG_ENDIAN ? MD_REG_FIRST + 1 : MD_REG_FIRST)
 
+/* A few bitfield locations for the coprocessor registers.  */
+/* Request Interrupt Priority Level is from bit 10 to bit 15 of
+   the cause register for the EIC interrupt mode.  */
+#define CAUSE_IPL      10
+/* Interrupt Priority Level is from bit 10 to bit 15 of the status register.  */
+#define SR_IPL         10
+/* Exception Level is at bit 1 of the status register.  */
+#define SR_EXL         1
+/* Interrupt Enable is at bit 0 of the status register.  */
+#define SR_IE          0
+
 /* FPSW_REGNUM is the single condition code used if !ISA_HAS_8CC.
    If ISA_HAS_8CC, it should not be used, and an arbitrary ST_REG
    should be used instead.  */
@@ -1657,18 +1754,38 @@ enum mips_code_readable_setting {
 #define FRAME_POINTER_REQUIRED (mips_frame_pointer_required ())
 
 /* Register in which static-chain is passed to a function.  */
-#define STATIC_CHAIN_REGNUM (GP_REG_FIRST + 2)
+#define STATIC_CHAIN_REGNUM (GP_REG_FIRST + 15)
 
-/* Registers used as temporaries in prologue/epilogue code.  If we're
-   generating mips16 code, these registers must come from the core set
-   of 8.  The prologue register mustn't conflict with any incoming
-   arguments, the static chain pointer, or the frame pointer.  The
-   epilogue temporary mustn't conflict with the return registers, the
-   frame pointer, the EH stack adjustment, or the EH data registers.  */
+/* Registers used as temporaries in prologue/epilogue code:
 
-#define MIPS_PROLOGUE_TEMP_REGNUM (GP_REG_FIRST + 3)
-#define MIPS_EPILOGUE_TEMP_REGNUM (GP_REG_FIRST + (TARGET_MIPS16 ? 6 : 8))
+   - If a MIPS16 PIC function needs access to _gp, it first loads
+     the value into MIPS16_PIC_TEMP and then copies it to $gp.
 
+   - The prologue can use MIPS_PROLOGUE_TEMP as a general temporary
+     register.  The register must not conflict with MIPS16_PIC_TEMP.
+
+   - The epilogue can use MIPS_EPILOGUE_TEMP as a general temporary
+     register.
+
+   If we're generating MIPS16 code, these registers must come from the
+   core set of 8.  The prologue registers mustn't conflict with any
+   incoming arguments, the static chain pointer, or the frame pointer.
+   The epilogue temporary mustn't conflict with the return registers,
+   the PIC call register ($25), the frame pointer, the EH stack adjustment,
+   or the EH data registers.
+
+   If we're generating interrupt handlers, we use K0 as a temporary register
+   in prologue/epilogue code.  */
+
+#define MIPS16_PIC_TEMP_REGNUM (GP_REG_FIRST + 2)
+#define MIPS_PROLOGUE_TEMP_REGNUM \
+  (cfun->machine->interrupt_handler_p ? K0_REG_NUM : GP_REG_FIRST + 3)
+#define MIPS_EPILOGUE_TEMP_REGNUM              \
+  (cfun->machine->interrupt_handler_p          \
+   ? K0_REG_NUM                                        \
+   : GP_REG_FIRST + (TARGET_MIPS16 ? 6 : 8))
+
+#define MIPS16_PIC_TEMP gen_rtx_REG (Pmode, MIPS16_PIC_TEMP_REGNUM)
 #define MIPS_PROLOGUE_TEMP(MODE) gen_rtx_REG (MODE, MIPS_PROLOGUE_TEMP_REGNUM)
 #define MIPS_EPILOGUE_TEMP(MODE) gen_rtx_REG (MODE, MIPS_EPILOGUE_TEMP_REGNUM)
 
@@ -1716,7 +1833,6 @@ enum mips_code_readable_setting {
 enum reg_class
 {
   NO_REGS,                     /* no registers in set */
-  M16_NA_REGS,                 /* mips16 regs not used to pass args */
   M16_REGS,                    /* mips16 directly accessible registers */
   T_REG,                       /* mips16 T register ($24) */
   M16_T_REGS,                  /* mips16 registers plus T register */
@@ -1731,17 +1847,14 @@ enum reg_class
   COP0_REGS,                   /* generic coprocessor classes */
   COP2_REGS,
   COP3_REGS,
-  HI_AND_GR_REGS,              /* union classes */
-  LO_AND_GR_REGS,
-  HI_AND_FP_REGS,
-  COP0_AND_GR_REGS,
-  COP2_AND_GR_REGS,
-  COP3_AND_GR_REGS,
-  ALL_COP_REGS,
-  ALL_COP_AND_GR_REGS,
   ST_REGS,                     /* status registers (fp status) */
   DSP_ACC_REGS,                        /* DSP accumulator registers */
   ACC_REGS,                    /* Hi/Lo and DSP accumulator registers */
+  FRAME_REGS,                  /* $arg and $frame */
+  GR_AND_MD0_REGS,             /* union classes */
+  GR_AND_MD1_REGS,
+  GR_AND_MD_REGS,
+  GR_AND_ACC_REGS,
   ALL_REGS,                    /* all registers */
   LIM_REG_CLASSES              /* max value + 1 */
 };
@@ -1757,7 +1870,6 @@ enum reg_class
 #define REG_CLASS_NAMES                                                        \
 {                                                                      \
   "NO_REGS",                                                           \
-  "M16_NA_REGS",                                                       \
   "M16_REGS",                                                          \
   "T_REG",                                                             \
   "M16_T_REGS",                                                                \
@@ -1773,17 +1885,14 @@ enum reg_class
   "COP0_REGS",                                                         \
   "COP2_REGS",                                                         \
   "COP3_REGS",                                                         \
-  "HI_AND_GR_REGS",                                                    \
-  "LO_AND_GR_REGS",                                                    \
-  "HI_AND_FP_REGS",                                                    \
-  "COP0_AND_GR_REGS",                                                  \
-  "COP2_AND_GR_REGS",                                                  \
-  "COP3_AND_GR_REGS",                                                  \
-  "ALL_COP_REGS",                                                      \
-  "ALL_COP_AND_GR_REGS",                                               \
   "ST_REGS",                                                           \
   "DSP_ACC_REGS",                                                      \
   "ACC_REGS",                                                          \
+  "FRAME_REGS",                                                                \
+  "GR_AND_MD0_REGS",                                                   \
+  "GR_AND_MD1_REGS",                                                   \
+  "GR_AND_MD_REGS",                                                    \
+  "GR_AND_ACC_REGS",                                                   \
   "ALL_REGS"                                                           \
 }
 
@@ -1800,34 +1909,30 @@ enum reg_class
 
 #define REG_CLASS_CONTENTS                                                                             \
 {                                                                                                      \
-  { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },  /* no registers */      \
-  { 0x0003000c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },  /* mips16 nonarg regs */\
-  { 0x000300fc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },  /* mips16 registers */  \
-  { 0x01000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },  /* mips16 T register */ \
-  { 0x010300fc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },  /* mips16 and T regs */ \
-  { 0x02000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },  /* SVR4 PIC function address register */ \
-  { 0x00000008, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },  /* only $v1 */ \
-  { 0xfdffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },  /* Every other GPR except $25 */   \
-  { 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },  /* integer registers */ \
-  { 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },  /* floating registers*/ \
-  { 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000 },  /* hi register */       \
-  { 0x00000000, 0x00000000, 0x00000002, 0x00000000, 0x00000000, 0x00000000 },  /* lo register */       \
-  { 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000000, 0x00000000 },  /* mul/div registers */ \
-  { 0x00000000, 0x00000000, 0xffff0000, 0x0000ffff, 0x00000000, 0x00000000 },   /* cop0 registers */    \
-  { 0x00000000, 0x00000000, 0x00000000, 0xffff0000, 0x0000ffff, 0x00000000 },   /* cop2 registers */    \
-  { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffff0000, 0x0000ffff },   /* cop3 registers */    \
-  { 0xffffffff, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000 },  /* union classes */     \
-  { 0xffffffff, 0x00000000, 0x00000002, 0x00000000, 0x00000000, 0x00000000 },                          \
-  { 0x00000000, 0xffffffff, 0x00000001, 0x00000000, 0x00000000, 0x00000000 },                          \
-  { 0xffffffff, 0x00000000, 0xffff0000, 0x0000ffff, 0x00000000, 0x00000000 },                          \
-  { 0xffffffff, 0x00000000, 0x00000000, 0xffff0000, 0x0000ffff, 0x00000000 },                          \
-  { 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffff0000, 0x0000ffff },                           \
-  { 0x00000000, 0x00000000, 0xffff0000, 0xffffffff, 0xffffffff, 0x0000ffff },                           \
-  { 0xffffffff, 0x00000000, 0xffff0000, 0xffffffff, 0xffffffff, 0x0000ffff },                           \
-  { 0x00000000, 0x00000000, 0x000007f8, 0x00000000, 0x00000000, 0x00000000 },  /* status registers */  \
-  { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x003f0000 },  /* dsp accumulator registers */ \
-  { 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000000, 0x003f0000 },  /* hi/lo and dsp accumulator registers */       \
-  { 0xffffffff, 0xffffffff, 0xffff07ff, 0xffffffff, 0xffffffff, 0x0fffffff }   /* all registers */     \
+  { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },  /* NO_REGS */           \
+  { 0x000300fc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },  /* M16_REGS */          \
+  { 0x01000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },  /* T_REG */             \
+  { 0x010300fc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },  /* M16_T_REGS */        \
+  { 0x02000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },  /* PIC_FN_ADDR_REG */   \
+  { 0x00000008, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },  /* V1_REG */            \
+  { 0xfdffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },  /* LEA_REGS */          \
+  { 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },  /* GR_REGS */           \
+  { 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },  /* FP_REGS */           \
+  { 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000 },  /* MD0_REG */           \
+  { 0x00000000, 0x00000000, 0x00000002, 0x00000000, 0x00000000, 0x00000000 },  /* MD1_REG */           \
+  { 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000000, 0x00000000 },  /* MD_REGS */           \
+  { 0x00000000, 0x00000000, 0xffff0000, 0x0000ffff, 0x00000000, 0x00000000 },   /* COP0_REGS */                \
+  { 0x00000000, 0x00000000, 0x00000000, 0xffff0000, 0x0000ffff, 0x00000000 },   /* COP2_REGS */                \
+  { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffff0000, 0x0000ffff },   /* COP3_REGS */                \
+  { 0x00000000, 0x00000000, 0x000007f8, 0x00000000, 0x00000000, 0x00000000 },  /* ST_REGS */           \
+  { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x003f0000 },  /* DSP_ACC_REGS */      \
+  { 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000000, 0x003f0000 },  /* ACC_REGS */          \
+  { 0x00000000, 0x00000000, 0x00006000, 0x00000000, 0x00000000, 0x00000000 },  /* FRAME_REGS */        \
+  { 0xffffffff, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000 },  /* GR_AND_MD0_REGS */   \
+  { 0xffffffff, 0x00000000, 0x00000002, 0x00000000, 0x00000000, 0x00000000 },  /* GR_AND_MD1_REGS */   \
+  { 0xffffffff, 0x00000000, 0x00000003, 0x00000000, 0x00000000, 0x00000000 },  /* GR_AND_MD_REGS */    \
+  { 0xffffffff, 0x00000000, 0x00000003, 0x00000000, 0x00000000, 0x003f0000 },  /* GR_AND_ACC_REGS */   \
+  { 0xffffffff, 0xffffffff, 0xffff67ff, 0xffffffff, 0xffffffff, 0x0fffffff }   /* ALL_REGS */          \
 }
 
 
@@ -1859,24 +1964,50 @@ enum reg_class
 
 #define SMALL_REGISTER_CLASSES (TARGET_MIPS16)
 
-/* REG_ALLOC_ORDER is to order in which to allocate registers.  This
-   is the default value (allocate the registers in numeric order).  We
-   define it just so that we can override it for the mips16 target in
-   ORDER_REGS_FOR_LOCAL_ALLOC.  */
+/* We generally want to put call-clobbered registers ahead of
+   call-saved ones.  (IRA expects this.)  */
 
 #define REG_ALLOC_ORDER                                                        \
-{  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,      \
-  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,      \
+{ /* Accumulator registers.  When GPRs and accumulators have equal     \
+     cost, we generally prefer to use accumulators.  For example,      \
+     a division of multiplication result is better allocated to LO,    \
+     so that we put the MFLO at the point of use instead of at the     \
+     point of definition.  It's also needed if we're to take advantage \
+     of the extra accumulators available with -mdspr2.  In some cases, \
+     it can also help to reduce register pressure.  */                 \
+  64, 65,176,177,178,179,180,181,                                      \
+  /* Call-clobbered GPRs.  */                                          \
+  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,           \
+  24, 25, 31,                                                          \
+  /* The global pointer.  This is call-clobbered for o32 and o64       \
+     abicalls, call-saved for n32 and n64 abicalls, and a program      \
+     invariant otherwise.  Putting it between the call-clobbered       \
+     and call-saved registers should cope with all eventualities.  */  \
+  28,                                                                  \
+  /* Call-saved GPRs.  */                                              \
+  16, 17, 18, 19, 20, 21, 22, 23, 30,                                  \
+  /* GPRs that can never be exposed to the register allocator.  */     \
+  0,  26, 27, 29,                                                      \
+  /* Call-clobbered FPRs.  */                                          \
   32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,      \
-  48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,      \
-  64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,      \
+  48, 49, 50, 51,                                                      \
+  /* FPRs that are usually call-saved.  The odd ones are actually      \
+     call-clobbered for n32, but listing them ahead of the even                \
+     registers might encourage the register allocator to fragment      \
+     the available FPR pairs.  We need paired FPRs to store long       \
+     doubles, so it isn't clear that using a different order           \
+     for n32 would be a win.  */                                       \
+  52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,                      \
+  /* None of the remaining classes have defined call-saved             \
+     registers.  */                                                    \
+  66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,              \
   80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,      \
   96, 97, 98, 99, 100,101,102,103,104,105,106,107,108,109,110,111,     \
   112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,     \
   128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,     \
   144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,     \
   160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,     \
-  176,177,178,179,180,181,182,183,184,185,186,187                      \
+  182,183,184,185,186,187                                              \
 }
 
 /* ORDER_REGS_FOR_LOCAL_ALLOC is a macro which permits reg_alloc_order
@@ -1958,10 +2089,32 @@ enum reg_class
 
 #define RETURN_ADDR_RTX mips_return_addr
 
-/* Since the mips16 ISA mode is encoded in the least-significant bit
-   of the address, mask it off return addresses for purposes of
-   finding exception handling regions.  */
+/* Mask off the MIPS16 ISA bit in unwind addresses.
+
+   The reason for this is a little subtle.  When unwinding a call,
+   we are given the call's return address, which on most targets
+   is the address of the following instruction.  However, what we
+   actually want to find is the EH region for the call itself.
+   The target-independent unwind code therefore searches for "RA - 1".
+
+   In the MIPS16 case, RA is always an odd-valued (ISA-encoded) address.
+   RA - 1 is therefore the real (even-valued) start of the return
+   instruction.  EH region labels are usually odd-valued MIPS16 symbols
+   too, so a search for an even address within a MIPS16 region would
+   usually work.
 
+   However, there is an exception.  If the end of an EH region is also
+   the end of a function, the end label is allowed to be even.  This is
+   necessary because a following non-MIPS16 function may also need EH
+   information for its first instruction.
+
+   Thus a MIPS16 region may be terminated by an ISA-encoded or a
+   non-ISA-encoded address.  This probably isn't ideal, but it is
+   the traditional (legacy) behavior.  It is therefore only safe
+   to search MIPS EH regions for an _odd-valued_ address.
+
+   Masking off the ISA bit means that the target-independent code
+   will search for "(RA & -2) - 1", which is guaranteed to be odd.  */
 #define MASK_RETURN_ADDR GEN_INT (-2)
 
 
@@ -2156,14 +2309,7 @@ typedef struct mips_args {
        (mips_abi == ABI_EABI && UNITS_PER_FPVALUE >= UNITS_PER_DOUBLE)
 
 \f
-/* Say that the epilogue uses the return address register.  Note that
-   in the case of sibcalls, the values "used by the epilogue" are
-   considered live at the start of the called function.
-
-   If using a GOT, say that the epilogue also uses GOT_VERSION_REGNUM.
-   See the comment above load_call<mode> for details.  */
-#define EPILOGUE_USES(REGNO) \
-  ((REGNO) == 31 || (TARGET_USE_GOT && (REGNO) == GOT_VERSION_REGNUM))
+#define EPILOGUE_USES(REGNO)   mips_epilogue_uses (REGNO)
 
 /* Treat LOC as a byte offset from the stack pointer and round it up
    to the next fully-aligned offset.  */
@@ -2178,9 +2324,21 @@ typedef struct mips_args {
 {                                                                      \
   if (TARGET_MIPS16)                                                   \
     sorry ("mips16 function profiling");                               \
+  if (TARGET_LONG_CALLS)                                               \
+    {                                                                  \
+      /*  For TARGET_LONG_CALLS use $3 for the address of _mcount.  */ \
+      if (Pmode == DImode)                                             \
+       fprintf (FILE, "\tdla\t%s,_mcount\n", reg_names[GP_REG_FIRST + 3]); \
+      else                                                             \
+       fprintf (FILE, "\tla\t%s,_mcount\n", reg_names[GP_REG_FIRST + 3]); \
+    }                                                                  \
   fprintf (FILE, "\t.set\tnoat\n");                                    \
   fprintf (FILE, "\tmove\t%s,%s\t\t# save current return address\n",   \
           reg_names[GP_REG_FIRST + 1], reg_names[GP_REG_FIRST + 31]);  \
+  /* _mcount treats $2 as the static chain register.  */               \
+  if (cfun->static_chain_decl != NULL)                                 \
+    fprintf (FILE, "\tmove\t%s,%s\n", reg_names[2],                    \
+            reg_names[STATIC_CHAIN_REGNUM]);                           \
   if (!TARGET_NEWABI)                                                  \
     {                                                                  \
       fprintf (FILE,                                                   \
@@ -2190,8 +2348,15 @@ typedef struct mips_args {
               reg_names[STACK_POINTER_REGNUM],                         \
               Pmode == DImode ? 16 : 8);                               \
     }                                                                  \
-  fprintf (FILE, "\tjal\t_mcount\n");                                   \
+  if (TARGET_LONG_CALLS)                                               \
+    fprintf (FILE, "\tjalr\t%s\n", reg_names[GP_REG_FIRST + 3]);       \
+  else                                                                 \
+    fprintf (FILE, "\tjal\t_mcount\n");                                        \
   fprintf (FILE, "\t.set\tat\n");                                      \
+  /* _mcount treats $2 as the static chain register.  */               \
+  if (cfun->static_chain_decl != NULL)                                 \
+    fprintf (FILE, "\tmove\t%s,%s\n", reg_names[STATIC_CHAIN_REGNUM],  \
+            reg_names[2]);                                             \
 }
 
 /* The profiler preserves all interesting registers, including $31.  */
@@ -2231,20 +2396,19 @@ typedef struct mips_args {
   fprintf (STREAM, "\t.word\t0x00000000\t\t# nop\n");                  \
   if (ptr_mode == DImode)                                              \
     {                                                                  \
-      fprintf (STREAM, "\t.word\t0xdfe30014\t\t# ld     $3,20($31)\n");        \
-      fprintf (STREAM, "\t.word\t0xdfe2001c\t\t# ld     $2,28($31)\n");        \
-      fprintf (STREAM, "\t.word\t0x0060c82d\t\t# dmove  $25,$3\n");    \
+      fprintf (STREAM, "\t.word\t0xdff90014\t\t# ld     $25,20($31)\n"); \
+      fprintf (STREAM, "\t.word\t0xdfef001c\t\t# ld     $15,28($31)\n"); \
     }                                                                  \
   else                                                                 \
     {                                                                  \
-      fprintf (STREAM, "\t.word\t0x8fe30014\t\t# lw     $3,20($31)\n");        \
-      fprintf (STREAM, "\t.word\t0x8fe20018\t\t# lw     $2,24($31)\n");        \
-      fprintf (STREAM, "\t.word\t0x0060c821\t\t# move   $25,$3\n");    \
+      fprintf (STREAM, "\t.word\t0x8ff90010\t\t# lw     $25,16($31)\n"); \
+      fprintf (STREAM, "\t.word\t0x8fef0014\t\t# lw     $15,20($31)\n"); \
     }                                                                  \
-  fprintf (STREAM, "\t.word\t0x00600008\t\t# jr     $3\n");            \
+  fprintf (STREAM, "\t.word\t0x03200008\t\t# jr     $25\n");           \
   if (ptr_mode == DImode)                                              \
     {                                                                  \
       fprintf (STREAM, "\t.word\t0x0020f82d\t\t# dmove   $31,$1\n");   \
+      fprintf (STREAM, "\t.word\t0x00000000\t\t# <padding>\n");                \
       fprintf (STREAM, "\t.dword\t0x00000000\t\t# <function address>\n"); \
       fprintf (STREAM, "\t.dword\t0x00000000\t\t# <static chain value>\n"); \
     }                                                                  \
@@ -2259,7 +2423,7 @@ typedef struct mips_args {
 /* A C expression for the size in bytes of the trampoline, as an
    integer.  */
 
-#define TRAMPOLINE_SIZE (32 + GET_MODE_SIZE (ptr_mode) * 2)
+#define TRAMPOLINE_SIZE (ptr_mode == DImode ? 48 : 36)
 
 /* Alignment required for trampolines, in bits.  */
 
@@ -2289,7 +2453,7 @@ typedef struct mips_args {
 {                                                                          \
   rtx func_addr, chain_addr, end_addr;                                      \
                                                                            \
-  func_addr = plus_constant (ADDR, 32);                                            \
+  func_addr = plus_constant (ADDR, ptr_mode == DImode ? 32 : 28);          \
   chain_addr = plus_constant (func_addr, GET_MODE_SIZE (ptr_mode));        \
   mips_emit_move (gen_rtx_MEM (ptr_mode, func_addr), FUNC);                \
   mips_emit_move (gen_rtx_MEM (ptr_mode, chain_addr), CHAIN);              \
@@ -2390,6 +2554,11 @@ typedef struct mips_args {
 #define SYMBOL_REF_LONG_CALL_P(X)                                      \
   ((SYMBOL_REF_FLAGS (X) & SYMBOL_FLAG_LONG_CALL) != 0)
 
+/* This flag marks functions that cannot be lazily bound.  */
+#define SYMBOL_FLAG_BIND_NOW (SYMBOL_FLAG_MACH_DEP << 1)
+#define SYMBOL_REF_BIND_NOW_P(RTX) \
+  ((SYMBOL_REF_FLAGS (RTX) & SYMBOL_FLAG_BIND_NOW) != 0)
+
 /* True if we're generating a form of MIPS16 code in which jump tables
    are stored in the text section and encoded as 16-bit PC-relative
    offsets.  This is only possible when general text loads are allowed,
@@ -2485,7 +2654,7 @@ typedef struct mips_args {
 /* A C expression for the cost of a branch instruction.  A value of
    1 is the default; other values are interpreted relative to that.  */
 
-#define BRANCH_COST mips_branch_cost
+#define BRANCH_COST(speed_p, predictable_p) mips_branch_cost
 #define LOGICAL_OP_NON_SHORT_CIRCUIT 0
 
 /* If defined, modifies the length assigned to instruction INSN as a
@@ -2515,7 +2684,7 @@ typedef struct mips_args {
    ? "%*" INSN "\t%" #OPNO "%/"                                        \
    : REG_P (OPERANDS[OPNO])                                    \
    ? "%*" INSN "r\t%" #OPNO "%/"                               \
-   : TARGET_ABICALLS                                           \
+   : TARGET_ABICALLS_PIC2                                      \
    ? (".option\tpic0\n\t"                                      \
       "%*" INSN "\t%" #OPNO "%/\n\t"                           \
       ".option\tpic2")                                         \
@@ -2712,6 +2881,32 @@ while (0)
 #define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM)                  \
   sprintf ((LABEL), "*%s%s%ld", (LOCAL_LABEL_PREFIX), (PREFIX), (long)(NUM))
 
+/* Print debug labels as "foo = ." rather than "foo:" because they should
+   represent a byte pointer rather than an ISA-encoded address.  This is
+   particularly important for code like:
+
+       $LFBxxx = .
+               .cfi_startproc
+               ...
+               .section .gcc_except_table,...
+               ...
+               .uleb128 foo-$LFBxxx
+
+   The .uleb128 requies $LFBxxx to match the FDE start address, which is
+   likewise a byte pointer rather than an ISA-encoded address.
+
+   At the time of writing, this hook is not used for the function end
+   label:
+
+       $LFExxx:
+               .end foo
+
+   But this doesn't matter, because GAS doesn't treat a pre-.end label
+   as a MIPS16 one anyway.  */
+
+#define ASM_OUTPUT_DEBUG_LABEL(FILE, PREFIX, NUM)                      \
+  fprintf (FILE, "%s%s%d = .\n", LOCAL_LABEL_PREFIX, PREFIX, NUM)
+
 /* This is how to output an element of a case-vector that is absolute.  */
 
 #define ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE)                         \
@@ -2868,7 +3063,7 @@ while (0)
    we'll have to generate a load/store pair for each, halve the
    value of MIPS_CALL_RATIO to take that into account.  */
 
-#define MOVE_RATIO                                     \
+#define MOVE_RATIO(speed)                              \
   (HAVE_movmemsi                                       \
    ? MIPS_MAX_MOVE_BYTES_STRAIGHT / MOVE_MAX           \
    : MIPS_CALL_RATIO / 2)
@@ -2889,20 +3084,20 @@ while (0)
          ? (SIZE) < UNITS_PER_WORD                             \
          : (SIZE) <= MIPS_MAX_MOVE_BYTES_STRAIGHT))            \
    : (move_by_pieces_ninsns (SIZE, ALIGN, MOVE_MAX_PIECES + 1) \
-      < (unsigned int) MOVE_RATIO))
+      < (unsigned int) MOVE_RATIO (false)))
 
 /* For CLEAR_RATIO, when optimizing for size, give a better estimate
    of the length of a memset call, but use the default otherwise.  */
 
-#define CLEAR_RATIO \
-  (optimize_size ? MIPS_CALL_RATIO : 15)
+#define CLEAR_RATIO(speed)\
+  ((speed) ? 15 : MIPS_CALL_RATIO)
 
 /* This is similar to CLEAR_RATIO, but for a non-zero constant, so when
    optimizing for size adjust the ratio to account for the overhead of
    loading the constant and replicating it across the word.  */
 
-#define SET_RATIO \
-  (optimize_size ? MIPS_CALL_RATIO - 2 : 15)
+#define SET_RATIO(speed) \
+  ((speed) ? 15 : MIPS_CALL_RATIO - 2)
 
 /* STORE_BY_PIECES_P can be used when copying a constant string, but
    in that case each word takes 3 insns (lui, ori, sw), or more in
@@ -2966,7 +3161,7 @@ while (0)
   "\tbne\t%0,%z2,2f\n"                         \
   "\t" OP "\t%@,%3\n"                          \
   "\tsc" SUFFIX "\t%@,%1\n"                    \
-  "\tbeq\t%@,%.,1b\n"                          \
+  "\tbeq%?\t%@,%.,1b\n"                                \
   "\tnop\n"                                    \
   "\tsync%-%]%>%)\n"                           \
   "2:\n"
@@ -2991,7 +3186,7 @@ while (0)
   "\tand\t%@,%0,%3\n"                          \
   OPS                                          \
   "\tsc\t%@,%1\n"                              \
-  "\tbeq\t%@,%.,1b\n"                          \
+  "\tbeq%?\t%@,%.,1b\n"                                \
   "\tnop\n"                                    \
   "\tsync%-%]%>%)\n"                           \
   "2:\n"
@@ -3011,7 +3206,7 @@ while (0)
   "1:\tll" SUFFIX "\t%@,%0\n"                  \
   "\t" INSN "\t%@,%@,%1\n"                     \
   "\tsc" SUFFIX "\t%@,%0\n"                    \
-  "\tbeq\t%@,%.,1b\n"                          \
+  "\tbeq%?\t%@,%.,1b\n"                                \
   "\tnop\n"                                    \
   "\tsync%-%]%>%)"
 
@@ -3024,24 +3219,25 @@ while (0)
 
      - Uses scratch register %4.
 
-    NOT_OP are the optional instructions to do a bit-wise not
-    operation in conjunction with an AND INSN to generate a sync_nand
-    operation.  */
-#define MIPS_SYNC_OP_12(INSN, NOT_OP)          \
+    AND_OP is an instruction done after INSN to mask INSN's result
+    with the mask.  For most operations, this is an AND with the
+    inclusive mask (%1).  For nand operations -- where the result of
+    INSN is already correctly masked -- it instead performs a bitwise
+    not.  */
+#define MIPS_SYNC_OP_12(INSN, AND_OP)          \
   "%(%<%[%|sync\n"                             \
   "1:\tll\t%4,%0\n"                            \
   "\tand\t%@,%4,%2\n"                          \
-  NOT_OP                                       \
   "\t" INSN "\t%4,%4,%z3\n"                    \
-  "\tand\t%4,%4,%1\n"                          \
+  AND_OP                                       \
   "\tor\t%@,%@,%4\n"                           \
   "\tsc\t%@,%0\n"                              \
-  "\tbeq\t%@,%.,1b\n"                          \
+  "\tbeq%?\t%@,%.,1b\n"                                \
   "\tnop\n"                                    \
   "\tsync%-%]%>%)"
 
-#define MIPS_SYNC_OP_12_NOT_NOP ""
-#define MIPS_SYNC_OP_12_NOT_NOT "\tnor\t%4,%4,%.\n"
+#define MIPS_SYNC_OP_12_AND "\tand\t%4,%4,%1\n"
+#define MIPS_SYNC_OP_12_XOR "\txor\t%4,%4,%1\n"
 
 /* Return an asm string that atomically:
 
@@ -3054,29 +3250,25 @@ while (0)
 
      - Uses scratch register %5.
 
-    NOT_OP are the optional instructions to do a bit-wise not
-    operation in conjunction with an AND INSN to generate a sync_nand
-    operation.
-
-    REG is used in conjunction with NOT_OP and is used to select the
-    register operated on by the INSN.  */
-#define MIPS_SYNC_OLD_OP_12(INSN, NOT_OP, REG) \
+    AND_OP is an instruction done after INSN to mask INSN's result
+    with the mask.  For most operations, this is an AND with the
+    inclusive mask (%1).  For nand operations -- where the result of
+    INSN is already correctly masked -- it instead performs a bitwise
+    not.  */
+#define MIPS_SYNC_OLD_OP_12(INSN, AND_OP)      \
   "%(%<%[%|sync\n"                             \
   "1:\tll\t%0,%1\n"                            \
   "\tand\t%@,%0,%3\n"                          \
-  NOT_OP                                       \
-  "\t" INSN "\t%5," REG ",%z4\n"               \
-  "\tand\t%5,%5,%2\n"                          \
+  "\t" INSN "\t%5,%0,%z4\n"                    \
+  AND_OP                                       \
   "\tor\t%@,%@,%5\n"                           \
   "\tsc\t%@,%1\n"                              \
-  "\tbeq\t%@,%.,1b\n"                          \
+  "\tbeq%?\t%@,%.,1b\n"                                \
   "\tnop\n"                                    \
   "\tsync%-%]%>%)"
 
-#define MIPS_SYNC_OLD_OP_12_NOT_NOP ""
-#define MIPS_SYNC_OLD_OP_12_NOT_NOP_REG "%0"
-#define MIPS_SYNC_OLD_OP_12_NOT_NOT "\tnor\t%5,%0,%.\n"
-#define MIPS_SYNC_OLD_OP_12_NOT_NOT_REG "%5"
+#define MIPS_SYNC_OLD_OP_12_AND "\tand\t%5,%5,%2\n"
+#define MIPS_SYNC_OLD_OP_12_XOR "\txor\t%5,%5,%2\n"
 
 /* Return an asm string that atomically:
 
@@ -3087,24 +3279,25 @@ while (0)
 
      - Sets %0 to the new value of %1.
 
-    NOT_OP are the optional instructions to do a bit-wise not
-    operation in conjunction with an AND INSN to generate a sync_nand
-    operation.  */
-#define MIPS_SYNC_NEW_OP_12(INSN, NOT_OP)      \
+    AND_OP is an instruction done after INSN to mask INSN's result
+    with the mask.  For most operations, this is an AND with the
+    inclusive mask (%1).  For nand operations -- where the result of
+    INSN is already correctly masked -- it instead performs a bitwise
+    not.  */
+#define MIPS_SYNC_NEW_OP_12(INSN, AND_OP)      \
   "%(%<%[%|sync\n"                             \
   "1:\tll\t%0,%1\n"                            \
   "\tand\t%@,%0,%3\n"                          \
-  NOT_OP                                       \
   "\t" INSN "\t%0,%0,%z4\n"                    \
-  "\tand\t%0,%0,%2\n"                          \
+  AND_OP                                       \
   "\tor\t%@,%@,%0\n"                           \
   "\tsc\t%@,%1\n"                              \
-  "\tbeq\t%@,%.,1b\n"                          \
+  "\tbeq%?\t%@,%.,1b\n"                                \
   "\tnop\n"                                    \
   "\tsync%-%]%>%)"
 
-#define MIPS_SYNC_NEW_OP_12_NOT_NOP ""
-#define MIPS_SYNC_NEW_OP_12_NOT_NOT "\tnor\t%0,%0,%.\n"
+#define MIPS_SYNC_NEW_OP_12_AND "\tand\t%0,%0,%2\n"
+#define MIPS_SYNC_NEW_OP_12_XOR "\txor\t%0,%0,%2\n"
 
 /* Return an asm string that atomically:
 
@@ -3119,7 +3312,7 @@ while (0)
   "1:\tll" SUFFIX "\t%0,%1\n"                  \
   "\t" INSN "\t%@,%0,%2\n"                     \
   "\tsc" SUFFIX "\t%@,%1\n"                    \
-  "\tbeq\t%@,%.,1b\n"                          \
+  "\tbeq%?\t%@,%.,1b\n"                                \
   "\tnop\n"                                    \
   "\tsync%-%]%>%)"
 
@@ -3136,13 +3329,13 @@ while (0)
   "1:\tll" SUFFIX "\t%0,%1\n"                  \
   "\t" INSN "\t%@,%0,%2\n"                     \
   "\tsc" SUFFIX "\t%@,%1\n"                    \
-  "\tbeq\t%@,%.,1b\n"                          \
+  "\tbeq%?\t%@,%.,1b%~\n"                      \
   "\t" INSN "\t%0,%0,%2\n"                     \
   "\tsync%-%]%>%)"
 
 /* Return an asm string that atomically:
 
-     - Sets memory reference %0 to ~%0 AND %1.
+     - Sets memory reference %0 to ~(%0 AND %1).
 
    SUFFIX is the suffix that should be added to "ll" and "sc"
    instructions.  INSN is the and instruction needed to and a register
@@ -3150,16 +3343,16 @@ while (0)
 #define MIPS_SYNC_NAND(SUFFIX, INSN)           \
   "%(%<%[%|sync\n"                             \
   "1:\tll" SUFFIX "\t%@,%0\n"                  \
-  "\tnor\t%@,%@,%.\n"                          \
   "\t" INSN "\t%@,%@,%1\n"                     \
+  "\tnor\t%@,%@,%.\n"                          \
   "\tsc" SUFFIX "\t%@,%0\n"                    \
-  "\tbeq\t%@,%.,1b\n"                          \
+  "\tbeq%?\t%@,%.,1b\n"                                \
   "\tnop\n"                                    \
   "\tsync%-%]%>%)"
 
 /* Return an asm string that atomically:
 
-     - Sets memory reference %1 to ~%1 AND %2.
+     - Sets memory reference %1 to ~(%1 AND %2).
 
      - Sets register %0 to the old value of memory reference %1.
 
@@ -3169,16 +3362,16 @@ while (0)
 #define MIPS_SYNC_OLD_NAND(SUFFIX, INSN)       \
   "%(%<%[%|sync\n"                             \
   "1:\tll" SUFFIX "\t%0,%1\n"                  \
-  "\tnor\t%@,%0,%.\n"                          \
-  "\t" INSN "\t%@,%@,%2\n"                     \
+  "\t" INSN "\t%@,%0,%2\n"                     \
+  "\tnor\t%@,%@,%.\n"                          \
   "\tsc" SUFFIX "\t%@,%1\n"                    \
-  "\tbeq\t%@,%.,1b\n"                          \
+  "\tbeq%?\t%@,%.,1b\n"                                \
   "\tnop\n"                                    \
   "\tsync%-%]%>%)"
 
 /* Return an asm string that atomically:
 
-     - Sets memory reference %1 to ~%1 AND %2.
+     - Sets memory reference %1 to ~(%1 AND %2).
 
      - Sets register %0 to the new value of memory reference %1.
 
@@ -3188,11 +3381,11 @@ while (0)
 #define MIPS_SYNC_NEW_NAND(SUFFIX, INSN)       \
   "%(%<%[%|sync\n"                             \
   "1:\tll" SUFFIX "\t%0,%1\n"                  \
-  "\tnor\t%0,%0,%.\n"                          \
-  "\t" INSN "\t%@,%0,%2\n"                     \
-  "\tsc" SUFFIX "\t%@,%1\n"                    \
-  "\tbeq\t%@,%.,1b\n"                          \
   "\t" INSN "\t%0,%0,%2\n"                     \
+  "\tnor\t%@,%0,%.\n"                          \
+  "\tsc" SUFFIX "\t%@,%1\n"                    \
+  "\tbeq%?\t%@,%.,1b%~\n"                      \
+  "\tnor\t%0,%0,%.\n"                          \
   "\tsync%-%]%>%)"
 
 /* Return an asm string that atomically:
@@ -3209,7 +3402,7 @@ while (0)
   "1:\tll" SUFFIX "\t%0,%1\n"                  \
   "\t" OP "\t%@,%2\n"                          \
   "\tsc" SUFFIX "\t%@,%1\n"                    \
-  "\tbeq\t%@,%.,1b\n"                          \
+  "\tbeq%?\t%@,%.,1b\n"                                \
   "\tnop\n"                                    \
   "\tsync%-%]%>%)"
 
@@ -3233,7 +3426,7 @@ while (0)
   "\tand\t%@,%0,%3\n"                          \
   OPS                                          \
   "\tsc\t%@,%1\n"                              \
-  "\tbeq\t%@,%.,1b\n"                          \
+  "\tbeq%?\t%@,%.,1b\n"                                \
   "\tnop\n"                                    \
   "\tsync%-%]%>%)"
 
@@ -3251,6 +3444,7 @@ extern int set_nomacro;                   /* # of nested .set nomacro's  */
 extern int mips_dbx_regno[];
 extern int mips_dwarf_regno[];
 extern bool mips_split_p[];
+extern bool mips_split_hi_p[];
 extern GTY(()) rtx cmp_operands[2];
 extern enum processor_type mips_arch;   /* which cpu to codegen for */
 extern enum processor_type mips_tune;   /* which cpu to schedule for */