From 22219d9b1a5bcf9b96020f830493fed6525d936c Mon Sep 17 00:00:00 2001 From: Matthew Fortune Date: Tue, 1 Sep 2015 22:41:08 +0000 Subject: [PATCH] MIPS 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): Likewise. (*branch_order_inverted): Likewise. (*branch_equality): Likewise. (*branch_equality_inverted): Likewise. (*jump_absolute): Likewise. (*jump_pic): Likewise. (indirect_jump): Use mips_output_jump to produce assembly output. (tablejump_"): Likewise. (*"): Likewise. (_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_): Likewise. (mips_set_fcsr_mips16_): Likewise. (tls_get_tp_mips16_): 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 From-SVN: r227385 --- gcc/ChangeLog | 74 ++++ 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 | 25 ++ gcc/testsuite/ChangeLog | 39 ++ 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.target/mips/compact-branches-1.c | 12 + .../gcc.target/mips/compact-branches-2.c | 12 + .../gcc.target/mips/compact-branches-3.c | 13 + .../gcc.target/mips/compact-branches-4.c | 11 + .../gcc.target/mips/compact-branches-5.c | 10 + .../gcc.target/mips/compact-branches-6.c | 10 + .../gcc.target/mips/compact-branches-7.c | 12 + .../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.target/mips/umips-branch-3.c | 2 +- 42 files changed, 801 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/ChangeLog b/gcc/ChangeLog index 690e57eb74b..b9e7bac3266 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,77 @@ +2015-09-01 Matthew Fortune + Andrew Bennett + + * 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): Likewise. + (*branch_order_inverted): Likewise. + (*branch_equality): Likewise. + (*branch_equality_inverted): Likewise. + (*jump_absolute): Likewise. + (*jump_pic): Likewise. + (indirect_jump): Use mips_output_jump to produce assembly output. + (tablejump_"): Likewise. + (*"): Likewise. + (_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_): Likewise. + (mips_set_fcsr_mips16_): Likewise. + (tls_get_tp_mips16_): 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 PR target/61578 diff --git a/gcc/config/mips/mips-opts.h b/gcc/config/mips/mips-opts.h index 79882051595..3c2c6590e3d 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 d9ad9100f99..8a9ae0147ed 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 0b4a5faacdb..0e0ecf232d9 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 @@ -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++) { diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index 2d44735e6ca..25a1e0622cd 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. */ @@ -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 "%/")) - /* Control the assembler format that we output. */ diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index f4ffd682415..1d1c42bf5f5 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -409,6 +409,15 @@ (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 @@ ;; 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 @@ (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 @@ [(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_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 @@ (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_inverted" [(set (pc) @@ -5868,20 +5887,10 @@ (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 @@ "!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 @@ "!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_insn "indirect_jump_" [(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 @@ (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 @@ [(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 @@ [(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 @@ [(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 @@ (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 @@ (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 @@ (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 @@ (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 @@ (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 @@ (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 @@ (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 @@ (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 @@ (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 @@ (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 @@ (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 @@ (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 @@ (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" "")]) @@ -7452,7 +7471,7 @@ (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 @@ (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 348c6e03f1e..84887d11623 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 4929c3dc27e..3259232bb89 100644 --- a/gcc/config/mips/predicates.md +++ b/gcc/config/mips/predicates.md @@ -475,7 +475,18 @@ (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 101335ea75b..e7bbcec27bb 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e955e8a79f7..6d2f6280e20 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,42 @@ +2015-09-01 Matthew Fortune + Andrew Bennett + + * 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 * gfortran.dg/read_dir.f90: XFAIL this testcase on FreeBSD. diff --git a/gcc/testsuite/gcc.target/mips/branch-10.c b/gcc/testsuite/gcc.target/mips/branch-10.c index eb21c165462..9428254f0df 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 bd8e83418c0..9238d9ca1eb 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 49446341ad2..97261acea60 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 f5269b9b33b..5ea5f1b64fe 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 69300f6417c..310812aa4da 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 29f5c9f2be3..9dec90469f5 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 0538646210a..60daf27d06b 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 19baee1db9f..4262ba7e849 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 16c6d8e1ac6..a0c28a2bb65 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 2e468448fe9..5a5494e0bd1 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 b87f2ba675b..88a6d9a063f 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 f72f2acfb3a..61c3029dd77 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 a00126eb693..46a2536754b 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 58cc2c6b03c..175933cbe77 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 4a662e300ec..08cf336a424 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 a343c429a6a..bf357c7a5b0 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 d8d84d3782e..f6ebae9db79 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 e6c90d7b5a3..00f4a1ef353 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 00000000000..9c7365e2659 --- /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 00000000000..0f8064f5d88 --- /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 00000000000..d6becb10eee --- /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 00000000000..fd99ad64f6d --- /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 00000000000..90d312c614d --- /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 00000000000..dd35a5581bd --- /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 00000000000..36700c9a2ce --- /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 a30594840dd..a112781a99e 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 55e4223d7fd..42e7fff0de5 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] } { @@ -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" diff --git a/gcc/testsuite/gcc.target/mips/near-far-1.c b/gcc/testsuite/gcc.target/mips/near-far-1.c index 8806e930fc3..b746cf6030c 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 b4062a744cf..2c140e2ceb2 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 e6af939e081..7bf3e14bc80 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 969f68f3811..cd12a1dbcbb 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 8717362e044..74465c9f808 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.30.2