diff mbox

[MIPS,committed] Fix handling of long branches with delay slots

Message ID 87fw7931ax.fsf@talisman.home
State New
Headers show

Commit Message

Richard Sandiford Aug. 26, 2012, 7:23 p.m. UTC
Converting gcc.target/mips to gcc-dg showed up a brown-paper-bag bug
in my long-branch code.  The function that checks whether $gp is needed
only for long branches runs (and must run) after delayed-branch scheduling,
but it wasn't looking inside the SEQUENCEs.

I also made the code check the same jump condition as
mips16_split_long_branches.

Tested on mipsisa64-elf, mips64-elf and mips64-linux-gnu.  Applied.
Will be tested once gcc.target/mips uses gcc-dg.

Richard


gcc/
	* config/mips/mips.c (mips_has_long_branch_p): New function,
	split out from...
	(mips_expand_ghost_gp_insns): ...here.  Look inside sequences.
diff mbox

Patch

Index: gcc/config/mips/mips.c
===================================================================
--- gcc/config/mips/mips.c	2012-08-26 11:21:13.000000000 +0100
+++ gcc/config/mips/mips.c	2012-08-26 11:32:09.530815882 +0100
@@ -15513,23 +15513,15 @@  mips_reorg_process_insns (void)
   htab_delete (htab);
 }
 
-/* If we are using a GOT, but have not decided to use a global pointer yet,
-   see whether we need one to implement long branches.  Convert the ghost
-   global-pointer instructions into real ones if so.  */
+/* Return true if the function has a long branch instruction.  */
 
 static bool
-mips_expand_ghost_gp_insns (void)
+mips_has_long_branch_p (void)
 {
-  rtx insn;
+  rtx insn, subinsn;
   int normal_length;
 
-  /* Quick exit if we already know that we will or won't need a
-     global pointer.  */
-  if (!TARGET_USE_GOT
-      || cfun->machine->global_pointer == INVALID_REGNUM
-      || mips_must_initialize_gp_p ())
-    return false;
-
+  /* We need up-to-date instruction lengths.  */
   shorten_branches (get_insns ());
 
   /* Look for a branch that is longer than normal.  The normal length for
@@ -15538,12 +15530,32 @@  mips_expand_ghost_gp_insns (void)
      but they have no delay slot.  */
   normal_length = (TARGET_MIPS16 ? 4 : 8);
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-    if (JUMP_P (insn)
-	&& USEFUL_INSN_P (insn)
-	&& get_attr_length (insn) > normal_length)
-      break;
+    FOR_EACH_SUBINSN (subinsn, insn)
+      if (JUMP_P (subinsn)
+	  && USEFUL_INSN_P (subinsn)
+	  && get_attr_length (subinsn) > normal_length
+	  && (any_condjump_p (subinsn) || any_uncondjump_p (subinsn)))
+	return true;
+
+  return false;
+}
+
+/* If we are using a GOT, but have not decided to use a global pointer yet,
+   see whether we need one to implement long branches.  Convert the ghost
+   global-pointer instructions into real ones if so.  */
+
+static bool
+mips_expand_ghost_gp_insns (void)
+{
+  /* Quick exit if we already know that we will or won't need a
+     global pointer.  */
+  if (!TARGET_USE_GOT
+      || cfun->machine->global_pointer == INVALID_REGNUM
+      || mips_must_initialize_gp_p ())
+    return false;
 
-  if (insn == NULL_RTX)
+  /* Run a full check for long branches.  */
+  if (!mips_has_long_branch_p ())
     return false;
 
   /* We've now established that we need $gp.  */