aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorSimon Dardis <simon.dardis@imgtec.com>2015-11-11 13:40:08 +0000
committerSimon Dardis <dardiss@gcc.gnu.org>2015-11-11 13:40:08 +0000
commitdcfe3c8f32c207cb4d8cb77425604ae72bee406a (patch)
treee493a662bd56a720d799d846a21967c6d3efd7a3 /gcc
parentc08de514880f6cc238123da828eca9122dbf74bd (diff)
downloadgcc-dcfe3c8f32c207cb4d8cb77425604ae72bee406a.zip
gcc-dcfe3c8f32c207cb4d8cb77425604ae72bee406a.tar.gz
gcc-dcfe3c8f32c207cb4d8cb77425604ae72bee406a.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/config/mips/mips.c117
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.target/mips/split-ds-sequence.c19
4 files changed, 147 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 546cad8..e955e41 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+2015-11-11 Simon Dardis <simon.dardis@imgtec.com>
+
+ * 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 <alan.lawrence@arm.com>
* 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 9880b23..d3b7730 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 7862991..4637d5f 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2015-11-11 Simon Dardis <simon.dardis@imgtec.com>
+
+ * gcc.target/mips/split-ds-sequence.c: New test.
+
2015-11-11 Julia Koval <julia.koval@intel.com>
* 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 0000000..e60270d
--- /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;
+
+}