mips.c (machine_function): Add new fields: ignore_hazard_length_p and all_noreorder_p.
authorRichard Sandiford <rsandifo@redhat.com>
Wed, 2 Jul 2003 07:34:27 +0000 (07:34 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Wed, 2 Jul 2003 07:34:27 +0000 (07:34 +0000)
* config/mips/mips.c (machine_function): Add new fields:
ignore_hazard_length_p and all_noreorder_p.
(mips_flag_delayed_branch): New variable.
(override_options): Treat '/' as an operand punctuation character.
Set up mips_flag_delayed_branch.
(print_operand): Handle '/'.
(mips_output_function_prologue): Put the whole function in
.set noreorder and .set nomacro if all_noreorder_p is true.
(mips_output_function_epilogue): End the noreorder/nomacro sequence.
(mips16_optimize_gp): Remove "first insn" parameter.
(mips16_lay_out_constants): New function, split out from mips_reorg.
(mips_avoid_hazard, mips_avoid_hazards): New functions.
(mips_reorg): For mips16 code, call mips16_lay_out_constant
and (optionally) mips16_optimize.  If TARGET_EXPLICIT_RELOCS,
do delayed-branch scheduling followed by hazard detection.
(mips_adjust_insn_length): Only account for hazards if
!ignore_hazard_length_p.
(mips_output_load_label): Add a nop to the o32 sequence if
the target suffers from load delays.
(mips_output_conditional_branch): Add %/ to the end of branches.
(mips_output_division): Fill the branch delay slot with %#.
* config/mips/mips.md: Remove redundant '%*' from mips16 branch
instructions.  End all other %* branches with %/.
(ffssi2, ffsdi2): Fix lengths.
(truncdisi2, truncdihi2, truncdiqi2): Add store attributes.
(fix_truncdfsi2_macro): Turn off .set nomacro if appropriate.
(fix_truncsfsi2_macro): Likewise.
(mov_lwl): Set hazard to "none".
(ashldi3_internal): Fill the branch delay slot with %#.
(ashrdi3_internal, lshrdi3_internal): Likewise.
(exception_receiver): Explicitly set $28.
(hazard_nop): New pattern.

From-SVN: r68821

gcc/ChangeLog
gcc/config/mips/mips.c
gcc/config/mips/mips.md

index 0b7a461..d76a77c 100644 (file)
@@ -1,3 +1,38 @@
+2003-07-02  Richard Sandiford  <rsandifo@redhat.com>
+
+       * config/mips/mips.c (machine_function): Add new fields:
+       ignore_hazard_length_p and all_noreorder_p.
+       (mips_flag_delayed_branch): New variable.
+       (override_options): Treat '/' as an operand punctuation character.
+       Set up mips_flag_delayed_branch.
+       (print_operand): Handle '/'.
+       (mips_output_function_prologue): Put the whole function in
+       .set noreorder and .set nomacro if all_noreorder_p is true.
+       (mips_output_function_epilogue): End the noreorder/nomacro sequence.
+       (mips16_optimize_gp): Remove "first insn" parameter.
+       (mips16_lay_out_constants): New function, split out from mips_reorg.
+       (mips_avoid_hazard, mips_avoid_hazards): New functions.
+       (mips_reorg): For mips16 code, call mips16_lay_out_constant
+       and (optionally) mips16_optimize.  If TARGET_EXPLICIT_RELOCS,
+       do delayed-branch scheduling followed by hazard detection.
+       (mips_adjust_insn_length): Only account for hazards if
+       !ignore_hazard_length_p.
+       (mips_output_load_label): Add a nop to the o32 sequence if
+       the target suffers from load delays.
+       (mips_output_conditional_branch): Add %/ to the end of branches.
+       (mips_output_division): Fill the branch delay slot with %#.
+       * config/mips/mips.md: Remove redundant '%*' from mips16 branch
+       instructions.  End all other %* branches with %/.
+       (ffssi2, ffsdi2): Fix lengths.
+       (truncdisi2, truncdihi2, truncdiqi2): Add store attributes.
+       (fix_truncdfsi2_macro): Turn off .set nomacro if appropriate.
+       (fix_truncsfsi2_macro): Likewise.
+       (mov_lwl): Set hazard to "none".
+       (ashldi3_internal): Fill the branch delay slot with %#.
+       (ashrdi3_internal, lshrdi3_internal): Likewise.
+       (exception_receiver): Explicitly set $28.
+       (hazard_nop): New pattern.
+
 Wed Jul  2 08:12:36 CEST 2003  Jan Hubicka  <jh@suse.cz>
 
        * cgraphunit.c (cgraph_finalize_unit): Set current_function_decl
index d909e4e..b06bf57 100644 (file)
@@ -243,13 +243,17 @@ static void save_restore_insns                    PARAMS ((int, rtx, long));
 static void mips_gp_insn                       PARAMS ((rtx, rtx));
 static void mips16_fp_args                     PARAMS ((FILE *, int, int));
 static void build_mips16_function_stub         PARAMS ((FILE *));
-static void mips16_optimize_gp                 PARAMS ((rtx));
+static void mips16_optimize_gp                 PARAMS ((void));
 static rtx add_constant                                PARAMS ((struct constant **,
                                                        rtx,
                                                        enum machine_mode));
 static void dump_constants                     PARAMS ((struct constant *,
                                                        rtx));
 static rtx mips_find_symbol                    PARAMS ((rtx));
+static void mips16_lay_out_constants           PARAMS ((void));
+static void mips_avoid_hazard                  PARAMS ((rtx, rtx, int *,
+                                                        rtx *, rtx));
+static void mips_avoid_hazards                 PARAMS ((void));
 static void mips_reorg                         PARAMS ((void));
 static void abort_with_insn                    PARAMS ((rtx, const char *))
   ATTRIBUTE_NORETURN;
@@ -335,6 +339,14 @@ struct machine_function GTY(()) {
 
   /* The register to use as the global pointer within this function.  */
   unsigned int global_pointer;
+
+  /* True if mips_adjust_insn_length should ignore an instruction's
+     hazard attribute.  */
+  bool ignore_hazard_length_p;
+
+  /* True if the whole function is suitable for .set noreorder and
+     .set nomacro.  */
+  bool all_noreorder_p;
 };
 
 /* Information about a single argument.  */
@@ -585,6 +597,9 @@ int mips_dbx_regno[FIRST_PSEUDO_REGISTER];
 /* An alias set for the GOT.  */
 static int mips_got_alias_set;
 
+/* A copy of the original flag_delayed_branch: see override_options.  */
+static int mips_flag_delayed_branch;
+
 static GTY (()) int mips_output_filename_first_time = 1;
 
 /* Hardware names for the registers.  If -mrnames is used, this
@@ -5153,6 +5168,14 @@ override_options ()
   else
     mips16 = 0;
 
+  /* When using explicit relocs, we call dbr_schedule from within
+     mips_reorg.  */
+  if (TARGET_EXPLICIT_RELOCS)
+    {
+      mips_flag_delayed_branch = flag_delayed_branch;
+      flag_delayed_branch = 0;
+    }
+
   real_format_for_mode[SFmode - QFmode] = &mips_single_format;
   real_format_for_mode[DFmode - QFmode] = &mips_double_format;
 #ifdef MIPS_TFMODE_FORMAT
@@ -5163,6 +5186,7 @@ override_options ()
 
   mips_print_operand_punct['?'] = 1;
   mips_print_operand_punct['#'] = 1;
+  mips_print_operand_punct['/'] = 1;
   mips_print_operand_punct['&'] = 1;
   mips_print_operand_punct['!'] = 1;
   mips_print_operand_punct['*'] = 1;
@@ -5478,6 +5502,7 @@ mips_debugger_offset (addr, offset)
    '*' Turn on both .set noreorder and .set nomacro if filling delay slots
    '!' Turn on .set nomacro if filling delay slots
    '#' Print nop if in a .set noreorder section.
+   '/' Like '#', but does nothing within a delayed branch sequence
    '?' Print 'l' if we are to use a branch likely instead of normal branch.
    '@' Print the name of the assembler temporary register (at or $1).
    '.' Print the name of the register with a hard-wired zero (zero or $0).
@@ -5551,6 +5576,14 @@ print_operand (file, op, letter)
            fputs ("\n\tnop", file);
          break;
 
+       case '/':
+         /* Print an extra newline so that the delayed insn is separated
+            from the following ones.  This looks neater and is consistent
+            with non-nop delayed sequences.  */
+         if (set_noreorder != 0 && final_sequence == 0)
+           fputs ("\n\tnop\n", file);
+         break;
+
        case '(':
          if (set_noreorder++ == 0)
            fputs (".set\tnoreorder\n\t", file);
@@ -7073,10 +7106,16 @@ mips_output_function_prologue (file, size)
       fprintf (file, "\n");
     }
 
-  /* Handle the initialization of $gp for SVR4 PIC.  */
   if (TARGET_ABICALLS && !TARGET_NEWABI && cfun->machine->global_pointer > 0)
-    fprintf (file, "\t.set\tnoreorder\n\t.cpload\t%s\n\t.set\treorder\n",
-            reg_names[PIC_FUNCTION_ADDR_REGNUM]);
+    {
+      /* Handle the initialization of $gp for SVR4 PIC.  */
+      if (!cfun->machine->all_noreorder_p)
+       output_asm_insn ("%(.cpload\t%^%)", 0);
+      else
+       output_asm_insn ("%(.cpload\t%^\n\t%<", 0);
+    }
+  else if (cfun->machine->all_noreorder_p)
+    output_asm_insn ("%(%<", 0);
 }
 \f
 /* Emit an instruction to move SRC into DEST.  When generating
@@ -7487,6 +7526,14 @@ mips_output_function_epilogue (file, size)
 {
   rtx string;
 
+  if (cfun->machine->all_noreorder_p)
+    {
+      /* Avoid using %>%) since it adds excess whitespace.  */
+      output_asm_insn (".set\tmacro", 0);
+      output_asm_insn (".set\treorder", 0);
+      set_noreorder = set_nomacro = 0;
+    }
+
 #ifndef FUNCTION_NAME_ALREADY_DECLARED
   if (!flag_inhibit_size_directive)
     {
@@ -8893,8 +8940,7 @@ build_mips16_call_stub (retval, fn, arg_size, fp_code)
    generated is correct, so we do not need to catch all cases.  */
 
 static void
-mips16_optimize_gp (first)
-     rtx first;
+mips16_optimize_gp ()
 {
   rtx gpcopy, slot, insn;
 
@@ -8907,7 +8953,7 @@ mips16_optimize_gp (first)
 
   gpcopy = NULL_RTX;
   slot = NULL_RTX;
-  for (insn = first; insn != NULL_RTX; insn = next_active_insn (insn))
+  for (insn = get_insns (); insn != NULL_RTX; insn = next_active_insn (insn))
     {
       rtx set;
 
@@ -8990,7 +9036,7 @@ mips16_optimize_gp (first)
 
 #if 0
   /* ??? FIXME.  Rewrite for new UNSPEC_RELOC stuff.  */
-      for (insn = first; insn != NULL_RTX; insn = next)
+      for (insn = get_insns (); insn != NULL_RTX; insn = next)
        {
          rtx set1, set2;
 
@@ -9059,7 +9105,7 @@ mips16_optimize_gp (first)
      replace all assignments from SLOT to GPCOPY with assignments from
      $28.  */
 
-  for (insn = first; insn != NULL_RTX; insn = next_active_insn (insn))
+  for (insn = get_insns (); insn != NULL_RTX; insn = next_active_insn (insn))
     {
       rtx set;
 
@@ -9236,22 +9282,14 @@ mips_find_symbol (addr)
    PC relative loads that are out of range.  */
 
 static void
-mips_reorg ()
+mips16_lay_out_constants ()
 {
   int insns_len, max_internal_pool_size, pool_size, addr, first_constant_ref;
   rtx first, insn;
   struct constant *constants;
 
-  if (! TARGET_MIPS16)
-    return;
-
   first = get_insns ();
 
-  /* If $gp is used, try to remove stores, and replace loads with
-     copies from $gp.  */
-  if (optimize)
-    mips16_optimize_gp (first);
-
   /* Scan the function looking for PC relative loads which may be out
      of range.  All such loads will either be from the constant table,
      or be getting the address of a constant string.  If the size of
@@ -9436,6 +9474,144 @@ mips_reorg ()
      constant table, but we have no way to prevent that.  */
 }
 
+
+/* Subroutine of mips_reorg.  If there is a hazard between INSN
+   and a previous instruction, avoid it by inserting nops after
+   instruction AFTER.
+
+   *DELAYED_REG and *HILO_DELAY describe the hazards that apply at
+   this point.  If *DELAYED_REG is non-null, INSN must wait a cycle
+   before using the value of that register.  *HILO_DELAY counts the
+   number of instructions since the last hilo hazard (that is,
+   the number of instructions since the last mflo or mfhi).
+
+   After inserting nops for INSN, update *DELAYED_REG and *HILO_DELAY
+   for the next instruction.
+
+   LO_REG is an rtx for the LO register, used in dependence checking.  */
+
+static void
+mips_avoid_hazard (after, insn, hilo_delay, delayed_reg, lo_reg)
+     rtx after, insn, *delayed_reg, lo_reg;
+     int *hilo_delay;
+{
+  rtx pattern, set;
+  int nops, ninsns;
+
+  if (!INSN_P (insn))
+    return;
+
+  pattern = PATTERN (insn);
+
+  /* Do not put the whole function in .set noreorder if it contains
+     an asm statement.  We don't know whether there will be hazards
+     between the asm statement and the gcc-generated code.  */
+  if (GET_CODE (pattern) == ASM_INPUT || asm_noperands (pattern) >= 0)
+    cfun->machine->all_noreorder_p = false;
+
+  /* Ignore zero-length instructions (barriers and the like).  */
+  ninsns = get_attr_length (insn) / 4;
+  if (ninsns == 0)
+    return;
+
+  /* Work out how many nops are needed.  Note that we only care about
+     registers that are explicitly mentioned in the instruction's pattern.
+     It doesn't matter that calls use the argument registers or that they
+     clobber hi and lo.  */
+  if (*hilo_delay < 2 && reg_set_p (lo_reg, pattern))
+    nops = 2 - *hilo_delay;
+  else if (*delayed_reg != 0 && reg_referenced_p (*delayed_reg, pattern))
+    nops = 1;
+  else
+    nops = 0;
+
+  /* Insert the nops between this instruction and the previous one.
+     Each new nop takes us further from the last hilo hazard.  */
+  *hilo_delay += nops;
+  while (nops-- > 0)
+    emit_insn_after (gen_hazard_nop (), after);
+
+  /* Set up the state for the next instruction.  */
+  *hilo_delay += ninsns;
+  *delayed_reg = 0;
+  if (INSN_CODE (insn) >= 0)
+    switch (get_attr_hazard (insn))
+      {
+      case HAZARD_NONE:
+       break;
+
+      case HAZARD_HILO:
+       *hilo_delay = 0;
+       break;
+
+      case HAZARD_DELAY:
+       set = single_set (insn);
+       if (set == 0)
+         abort ();
+       *delayed_reg = SET_DEST (set);
+       break;
+      }
+}
+
+
+/* Go through the instruction stream and insert nops where necessary.
+   See if the whole function can then be put into .set noreorder &
+   .set nomacro.  */
+
+static void
+mips_avoid_hazards ()
+{
+  rtx insn, last_insn, lo_reg, delayed_reg;
+  int hilo_delay, i;
+
+  /* Recalculate instruction lengths without taking nops into account.  */
+  cfun->machine->ignore_hazard_length_p = true;
+  shorten_branches (get_insns ());
+
+  /* The profiler code uses assembler macros.  */
+  cfun->machine->all_noreorder_p = !current_function_profile;
+
+  last_insn = 0;
+  hilo_delay = 2;
+  delayed_reg = 0;
+  lo_reg = gen_rtx_REG (SImode, LO_REGNUM);
+
+  for (insn = get_insns (); insn != 0; insn = NEXT_INSN (insn))
+    if (INSN_P (insn))
+      {
+       if (GET_CODE (PATTERN (insn)) == SEQUENCE)
+         for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
+           mips_avoid_hazard (last_insn, XVECEXP (PATTERN (insn), 0, i),
+                              &hilo_delay, &delayed_reg, lo_reg);
+       else
+         mips_avoid_hazard (last_insn, insn, &hilo_delay,
+                            &delayed_reg, lo_reg);
+
+       last_insn = insn;
+      }
+}
+
+
+/* Implement TARGET_MACHINE_DEPENDENT_REORG.  */
+
+static void
+mips_reorg ()
+{
+  if (TARGET_MIPS16)
+    {
+      if (optimize)
+       mips16_optimize_gp ();
+      mips16_lay_out_constants ();
+    }
+  else if (TARGET_EXPLICIT_RELOCS)
+    {
+      if (mips_flag_delayed_branch)
+       dbr_schedule (get_insns (), rtl_dump_file);
+      mips_avoid_hazards ();
+    }
+}
+
+
 /* Return a number assessing the cost of moving a register in class
    FROM to class TO.  The classes are expressed using the enumeration
    values such as `GENERAL_REGS'.  A value of 2 is the default; other
@@ -9551,7 +9727,7 @@ mips_adjust_insn_length (insn, length)
     length += 4;
 
   /* See how many nops might be needed to avoid hardware hazards.  */
-  if (INSN_CODE (insn) >= 0)
+  if (!cfun->machine->ignore_hazard_length_p && INSN_CODE (insn) >= 0)
     switch (get_attr_hazard (insn))
       {
       case HAZARD_NONE:
@@ -9590,6 +9766,8 @@ mips_output_load_label ()
        return "%[ld\t%@,%%got_page(%0)(%+)\n\tdaddiu\t%@,%@,%%got_ofst(%0)";
 
       default:
+       if (ISA_HAS_LOAD_DELAY)
+         return "%[lw\t%@,%%got(%0)(%+)%#\n\taddiu\t%@,%@,%%lo(%0)";
        return "%[lw\t%@,%%got(%0)(%+)\n\taddiu\t%@,%@,%%lo(%0)";
       }
   else
@@ -9709,10 +9887,10 @@ mips_output_conditional_branch (insn,
     case 8:
       /* Just a simple conditional branch.  */
       if (float_p)
-       sprintf (buffer, "%%*b%s%%?\t%%Z2%%1",
+       sprintf (buffer, "%%*b%s%%?\t%%Z2%%1%%/",
                 inverted_p ? inverted_comp : comp);
       else
-       sprintf (buffer, "%%*b%s%s%%?\t%s%s,%%1",
+       sprintf (buffer, "%%*b%s%s%%?\t%s%s,%%1%%/",
                 inverted_p ? inverted_comp : comp,
                 need_z_p ? "z" : "",
                 op1,
@@ -9930,7 +10108,7 @@ mips_output_division (division, operands)
       if (TARGET_MIPS16)
        return "bnez\t%2,1f\n\tbreak\t7\n1:";
       else
-       return "bne\t%2,%.,1f\n\t%#break\t7\n1:";
+       return "bne\t%2,%.,1f%#\n\tbreak\t7\n1:";
     }
   return division;
 }
index 2841369..7621530 100644 (file)
@@ -3040,7 +3040,7 @@ move\\t%0,%z4\\n\\
 }"
   [(set_attr "type"    "multi")
    (set_attr "mode"    "SI")
-   (set_attr "length"  "12")])
+   (set_attr "length"  "28")])
 
 (define_insn "ffsdi2"
   [(set (match_operand:DI 0 "register_operand" "=&d")
@@ -3074,7 +3074,7 @@ move\\t%0,%z4\\n\\
 }"
   [(set_attr "type"    "multi")
    (set_attr "mode"    "DI")
-   (set_attr "length"  "24")])
+   (set_attr "length"  "28")])
 
 \f
 
@@ -3489,7 +3489,7 @@ move\\t%0,%z4\\n\\
   "@
     sll\t%0,%1,0
     sw\t%1,%0"
-  [(set_attr "type" "darith")
+  [(set_attr "type" "darith,store")
    (set_attr "mode" "SI")
    (set_attr "extended_mips16" "yes,*")])
 
@@ -3500,7 +3500,7 @@ move\\t%0,%z4\\n\\
   "@
     sll\t%0,%1,0
     sh\t%1,%0"
-  [(set_attr "type" "darith")
+  [(set_attr "type" "darith,store")
    (set_attr "mode" "SI")
    (set_attr "extended_mips16" "yes,*")])
 
@@ -3511,7 +3511,7 @@ move\\t%0,%z4\\n\\
   "@
     sll\t%0,%1,0
     sb\t%1,%0"
-  [(set_attr "type" "darith")
+  [(set_attr "type" "darith,store")
    (set_attr "mode" "SI")
    (set_attr "extended_mips16" "yes,*")])
 
@@ -4075,7 +4075,11 @@ move\\t%0,%z4\\n\\
        (fix:SI (match_operand:DF 1 "register_operand" "f")))
    (clobber (match_scratch:DF 2 "=d"))]
   "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !ISA_HAS_TRUNC_W"
-  "trunc.w.d %0,%1,%2"
+  {
+    if (set_nomacro)
+      return ".set\tmacro\n\ttrunc.w.d %0,%1,%2\n\t.set\tmacro";
+    return "trunc.w.d %0,%1,%2";
+  }
   [(set_attr "type"    "fcvt")
    (set_attr "mode"    "DF")
    (set_attr "length"  "36")])
@@ -4106,7 +4110,11 @@ move\\t%0,%z4\\n\\
        (fix:SI (match_operand:SF 1 "register_operand" "f")))
    (clobber (match_scratch:SF 2 "=d"))]
   "TARGET_HARD_FLOAT && !ISA_HAS_TRUNC_W"
-  "trunc.w.s %0,%1,%2"
+  {
+    if (set_nomacro)
+      return ".set\tmacro\n\ttrunc.w.s %0,%1,%2\n\t.set\tmacro";
+    return "trunc.w.s %0,%1,%2";
+  }
   [(set_attr "type"    "fcvt")
    (set_attr "mode"    "DF")
    (set_attr "length"  "36")])
@@ -4437,7 +4445,8 @@ move\\t%0,%z4\\n\\
   "!TARGET_MIPS16"
   "lwl\t%0,%2"
   [(set_attr "type" "load")
-   (set_attr "mode" "SI")])
+   (set_attr "mode" "SI")
+   (set_attr "hazard" "none")])
 
 (define_insn "mov_lwr"
   [(set (match_operand:SI 0 "register_operand" "=d")
@@ -5636,7 +5645,7 @@ move\\t%0,%z4\\n\\
   operands[4] = const0_rtx;
 
   return \"sll\\t%3,%2,26\\n\\
-\\tbgez\\t%3,1f\\n\\
+\\tbgez\\t%3,1f%#\\n\\
 \\tsll\\t%M0,%L1,%2\\n\\
 \\t%(b\\t3f\\n\\
 \\tmove\\t%L0,%z4%)\\n\\
@@ -5991,7 +6000,7 @@ move\\t%0,%z4\\n\\
   operands[4] = const0_rtx;
 
   return \"sll\\t%3,%2,26\\n\\
-\\tbgez\\t%3,1f\\n\\
+\\tbgez\\t%3,1f%#\\n\\
 \\tsra\\t%L0,%M1,%2\\n\\
 \\t%(b\\t3f\\n\\
 \\tsra\\t%M0,%M1,31%)\\n\\
@@ -6369,7 +6378,7 @@ move\\t%0,%z4\\n\\
   operands[4] = const0_rtx;
 
   return \"sll\\t%3,%2,26\\n\\
-\\tbgez\\t%3,1f\\n\\
+\\tbgez\\t%3,1f%#\\n\\
 \\tsrl\\t%L0,%M1,%2\\n\\
 \\t%(b\\t3f\\n\\
 \\tmove\\t%M0,%z4%)\\n\\
@@ -6988,16 +6997,16 @@ move\\t%0,%z4\\n\\
   if (operands[2] != pc_rtx)
     {
       if (which_alternative == 0)
-       return \"%*b%C0z\\t%1,%2\";
+       return \"b%C0z\\t%1,%2\";
       else
-       return \"%*bt%C0z\\t%2\";
+       return \"bt%C0z\\t%2\";
     }
   else
     {
       if (which_alternative == 0)
-       return \"%*b%N0z\\t%1,%3\";
+       return \"b%N0z\\t%1,%3\";
       else
-       return \"%*bt%N0z\\t%3\";
+       return \"bt%N0z\\t%3\";
     }
 }"
   [(set_attr "type"    "branch")
@@ -7017,16 +7026,16 @@ move\\t%0,%z4\\n\\
   if (operands[2] != pc_rtx)
     {
       if (which_alternative == 0)
-       return \"%*b%C0z\\t%1,%2\";
+       return \"b%C0z\\t%1,%2\";
       else
-       return \"%*bt%C0z\\t%2\";
+       return \"bt%C0z\\t%2\";
     }
   else
     {
       if (which_alternative == 0)
-       return \"%*b%N0z\\t%1,%3\";
+       return \"b%N0z\\t%1,%3\";
       else
-       return \"%*bt%N0z\\t%3\";
+       return \"bt%N0z\\t%3\";
     }
 }"
   [(set_attr "type"    "branch")
@@ -8389,15 +8398,15 @@ move\\t%0,%z4\\n\\
   if (flag_pic && ! TARGET_EMBEDDED_PIC)
     {
       if (get_attr_length (insn) <= 8)
-       return \"%*b\\t%l0\";
+       return \"%*b\\t%l0%/\";
       else
        {
          output_asm_insn (mips_output_load_label (), operands);
-         return \"%*jr\\t%@%]\";
+         return \"%*jr\\t%@%/%]\";
        }
     }
   else
-    return \"%*j\\t%l0\";
+    return \"%*j\\t%l0%/\";
 }"
   [(set_attr "type"    "jump")
    (set_attr "mode"    "none")
@@ -8450,14 +8459,14 @@ move\\t%0,%z4\\n\\
 (define_insn "indirect_jump_internal1"
   [(set (pc) (match_operand:SI 0 "register_operand" "d"))]
   "!(Pmode == DImode)"
-  "%*j\\t%0"
+  "%*j\t%0%/"
   [(set_attr "type"    "jump")
    (set_attr "mode"    "none")])
 
 (define_insn "indirect_jump_internal2"
   [(set (pc) (match_operand:DI 0 "register_operand" "d"))]
   "Pmode == DImode"
-  "%*j\\t%0"
+  "%*j\t%0%/"
   [(set_attr "type"    "jump")
    (set_attr "mode"    "none")])
 
@@ -8501,7 +8510,7 @@ move\\t%0,%z4\\n\\
        (match_operand:SI 0 "register_operand" "d"))
    (use (label_ref (match_operand 1 "" "")))]
   ""
-  "%*j\\t%0"
+  "%*j\t%0%/"
   [(set_attr "type"    "jump")
    (set_attr "mode"    "none")])
 
@@ -8510,7 +8519,7 @@ move\\t%0,%z4\\n\\
        (match_operand:DI 0 "register_operand" "d"))
    (use (label_ref (match_operand 1 "" "")))]
   "TARGET_64BIT"
-  "%*j\\t%0"
+  "%*j\t%0%/"
   [(set_attr "type"    "jump")
    (set_attr "mode"    "none")])
 
@@ -8626,7 +8635,7 @@ move\\t%0,%z4\\n\\
    (clobber (reg:SI 31))]
   "TARGET_EMBEDDED_PIC"
   "%(bal\\t%S1\;sll\\t%2,%0,2\\n%~%S1:\;addu\\t%2,%2,$31%)\;\\
-lw\\t%2,%1-%S1(%2)\;addu\\t%2,%2,$31\\n\\t%*j\\t%2"
+lw\\t%2,%1-%S1(%2)\;addu\\t%2,%2,$31\\n\\t%*j\\t%2%/"
   [(set_attr "type"    "jump")
    (set_attr "mode"    "none")
    (set_attr "length"  "24")])
@@ -8643,7 +8652,7 @@ lw\\t%2,%1-%S1(%2)\;addu\\t%2,%2,$31\\n\\t%*j\\t%2"
    (clobber (reg:DI 31))]
   "TARGET_EMBEDDED_PIC"
   "%(bal\\t%S1\;sll\\t%2,%0,3\\n%~%S1:\;daddu\\t%2,%2,$31%)\;\\
-ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
+ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2%/"
   [(set_attr "type"    "jump")
    (set_attr "mode"    "none")
    (set_attr "length"  "24")])
@@ -8751,7 +8760,7 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
 (define_insn "return"
   [(return)]
   "mips_can_use_return_insn ()"
-  "%*j\\t$31"
+  "%*j\t$31%/"
   [(set_attr "type"    "jump")
    (set_attr "mode"    "none")])
 
@@ -8761,10 +8770,7 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
   [(use (match_operand 0 "pmode_register_operand" ""))
    (return)]
   ""
-  "*
-{
-  return \"%*j\\t%0\";
-}"
+  "%*j\t%0%/"
   [(set_attr "type"    "jump")
    (set_attr "mode"    "none")])
 
@@ -8827,7 +8833,8 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
 }")
 
 (define_insn "exception_receiver"
-  [(unspec_volatile [(const_int 0)] UNSPEC_EH_RECEIVER)]
+  [(set (reg:SI 28)
+       (unspec_volatile [(const_int 0)] UNSPEC_EH_RECEIVER))]
   "TARGET_ABICALLS && (mips_abi == ABI_32 || mips_abi == ABI_O64)"
   { return mips_restore_gp (operands); }
   [(set_attr "type"   "load")
@@ -8867,8 +8874,8 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
         (match_operand 1 "" ""))]
   "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
   "@
-    %*jr\\t%0
-    %*j\\t%0"
+    %*jr\t%0%/
+    %*j\t%0%/"
   [(set_attr "type" "call")])
 
 (define_expand "sibcall_value"
@@ -8889,8 +8896,8 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
               (match_operand 2 "" "")))]
   "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
   "@
-    %*jr\\t%1
-    %*j\\t%1"
+    %*jr\t%1%/
+    %*j\t%1%/"
   [(set_attr "type" "call")])
 
 (define_insn "sibcall_value_multiple_internal"
@@ -8902,8 +8909,8 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
              (match_dup 2)))]
   "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
   "@
-    %*jr\\t%1
-    %*j\\t%1"
+    %*jr\t%1%/
+    %*j\t%1%/"
   [(set_attr "type" "call")])
 
 (define_expand "call"
@@ -8922,7 +8929,7 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
         (match_operand 1 "" ""))
    (clobber (reg:SI 31))]
   ""
-  "%*jal\\t%0"
+  "%*jal\t%0%/"
   "reload_completed && TARGET_SPLIT_CALLS"
   [(const_int 0)]
   {
@@ -8939,7 +8946,7 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
    (clobber (reg:SI 31))
    (const_int 1)]
   "TARGET_SPLIT_CALLS"
-  "%*jalr\\t%0"
+  "%*jalr\t%0%/"
   [(set_attr "type" "call")])
 
 (define_expand "call_value"
@@ -8960,7 +8967,7 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
               (match_operand 2 "" "")))
    (clobber (reg:SI 31))]
   ""
-  "%*jal\\t%1"
+  "%*jal\t%1%/"
   "reload_completed && TARGET_SPLIT_CALLS"
   [(const_int 0)]
   {
@@ -8979,7 +8986,7 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
    (clobber (reg:SI 31))
    (const_int 1)]
   "TARGET_SPLIT_CALLS"
-  "%*jalr\\t%1"
+  "%*jalr\t%1%/"
   [(set_attr "type" "call")])
 
 (define_insn_and_split "call_value_multiple_internal"
@@ -8991,7 +8998,7 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
              (match_dup 2)))
    (clobber (reg:SI 31))]
   ""
-  "%*jal\\t%1"
+  "%*jal\t%1%/"
   "reload_completed && TARGET_SPLIT_CALLS"
   [(const_int 0)]
   {
@@ -9013,7 +9020,7 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
    (clobber (reg:SI 31))
    (const_int 1)]
   "TARGET_SPLIT_CALLS"
-  "%*jalr\\t%1"
+  "%*jalr\t%1%/"
   [(set_attr "type" "call")])
 
 ;; Call subroutine returning any type.
@@ -9100,6 +9107,18 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
   [(set_attr "type"    "nop")
    (set_attr "mode"    "none")])
 
+;; Like nop, but commented out when outside a .set noreorder block.
+(define_insn "hazard_nop"
+  [(const_int 1)]
+  ""
+  {
+    if (set_noreorder)
+      return "nop";
+    else
+      return "#nop";
+  }
+  [(set_attr "type"    "arith")])
+
 ;; The MIPS chip does not seem to require stack probes.
 ;;
 ;; (define_expand "probe"
@@ -9509,9 +9528,9 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
   "*
 {
   if (operands[3] != pc_rtx)
-    return \"%*b%C2z\\t%1,%3\";
+    return \"b%C2z\\t%1,%3\";
   else
-    return \"%*b%N2z\\t%1,%4\";
+    return \"b%N2z\\t%1,%4\";
 }"
   [(set_attr "type"    "branch")
    (set_attr "mode"    "none")
@@ -9534,9 +9553,9 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
   "*
 {
   if (operands[3] != pc_rtx)
-    return \"%*b%C2z\\t%1,%3\";
+    return \"b%C2z\\t%1,%3\";
   else
-    return \"%*b%N2z\\t%1,%4\";
+    return \"b%N2z\\t%1,%4\";
 }"
   [(set_attr "type"    "branch")
    (set_attr "mode"    "none")
@@ -9563,9 +9582,9 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
   "*
 {
   if (operands[3] != pc_rtx)
-    return \"%*bt%C2z\\t%3\";
+    return \"bt%C2z\\t%3\";
   else
-    return \"%*bt%N2z\\t%4\";
+    return \"bt%N2z\\t%4\";
 }"
   [(set_attr "type"    "branch")
    (set_attr "mode"    "none")
@@ -9588,9 +9607,9 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
   "*
 {
   if (operands[3] != pc_rtx)
-    return \"%*bt%C2z\\t%3\";
+    return \"bt%C2z\\t%3\";
   else
-    return \"%*bt%N2z\\t%4\";
+    return \"bt%N2z\\t%4\";
 }"
   [(set_attr "type"    "branch")
    (set_attr "mode"    "none")