MIPS compact branch support
authorMatthew Fortune <matthew.fortune@imgtec.com>
Tue, 1 Sep 2015 22:41:08 +0000 (22:41 +0000)
committerMatthew Fortune <mpf@gcc.gnu.org>
Tue, 1 Sep 2015 22:41:08 +0000 (22:41 +0000)
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.

Co-Authored-By: Andrew Bennett <andrew.bennett@imgtec.com>
From-SVN: r227385

42 files changed:
gcc/ChangeLog
gcc/config/mips/mips-opts.h
gcc/config/mips/mips-protos.h
gcc/config/mips/mips.c
gcc/config/mips/mips.h
gcc/config/mips/mips.md
gcc/config/mips/mips.opt
gcc/config/mips/predicates.md
gcc/doc/invoke.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/mips/branch-10.c
gcc/testsuite/gcc.target/mips/branch-11.c
gcc/testsuite/gcc.target/mips/branch-12.c
gcc/testsuite/gcc.target/mips/branch-13.c
gcc/testsuite/gcc.target/mips/branch-3.c
gcc/testsuite/gcc.target/mips/branch-4.c
gcc/testsuite/gcc.target/mips/branch-5.c
gcc/testsuite/gcc.target/mips/branch-6.c
gcc/testsuite/gcc.target/mips/branch-7.c
gcc/testsuite/gcc.target/mips/branch-8.c
gcc/testsuite/gcc.target/mips/branch-9.c
gcc/testsuite/gcc.target/mips/branch-cost-1.c
gcc/testsuite/gcc.target/mips/call-1.c
gcc/testsuite/gcc.target/mips/call-2.c
gcc/testsuite/gcc.target/mips/call-3.c
gcc/testsuite/gcc.target/mips/call-4.c
gcc/testsuite/gcc.target/mips/call-5.c
gcc/testsuite/gcc.target/mips/call-6.c
gcc/testsuite/gcc.target/mips/compact-branches-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/compact-branches-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/compact-branches-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/compact-branches-4.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/compact-branches-5.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/compact-branches-6.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/compact-branches-7.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/lazy-binding-1.c
gcc/testsuite/gcc.target/mips/mips.exp
gcc/testsuite/gcc.target/mips/near-far-1.c
gcc/testsuite/gcc.target/mips/near-far-2.c
gcc/testsuite/gcc.target/mips/near-far-3.c
gcc/testsuite/gcc.target/mips/near-far-4.c
gcc/testsuite/gcc.target/mips/umips-branch-3.c

index 690e57eb74b2539cc2a28a39cfccca9f6a89f957..b9e7bac3266409142f9c3b096ee09894de0006ca 100644 (file)
@@ -1,3 +1,77 @@
+2015-09-01  Matthew Fortune  <matthew.fortune@imgtec.com>
+           Andrew Bennett  <andrew.bennett@imgtec.com>
+
+       * 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.
+
 2015-09-01  Vladimir Makarov  <vmakarov@redhat.com>
 
        PR target/61578
index 79882051595aa1227065cb751357fb8d94087b0e..3c2c6590e3dc3c6d00b7cb202de609d310daa439 100644 (file)
@@ -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
index d9ad9100f99616f8c722d369ac303993041554a0..8a9ae0147ed2aee8dab5a90db6d11d9b19f126dd 100644 (file)
@@ -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 *);
index 0b4a5faacdb93ed5b6ad436ef79f44185b816eb6..0e0ecf232d9b57724a801720f8cd6b44530abdd2 100644 (file)
@@ -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
@@ -8378,7 +8418,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)
@@ -8462,7 +8502,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;
@@ -8470,8 +8511,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;
 
@@ -12969,6 +13011,7 @@ mips_adjust_insn_length (rtx_insn *insn, int length)
        break;
 
       case HAZARD_DELAY:
+      case HAZARD_FORBIDDEN_SLOT:
        length += NOP_INSN_LENGTH;
        break;
 
@@ -12980,6 +13023,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]
@@ -13033,12 +13148,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.  */
@@ -13052,7 +13180,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");
     }
@@ -13063,43 +13191,156 @@ mips_output_conditional_branch (rtx_insn *insn, rtx *operands,
   return "";
 }
 
+/* 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]);
 }
@@ -13302,11 +13543,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.  */
@@ -13369,7 +13617,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)
@@ -16651,7 +16902,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;
@@ -16677,6 +16928,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;
 
@@ -16689,12 +16949,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;
@@ -16718,6 +16984,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 ();
@@ -16786,6 +17053,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
@@ -16809,7 +17077,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;
            }
@@ -16830,7 +17098,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;
                }
            }
@@ -17695,6 +17963,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)
     {
@@ -18714,6 +19003,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++)
     {
index 2d44735e6ca35fc9a97ffff82612f1c5ae92441d..25a1e0622cd4024f70e4c30431caeac6df83486a 100644 (file)
@@ -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.  */
@@ -2645,6 +2676,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) \
@@ -2652,45 +2686,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 "%/"))
-
 \f
 /* Control the assembler format that we output.  */
 
index f4ffd682415399352d19d322b11fedd2b539e40a..1d1c42bf5f5552c1ba97b449277224985b6df6d4 100644 (file)
         (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)
 ;; 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")
    (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)])
   [(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.
 
         (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)
         (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
 
   "!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)
   "!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.
 (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")])
 
        (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")])
 
   [(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")])
   [(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")])
 
   [(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")])
 
         (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")])
 
        (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")])
 
         (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)]
 {
    (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")])
 
    (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)]
 {
    (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")])
 
               (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)]
 {
    (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")])
 
    (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)]
 {
    (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")])
 
              (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)]
 {
    (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")])
 
    (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>")])
    (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")])
 
    (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")])
 
index 348c6e03f1ef5d571b70c0380c2ca7f3f4e9820a..84887d11623c47e5ed97b77cb2b297578404152b 100644 (file)
@@ -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)
index 4929c3dc27ee000df82e31a27d56f2addde80d6b..3259232bb89e646772249b2b8176449cf7257cac 100644 (file)
   (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.
index 101335ea75b82ec96c0ce85e7b8810d549da4768..e7bbcec27bbc663bf463d9a497a97758078a2b7b 100644 (file)
@@ -782,6 +782,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
@@ -17303,6 +17304,30 @@ 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 compact branch
+instructions will never be generated.
+
+The @option{-mcompact-branches=always} option ensures that a compact
+branch instruction will be generated if available.  If a compact branch
+instruction is not available, a delay slot form of the branch will be
+used instead.
+
+This option is supported from MIPS Release 6 onwards.
+
+The @option{-mcompact-branches=optimal} option will cause a delay slot
+branch to be used if one is available in the current ISA and the delay
+slot is successfully filled.  If the delay slot is not filled, a compact
+branch will be chosen if one is available.
+
 @item -mabs=2008
 @itemx -mabs=legacy
 @opindex mabs=2008
index e955e8a79f77c22c5207a07b25ed6a275c907de5..6d2f6280e20b9193a335dcfdbc30c2f48e68623f 100644 (file)
@@ -1,3 +1,42 @@
+2015-09-01  Matthew Fortune  <matthew.fortune@imgtec.com>
+           Andrew Bennett  <andrew.bennett@imgtec.com>
+
+       * 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.
+
 2015-09-01  Steven G. Kargl  <kargl@gcc.gnu.org>
 
        * gfortran.dg/read_dir.f90: XFAIL this testcase on FreeBSD.
index eb21c16546266c3ee513f9c8a8627cd06ff302f2..9428254f0dfd2be8a87b67120fc9f60d174d778d 100644 (file)
@@ -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"
 
index bd8e83418c00dadc01f3131f2dc663fb8d092c99..9238d9ca1eba987e7f1c7dacad83b8deabc4dcfe 100644 (file)
@@ -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"
 
index 49446341ad29236c6582d91c4f1f59ceca2e6cab..97261acea6007206ad231a90cff74f569bd9a416 100644 (file)
@@ -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"
 
index f5269b9b33b7017efc697d984ec9d49be5bd1b5a..5ea5f1b64fef06cd7b9b9618a57e8595e9e04b7c 100644 (file)
@@ -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"
 
index 69300f6417c3728314e9e57269467262c5e1dbab..310812aa4da1d4279e5c3e20f94e3aa6ba8ec26d 100644 (file)
@@ -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"
index 29f5c9f2be3e10a499c7a5ee411bd4840ecc19b0..9dec90469f5aa7213d3946a6aeeb51bbb546378f 100644 (file)
@@ -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"
 
index 0538646210af8ae64290ff1c15067edc300822dc..60daf27d06b855ff4d32f4bdd7a3c76156c6f4c6 100644 (file)
@@ -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"
index 19baee1db9ff493e51abd9b690167f8478061266..4262ba7e8499f5f194a34c3476a97f2106b1be81 100644 (file)
@@ -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"
 
index 16c6d8e1ac65b64281b2fbd4b4f8bca6521a6374..a0c28a2bb6554fa9cd2125bb22e87467ed2656f4 100644 (file)
@@ -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"
index 2e468448fe9a4478109e3c6d2834081d13ec9d49..5a5494e0bd1a872b27a39090f5063612d76ab14d 100644 (file)
@@ -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"
 
index b87f2ba675b5e842682f1231480d08acf86ba9e6..88a6d9a063f332cc2e9f683c7a56177173f86165 100644 (file)
@@ -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"
index f72f2acfb3a54703f11733311b47a6bb1a3641df..61c3029dd77abd617eedbcd3f4d93030c166bbea 100644 (file)
@@ -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" } } */
index a00126eb69349818410c49450108a9fe8c98bc35..46a2536754b7b705a5446a7d63338d13a4242c53 100644 (file)
@@ -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 ();
index 58cc2c6b03cef128c8d9e52d1175d6498e5ffec1..175933cbe77b9e083e5c0f4350463d14f0168bc0 100644 (file)
@@ -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);
 
index 4a662e300ec6278e847a8cf11198c7857679d5b3..08cf336a4240c9365782199fa9d29246cda3d02b 100644 (file)
@@ -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 ();
index a343c429a6a68e6cb575a31cef8ae0abdd9ab565..bf357c7a5b07baa235f9f1d353bd160b79a7991d 100644 (file)
@@ -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);
 
index d8d84d3782e62f8e61b0b97e60a904caaf11d3c3..f6ebae9db79eda212ecdb85911a78fa0458e5aaf 100644 (file)
@@ -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 ();
index e6c90d7b5a360810e4ba3ca6bb0597d4abeb10c2..00f4a1ef3532ef24a71ec1ddc7e281209b035d71 100644 (file)
@@ -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 (file)
index 0000000..9c7365e
--- /dev/null
@@ -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 (file)
index 0000000..0f8064f
--- /dev/null
@@ -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 (file)
index 0000000..d6becb1
--- /dev/null
@@ -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 (file)
index 0000000..fd99ad6
--- /dev/null
@@ -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 (file)
index 0000000..90d312c
--- /dev/null
@@ -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 (file)
index 0000000..dd35a55
--- /dev/null
@@ -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 (file)
index 0000000..36700c9
--- /dev/null
@@ -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" } } */
index a30594840dd173cf9ceb0978aa177da2ad338dbb..a112781a99e15d17d448c487d8a31b4b076ab5ce 100644 (file)
@@ -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 } } */
index 55e4223d7fddeddddf622ac80d3046212c7084e7..42e7fff0de5073114ec99e8b272c69d887c2d375 100644 (file)
@@ -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] } {
@@ -1308,6 +1314,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"
index 8806e930fc3d1aa6026ba59b314c7430ec0e4111..b746cf6030c1686dfafbca7f4749de82a9ace665 100644 (file)
@@ -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" } } */
index b4062a744cf4d322902dbca82ee7838472d02e56..2c140e2ceb2db6c91856e0c809bf0e04e004b7a4 100644 (file)
@@ -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" } } */
index e6af939e0817d399b108d0070e33c7aa279df796..7bf3e14bc80a43b5f6a56137228c9e46958c7b18 100644 (file)
@@ -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" } } */
index 969f68f381139fee848c7ba07b0a65474bf4420d..cd12a1dbcbb6d95b8972d0c4c1e73c1fedb71cf7 100644 (file)
@@ -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" } } */
index 8717362e044ba603a0d42f86fcd0a9e822221713..74465c9f808e4235a0577da10f999a4e4e9f2571 100644 (file)
@@ -1,4 +1,4 @@
-/* { dg-options "(-mmicromips)" } */
+/* { dg-options "(-mmicromips) -mcompact-branches=optimal" } */
 /* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
 
 void MICROMIPS