From dcfe3c8f32c207cb4d8cb77425604ae72bee406a Mon Sep 17 00:00:00 2001 From: Simon Dardis Date: Wed, 11 Nov 2015 13:40:08 +0000 Subject: [PATCH] Undo delay slot filling and use compact branches in selected cases. gcc/ * config/mips/mips.c (mips_breakable_sequence_p): New function. (mips_break_sequence): New function. (mips_reorg_process_insns) Use them. Use compact branches in selected situations. gcc/testsuite/ * gcc.target/mips/split-ds-sequence.c: New test. From-SVN: r230160 --- gcc/ChangeLog | 7 ++ gcc/config/mips/mips.c | 117 ++++++++++++++++++ gcc/testsuite/ChangeLog | 4 + .../gcc.target/mips/split-ds-sequence.c | 19 +++ 4 files changed, 147 insertions(+) create mode 100644 gcc/testsuite/gcc.target/mips/split-ds-sequence.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 546cad83b2d..e955e4175b9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2015-11-11 Simon Dardis + + * config/mips/mips.c (mips_breakable_sequence_p): New function. + (mips_break_sequence): New function. + (mips_reorg_process_insns): Use them. Use compact branches in selected + situations. + 2015-11-11 Alan Lawrence * fold-const.c (get_array_ctor_element_at_index): Fix whitespace, typo. diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 9880b236d6d..d3b7730486d 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -16824,6 +16824,34 @@ mips_avoid_hazard (rtx_insn *after, rtx_insn *insn, int *hilo_delay, } } +/* A SEQUENCE is breakable iff the branch inside it has a compact form + and the target has compact branches. */ + +static bool +mips_breakable_sequence_p (rtx_insn *insn) +{ + return (insn && GET_CODE (PATTERN (insn)) == SEQUENCE + && TARGET_CB_MAYBE + && get_attr_compact_form (SEQ_BEGIN (insn)) != COMPACT_FORM_NEVER); +} + +/* Remove a SEQUENCE and replace it with the delay slot instruction + followed by the branch and return the instruction in the delay slot. + Return the first of the two new instructions. + Subroutine of mips_reorg_process_insns. */ + +static rtx_insn * +mips_break_sequence (rtx_insn *insn) +{ + rtx_insn *before = PREV_INSN (insn); + rtx_insn *branch = SEQ_BEGIN (insn); + rtx_insn *ds = SEQ_END (insn); + remove_insn (insn); + add_insn_after (ds, before, NULL); + add_insn_after (branch, ds, NULL); + return ds; +} + /* Go through the instruction stream and insert nops where necessary. Also delete any high-part relocations whose partnering low parts are now all dead. See if the whole function can then be put into @@ -16916,6 +16944,68 @@ mips_reorg_process_insns (void) { if (GET_CODE (PATTERN (insn)) == SEQUENCE) { + rtx_insn *next_active = next_active_insn (insn); + /* Undo delay slots to avoid bubbles if the next instruction can + be placed in a forbidden slot or the cost of adding an + explicit NOP in a forbidden slot is OK and if the SEQUENCE is + safely breakable. */ + if (TARGET_CB_MAYBE + && mips_breakable_sequence_p (insn) + && INSN_P (SEQ_BEGIN (insn)) + && INSN_P (SEQ_END (insn)) + && ((next_active + && INSN_P (next_active) + && GET_CODE (PATTERN (next_active)) != SEQUENCE + && get_attr_can_delay (next_active) == CAN_DELAY_YES) + || !optimize_size)) + { + /* To hide a potential pipeline bubble, if we scan backwards + from the current SEQUENCE and find that there is a load + of a value that is used in the CTI and there are no + dependencies between the CTI and instruction in the delay + slot, break the sequence so the load delay is hidden. */ + HARD_REG_SET uses; + CLEAR_HARD_REG_SET (uses); + note_uses (&PATTERN (SEQ_BEGIN (insn)), record_hard_reg_uses, + &uses); + HARD_REG_SET delay_sets; + CLEAR_HARD_REG_SET (delay_sets); + note_stores (PATTERN (SEQ_END (insn)), record_hard_reg_sets, + &delay_sets); + + rtx_insn *prev = prev_active_insn (insn); + if (prev + && GET_CODE (PATTERN (prev)) == SET + && MEM_P (SET_SRC (PATTERN (prev)))) + { + HARD_REG_SET sets; + CLEAR_HARD_REG_SET (sets); + note_stores (PATTERN (prev), record_hard_reg_sets, + &sets); + + /* Re-order if safe. */ + if (!hard_reg_set_intersect_p (delay_sets, uses) + && hard_reg_set_intersect_p (uses, sets)) + { + next_insn = mips_break_sequence (insn); + /* Need to process the hazards of the newly + introduced instructions. */ + continue; + } + } + + /* If we find an orphaned high-part relocation in a delay + slot then we can convert to a compact branch and get + the orphaned high part deleted. */ + if (mips_orphaned_high_part_p (&htab, SEQ_END (insn))) + { + next_insn = mips_break_sequence (insn); + /* Need to process the hazards of the newly + introduced instructions. */ + continue; + } + } + /* If we find an orphaned high-part relocation in a delay slot, it's easier to turn that instruction into a NOP than to delete it. The delay slot will be a NOP either way. */ @@ -16950,6 +17040,33 @@ mips_reorg_process_insns (void) { mips_avoid_hazard (last_insn, insn, &hilo_delay, &delayed_reg, lo_reg, &fs_delay); + /* When a compact branch introduces a forbidden slot hazard + and the next useful instruction is a SEQUENCE of a jump + and a non-nop instruction in the delay slot, remove the + sequence and replace it with the delay slot instruction + then the jump to clear the forbidden slot hazard. */ + + if (fs_delay) + { + /* Search onwards from the current position looking for + a SEQUENCE. We are looking for pipeline hazards here + and do not need to worry about labels or barriers as + the optimization only undoes delay slot filling which + only affects the order of the branch and its delay + slot. */ + rtx_insn *next = next_active_insn (insn); + if (next + && USEFUL_INSN_P (next) + && GET_CODE (PATTERN (next)) == SEQUENCE + && mips_breakable_sequence_p (next)) + { + last_insn = insn; + next_insn = mips_break_sequence (next); + /* Need to process the hazards of the newly + introduced instructions. */ + continue; + } + } last_insn = insn; } } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7862991c67f..4637d5fc6a8 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2015-11-11 Simon Dardis + + * gcc.target/mips/split-ds-sequence.c: New test. + 2015-11-11 Julia Koval * g++.dg/ext/mv16.C: New functions. diff --git a/gcc/testsuite/gcc.target/mips/split-ds-sequence.c b/gcc/testsuite/gcc.target/mips/split-ds-sequence.c new file mode 100644 index 00000000000..e60270db304 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/split-ds-sequence.c @@ -0,0 +1,19 @@ +/* { dg-options "isa_rev>=6" } */ +/* { dg-skip-if "code quality test" { *-*-* } { "-mcompact-branches=never" } { "" } } */ +/* { dg-final { scan-assembler-not "nop" } } */ + +int +testg2 (int a, int c) +{ + + int j = 0; + do + { + j += a; + } + while (j < 56); + + j += c; + return j; + +} -- 2.30.2