This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RE: [PATCH, MIPS] Compact branch support for MIPS32R6/MIPS64R6


Moore, Catherine <Catherine_Moore@mentor.com> writes:
> Hi Matthew,
> 
> > -----Original Message-----
> > From: Matthew Fortune [mailto:Matthew.Fortune@imgtec.com]
> > Sent: Wednesday, July 22, 2015 6:19 PM
> > Subject: [PATCH, MIPS] Compact branch support for MIPS32R6/MIPS64R6
> >
> This patch looks really good.  I have a couple of questions and a couple of nits that need
> to be fixed up.
> 
> > A full range of 'compact' branch instructions were introduced to MIPS
> > as part of Release 6. The compact term is used to identify the fact
> > that these do not have a delay slot.
> >
> > So how does all this work in GCC?
> >
> > Compact branches are used based on a branch policy. The polices are:
> >
> > never: Only use delay slot branches
> > optimal: Do whatever is best for the current architecture.  This will
> >          generally mean that delay slot branches will be used if the delay
> >          slot gets filled but otherwise a compact branch will be used. A
> >          special case here is that JAL and J will not be used in R6 code
> >          regardless of whether the delay slot could be filled.
> > always: Never emit a delay slot form of a branch if a compact form exists.
> >         This policy cannot apply 100% as FP branches (and MSA branches when
> >         committed) only have delay slot forms.
> >
> > These user choices are combined with the features available in the chosen
> > architecture and, in particular, the optimal form will get handled like
> > 'never' when there are no compact branches available and will get handled
> > like 'always' when there are no delay slot branches available.
> >
> 
> Why did you choose to make this a user-selectable option?  Why not always generated
> optimal?
> I don't have a strong opinion about it, but the options seem to complicate things and I'm
> interested in your rationale.

This is down to micro-architecture decisions that different implementers may make.
Honestly, I have not absorbed all of the rationale behind choosing one form over
the other but our arch team have made enough comments about this to mean the support
in the compiler is worth the extra bit of effort. I can attempt a write-up of some
of the pipeline possibilities if you would like more detail but I'd probably have to
refresh my mind on this with our hardware teams.

> > diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
> > index c3cd52d..c0f2884 100644
> > --- a/gcc/config/mips/mips.c
> > +++ b/gcc/config/mips/mips.c
> >
> > +/* Return the asm template for a call.  OPERANDS are the operands,
> > TARGET_OPNO
> > +   is the operand number of the target.  SIZE_OPNO is the operand number
> > of
> > +   the argument size operand that can optionally hold the call attributes.  If
> > +   SIZE_OPNO is not -1 and the call is indirect, use the function symbol from
> > +   the call attributes to attach a R_MIPS_JALR relocation to the call.
> > +
> 
> Might as well mention LINK_P here as well.

Done.

> > +   When generating GOT code without explicit relocation operators, all calls
> > +   should use assembly macros.  Otherwise, all indirect calls should use "jr"
> > +   or "jalr"; we will arrange to restore $gp afterwards if necessary.  Finally,
> > +   we can only generate direct calls for -mabicalls by temporarily switching
> > +   to non-PIC mode.
> > +
> > +   For microMIPS jal(r), we try to generate jal(r)s when a 16-bit
> > +   instruction is in the delay slot of jal(r).
> > +
> > +   Where compact branches are available, we try to use them if the delay
> > slot
> > +   has a NOP (or equivalently delay slots were not enabled for the instruction
> > +   anyway).  */
> > +
> > +const char *
> > +mips_output_jump (rtx *operands, int target_opno, int size_opno, bool
> > link_p)
> > +{
> > @@ -13038,6 +13165,59 @@ mips_output_conditional_branch (rtx_insn
> > *insn, rtx *operands,
> >    return "";
> >  }
> >
> > +const char *
> > +mips_output_equal_conditional_branch (rtx_insn* insn, rtx *operands,
> > +				      bool inverted_p)
> 
> This function needs a comment.

Done.

> diff --git a/gcc/config/mips/mips.opt b/gcc/config/mips/mips.opt
> index 348c6e0..84887d1 100644
> --- a/gcc/config/mips/mips.opt
> +++ b/gcc/config/mips/mips.opt
> @@ -418,3 +418,20 @@ Driver
>  mload-store-pairs
>  Target Report Var(TARGET_LOAD_STORE_PAIRS) Init(1)
>  Enable load/store bonding.
> +
> +mcompact-branches=
> +Target RejectNegative JoinedOrMissing Var(mips_cb) Report Enum(mips_cb_setting)
> Init(MIPS_CB_OPTIMAL)
> +Specify the compact branch usage policy
> +
> +Enum
> +Name(mips_cb_setting) Type(enum mips_cb_setting)
> +Policies available for use with -mcompact-branches=:
> +
> +EnumValue
> +Enum(mips_cb_setting) String(never) Value(MIPS_CB_NEVER)
> +
> +EnumValue
> +Enum(mips_cb_setting) String(optimal) Value(MIPS_CB_OPTIMAL)
> +
> +EnumValue
> +Enum(mips_cb_setting) String(always) Value(MIPS_CB_ALWAYS)
> 
> These need to be documented in invoke.texi.

Done.

> diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
> index 5bc562e..04fe6d0 100644
> --- a/gcc/config/mips/mips.h
> +++ b/gcc/config/mips/mips.h
> > @@ -92,6 +92,23 @@ struct mips_cpu_info {
> >  /* True if we are generating position-independent VxWorks RTP code.  */
> >  #define TARGET_RTP_PIC (TARGET_VXWORKS_RTP && flag_pic)
> >
> > +/* Set based on a combination of compact branch policy and ISA support.
> > */
> > +#define TARGET_CB_NEVER (mips_cb == MIPS_CB_NEVER	\
> > +			 || (mips_cb == MIPS_CB_OPTIMAL \
> > +			     && !ISA_HAS_COMPACT_BRANCHES))
> > +#define TARGET_CB_MAYBE (TARGET_CB_ALWAYS		\
> > +			 || (mips_cb == MIPS_CB_OPTIMAL \
> > +			     && ISA_HAS_COMPACT_BRANCHES))
> > +#define TARGET_CB_ALWAYS (mips_cb == MIPS_CB_ALWAYS	\
> > +			 || (mips_cb == MIPS_CB_OPTIMAL \
> > +			     && !ISA_HAS_DELAY_SLOTS))
> > +
> I would appreciate a more detailed comment here ...

I've made this more descriptive but stopped short of explaining when each
of them should be used as I think that is captured better by just looking
at the places that they are used.

> @@ -871,6 +888,10 @@ struct mips_cpu_info {
> 
>  #define ISA_HAS_JR             (mips_isa_rev <= 5)
> 
> +#define ISA_HAS_DELAY_SLOTS    1
> 
> If this is a placeholder for the microMIPS patch, then OK.  Otherwise, what's the point?

Yes, this is preparation for microMIPSR6. I was so relieved to have microMIPSR6 be made
a public specification before I had to push this as it would have been irritating to
split it up. This patch is 99% of the changes required for microMIPSR6 as it is essentially
compact-branches=always and a couple of macro/pattern changes.

> My test run had only one test that executed with the -mcompact-branch= option.  That may
> have been because I used RUNTESTFLAGS (the problem that we discussed at Cauldron).  It

The RUNTESTFLAGS issue should only affect the scan-assembly tests with lto enabled. One of
us will undoubtedly get so irritated that we figure it out and fix it.

> looks like you put the logic in mips.exp though to have the option throw more often.  In
> any case, I would like to see some explicit testing of the options (if they are kept).
> You've modified the tests to accept both the compact and non-compact forms.  It would be
> nice to ensure that the compact form is not generated when -mcompact-branch=never.

Good point; too absorbed in implementing this to notice the lack of tests. I've added 7
tests to cover some of the important parts of the design. I've tried to create a test
to reliably not fill a delay slot and therefore test the 'optimal' policy switching between
compact and non-compact depending on the delay slot filler. All being well I have covered
enough variants to mean the tests are safe for any test configuration. I still intend to
resolve all test failures in the MIPS backend over the coming weeks/months so if I missed
any particular config it will get cleaned up.

Let me know if you think it needs more tests or any other comments. I'll commit in a couple
of days otherwise.

Thanks,
Matthew

Add compact branch support.

gcc/
	* config/mips/mips-opts.h (mips_cb_setting): New enum.
	* config/mips/mips-protos.h: Add definitions for
	mips_output_jump and mips_output_equal_conditional_branch
	* gcc/config/mips/mips.c (MIPS_JR): Change to support the
	JIC instruction.
	(mips_emit_compare): Add support for the MIPS R6 conditional
	compact branches.
	(mips_process_sync_loop): Likewise.
	(mips_output_order_conditional_branch): Likewise.
	(mips16_build_call_stub): Change MIPS_CALL to
	mips_output_jump.
	(mips_print_operand_punctuation): Update 's' case to only
	apply to micromips r2.
	(mips_adjust_insn_length): Add support for forbidden slot
	hazards.
	(mips_avoid_hazard): Likewise.
	(mips_reorg_process_insns): Likewise.
	(mips_output_jump): New function.
	(mips_output_equal_conditional_branch): Likewise.
	(mips_output_conditional_branch): Use jrc/bc if compact
	branch support is enabled.  Ensure the forbidden slots
	between the two branch instructions is filled with a nop.
	(mips_option_override): Add support to process the compact
	branch option and set the correct defaults.  Prevent
	non-explict relocs being using for MIPS R6.
	(mips_trampoline_init): Add compact branch support.
	(mips_mult_zero_zero_cost): Allow zero initialisation of
	accumulators with TARGET_DSP.
	* gcc/config/mips/mips.h (TARGET_CB_NEVER): New define.
	(TARGET_CB_MAYBE): New define.
	(TARGET_CB_ALWAYS): New define.
	(ISA_HAS_DELAY_SLOTS): New define.
	(ISA_HAS_COMPACT_BRANCHES): New define.
	(ISA_HAS_JRC): New define.
	(MIPS_BRANCH_C): New define.
	(MIPS_CALL): Removed.
	(MICROMIPS_J): Removed.
	* config/mips/mips.md (compact_form): New attr.
	(hazard): Add support for forbidden slots.
	(define_delay): Add support for compact branches.
	(*branch_order<mode>): Likewise.
	(*branch_order<mode>_inverted): Likewise.
	(*branch_equality<mode>): Likewise.
	(*branch_equality<mode>_inverted): Likewise.
	(*jump_absolute): Likewise.
	(*jump_pic): Likewise.
	(indirect_jump): Use mips_output_jump to produce assembly output.
	(tablejump_<mode>"): Likewise.
	(*<optab>"): Likewise.
	(<optab>_internal): Likewise.
	(sibcall_internal): Likewise.
	(sibcall_value_internal): Likewise.
	(sibcall_value_multiple_internal): Likewise.
	(call_internal): Likewise.
	(call_split): Likewise.
	(call_internal_direct): Likewise.
	(call_direct_split): Likewise.
	(call_value_internal): Likewise.
	(call_value_split): Likewise.
	(call_value_internal_direct): Likewise.
	(call_value_direct_split): Likewise.
	(call_value_multiple_internal): Likewise.
	(call_value_multiple_split): Likewise.
	(mips_get_fcsr_mips16_<mode>): Likewise.
	(mips_set_fcsr_mips16_<mode>): Likewise.
	(tls_get_tp_mips16_<mode>): Likewise.
	* config/mips/mips.opt: Add -mcompact-branches option.
	* config/mips/predicates.md (order_operator): Ensure the
	conditional compact branches are only used if the ISA them.
	* doc/invoke.texi: Document -mcompact-branches option.

gcc/testsuite/
	* gcc.target/mips/mips.exp (mips-dg-options): Handle the
	dependencies between ISA level and compact-branches.
	* gcc.target/mips/branch-10.c: Update expected output to allow
	compact forms of b/bal.
	* gcc.target/mips/branch-11.c: Likewise.
	* gcc.target/mips/branch-12.c: Likewise.
	* gcc.target/mips/branch-13.c: Likewise.
	* gcc.target/mips/branch-3.c: Likewise.
	* gcc.target/mips/branch-4.c: Likewise.
	* gcc.target/mips/branch-5.c: Likewise.
	* gcc.target/mips/branch-6.c: Likewise.
	* gcc.target/mips/branch-7.c: Likewise.
	* gcc.target/mips/branch-8.c: Likewise.
	* gcc.target/mips/branch-9.c: Likewise.
	* gcc.target/mips/branch-cost-1.c: Likewise.
	* gcc.target/mips/call-1.c: Likewise.
	* gcc.target/mips/call-2.c: Likewise.
	* gcc.target/mips/call-3.c: Likewise.
	* gcc.target/mips/call-4.c: Likewise.
	* gcc.target/mips/call-5.c: Likewise.
	* gcc.target/mips/call-6.c: Likewise.
	* gcc.target/mips/lazy-binding-1.c: Likewise.
	* gcc.target/mips/near-far-1.c: Likewise.
	* gcc.target/mips/near-far-2.c: Likewise.
	* gcc.target/mips/near-far-3.c: Likewise.
	* gcc.target/mips/near-far-4.c: Likewise.
	* gcc.target/mips/umips-branch-3.c: Ensure the test is
	run with compact branches allowed.
	* gcc.target/mips/compact-branches-1.c: New file.
	* gcc.target/mips/compact-branches-2.c: Likewise.
	* gcc.target/mips/compact-branches-3.c: Likewise.
	* gcc.target/mips/compact-branches-4.c: Likewise.
	* gcc.target/mips/compact-branches-5.c: Likewise.
	* gcc.target/mips/compact-branches-6.c: Likewise.
	* gcc.target/mips/compact-branches-7.c: Likewise.
---
 gcc/config/mips/mips-opts.h                        |   6 +
 gcc/config/mips/mips-protos.h                      |   3 +
 gcc/config/mips/mips.c                             | 377 ++++++++++++++++++---
 gcc/config/mips/mips.h                             |  73 ++--
 gcc/config/mips/mips.md                            | 213 ++++++------
 gcc/config/mips/mips.opt                           |  17 +
 gcc/config/mips/predicates.md                      |  13 +-
 gcc/doc/invoke.texi                                |  22 ++
 gcc/testsuite/gcc.target/mips/branch-10.c          |   2 +-
 gcc/testsuite/gcc.target/mips/branch-11.c          |   2 +-
 gcc/testsuite/gcc.target/mips/branch-12.c          |   2 +-
 gcc/testsuite/gcc.target/mips/branch-13.c          |   2 +-
 gcc/testsuite/gcc.target/mips/branch-3.c           |   2 +-
 gcc/testsuite/gcc.target/mips/branch-4.c           |   2 +-
 gcc/testsuite/gcc.target/mips/branch-5.c           |   2 +-
 gcc/testsuite/gcc.target/mips/branch-6.c           |   2 +-
 gcc/testsuite/gcc.target/mips/branch-7.c           |   2 +-
 gcc/testsuite/gcc.target/mips/branch-8.c           |   2 +-
 gcc/testsuite/gcc.target/mips/branch-9.c           |   2 +-
 gcc/testsuite/gcc.target/mips/branch-cost-1.c      |   2 +-
 gcc/testsuite/gcc.target/mips/call-1.c             |  14 +-
 gcc/testsuite/gcc.target/mips/call-2.c             |   2 +-
 gcc/testsuite/gcc.target/mips/call-3.c             |   2 +-
 gcc/testsuite/gcc.target/mips/call-4.c             |   2 +-
 gcc/testsuite/gcc.target/mips/call-5.c             |  14 +-
 gcc/testsuite/gcc.target/mips/call-6.c             |  14 +-
 gcc/testsuite/gcc.target/mips/compact-branches-1.c |  12 +
 gcc/testsuite/gcc.target/mips/compact-branches-2.c |  12 +
 gcc/testsuite/gcc.target/mips/compact-branches-3.c |  13 +
 gcc/testsuite/gcc.target/mips/compact-branches-4.c |  11 +
 gcc/testsuite/gcc.target/mips/compact-branches-5.c |  10 +
 gcc/testsuite/gcc.target/mips/compact-branches-6.c |  10 +
 gcc/testsuite/gcc.target/mips/compact-branches-7.c |  12 +
 gcc/testsuite/gcc.target/mips/lazy-binding-1.c     |   2 +-
 gcc/testsuite/gcc.target/mips/mips.exp             |  13 +-
 gcc/testsuite/gcc.target/mips/near-far-1.c         |   2 +-
 gcc/testsuite/gcc.target/mips/near-far-2.c         |   4 +-
 gcc/testsuite/gcc.target/mips/near-far-3.c         |   2 +-
 gcc/testsuite/gcc.target/mips/near-far-4.c         |   4 +-
 gcc/testsuite/gcc.target/mips/umips-branch-3.c     |   2 +-
 40 files changed, 685 insertions(+), 220 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/mips/compact-branches-1.c
 create mode 100644 gcc/testsuite/gcc.target/mips/compact-branches-2.c
 create mode 100644 gcc/testsuite/gcc.target/mips/compact-branches-3.c
 create mode 100644 gcc/testsuite/gcc.target/mips/compact-branches-4.c
 create mode 100644 gcc/testsuite/gcc.target/mips/compact-branches-5.c
 create mode 100644 gcc/testsuite/gcc.target/mips/compact-branches-6.c
 create mode 100644 gcc/testsuite/gcc.target/mips/compact-branches-7.c

diff --git a/gcc/config/mips/mips-opts.h b/gcc/config/mips/mips-opts.h
index 7988205..3c2c659 100644
--- a/gcc/config/mips/mips-opts.h
+++ b/gcc/config/mips/mips-opts.h
@@ -47,4 +47,10 @@ enum mips_r10k_cache_barrier_setting {
 #define MIPS_ARCH_OPTION_FROM_ABI -1
 #define MIPS_ARCH_OPTION_NATIVE -2
 
+/* Enumerates the setting of the -mcompact-branches= option.  */
+enum mips_cb_setting {
+  MIPS_CB_NEVER,
+  MIPS_CB_OPTIMAL,
+  MIPS_CB_ALWAYS
+};
 #endif
diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h
index 244eb8d..e7db044 100644
--- a/gcc/config/mips/mips-protos.h
+++ b/gcc/config/mips/mips-protos.h
@@ -298,6 +298,9 @@ extern const char *mips_output_conditional_branch (rtx_insn *, rtx *,
 						   const char *, const char *);
 extern const char *mips_output_order_conditional_branch (rtx_insn *, rtx *,
 							 bool);
+extern const char *mips_output_equal_conditional_branch (rtx_insn *, rtx *,
+							 bool);
+extern const char *mips_output_jump (rtx *, int, int, bool);
 extern const char *mips_output_sync (void);
 extern const char *mips_output_sync_loop (rtx_insn *, rtx *);
 extern unsigned int mips_sync_loop_insns (rtx_insn *, rtx *);
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index 238b9b0..5611ac4 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -176,7 +176,8 @@ along with GCC; see the file COPYING3.  If not see
 /* Return the opcode to jump to register DEST.  When the JR opcode is not
    available use JALR $0, DEST.  */
 #define MIPS_JR(DEST) \
-  (((DEST) << 21) | (ISA_HAS_JR ? 0x8 : 0x9))
+  (TARGET_CB_ALWAYS ? ((0x1b << 27) | ((DEST) << 16)) \
+		    : (((DEST) << 21) | (ISA_HAS_JR ? 0x8 : 0x9)))
 
 /* Return the opcode for:
 
@@ -5181,7 +5182,8 @@ mips_allocate_fcc (machine_mode mode)
    conditions are:
 
       - EQ or NE between two registers.
-      - any comparison between a register and zero.  */
+      - any comparison between a register and zero.
+      - if compact branches are available then any condition is valid.  */
 
 static void
 mips_emit_compare (enum rtx_code *code, rtx *op0, rtx *op1, bool need_eq_ne_p)
@@ -5203,6 +5205,44 @@ mips_emit_compare (enum rtx_code *code, rtx *op0, rtx *op1, bool need_eq_ne_p)
 	  else
 	    *op1 = force_reg (GET_MODE (cmp_op0), cmp_op1);
 	}
+      else if (!need_eq_ne_p && TARGET_CB_MAYBE)
+	{
+	  bool swap = false;
+	  switch (*code)
+	    {
+	    case LE:
+	      swap = true;
+	      *code = GE;
+	      break;
+	    case GT:
+	      swap = true;
+	      *code = LT;
+	      break;
+	    case LEU:
+	      swap = true;
+	      *code = GEU;
+	      break;
+	    case GTU:
+	      swap = true;
+	      *code = LTU;
+	      break;
+	    case GE:
+	    case LT:
+	    case GEU:
+	    case LTU:
+	      /* Do nothing.  */
+	      break;
+	    default:
+	      gcc_unreachable ();
+	    }
+	  *op1 = force_reg (GET_MODE (cmp_op0), cmp_op1);
+	  if (swap)
+	    {
+	      rtx tmp = *op1;
+	      *op1 = *op0;
+	      *op0 = tmp;
+	    }
+	}
       else
 	{
 	  /* The comparison needs a separate scc instruction.  Store the
@@ -7260,7 +7300,7 @@ mips16_build_call_stub (rtx retval, rtx *fn_ptr, rtx args_size, int fp_code)
       if (fp_ret_p)
 	{
 	  /* Now call the non-MIPS16 function.  */
-	  output_asm_insn (MIPS_CALL ("jal", &fn, 0, -1), &fn);
+	  output_asm_insn (mips_output_jump (&fn, 0, -1, true), &fn);
 	  fprintf (asm_out_file, "\t.cfi_register 31,18\n");
 
 	  /* Move the result from floating-point registers to
@@ -8367,7 +8407,7 @@ mips_pop_asm_switch (struct mips_asm_switch *asm_switch)
    '!'  Print "s" to use the short version if the delay slot contains a
 	16-bit instruction.
 
-   See also mips_init_print_operand_pucnt.  */
+   See also mips_init_print_operand_punct.  */
 
 static void
 mips_print_operand_punctuation (FILE *file, int ch)
@@ -8451,7 +8491,8 @@ mips_print_operand_punctuation (FILE *file, int ch)
 
     case ':':
       /* When final_sequence is 0, the delay slot will be a nop.  We can
-	 use the compact version for microMIPS.  */
+	 use the compact version where available.  The %: formatter will
+	 only be present if a compact form of the branch is available.  */
       if (final_sequence == 0)
 	putc ('c', file);
       break;
@@ -8459,8 +8500,9 @@ mips_print_operand_punctuation (FILE *file, int ch)
     case '!':
       /* If the delay slot instruction is short, then use the
 	 compact version.  */
-      if (final_sequence == 0
-	  || get_attr_length (final_sequence->insn (1)) == 2)
+      if (TARGET_MICROMIPS && !TARGET_INTERLINK_COMPRESSED && mips_isa_rev <= 5
+	  && (final_sequence == 0
+	      || get_attr_length (final_sequence->insn (1)) == 2))
 	putc ('s', file);
       break;
 
@@ -12931,6 +12973,7 @@ mips_adjust_insn_length (rtx_insn *insn, int length)
 	break;
 
       case HAZARD_DELAY:
+      case HAZARD_FORBIDDEN_SLOT:
 	length += NOP_INSN_LENGTH;
 	break;
 
@@ -12942,6 +12985,78 @@ mips_adjust_insn_length (rtx_insn *insn, int length)
   return length;
 }
 
+/* Return the asm template for a call.  OPERANDS are the operands, TARGET_OPNO
+   is the operand number of the target.  SIZE_OPNO is the operand number of
+   the argument size operand that can optionally hold the call attributes.  If
+   SIZE_OPNO is not -1 and the call is indirect, use the function symbol from
+   the call attributes to attach a R_MIPS_JALR relocation to the call.  LINK_P
+   indicates whether the jump is a call and needs to set the link register.
+
+   When generating GOT code without explicit relocation operators, all calls
+   should use assembly macros.  Otherwise, all indirect calls should use "jr"
+   or "jalr"; we will arrange to restore $gp afterwards if necessary.  Finally,
+   we can only generate direct calls for -mabicalls by temporarily switching
+   to non-PIC mode.
+
+   For microMIPS jal(r), we try to generate jal(r)s when a 16-bit
+   instruction is in the delay slot of jal(r).
+
+   Where compact branches are available, we try to use them if the delay slot
+   has a NOP (or equivalently delay slots were not enabled for the instruction
+   anyway).  */
+
+const char *
+mips_output_jump (rtx *operands, int target_opno, int size_opno, bool link_p)
+{
+  static char buffer[300];
+  char *s = buffer;
+  bool reg_p = REG_P (operands[target_opno]);
+
+  const char *and_link = link_p ? "al" : "";
+  const char *reg = reg_p ? "r" : "";
+  const char *compact = "";
+  const char *nop = "%/";
+  const char *short_delay = link_p ? "%!" : "";
+  const char *insn_name = TARGET_CB_NEVER || reg_p ? "j" : "b";
+
+  /* Compact branches can only be described when the ISA has support for them
+     as both the compact formatter '%:' and the delay slot NOP formatter '%/'
+     work as a mutually exclusive pair.  I.e. a NOP is never required if a
+     compact form is available.  */
+  if (!final_sequence
+      && (TARGET_CB_MAYBE
+	  || (ISA_HAS_JRC && !link_p && reg_p)))
+    {
+      compact = "c";
+      nop = "";
+    }
+
+  if (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS)
+    sprintf (s, "%%*%s%s\t%%%d%%/", insn_name, and_link, target_opno);
+  else
+    {
+      if (!reg_p && TARGET_ABICALLS_PIC2)
+	s += sprintf (s, ".option\tpic0\n\t");
+
+      if (reg_p && mips_get_pic_call_symbol (operands, size_opno))
+	{
+	  s += sprintf (s, "%%*.reloc\t1f,R_MIPS_JALR,%%%d\n1:\t", size_opno);
+	  /* Not sure why this shouldn't permit a short delay but it did not
+	     allow it before so we still don't allow it.  */
+	  short_delay = "";
+	}
+      else
+	s += sprintf (s, "%%*");
+
+      s += sprintf (s, "%s%s%s%s%s\t%%%d%s", insn_name, and_link, reg, compact, short_delay,
+					    target_opno, nop);
+
+      if (!reg_p && TARGET_ABICALLS_PIC2)
+	s += sprintf (s, "\n\t.option\tpic2");
+    }
+  return buffer;
+}
+
 /* Return the assembly code for INSN, which has the operands given by
    OPERANDS, and which branches to OPERANDS[0] if some condition is true.
    BRANCH_IF_TRUE is the asm template that should be used if OPERANDS[0]
@@ -12995,12 +13110,25 @@ mips_output_conditional_branch (rtx_insn *insn, rtx *operands,
     }
 
   /* Output the unconditional branch to TAKEN.  */
-  if (TARGET_ABSOLUTE_JUMPS)
+  if (TARGET_ABSOLUTE_JUMPS && TARGET_CB_MAYBE)
+    {
+      /* Add a hazard nop.  */
+      if (!final_sequence)
+	{
+	  output_asm_insn ("nop\t\t# hazard nop", 0);
+	  fprintf (asm_out_file, "\n");
+	}
+      output_asm_insn (MIPS_ABSOLUTE_JUMP ("bc\t%0"), &taken);
+    }
+  else if (TARGET_ABSOLUTE_JUMPS)
     output_asm_insn (MIPS_ABSOLUTE_JUMP ("j\t%0%/"), &taken);
   else
     {
       mips_output_load_label (taken);
-      output_asm_insn ("jr\t%@%]%/", 0);
+      if (TARGET_CB_MAYBE)
+	output_asm_insn ("jrc\t%@%]", 0);
+      else
+	output_asm_insn ("jr\t%@%]%/", 0);
     }
 
   /* Now deal with its delay slot; see above.  */
@@ -13014,7 +13142,7 @@ mips_output_conditional_branch (rtx_insn *insn, rtx *operands,
 			   asm_out_file, optimize, 1, NULL);
 	  final_sequence->insn (1)->set_deleted ();
 	}
-      else
+      else if (TARGET_CB_NEVER)
 	output_asm_insn ("nop", 0);
       fprintf (asm_out_file, "\n");
     }
@@ -13026,42 +13154,155 @@ mips_output_conditional_branch (rtx_insn *insn, rtx *operands,
 }
 
 /* Return the assembly code for INSN, which branches to OPERANDS[0]
+   if some equality condition is true.  The condition is given by
+   OPERANDS[1] if !INVERTED_P, otherwise it is the inverse of
+   OPERANDS[1].  OPERANDS[2] is the comparison's first operand;
+   OPERANDS[3] is the second operand and may be zero or a register.  */
+
+const char *
+mips_output_equal_conditional_branch (rtx_insn* insn, rtx *operands,
+				      bool inverted_p)
+{
+  const char *branch[2];
+  /* For a simple BNEZ or BEQZ microMIPSr3 branch.  */
+  if (TARGET_MICROMIPS
+      && mips_isa_rev <= 5
+      && operands[3] == const0_rtx
+      && get_attr_length (insn) <= 8)
+    {
+      if (mips_cb == MIPS_CB_OPTIMAL)
+	{
+	  branch[!inverted_p] = "%*b%C1z%:\t%2,%0";
+	  branch[inverted_p] = "%*b%N1z%:\t%2,%0";
+	}
+      else
+	{
+	  branch[!inverted_p] = "%*b%C1z\t%2,%0%/";
+	  branch[inverted_p] = "%*b%N1z\t%2,%0%/";
+	}
+    }
+  else if (TARGET_CB_MAYBE)
+    {
+      if (operands[3] == const0_rtx)
+	{
+	  branch[!inverted_p] = MIPS_BRANCH_C ("b%C1z", "%2,%0");
+	  branch[inverted_p] = MIPS_BRANCH_C ("b%N1z", "%2,%0");
+	}
+      else if (REGNO (operands[2]) != REGNO (operands[3]))
+	{
+	  branch[!inverted_p] = MIPS_BRANCH_C ("b%C1", "%2,%3,%0");
+	  branch[inverted_p] = MIPS_BRANCH_C ("b%N1", "%2,%3,%0");
+	}
+      else
+	{
+	  /* This case is degenerate.  It should not happen, but does.  */
+	  if (GET_CODE (operands[1]) == NE)
+	    inverted_p = !inverted_p;
+
+	  branch[!inverted_p] = MIPS_BRANCH_C ("b", "%0");
+	  branch[inverted_p] = "%*\t\t# branch never";
+	}
+    }
+  else
+    {
+      branch[!inverted_p] = MIPS_BRANCH ("b%C1", "%2,%z3,%0");
+      branch[inverted_p] = MIPS_BRANCH ("b%N1", "%2,%z3,%0");
+    }
+
+  return mips_output_conditional_branch (insn, operands, branch[1], branch[0]);
+}
+
+/* Return the assembly code for INSN, which branches to OPERANDS[0]
    if some ordering condition is true.  The condition is given by
    OPERANDS[1] if !INVERTED_P, otherwise it is the inverse of
    OPERANDS[1].  OPERANDS[2] is the comparison's first operand;
-   its second is always zero.  */
+   OPERANDS[3] is the second operand and may be zero or a register.  */
 
 const char *
-mips_output_order_conditional_branch (rtx_insn *insn, rtx *operands, bool inverted_p)
+mips_output_order_conditional_branch (rtx_insn *insn, rtx *operands,
+				      bool inverted_p)
 {
   const char *branch[2];
 
   /* Make BRANCH[1] branch to OPERANDS[0] when the condition is true.
      Make BRANCH[0] branch on the inverse condition.  */
-  switch (GET_CODE (operands[1]))
+  if (operands[3] != const0_rtx)
     {
-      /* These cases are equivalent to comparisons against zero.  */
-    case LEU:
-      inverted_p = !inverted_p;
-      /* Fall through.  */
-    case GTU:
-      branch[!inverted_p] = MIPS_BRANCH ("bne", "%2,%.,%0");
-      branch[inverted_p] = MIPS_BRANCH ("beq", "%2,%.,%0");
-      break;
+      /* Handle degenerate cases that should not, but do, occur.  */
+      if (REGNO (operands[2]) == REGNO (operands[3]))
+	{
+	  switch (GET_CODE (operands[1]))
+	    {
+	    case LT:
+	    case LTU:
+	      inverted_p = !inverted_p;
+	      /* Fall through.  */
+	    case GE:
+	    case GEU:
+	      branch[!inverted_p] = MIPS_BRANCH_C ("b", "%0");
+	      branch[inverted_p] = "%*\t\t# branch never";
+	      break;
+	   default:
+	      gcc_unreachable ();
+	    }
+	}
+      else
+	{
+	  branch[!inverted_p] = MIPS_BRANCH_C ("b%C1", "%2,%3,%0");
+	  branch[inverted_p] = MIPS_BRANCH_C ("b%N1", "%2,%3,%0");
+	}
+    }
+  else
+    {
+      switch (GET_CODE (operands[1]))
+	{
+	  /* These cases are equivalent to comparisons against zero.  */
+	case LEU:
+	  inverted_p = !inverted_p;
+	  /* Fall through.  */
+	case GTU:
+	  if (TARGET_CB_MAYBE)
+	    {
+	      branch[!inverted_p] = MIPS_BRANCH_C ("bnez", "%2,%0");
+	      branch[inverted_p] = MIPS_BRANCH_C ("beqz", "%2,%0");
+	    }
+	  else
+	    {
+	      branch[!inverted_p] = MIPS_BRANCH ("bne", "%2,%.,%0");
+	      branch[inverted_p] = MIPS_BRANCH ("beq", "%2,%.,%0");
+	    }
+	  break;
 
-      /* These cases are always true or always false.  */
-    case LTU:
-      inverted_p = !inverted_p;
-      /* Fall through.  */
-    case GEU:
-      branch[!inverted_p] = MIPS_BRANCH ("beq", "%.,%.,%0");
-      branch[inverted_p] = MIPS_BRANCH ("bne", "%.,%.,%0");
-      break;
+	  /* These cases are always true or always false.  */
+	case LTU:
+	  inverted_p = !inverted_p;
+	  /* Fall through.  */
+	case GEU:
+	  if (TARGET_CB_MAYBE)
+	    {
+	      branch[!inverted_p] = MIPS_BRANCH_C ("b", "%0");
+	      branch[inverted_p] = "%*\t\t# branch never";
+	    }
+	  else
+	    {
+	      branch[!inverted_p] = MIPS_BRANCH ("beq", "%.,%.,%0");
+	      branch[inverted_p] = MIPS_BRANCH ("bne", "%.,%.,%0");
+	    }
+	  break;
 
-    default:
-      branch[!inverted_p] = MIPS_BRANCH ("b%C1z", "%2,%0");
-      branch[inverted_p] = MIPS_BRANCH ("b%N1z", "%2,%0");
-      break;
+	default:
+	  if (TARGET_CB_MAYBE)
+	    {
+	      branch[!inverted_p] = MIPS_BRANCH_C ("b%C1z", "%2,%0");
+	      branch[inverted_p] = MIPS_BRANCH_C ("b%N1z", "%2,%0");
+	    }
+	  else
+	    {
+	      branch[!inverted_p] = MIPS_BRANCH ("b%C1z", "%2,%0");
+	      branch[inverted_p] = MIPS_BRANCH ("b%N1z", "%2,%0");
+	    }
+	  break;
+	}
     }
   return mips_output_conditional_branch (insn, operands, branch[1], branch[0]);
 }
@@ -13264,11 +13505,18 @@ mips_process_sync_loop (rtx_insn *insn, rtx *operands)
 			       at, oldval, inclusive_mask, NULL);
 	  tmp1 = at;
 	}
-      mips_multi_add_insn ("bne\t%0,%z1,2f", tmp1, required_oldval, NULL);
+      if (TARGET_CB_NEVER)
+	mips_multi_add_insn ("bne\t%0,%z1,2f", tmp1, required_oldval, NULL);
 
       /* CMP = 0 [delay slot].  */
       if (cmp)
         mips_multi_add_insn ("li\t%0,0", cmp, NULL);
+
+      if (TARGET_CB_MAYBE && required_oldval == const0_rtx)
+	mips_multi_add_insn ("bnezc\t%0,2f", tmp1, NULL);
+      else if (TARGET_CB_MAYBE)
+	mips_multi_add_insn ("bnec\t%0,%1,2f", tmp1, required_oldval, NULL);
+
     }
 
   /* $TMP1 = OLDVAL & EXCLUSIVE_MASK.  */
@@ -13331,7 +13579,10 @@ mips_process_sync_loop (rtx_insn *insn, rtx *operands)
      be annulled.  To ensure this behaviour unconditionally use a NOP
      in the delay slot for the branch likely case.  */
 
-  mips_multi_add_insn ("beq%?\t%0,%.,1b%~", at, NULL);
+  if (TARGET_CB_MAYBE)
+    mips_multi_add_insn ("beqzc\t%0,1b", at, NULL);
+  else
+    mips_multi_add_insn ("beq%?\t%0,%.,1b%~", at, NULL);
 
   /* if (INSN1 != MOVE && INSN1 != LI) NEWVAL = $TMP3 [delay slot].  */
   if (insn1 != SYNC_INSN1_MOVE && insn1 != SYNC_INSN1_LI && tmp3 != newval)
@@ -16613,7 +16864,7 @@ mips_orphaned_high_part_p (mips_offset_table *htab, rtx_insn *insn)
 
 static void
 mips_avoid_hazard (rtx_insn *after, rtx_insn *insn, int *hilo_delay,
-		   rtx *delayed_reg, rtx lo_reg)
+		   rtx *delayed_reg, rtx lo_reg, bool *fs_delay)
 {
   rtx pattern, set;
   int nops, ninsns;
@@ -16639,6 +16890,15 @@ mips_avoid_hazard (rtx_insn *after, rtx_insn *insn, int *hilo_delay,
     nops = 2 - *hilo_delay;
   else if (*delayed_reg != 0 && reg_referenced_p (*delayed_reg, pattern))
     nops = 1;
+  /* If processing a forbidden slot hazard then a NOP is required if the
+     branch instruction was not in a sequence (as the sequence would
+     imply it is not actually a compact branch anyway) and the current
+     insn is not an inline asm, and can't go in a delay slot.  */
+  else if (*fs_delay && get_attr_can_delay (insn) == CAN_DELAY_NO
+	   && GET_CODE (PATTERN (after)) != SEQUENCE
+	   && GET_CODE (pattern) != ASM_INPUT
+	   && asm_noperands (pattern) < 0)
+    nops = 1;
   else
     nops = 0;
 
@@ -16651,12 +16911,18 @@ mips_avoid_hazard (rtx_insn *after, rtx_insn *insn, int *hilo_delay,
   /* Set up the state for the next instruction.  */
   *hilo_delay += ninsns;
   *delayed_reg = 0;
+  *fs_delay = false;
   if (INSN_CODE (insn) >= 0)
     switch (get_attr_hazard (insn))
       {
       case HAZARD_NONE:
 	break;
 
+      case HAZARD_FORBIDDEN_SLOT:
+	if (TARGET_CB_MAYBE)
+	  *fs_delay = true;
+	break;
+
       case HAZARD_HILO:
 	*hilo_delay = 0;
 	break;
@@ -16680,6 +16946,7 @@ mips_reorg_process_insns (void)
   rtx_insn *insn, *last_insn, *subinsn, *next_insn;
   rtx lo_reg, delayed_reg;
   int hilo_delay;
+  bool fs_delay;
 
   /* Force all instructions to be split into their final form.  */
   split_all_insns_noflow ();
@@ -16748,6 +17015,7 @@ mips_reorg_process_insns (void)
   hilo_delay = 2;
   delayed_reg = 0;
   lo_reg = gen_rtx_REG (SImode, LO_REGNUM);
+  fs_delay = false;
 
   /* Make a second pass over the instructions.  Delete orphaned
      high-part relocations or turn them into NOPs.  Avoid hazards
@@ -16771,7 +17039,7 @@ mips_reorg_process_insns (void)
 			INSN_CODE (subinsn) = CODE_FOR_nop;
 		      }
 		    mips_avoid_hazard (last_insn, subinsn, &hilo_delay,
-				       &delayed_reg, lo_reg);
+				       &delayed_reg, lo_reg, &fs_delay);
 		  }
 	      last_insn = insn;
 	    }
@@ -16792,7 +17060,7 @@ mips_reorg_process_insns (void)
 	      else
 		{
 		  mips_avoid_hazard (last_insn, insn, &hilo_delay,
-				     &delayed_reg, lo_reg);
+				     &delayed_reg, lo_reg, &fs_delay);
 		  last_insn = insn;
 		}
 	    }
@@ -17657,6 +17925,27 @@ mips_option_override (void)
       target_flags |= MASK_ODD_SPREG;
     }
 
+  if (!ISA_HAS_COMPACT_BRANCHES && mips_cb == MIPS_CB_ALWAYS)
+    {
+      error ("unsupported combination: %qs%s %s",
+	      mips_arch_info->name, TARGET_MICROMIPS ? " -mmicromips" : "",
+	      "-mcompact-branches=always");
+    }
+  else if (!ISA_HAS_DELAY_SLOTS && mips_cb == MIPS_CB_NEVER)
+    {
+      error ("unsupported combination: %qs%s %s",
+	      mips_arch_info->name, TARGET_MICROMIPS ? " -mmicromips" : "",
+	      "-mcompact-branches=never");
+    }
+
+  /* Require explicit relocs for MIPS R6 onwards.  This enables simplification
+     of the compact branch and jump support through the backend.  */
+  if (!TARGET_EXPLICIT_RELOCS && mips_isa_rev >= 6)
+    {
+      error ("unsupported combination: %qs %s",
+	     mips_arch_info->name, "-mno-explicit-relocs");
+    }
+
   /* The effect of -mabicalls isn't defined for the EABI.  */
   if (mips_abi == ABI_EABI && TARGET_ABICALLS)
     {
@@ -18676,6 +18965,18 @@ mips_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
 
 #undef OP
 
+  /* If we are using compact branches we don't have delay slots so
+     place the instruction that was in the delay slot before the JRC
+     instruction.  */
+
+  if (TARGET_CB_ALWAYS)
+    {
+      rtx temp;
+      temp = trampoline[i-2];
+      trampoline[i-2] = trampoline[i-1];
+      trampoline[i-1] = temp;
+    }
+
   /* Copy the trampoline code.  Leave any padding uninitialized.  */
   for (j = 0; j < i; j++)
     {
diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index 6e262d6..e9fa80c 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -92,6 +92,33 @@ struct mips_cpu_info {
 /* True if we are generating position-independent VxWorks RTP code.  */
 #define TARGET_RTP_PIC (TARGET_VXWORKS_RTP && flag_pic)
 
+/* Compact branches must not be used if the user either selects the
+   'never' policy or the 'optimal' policy on a core that lacks
+   compact branch instructions.  */
+#define TARGET_CB_NEVER (mips_cb == MIPS_CB_NEVER	\
+			 || (mips_cb == MIPS_CB_OPTIMAL \
+			     && !ISA_HAS_COMPACT_BRANCHES))
+
+/* Compact branches may be used if the user either selects the
+   'always' policy or the 'optimal' policy on a core that supports
+   compact branch instructions.  */
+#define TARGET_CB_MAYBE (TARGET_CB_ALWAYS		\
+			 || (mips_cb == MIPS_CB_OPTIMAL \
+			     && ISA_HAS_COMPACT_BRANCHES))
+
+/* Compact branches must always be generated if the user selects
+   the 'always' policy or the 'optimal' policy om a core that
+   lacks delay slot branch instructions.  */
+#define TARGET_CB_ALWAYS (mips_cb == MIPS_CB_ALWAYS	\
+			 || (mips_cb == MIPS_CB_OPTIMAL \
+			     && !ISA_HAS_DELAY_SLOTS))
+
+/* Special handling for JRC that exists in microMIPSR3 as well as R6
+   ISAs with full compact branch support.  */
+#define ISA_HAS_JRC ((ISA_HAS_COMPACT_BRANCHES		\
+		      || TARGET_MICROMIPS)		\
+		     && mips_cb != MIPS_CB_NEVER)
+
 /* True if the output file is marked as ".abicalls; .option pic0"
    (-call_nonpic).  */
 #define TARGET_ABICALLS_PIC0 \
@@ -872,6 +899,10 @@ struct mips_cpu_info {
 
 #define ISA_HAS_JR		(mips_isa_rev <= 5)
 
+#define ISA_HAS_DELAY_SLOTS	1
+
+#define ISA_HAS_COMPACT_BRANCHES (mips_isa_rev >= 6)
+
 /* ISA has branch likely instructions (e.g. mips2).  */
 /* Disable branchlikely for tx39 until compare rewrite.  They haven't
    been generated up to this point.  */
@@ -2642,6 +2673,9 @@ typedef struct mips_args {
 #define MIPS_BRANCH(OPCODE, OPERANDS) \
   "%*" OPCODE "%?\t" OPERANDS "%/"
 
+#define MIPS_BRANCH_C(OPCODE, OPERANDS) \
+  "%*" OPCODE "%:\t" OPERANDS
+
 /* Return an asm string that forces INSN to be treated as an absolute
    J or JAL instruction instead of an assembler macro.  */
 #define MIPS_ABSOLUTE_JUMP(INSN) \
@@ -2649,45 +2683,6 @@ typedef struct mips_args {
    ? ".option\tpic0\n\t" INSN "\n\t.option\tpic2"		\
    : INSN)
 
-/* Return the asm template for a call.  INSN is the instruction's mnemonic
-   ("j" or "jal"), OPERANDS are its operands, TARGET_OPNO is the operand
-   number of the target.  SIZE_OPNO is the operand number of the argument size
-   operand that can optionally hold the call attributes.  If SIZE_OPNO is not
-   -1 and the call is indirect, use the function symbol from the call
-   attributes to attach a R_MIPS_JALR relocation to the call.
-
-   When generating GOT code without explicit relocation operators,
-   all calls should use assembly macros.  Otherwise, all indirect
-   calls should use "jr" or "jalr"; we will arrange to restore $gp
-   afterwards if necessary.  Finally, we can only generate direct
-   calls for -mabicalls by temporarily switching to non-PIC mode.
-
-   For microMIPS jal(r), we try to generate jal(r)s when a 16-bit
-   instruction is in the delay slot of jal(r).  */
-#define MIPS_CALL(INSN, OPERANDS, TARGET_OPNO, SIZE_OPNO)	\
-  (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS			\
-   ? "%*" INSN "\t%" #TARGET_OPNO "%/"				\
-   : REG_P (OPERANDS[TARGET_OPNO])				\
-   ? (mips_get_pic_call_symbol (OPERANDS, SIZE_OPNO)		\
-      ? ("%*.reloc\t1f,R_MIPS_JALR,%" #SIZE_OPNO "\n"		\
-	 "1:\t" INSN "r\t%" #TARGET_OPNO "%/")			\
-      : TARGET_MICROMIPS && !TARGET_INTERLINK_COMPRESSED	\
-      ? "%*" INSN "r%!\t%" #TARGET_OPNO "%/"			\
-      : "%*" INSN "r\t%" #TARGET_OPNO "%/")			\
-   : TARGET_MICROMIPS && !TARGET_INTERLINK_COMPRESSED		\
-     ? MIPS_ABSOLUTE_JUMP ("%*" INSN "%!\t%" #TARGET_OPNO "%/")	\
-     : MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #TARGET_OPNO "%/"))	\
-
-/* Similar to MIPS_CALL, but this is for MICROMIPS "j" to generate
-   "jrc" when nop is in the delay slot of "jr".  */
-
-#define MICROMIPS_J(INSN, OPERANDS, OPNO)			\
-  (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS			\
-   ? "%*j\t%" #OPNO "%/"					\
-   : REG_P (OPERANDS[OPNO])					\
-   ? "%*jr%:\t%" #OPNO						\
-   : MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #OPNO "%/"))
-
 

 /* Control the assembler format that we output.  */
 
diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
index a0079d5..01887d2 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -409,6 +409,15 @@ (define_attr "type"
 	 (eq_attr "sync_mem" "!none") (const_string "syncloop")]
 	(const_string "unknown")))
 
+(define_attr "compact_form" "always,maybe,never"
+  (cond [(eq_attr "jal" "direct")
+	 (const_string "always")
+	 (eq_attr "jal" "indirect")
+	 (const_string "maybe")
+	 (eq_attr "type" "jump")
+	 (const_string "maybe")]
+	(const_string "never")))
+
 ;; Mode for conversion types (fcvt)
 ;; I2S          integer to float single (SI/DI to SF)
 ;; I2D          integer to float double (SI/DI to DF)
@@ -694,7 +703,7 @@ (define_enum_attr "cpu" "processor"
 ;; DELAY means that the next instruction cannot read the result
 ;; of this one.  HILO means that the next two instructions cannot
 ;; write to HI or LO.
-(define_attr "hazard" "none,delay,hilo"
+(define_attr "hazard" "none,delay,hilo,forbidden_slot"
   (cond [(and (eq_attr "type" "load,fpload,fpidxload")
 	      (match_test "ISA_HAS_LOAD_DELAY"))
 	 (const_string "delay")
@@ -1045,21 +1054,37 @@ (define_delay (and (eq_attr "type" "branch")
    (nil)
    (eq_attr "can_delay" "yes")])
 
-;; Branches that don't have likely variants do not annul on false.
+;; Branches that have delay slots and don't have likely variants do
+;; not annul on false.
 (define_delay (and (eq_attr "type" "branch")
 		   (not (match_test "TARGET_MIPS16"))
+		   (ior (match_test "TARGET_CB_NEVER")
+			(and (eq_attr "compact_form" "maybe")
+			     (not (match_test "TARGET_CB_ALWAYS")))
+			(eq_attr "compact_form" "never"))
 		   (eq_attr "branch_likely" "no"))
   [(eq_attr "can_delay" "yes")
    (nil)
    (nil)])
 
-(define_delay (eq_attr "type" "jump")
+(define_delay (and (eq_attr "type" "jump")
+		   (ior (match_test "TARGET_CB_NEVER")
+			(and (eq_attr "compact_form" "maybe")
+			     (not (match_test "TARGET_CB_ALWAYS")))
+			(eq_attr "compact_form" "never")))
   [(eq_attr "can_delay" "yes")
    (nil)
    (nil)])
 
+;; Call type instructions should never have a compact form as the
+;; type is only used for MIPS16 patterns.  For safety put the compact
+;; branch detection condition in anyway.
 (define_delay (and (eq_attr "type" "call")
-		   (eq_attr "jal_macro" "no"))
+		   (eq_attr "jal_macro" "no")
+		   (ior (match_test "TARGET_CB_NEVER")
+			(and (eq_attr "compact_form" "maybe")
+			     (not (match_test "TARGET_CB_ALWAYS")))
+			(eq_attr "compact_form" "never")))
   [(eq_attr "can_delay" "yes")
    (nil)
    (nil)])
@@ -5813,25 +5838,29 @@ (define_insn "*branch_order<mode>"
   [(set (pc)
 	(if_then_else
 	 (match_operator 1 "order_operator"
-			 [(match_operand:GPR 2 "register_operand" "d")
-			  (const_int 0)])
+			 [(match_operand:GPR 2 "register_operand" "d,d")
+			  (match_operand:GPR 3 "reg_or_0_operand" "J,d")])
 	 (label_ref (match_operand 0 "" ""))
 	 (pc)))]
   "!TARGET_MIPS16"
   { return mips_output_order_conditional_branch (insn, operands, false); }
-  [(set_attr "type" "branch")])
+  [(set_attr "type" "branch")
+   (set_attr "compact_form" "maybe,always")
+   (set_attr "hazard" "forbidden_slot")])
 
 (define_insn "*branch_order<mode>_inverted"
   [(set (pc)
 	(if_then_else
 	 (match_operator 1 "order_operator"
-			 [(match_operand:GPR 2 "register_operand" "d")
-			  (const_int 0)])
+			 [(match_operand:GPR 2 "register_operand" "d,d")
+			  (match_operand:GPR 3 "reg_or_0_operand" "J,d")])
 	 (pc)
 	 (label_ref (match_operand 0 "" ""))))]
   "!TARGET_MIPS16"
   { return mips_output_order_conditional_branch (insn, operands, true); }
-  [(set_attr "type" "branch")])
+  [(set_attr "type" "branch")
+   (set_attr "compact_form" "maybe,always")
+   (set_attr "hazard" "forbidden_slot")])
 
 ;; Conditional branch on equality comparison.
 
@@ -5844,20 +5873,10 @@ (define_insn "*branch_equality<mode>"
 	 (label_ref (match_operand 0 "" ""))
 	 (pc)))]
   "!TARGET_MIPS16"
-{
-  /* For a simple BNEZ or BEQZ microMIPS branch.  */
-  if (TARGET_MICROMIPS
-      && operands[3] == const0_rtx
-      && get_attr_length (insn) <= 8)
-    return mips_output_conditional_branch (insn, operands,
-					   "%*b%C1z%:\t%2,%0",
-					   "%*b%N1z%:\t%2,%0");
-
-  return mips_output_conditional_branch (insn, operands,
-					 MIPS_BRANCH ("b%C1", "%2,%z3,%0"),
-					 MIPS_BRANCH ("b%N1", "%2,%z3,%0"));
-}
-  [(set_attr "type" "branch")])
+  { return mips_output_equal_conditional_branch (insn, operands, false); }
+  [(set_attr "type" "branch")
+   (set_attr "compact_form" "maybe")
+   (set_attr "hazard" "forbidden_slot")])
 
 (define_insn "*branch_equality<mode>_inverted"
   [(set (pc)
@@ -5868,20 +5887,10 @@ (define_insn "*branch_equality<mode>_inverted"
 	 (pc)
 	 (label_ref (match_operand 0 "" ""))))]
   "!TARGET_MIPS16"
-{
-  /* For a simple BNEZ or BEQZ microMIPS branch.  */
-  if (TARGET_MICROMIPS
-      && operands[3] == const0_rtx
-      && get_attr_length (insn) <= 8)
-    return mips_output_conditional_branch (insn, operands,
-					   "%*b%N0z%:\t%2,%1",
-					   "%*b%C0z%:\t%2,%1");
-
-  return mips_output_conditional_branch (insn, operands,
-					 MIPS_BRANCH ("b%N1", "%2,%z3,%0"),
-					 MIPS_BRANCH ("b%C1", "%2,%z3,%0"));
-}
-  [(set_attr "type" "branch")])
+  { return mips_output_equal_conditional_branch (insn, operands, true); }
+  [(set_attr "type" "branch")
+   (set_attr "compact_form" "maybe")
+   (set_attr "hazard" "forbidden_slot")])
 
 ;; MIPS16 branches
 
@@ -6176,11 +6185,22 @@ (define_insn "*jump_absolute"
   "!TARGET_MIPS16 && TARGET_ABSOLUTE_JUMPS"
 {
   if (get_attr_length (insn) <= 8)
-    return "%*b\t%l0%/";
+    {
+      if (TARGET_CB_MAYBE)
+	return MIPS_ABSOLUTE_JUMP ("%*b%:\t%l0");
+      else
+	return MIPS_ABSOLUTE_JUMP ("%*b\t%l0%/");
+    }
   else
-    return MIPS_ABSOLUTE_JUMP ("%*j\t%l0%/");
+    {
+      if (TARGET_CB_MAYBE && !final_sequence)
+	return MIPS_ABSOLUTE_JUMP ("%*bc\t%l0");
+      else
+	return MIPS_ABSOLUTE_JUMP ("%*j\t%l0%/");
+    }
 }
-  [(set_attr "type" "branch")])
+  [(set_attr "type" "branch")
+   (set_attr "compact_form" "maybe")])
 
 (define_insn "*jump_pic"
   [(set (pc)
@@ -6188,14 +6208,23 @@ (define_insn "*jump_pic"
   "!TARGET_MIPS16 && !TARGET_ABSOLUTE_JUMPS"
 {
   if (get_attr_length (insn) <= 8)
-    return "%*b\t%l0%/";
+    {
+      if (TARGET_CB_MAYBE)
+	return "%*b%:\t%l0";
+      else
+	return "%*b\t%l0%/";
+    }
   else
     {
       mips_output_load_label (operands[0]);
-      return "%*jr\t%@%/%]";
+      if (TARGET_CB_MAYBE)
+	return "%*jr%:\t%@%]";
+      else
+	return "%*jr\t%@%/%]";
     }
 }
-  [(set_attr "type" "branch")])
+  [(set_attr "type" "branch")
+   (set_attr "compact_form" "maybe")])
 
 ;; We need a different insn for the mips16, because a mips16 branch
 ;; does not have a delay slot.
@@ -6242,12 +6271,9 @@ (define_expand "indirect_jump"
 (define_insn "indirect_jump_<mode>"
   [(set (pc) (match_operand:P 0 "register_operand" "d"))]
   ""
-{
-  if (TARGET_MICROMIPS)
-    return "%*jr%:\t%0";
-  else
-    return "%*j\t%0%/";
-}
+  {
+    return mips_output_jump (operands, 0, -1, false);
+  }
   [(set_attr "type" "jump")
    (set_attr "mode" "none")])
 
@@ -6291,12 +6317,9 @@ (define_insn "tablejump_<mode>"
 	(match_operand:P 0 "register_operand" "d"))
    (use (label_ref (match_operand 1 "" "")))]
   ""
-{
-  if (TARGET_MICROMIPS)
-    return "%*jr%:\t%0";
-  else
-    return "%*j\t%0%/";
-}
+  {
+    return mips_output_jump (operands, 0, -1, false);
+  }
   [(set_attr "type" "jump")
    (set_attr "mode" "none")])
 
@@ -6508,10 +6531,8 @@ (define_insn "*<optab>"
   [(any_return)]
   ""
   {
-    if (TARGET_MICROMIPS)
-      return "%*jr%:\t$31";
-    else
-      return "%*j\t$31%/";
+    operands[0] = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
+    return mips_output_jump (operands, 0, -1, false);
   }
   [(set_attr "type"	"jump")
    (set_attr "mode"	"none")])
@@ -6522,12 +6543,10 @@ (define_insn "<optab>_internal"
   [(any_return)
    (use (match_operand 0 "pmode_register_operand" ""))]
   ""
-{
-  if (TARGET_MICROMIPS)
-    return "%*jr%:\t%0";
-  else
-    return "%*j\t%0%/";
-}
+  {
+    operands[0] = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
+    return mips_output_jump (operands, 0, -1, false);
+  }
   [(set_attr "type"	"jump")
    (set_attr "mode"	"none")])
 
@@ -6783,12 +6802,7 @@ (define_insn "sibcall_internal"
   [(call (mem:SI (match_operand 0 "call_insn_operand" "j,S"))
 	 (match_operand 1 "" ""))]
   "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
-{
-  if (TARGET_MICROMIPS)
-    return MICROMIPS_J ("j", operands, 0);
-  else
-    return MIPS_CALL ("j", operands, 0, 1);
-}
+  { return mips_output_jump (operands, 0, 1, false); }
   [(set_attr "jal" "indirect,direct")
    (set_attr "jal_macro" "no")])
 
@@ -6809,12 +6823,7 @@ (define_insn "sibcall_value_internal"
         (call (mem:SI (match_operand 1 "call_insn_operand" "j,S"))
               (match_operand 2 "" "")))]
   "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
-{
-  if (TARGET_MICROMIPS)
-    return MICROMIPS_J ("j", operands, 1);
-  else
-    return MIPS_CALL ("j", operands, 1, 2);
-}
+  { return mips_output_jump (operands, 1, 2, false); }
   [(set_attr "jal" "indirect,direct")
    (set_attr "jal_macro" "no")])
 
@@ -6826,12 +6835,7 @@ (define_insn "sibcall_value_multiple_internal"
 	(call (mem:SI (match_dup 1))
 	      (match_dup 2)))]
   "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
-{
-  if (TARGET_MICROMIPS)
-    return MICROMIPS_J ("j", operands, 1);
-  else
-    return MIPS_CALL ("j", operands, 1, 2);
-}
+  { return mips_output_jump (operands, 1, 2, false); }
   [(set_attr "jal" "indirect,direct")
    (set_attr "jal_macro" "no")])
 
@@ -6887,7 +6891,10 @@ (define_insn_and_split "call_internal"
 	 (match_operand 1 "" ""))
    (clobber (reg:SI RETURN_ADDR_REGNUM))]
   ""
-  { return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 0, 1); }
+  {
+    return (TARGET_SPLIT_CALLS ? "#"
+	    : mips_output_jump (operands, 0, 1, true));
+  }
   "reload_completed && TARGET_SPLIT_CALLS"
   [(const_int 0)]
 {
@@ -6902,7 +6909,7 @@ (define_insn "call_split"
    (clobber (reg:SI RETURN_ADDR_REGNUM))
    (clobber (reg:SI 28))]
   "TARGET_SPLIT_CALLS"
-  { return MIPS_CALL ("jal", operands, 0, 1); }
+  { return mips_output_jump (operands, 0, 1, true); }
   [(set_attr "jal" "indirect,direct")
    (set_attr "jal_macro" "no")])
 
@@ -6916,7 +6923,10 @@ (define_insn_and_split "call_internal_direct"
    (const_int 1)
    (clobber (reg:SI RETURN_ADDR_REGNUM))]
   ""
-  { return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 0, -1); }
+  {
+    return (TARGET_SPLIT_CALLS ? "#"
+	    : mips_output_jump (operands, 0, -1, true));
+  }
   "reload_completed && TARGET_SPLIT_CALLS"
   [(const_int 0)]
 {
@@ -6933,7 +6943,7 @@ (define_insn "call_direct_split"
    (clobber (reg:SI RETURN_ADDR_REGNUM))
    (clobber (reg:SI 28))]
   "TARGET_SPLIT_CALLS"
-  { return MIPS_CALL ("jal", operands, 0, -1); }
+  { return mips_output_jump (operands, 0, -1, true); }
   [(set_attr "jal" "direct")
    (set_attr "jal_macro" "no")])
 
@@ -6956,7 +6966,10 @@ (define_insn_and_split "call_value_internal"
               (match_operand 2 "" "")))
    (clobber (reg:SI RETURN_ADDR_REGNUM))]
   ""
-  { return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 1, 2); }
+  {
+    return (TARGET_SPLIT_CALLS ? "#"
+	    : mips_output_jump (operands, 1, 2, true));
+  }
   "reload_completed && TARGET_SPLIT_CALLS"
   [(const_int 0)]
 {
@@ -6974,7 +6987,7 @@ (define_insn "call_value_split"
    (clobber (reg:SI RETURN_ADDR_REGNUM))
    (clobber (reg:SI 28))]
   "TARGET_SPLIT_CALLS"
-  { return MIPS_CALL ("jal", operands, 1, 2); }
+  { return mips_output_jump (operands, 1, 2, true); }
   [(set_attr "jal" "indirect,direct")
    (set_attr "jal_macro" "no")])
 
@@ -6986,7 +6999,10 @@ (define_insn_and_split "call_value_internal_direct"
    (const_int 1)
    (clobber (reg:SI RETURN_ADDR_REGNUM))]
   ""
-  { return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 1, -1); }
+  {
+    return (TARGET_SPLIT_CALLS ? "#"
+	    : mips_output_jump (operands, 1, -1, true));
+  }
   "reload_completed && TARGET_SPLIT_CALLS"
   [(const_int 0)]
 {
@@ -7005,7 +7021,7 @@ (define_insn "call_value_direct_split"
    (clobber (reg:SI RETURN_ADDR_REGNUM))
    (clobber (reg:SI 28))]
   "TARGET_SPLIT_CALLS"
-  { return MIPS_CALL ("jal", operands, 1, -1); }
+  { return mips_output_jump (operands, 1, -1, true); }
   [(set_attr "jal" "direct")
    (set_attr "jal_macro" "no")])
 
@@ -7019,7 +7035,10 @@ (define_insn_and_split "call_value_multiple_internal"
 	      (match_dup 2)))
    (clobber (reg:SI RETURN_ADDR_REGNUM))]
   ""
-  { return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 1, 2); }
+  {
+    return (TARGET_SPLIT_CALLS ? "#"
+	    : mips_output_jump (operands, 1, 2, true));
+  }
   "reload_completed && TARGET_SPLIT_CALLS"
   [(const_int 0)]
 {
@@ -7040,7 +7059,7 @@ (define_insn "call_value_multiple_split"
    (clobber (reg:SI RETURN_ADDR_REGNUM))
    (clobber (reg:SI 28))]
   "TARGET_SPLIT_CALLS"
-  { return MIPS_CALL ("jal", operands, 1, 2); }
+  { return mips_output_jump (operands, 1, 2, true); }
   [(set_attr "jal" "indirect,direct")
    (set_attr "jal_macro" "no")])
 
@@ -7411,7 +7430,7 @@ (define_insn "*tls_get_tp_mips16_call_<mode>"
    (clobber (reg:P PIC_FUNCTION_ADDR_REGNUM))
    (clobber (reg:P RETURN_ADDR_REGNUM))]
   "HAVE_AS_TLS && TARGET_MIPS16"
-  { return MIPS_CALL ("jal", operands, 0, -1); }
+  { return mips_output_jump (operands, 0, -1, true); }
   [(set_attr "type" "call")
    (set_attr "insn_count" "3")
    (set_attr "mode" "<MODE>")])
@@ -7452,7 +7471,7 @@ (define_insn "mips_get_fcsr_mips16_<mode>"
    (clobber (reg:P PIC_FUNCTION_ADDR_REGNUM))
    (clobber (reg:P RETURN_ADDR_REGNUM))]
   "TARGET_HARD_FLOAT_ABI && TARGET_MIPS16"
-  { return MIPS_CALL ("jal", operands, 0, -1); }
+  { return mips_output_jump (operands, 0, -1, true); }
   [(set_attr "type" "call")
    (set_attr "insn_count" "3")])
 
@@ -7482,7 +7501,7 @@ (define_insn "mips_set_fcsr_mips16_<mode>"
    (clobber (reg:P PIC_FUNCTION_ADDR_REGNUM))
    (clobber (reg:P RETURN_ADDR_REGNUM))]
   "TARGET_HARD_FLOAT_ABI && TARGET_MIPS16"
-  { return MIPS_CALL ("jal", operands, 0, -1); }
+  { return mips_output_jump (operands, 0, -1, true); }
   [(set_attr "type" "call")
    (set_attr "insn_count" "3")])
 
diff --git a/gcc/config/mips/mips.opt b/gcc/config/mips/mips.opt
index 348c6e0..84887d1 100644
--- a/gcc/config/mips/mips.opt
+++ b/gcc/config/mips/mips.opt
@@ -418,3 +418,20 @@ Driver
 mload-store-pairs
 Target Report Var(TARGET_LOAD_STORE_PAIRS) Init(1)
 Enable load/store bonding.
+
+mcompact-branches=
+Target RejectNegative JoinedOrMissing Var(mips_cb) Report Enum(mips_cb_setting) Init(MIPS_CB_OPTIMAL)
+Specify the compact branch usage policy
+
+Enum
+Name(mips_cb_setting) Type(enum mips_cb_setting)
+Policies available for use with -mcompact-branches=:
+
+EnumValue
+Enum(mips_cb_setting) String(never) Value(MIPS_CB_NEVER)
+
+EnumValue
+Enum(mips_cb_setting) String(optimal) Value(MIPS_CB_OPTIMAL)
+
+EnumValue
+Enum(mips_cb_setting) String(always) Value(MIPS_CB_ALWAYS)
diff --git a/gcc/config/mips/predicates.md b/gcc/config/mips/predicates.md
index 4929c3d..3259232 100644
--- a/gcc/config/mips/predicates.md
+++ b/gcc/config/mips/predicates.md
@@ -475,7 +475,18 @@ (define_predicate "trap_comparison_operator"
   (match_code "eq,ne,lt,ltu,ge,geu"))
 
 (define_predicate "order_operator"
-  (match_code "lt,ltu,le,leu,ge,geu,gt,gtu"))
+  (match_code "lt,ltu,le,leu,ge,geu,gt,gtu")
+{
+  if (XEXP (op, 1) == const0_rtx)
+    return true;
+
+  if (TARGET_CB_MAYBE
+      && (GET_CODE (op) == LT || GET_CODE (op) == LTU
+	  || GET_CODE (op) == GE || GET_CODE (op) == GEU))
+    return true;
+
+  return false;
+})
 
 ;; For NE, cstore uses sltu instructions in which the first operand is $0.
 ;; This isn't possible in mips16 code.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 27be317..d7d9586 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -781,6 +781,7 @@ Objective-C and Objective-C++ Dialects}.
 -mgp32  -mgp64  -mfp32  -mfpxx  -mfp64  -mhard-float  -msoft-float @gol
 -mno-float  -msingle-float  -mdouble-float @gol
 -modd-spreg -mno-odd-spreg @gol
+-mcompact-branches=@var{policy} @gol
 -mabs=@var{mode}  -mnan=@var{encoding} @gol
 -mdsp  -mno-dsp  -mdspr2  -mno-dspr2 @gol
 -mmcu -mmno-mcu @gol
@@ -17387,6 +17388,27 @@ for the o32 ABI.  This is the default for processors that are known to
 support these registers.  When using the o32 FPXX ABI, @option{-mno-odd-spreg}
 is set by default.
 
+@item -mcompact-branches=never
+@itemx -mcompact-branches=optimal
+@itemx -mcompact-branches=always
+@opindex mcompact-branches=never
+@opindex mcompact-branches=optimal
+@opindex mcompact-branches=always
+These options control which form of branches will be generated.  The
+default is @option{-mcompact-branches=optimal}.
+
+The @option{-mcompact-branches=never} option ensures that no compact
+branch instructions are generated.
+
+The @option{-mcompact-branches=always} option ensures that only compact
+branch instructions are used unless there is only a delay slot form
+of a branch.  This option is supported from MIPS Release 6 onwards.
+
+The @option{-mcompact-branches=optimal} option will use delay slot
+branches if available in the current ISA and the delay slot filler
+successfully fills a delay slot. Otherwise, a compact branch will be
+used if available.
+
 @item -mabs=2008
 @itemx -mabs=legacy
 @opindex mabs=2008
diff --git a/gcc/testsuite/gcc.target/mips/branch-10.c b/gcc/testsuite/gcc.target/mips/branch-10.c
index eb21c16..9428254 100644
--- a/gcc/testsuite/gcc.target/mips/branch-10.c
+++ b/gcc/testsuite/gcc.target/mips/branch-10.c
@@ -1,6 +1,6 @@
 /* { dg-options "-mshared -mabi=n32" } */
 /* { dg-final { scan-assembler-not "(\\\$28|%gp_rel|%got)" } } */
-/* { dg-final { scan-assembler-not "\tjr\t\\\$1\n" } } */
+/* { dg-final { scan-assembler-not "\tjrc?\t\\\$1\n" } } */
 
 #include "branch-helper.h"
 
diff --git a/gcc/testsuite/gcc.target/mips/branch-11.c b/gcc/testsuite/gcc.target/mips/branch-11.c
index bd8e834..9238d9c 100644
--- a/gcc/testsuite/gcc.target/mips/branch-11.c
+++ b/gcc/testsuite/gcc.target/mips/branch-11.c
@@ -4,7 +4,7 @@
 /* { dg-final { scan-assembler "\taddiu\t\\\$28,\\\$28,%lo\\(%neg\\(%gp_rel\\(foo\\)\\)\\)\n" } } */
 /* { dg-final { scan-assembler "\tlw\t\\\$1,%got_page\\(\[^)\]*\\)\\(\\\$28\\)\n" } } */
 /* { dg-final { scan-assembler "\taddiu\t\\\$1,\\\$1,%got_ofst\\(\[^)\]*\\)\n" } } */
-/* { dg-final { scan-assembler "\tjr\t\\\$1\n" } } */
+/* { dg-final { scan-assembler "\tjrc?\t\\\$1\n" } } */
 
 #include "branch-helper.h"
 
diff --git a/gcc/testsuite/gcc.target/mips/branch-12.c b/gcc/testsuite/gcc.target/mips/branch-12.c
index 4944634..97261ac 100644
--- a/gcc/testsuite/gcc.target/mips/branch-12.c
+++ b/gcc/testsuite/gcc.target/mips/branch-12.c
@@ -1,6 +1,6 @@
 /* { dg-options "-mshared -mabi=64" } */
 /* { dg-final { scan-assembler-not "(\\\$28|%gp_rel|%got)" } } */
-/* { dg-final { scan-assembler-not "\tjr\t\\\$1\n" } } */
+/* { dg-final { scan-assembler-not "\tjrc?\t\\\$1\n" } } */
 
 #include "branch-helper.h"
 
diff --git a/gcc/testsuite/gcc.target/mips/branch-13.c b/gcc/testsuite/gcc.target/mips/branch-13.c
index f5269b9..5ea5f1b 100644
--- a/gcc/testsuite/gcc.target/mips/branch-13.c
+++ b/gcc/testsuite/gcc.target/mips/branch-13.c
@@ -4,7 +4,7 @@
 /* { dg-final { scan-assembler "\tdaddiu\t\\\$28,\\\$28,%lo\\(%neg\\(%gp_rel\\(foo\\)\\)\\)\n" } } */
 /* { dg-final { scan-assembler "\tld\t\\\$1,%got_page\\(\[^)\]*\\)\\(\\\$28\\)\n" } } */
 /* { dg-final { scan-assembler "\tdaddiu\t\\\$1,\\\$1,%got_ofst\\(\[^)\]*\\)\n" } } */
-/* { dg-final { scan-assembler "\tjr\t\\\$1\n" } } */
+/* { dg-final { scan-assembler "\tjrc?\t\\\$1\n" } } */
 
 #include "branch-helper.h"
 
diff --git a/gcc/testsuite/gcc.target/mips/branch-3.c b/gcc/testsuite/gcc.target/mips/branch-3.c
index 69300f6..310812a 100644
--- a/gcc/testsuite/gcc.target/mips/branch-3.c
+++ b/gcc/testsuite/gcc.target/mips/branch-3.c
@@ -1,6 +1,6 @@
 /* { dg-options "-mshared -mabi=32" } */
 /* { dg-final { scan-assembler "\t\\.cpload\t\\\$25\n" } } */
-/* { dg-final { scan-assembler "\tjr\t\\\$1\n" } } */
+/* { dg-final { scan-assembler "\tjrc?\t\\\$1\n" } } */
 /* { dg-final { scan-assembler-not "\\.cprestore" } } */
 
 #include "branch-helper.h"
diff --git a/gcc/testsuite/gcc.target/mips/branch-4.c b/gcc/testsuite/gcc.target/mips/branch-4.c
index 29f5c9f..9dec904 100644
--- a/gcc/testsuite/gcc.target/mips/branch-4.c
+++ b/gcc/testsuite/gcc.target/mips/branch-4.c
@@ -1,6 +1,6 @@
 /* { dg-options "-mshared -mabi=n32" } */
 /* { dg-final { scan-assembler-not "(\\\$25|\\\$28|%gp_rel|%got)" } } */
-/* { dg-final { scan-assembler-not "\tjr\t\\\$1\n" } } */
+/* { dg-final { scan-assembler-not "\tjrc?\t\\\$1\n" } } */
 
 #include "branch-helper.h"
 
diff --git a/gcc/testsuite/gcc.target/mips/branch-5.c b/gcc/testsuite/gcc.target/mips/branch-5.c
index 0538646..60daf27 100644
--- a/gcc/testsuite/gcc.target/mips/branch-5.c
+++ b/gcc/testsuite/gcc.target/mips/branch-5.c
@@ -1,7 +1,7 @@
 /* { dg-options "-mshared -mabi=n32" } */
 /* { dg-final { scan-assembler "\taddiu\t\\\$3,\\\$3,%lo\\(%neg\\(%gp_rel\\(foo\\)\\)\\)\n" } } */
 /* { dg-final { scan-assembler "\tlw\t\\\$1,%got_page\\(\[^)\]*\\)\\(\\\$3\\)\\n" } } */
-/* { dg-final { scan-assembler "\tjr\t\\\$1\n" } } */
+/* { dg-final { scan-assembler "\tjrc?\t\\\$1\n" } } */
 /* { dg-final { scan-assembler-not "\\\$28" } } */
 
 #include "branch-helper.h"
diff --git a/gcc/testsuite/gcc.target/mips/branch-6.c b/gcc/testsuite/gcc.target/mips/branch-6.c
index 19baee1..4262ba7 100644
--- a/gcc/testsuite/gcc.target/mips/branch-6.c
+++ b/gcc/testsuite/gcc.target/mips/branch-6.c
@@ -1,6 +1,6 @@
 /* { dg-options "-mshared -mabi=64" } */
 /* { dg-final { scan-assembler-not "(\\\$25|\\\$28|%gp_rel|%got)" } } */
-/* { dg-final { scan-assembler-not "\tjr\t\\\$1\n" } } */
+/* { dg-final { scan-assembler-not "\tjrc?\t\\\$1\n" } } */
 
 #include "branch-helper.h"
 
diff --git a/gcc/testsuite/gcc.target/mips/branch-7.c b/gcc/testsuite/gcc.target/mips/branch-7.c
index 16c6d8e..a0c28a2 100644
--- a/gcc/testsuite/gcc.target/mips/branch-7.c
+++ b/gcc/testsuite/gcc.target/mips/branch-7.c
@@ -1,7 +1,7 @@
 /* { dg-options "-mshared -mabi=64" } */
 /* { dg-final { scan-assembler "\tdaddiu\t\\\$3,\\\$3,%lo\\(%neg\\(%gp_rel\\(foo\\)\\)\\)\n" } } */
 /* { dg-final { scan-assembler "\tld\t\\\$1,%got_page\\(\[^)\]*\\)\\(\\\$3\\)\\n" } } */
-/* { dg-final { scan-assembler "\tjr\t\\\$1\n" } } */
+/* { dg-final { scan-assembler "\tjrc?\t\\\$1\n" } } */
 /* { dg-final { scan-assembler-not "\\\$28" } } */
 
 #include "branch-helper.h"
diff --git a/gcc/testsuite/gcc.target/mips/branch-8.c b/gcc/testsuite/gcc.target/mips/branch-8.c
index 2e46844..5a5494e 100644
--- a/gcc/testsuite/gcc.target/mips/branch-8.c
+++ b/gcc/testsuite/gcc.target/mips/branch-8.c
@@ -1,6 +1,6 @@
 /* { dg-options "-mshared -mabi=32" } */
 /* { dg-final { scan-assembler-not "(\\\$28|cpload|cprestore)" } } */
-/* { dg-final { scan-assembler-not "\tjr\t\\\$1\n" } } */
+/* { dg-final { scan-assembler-not "\tjrc?\t\\\$1\n" } } */
 
 #include "branch-helper.h"
 
diff --git a/gcc/testsuite/gcc.target/mips/branch-9.c b/gcc/testsuite/gcc.target/mips/branch-9.c
index b87f2ba..88a6d9a 100644
--- a/gcc/testsuite/gcc.target/mips/branch-9.c
+++ b/gcc/testsuite/gcc.target/mips/branch-9.c
@@ -4,7 +4,7 @@
 /* { dg-final { scan-assembler "\tlw\t\\\$1,16\\(\\\$(fp|sp)\\)\n" } } */
 /* { dg-final { scan-assembler "\tlw\t\\\$1,%got\\(\[^)\]*\\)\\(\\\$1\\)\n" } } */
 /* { dg-final { scan-assembler "\taddiu\t\\\$1,\\\$1,%lo\\(\[^)\]*\\)\n" } } */
-/* { dg-final { scan-assembler "\tjr\t\\\$1\n" } } */
+/* { dg-final { scan-assembler "\tjrc?\t\\\$1\n" } } */
 /* { dg-final { scan-assembler-not "\\\$28" } } */
 
 #include "branch-helper.h"
diff --git a/gcc/testsuite/gcc.target/mips/branch-cost-1.c b/gcc/testsuite/gcc.target/mips/branch-cost-1.c
index f72f2ac..61c3029 100644
--- a/gcc/testsuite/gcc.target/mips/branch-cost-1.c
+++ b/gcc/testsuite/gcc.target/mips/branch-cost-1.c
@@ -6,4 +6,4 @@ foo (int x, int y, int z, int k)
   return x == k ? x + y : z - x;
 }
 /* { dg-final { scan-assembler-not "\t(movz|movn)\t" } } */
-/* { dg-final { scan-assembler "\t(bne|beq)\t" } } */
+/* { dg-final { scan-assembler "\t(bnec?|beqc?)\t" } } */
diff --git a/gcc/testsuite/gcc.target/mips/call-1.c b/gcc/testsuite/gcc.target/mips/call-1.c
index a00126e..46a2536 100644
--- a/gcc/testsuite/gcc.target/mips/call-1.c
+++ b/gcc/testsuite/gcc.target/mips/call-1.c
@@ -1,12 +1,12 @@
 /* { dg-options "-mrelax-pic-calls -mshared -foptimize-sibling-calls -mabi=32" } */
 /* { dg-skip-if "requires -foptimize-sibling-calls" { *-*-* } { "-O0" } { "" } } */
-/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,normal\n1:\tjalrs?\t" } } */
-/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,normal2\n1:\tjalrs?\t" } } */
-/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,staticfunc\n1:\tjalrs?\t" } } */
-/* { dg-final { scan-assembler "(\\.reloc\t1f,R_MIPS_JALR,tail\n1:)?\tjrc?\t" } } */
-/* { dg-final { scan-assembler "(\\.reloc\t1f,R_MIPS_JALR,tail2\n1:)?\tjrc?\t" } } */
-/* { dg-final { scan-assembler "(\\.reloc\t1f,R_MIPS_JALR,tail3\n1:)?\tjrc?\t" } } */
-/* { dg-final { scan-assembler "(\\.reloc\t1f,R_MIPS_JALR,tail4\n1:)?\tjrc?\t" } } */
+/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,normal\n1:\tjalrc?s?\t" } } */
+/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,normal2\n1:\tjalrc?s?\t" } } */
+/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,staticfunc\n1:\tjalrc?s?\t" } } */
+/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,tail\n1:\tjrc?\t" } } */
+/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,tail2\n1:\tjrc?\t" } } */
+/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,tail3\n1:\tjrc?\t" } } */
+/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,tail4\n1:\tjrc?\t" } } */
 
 __attribute__ ((noinline)) static void staticfunc () { asm (""); }
 int normal ();
diff --git a/gcc/testsuite/gcc.target/mips/call-2.c b/gcc/testsuite/gcc.target/mips/call-2.c
index 58cc2c6..175933c 100644
--- a/gcc/testsuite/gcc.target/mips/call-2.c
+++ b/gcc/testsuite/gcc.target/mips/call-2.c
@@ -1,6 +1,6 @@
 /* See through some simple data-flow.  */
 /* { dg-options "-mrelax-pic-calls" } */
-/* { dg-final { scan-assembler-times "\\.reloc\t1f,R_MIPS_JALR,g\n1:\tjalrs?\t" 2 } } */
+/* { dg-final { scan-assembler-times "\\.reloc\t1f,R_MIPS_JALR,g\n1:\tjalrc?s?\t" 2 } } */
 
 extern void g (void);
 
diff --git a/gcc/testsuite/gcc.target/mips/call-3.c b/gcc/testsuite/gcc.target/mips/call-3.c
index 4a662e3..08cf336 100644
--- a/gcc/testsuite/gcc.target/mips/call-3.c
+++ b/gcc/testsuite/gcc.target/mips/call-3.c
@@ -1,5 +1,5 @@
 /* { dg-options "-mrelax-pic-calls -mno-shared" } */
-/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,g\n1:\tjalrs?\t" } } */
+/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,g\n1:\tjalrc?s?\t" } } */
 /* { dg-require-visibility "" } */
 
 __attribute__ ((visibility ("hidden"))) void g ();
diff --git a/gcc/testsuite/gcc.target/mips/call-4.c b/gcc/testsuite/gcc.target/mips/call-4.c
index a343c42..bf357c7 100644
--- a/gcc/testsuite/gcc.target/mips/call-4.c
+++ b/gcc/testsuite/gcc.target/mips/call-4.c
@@ -1,6 +1,6 @@
 /* See through some simple data-flow.  */
 /* { dg-options "-mrelax-pic-calls" } */
-/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,g\n1:\tjalr\t" } } */
+/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,g\n1:\tjalrc?\t" } } */
 
 extern void g (void);
 
diff --git a/gcc/testsuite/gcc.target/mips/call-5.c b/gcc/testsuite/gcc.target/mips/call-5.c
index d8d84d3..f6ebae9 100644
--- a/gcc/testsuite/gcc.target/mips/call-5.c
+++ b/gcc/testsuite/gcc.target/mips/call-5.c
@@ -2,13 +2,13 @@
    in this case (PR target/57260).  */
 /* { dg-options "-mrelax-pic-calls -mshared -foptimize-sibling-calls -mabi=n32" } */
 /* { dg-skip-if "requires -foptimize-sibling-calls" { *-*-* } { "-O0" } { "" } } */
-/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,normal\n1:\tjalr\t" } } */
-/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,normal2\n1:\tjalr\t" } } */
-/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,staticfunc\n1:\tjalr\t" } } */
-/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,tail\n1:\tjalr\t" } } */
-/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,tail2\n1:\tjalr\t" } } */
-/* { dg-final { scan-assembler "(\\.reloc\t1f,R_MIPS_JALR,tail3\n1:)?\tjrc?\t" } } */
-/* { dg-final { scan-assembler "(\\.reloc\t1f,R_MIPS_JALR,tail4\n1:)?\tjrc?\t" } } */
+/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,normal\n1:\tjalrc?\t" } } */
+/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,normal2\n1:\tjalrc?\t" } } */
+/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,staticfunc\n1:\tjalrc?\t" } } */
+/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,tail\n1:\tjalrc?\t" } } */
+/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,tail2\n1:\tjalrc?\t" } } */
+/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,tail3\n1:\tjrc?\t" } } */
+/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,tail4\n1:\tjrc?\t" } } */
 
 __attribute__ ((noinline)) static void staticfunc () { asm (""); }
 int normal ();
diff --git a/gcc/testsuite/gcc.target/mips/call-6.c b/gcc/testsuite/gcc.target/mips/call-6.c
index e6c90d7..00f4a1e 100644
--- a/gcc/testsuite/gcc.target/mips/call-6.c
+++ b/gcc/testsuite/gcc.target/mips/call-6.c
@@ -1,13 +1,13 @@
 /* Like call-5.c, but for n64.  */
 /* { dg-options "-mrelax-pic-calls -mshared -foptimize-sibling-calls -mabi=64" } */
 /* { dg-skip-if "requires -foptimize-sibling-calls" { *-*-* } { "-O0" } { "" } } */
-/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,normal\n1:\tjalr\t" } } */
-/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,normal2\n1:\tjalr\t" } } */
-/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,staticfunc\n1:\tjalr\t" } } */
-/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,tail\n1:\tjalr\t" } } */
-/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,tail2\n1:\tjalr\t" } } */
-/* { dg-final { scan-assembler "(\\.reloc\t1f,R_MIPS_JALR,tail3\n1:)?\tjrc?\t" } } */
-/* { dg-final { scan-assembler "(\\.reloc\t1f,R_MIPS_JALR,tail4\n1:)?\tjrc?\t" } } */
+/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,normal\n1:\tjalrc?\t" } } */
+/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,normal2\n1:\tjalrc?\t" } } */
+/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,staticfunc\n1:\tjalrc?\t" } } */
+/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,tail\n1:\tjalrc?\t" } } */
+/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,tail2\n1:\tjalrc?\t" } } */
+/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,tail3\n1:\tjrc?\t" } } */
+/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,tail4\n1:\tjrc?\t" } } */
 
 __attribute__ ((noinline)) static void staticfunc () { asm (""); }
 int normal ();
diff --git a/gcc/testsuite/gcc.target/mips/compact-branches-1.c b/gcc/testsuite/gcc.target/mips/compact-branches-1.c
new file mode 100644
index 0000000..9c7365e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/compact-branches-1.c
@@ -0,0 +1,12 @@
+/* { dg-options "-mcompact-branches=always -mno-micromips" } */
+int glob;
+
+void
+foo (int a, int b)
+{
+  if (a < b)
+    glob = 1;
+}
+
+/* { dg-final { scan-assembler "\tbgec\t\\\$\[0-9\]*,\\\$\[0-9\]*" } } */
+/* { dg-final { scan-assembler "\tjrc\t\\\$31" } } */
diff --git a/gcc/testsuite/gcc.target/mips/compact-branches-2.c b/gcc/testsuite/gcc.target/mips/compact-branches-2.c
new file mode 100644
index 0000000..0f8064f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/compact-branches-2.c
@@ -0,0 +1,12 @@
+/* { dg-options "-mcompact-branches=never" } */
+int glob;
+
+void
+foo (int a, int b)
+{
+  if (a < b)
+    glob = 1;
+}
+
+/* { dg-final { scan-assembler-not "\tb\[^ \t\]*c" } } */
+/* { dg-final { scan-assembler-not "\tj\[^ \t\]*c" } } */
diff --git a/gcc/testsuite/gcc.target/mips/compact-branches-3.c b/gcc/testsuite/gcc.target/mips/compact-branches-3.c
new file mode 100644
index 0000000..d6becb1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/compact-branches-3.c
@@ -0,0 +1,13 @@
+/* { dg-options "-mcompact-branches=never isa_rev>=6" } */
+int glob;
+
+void
+foo (int a, int b, volatile int * bar)
+{
+  if (a < b)
+    glob = *bar;
+}
+
+/* { dg-final { scan-assembler "\tnop" } } */
+/* { dg-final { scan-assembler-not "\tb\[^ \t\]*c" } } */
+/* { dg-final { scan-assembler-not "\tj\[^ \t\]*c" } } */
diff --git a/gcc/testsuite/gcc.target/mips/compact-branches-4.c b/gcc/testsuite/gcc.target/mips/compact-branches-4.c
new file mode 100644
index 0000000..fd99ad6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/compact-branches-4.c
@@ -0,0 +1,11 @@
+/* { dg-options "-mcompact-branches=optimal isa_rev>=6" } */
+int glob;
+
+void
+foo (int a, int b, volatile int * bar)
+{
+  if (a < b)
+    glob = *bar;
+}
+
+/* { dg-final { scan-assembler "\tb\[^ \t\]*c" } } */
diff --git a/gcc/testsuite/gcc.target/mips/compact-branches-5.c b/gcc/testsuite/gcc.target/mips/compact-branches-5.c
new file mode 100644
index 0000000..90d312c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/compact-branches-5.c
@@ -0,0 +1,10 @@
+/* { dg-options "-mno-abicalls -mcompact-branches=never isa_rev>=6" } */
+void bar (int);
+
+void
+foo ()
+{
+  bar (1);
+}
+
+/* { dg-final { scan-assembler "\t(j|jal)\t" } } */
diff --git a/gcc/testsuite/gcc.target/mips/compact-branches-6.c b/gcc/testsuite/gcc.target/mips/compact-branches-6.c
new file mode 100644
index 0000000..dd35a55
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/compact-branches-6.c
@@ -0,0 +1,10 @@
+/* { dg-options "-mno-abicalls -mcompact-branches=optimal isa_rev>=6" } */
+void bar (int);
+
+void
+foo ()
+{
+  bar (1);
+}
+
+/* { dg-final { scan-assembler "\t(bc|balc)\t" } } */
diff --git a/gcc/testsuite/gcc.target/mips/compact-branches-7.c b/gcc/testsuite/gcc.target/mips/compact-branches-7.c
new file mode 100644
index 0000000..36700c9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/compact-branches-7.c
@@ -0,0 +1,12 @@
+/* { dg-options "-mhard-float -mcompact-branches=always isa_rev>=6 -mno-micromips" } */
+int bar;
+
+void
+foo (float a, volatile int * b)
+{
+  if (a < 0.1)
+    bar = *b;
+}
+
+/* { dg-final { scan-assembler "\t(bc1eqz|bc1nez)\t" } } */
+/* { dg-final { scan-assembler "\tnop" } } */
diff --git a/gcc/testsuite/gcc.target/mips/lazy-binding-1.c b/gcc/testsuite/gcc.target/mips/lazy-binding-1.c
index a305948..a112781 100644
--- a/gcc/testsuite/gcc.target/mips/lazy-binding-1.c
+++ b/gcc/testsuite/gcc.target/mips/lazy-binding-1.c
@@ -19,6 +19,6 @@ foo (int n)
 /* There should be exactly five uses of $25: one to set up $gp, two to
    load the address of bar (), and two to call it.  */
 /* { dg-final { scan-assembler-times "\tl.\t\\\$25,%call16\\\(bar\\\)" 2 } } */
-/* { dg-final { scan-assembler-times "\tjalrs?\t\\\$25" 2 } } */
+/* { dg-final { scan-assembler-times "\tjalrc?s?\t\\\$25" 2 } } */
 /* { dg-final { scan-assembler "(\\\$28,|\t.cpload\t)\\\$25" } } */
 /* { dg-final { scan-assembler-times "\\\$25" 5 } } */
diff --git a/gcc/testsuite/gcc.target/mips/mips.exp b/gcc/testsuite/gcc.target/mips/mips.exp
index b3617e4..1ac22a5 100644
--- a/gcc/testsuite/gcc.target/mips/mips.exp
+++ b/gcc/testsuite/gcc.target/mips/mips.exp
@@ -243,6 +243,7 @@ set mips_option_groups {
     mips16 "-mips16|-mno-mips16|-mflip-mips16"
     mips3d "-mips3d|-mno-mips3d"
     pic "-f(no-|)(pic|PIC)"
+    cb "-mcompact-branches=.*"
     profiling "-pg"
     small-data "-G[0-9]+"
     warnings "-w"
@@ -1068,8 +1069,10 @@ proc mips-dg-options { args } {
 	# We need a revision 6 or better ISA for:
 	#
 	#   - When the LSA instruction is required
+	#   - When only using compact branches
 	if { $isa_rev < 6
-	     && ([mips_have_test_option_p options "HAS_LSA"]) } {
+	     && ([mips_have_test_option_p options "HAS_LSA"]
+		 || [mips_have_test_option_p options "-mcompact-branches=always"]) } {
 	    if { $gp_size == 32 } {
 		mips_make_test_option options "-mips32r6"
 	    } else {
@@ -1164,6 +1167,9 @@ proc mips-dg-options { args } {
 		mips_make_test_option options "-mips64r5"
 	    }
 	    mips_make_test_option options "-mnan=2008"
+	    if { [mips_have_option_p options "-mcompact-branches=always"] } {
+		mips_make_test_option options "-mcompact-branches=optimal"
+	    }
 	# Check whether we need to switch from a 32-bit processor to the
 	# "nearest" 64-bit processor.
 	} elseif { $gp_size == 64 && [mips_32bit_arch_p $arch] } {
@@ -1307,6 +1313,11 @@ proc mips-dg-options { args } {
 	    mips_make_test_option options "-mno-micromips"
 	    mips_make_test_option options "-mnan=legacy"
 	}
+	if { $isa_rev < 6 } {
+	    if { [mips_have_option_p options "-mcompact-branches=always"] } {
+		mips_make_test_option options "-mcompact-branches=optimal"
+	    }
+	}
         if { $isa_rev > 5 } {
 	    mips_make_test_option options "-mno-dsp"
 	    mips_make_test_option options "-mno-mips16"
diff --git a/gcc/testsuite/gcc.target/mips/near-far-1.c b/gcc/testsuite/gcc.target/mips/near-far-1.c
index 8806e93..b746cf6 100644
--- a/gcc/testsuite/gcc.target/mips/near-far-1.c
+++ b/gcc/testsuite/gcc.target/mips/near-far-1.c
@@ -16,5 +16,5 @@ int test ()
 
 /* { dg-final { scan-assembler-not "\tjal\tlong_call_func\n" } } */
 /* { dg-final { scan-assembler-not "\tjal\tfar_func\n" } } */
-/* { dg-final { scan-assembler     "\tjal(|s)\tnear_func\n" } } */
+/* { dg-final { scan-assembler     "\t(jal(|s)|balc)\tnear_func\n" } } */
 /* { dg-final { scan-assembler-not "\tjal\tnormal_func\n" } } */
diff --git a/gcc/testsuite/gcc.target/mips/near-far-2.c b/gcc/testsuite/gcc.target/mips/near-far-2.c
index b4062a7..2c140e2 100644
--- a/gcc/testsuite/gcc.target/mips/near-far-2.c
+++ b/gcc/testsuite/gcc.target/mips/near-far-2.c
@@ -16,5 +16,5 @@ int test ()
 
 /* { dg-final { scan-assembler-not "\tjal(|s)\tlong_call_func\n" } } */
 /* { dg-final { scan-assembler-not "\tjal(|s)\tfar_func\n" } } */
-/* { dg-final { scan-assembler     "\tjal(|s)\tnear_func\n" } } */
-/* { dg-final { scan-assembler     "\tjal(|s)\tnormal_func\n" } } */
+/* { dg-final { scan-assembler     "\t(jal(|s)|balc)\tnear_func\n" } } */
+/* { dg-final { scan-assembler     "\t(jal(|s)|balc)\tnormal_func\n" } } */
diff --git a/gcc/testsuite/gcc.target/mips/near-far-3.c b/gcc/testsuite/gcc.target/mips/near-far-3.c
index e6af939..7bf3e14 100644
--- a/gcc/testsuite/gcc.target/mips/near-far-3.c
+++ b/gcc/testsuite/gcc.target/mips/near-far-3.c
@@ -13,5 +13,5 @@ NOMIPS16 int test4 () { return normal_func (); }
 
 /* { dg-final { scan-assembler-not "\tj\tlong_call_func\n" } } */
 /* { dg-final { scan-assembler-not "\tj\tfar_func\n" } } */
-/* { dg-final { scan-assembler     "\tj(|al|als)\tnear_func\n" } } */
+/* { dg-final { scan-assembler     "\t(j(|al|als)|b(|al)c)\tnear_func\n" } } */
 /* { dg-final { scan-assembler-not "\tj\tnormal_func\n" } } */
diff --git a/gcc/testsuite/gcc.target/mips/near-far-4.c b/gcc/testsuite/gcc.target/mips/near-far-4.c
index 969f68f..cd12a1d 100644
--- a/gcc/testsuite/gcc.target/mips/near-far-4.c
+++ b/gcc/testsuite/gcc.target/mips/near-far-4.c
@@ -13,5 +13,5 @@ NOMIPS16 int test4 () { return normal_func (); }
 
 /* { dg-final { scan-assembler-not "\tj\tlong_call_func\n" } } */
 /* { dg-final { scan-assembler-not "\tj\tfar_func\n" } } */
-/* { dg-final { scan-assembler     "\tj(|al|als)\tnear_func\n" } } */
-/* { dg-final { scan-assembler     "\tj(|al|als)\tnormal_func\n" } } */
+/* { dg-final { scan-assembler     "\t(j(|al|als)|b(|al)c)\tnear_func\n" } } */
+/* { dg-final { scan-assembler     "\t(j(|al|als)|b(|al)c)\tnormal_func\n" } } */
diff --git a/gcc/testsuite/gcc.target/mips/umips-branch-3.c b/gcc/testsuite/gcc.target/mips/umips-branch-3.c
index 8717362..74465c9 100644
--- a/gcc/testsuite/gcc.target/mips/umips-branch-3.c
+++ b/gcc/testsuite/gcc.target/mips/umips-branch-3.c
@@ -1,4 +1,4 @@
-/* { dg-options "(-mmicromips)" } */
+/* { dg-options "(-mmicromips) -mcompact-branches=optimal" } */
 /* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
 
 void MICROMIPS
-- 
2.2.1

Attachment: 0001-How-does-the-compact-branch-support-work.patch
Description: 0001-How-does-the-compact-branch-support-work.patch


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]