Undo delay slot filling and use compact branches in selected cases.
authorSimon Dardis <simon.dardis@imgtec.com>
Wed, 11 Nov 2015 13:40:08 +0000 (13:40 +0000)
committerSimon Dardis <dardiss@gcc.gnu.org>
Wed, 11 Nov 2015 13:40:08 +0000 (13:40 +0000)
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
gcc/config/mips/mips.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/mips/split-ds-sequence.c [new file with mode: 0644]

index 546cad83b2da79ac1f0f0be9bbb7d3d0d5196fc8..e955e4175b94f617b494652b90cd550379fb87e9 100644 (file)
@@ -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.
index 9880b236d6de9a9631e1dfe441c47132c6d35db1..d3b7730486db8d9e1a30631785d45efcdaa62cfa 100644 (file)
@@ -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;
                }
            }
index 7862991c67fa5c77883c7583e73f46d7c4d66093..4637d5fc6a8082600b7558f01719b6092e1c3f3d 100644 (file)
@@ -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 (file)
index 0000000..e60270d
--- /dev/null
@@ -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;
+
+}