]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
backport: re PR target/46915 (Wrong code is generated for conditional branch followed...
authorJohn David Anglin <dave.anglin@nrc-cnrc.gc.ca>
Wed, 22 Dec 2010 18:49:24 +0000 (18:49 +0000)
committerJohn David Anglin <danglin@gcc.gnu.org>
Wed, 22 Dec 2010 18:49:24 +0000 (18:49 +0000)
Backport from mainline:
2010-12-18  John David Anglin  <dave.anglin@nrc-cnrc.gc.ca>

PR target/46915
* config/pa/pa.c (branch_to_delay_slot_p): Use next_active_insn instead
of next_real_insn.  Search forward checking for both ASM_INPUT and
ASM_OPERANDS asms until exit condition is found.
(branch_needs_nop_p): Likewise.
(use_skip_p): New function.
(output_cbranch): Use use_skip_p.
(output_bb, output_bvb): Likewise.

2009-06-25  John David Anglin  <dave.anglin@nrc-cnrc.gc.ca>

PR target/40468
* pa.c (branch_to_delay_slot_p, branch_needs_nop_p): New functions.
(output_cbranch): Use new functions.
(output_bb, output_bvb, output_dbra, output_movb): Likewise.

From-SVN: r168178

gcc/ChangeLog
gcc/config/pa/pa.c

index 0bc1f19216bca913d7ec3c19cbd98064436554be..d895a58a3823a5d2d0720aac9cc73e227ec0915e 100644 (file)
@@ -1,3 +1,24 @@
+2010-12-22 John David Anglin  <dave.anglin@nrc-cnrc.gc.ca>
+
+       Backport from mainline:
+       2010-12-18  John David Anglin  <dave.anglin@nrc-cnrc.gc.ca>
+
+       PR target/46915
+       * config/pa/pa.c (branch_to_delay_slot_p): Use next_active_insn instead
+       of next_real_insn.  Search forward checking for both ASM_INPUT and
+       ASM_OPERANDS asms until exit condition is found.
+       (branch_needs_nop_p): Likewise.
+       (use_skip_p): New function.
+       (output_cbranch): Use use_skip_p.
+       (output_bb, output_bvb): Likewise.
+
+       2009-06-25  John David Anglin  <dave.anglin@nrc-cnrc.gc.ca>
+
+       PR target/40468
+       * pa.c (branch_to_delay_slot_p, branch_needs_nop_p): New functions.
+       (output_cbranch): Use new functions.
+       (output_bb, output_bvb, output_dbra, output_movb): Likewise.
+
 2010-12-05  Richard Guenther  <rguenther@suse.de>
            Ira Rosen  <irar@il.ibm.com>
 
index af09dcbf7a3912a9d1b08301b3b050b7f0e3ac8c..3ee7841108e71f3ecaaa5c008e227eedca0cdcd3 100644 (file)
@@ -6088,6 +6088,95 @@ pa_scalar_mode_supported_p (enum machine_mode mode)
     }
 }
 
+/* Return TRUE if INSN, a jump insn, has an unfilled delay slot and
+   it branches into the delay slot.  Otherwise, return FALSE.  */
+
+static bool
+branch_to_delay_slot_p (rtx insn)
+{
+  rtx jump_insn;
+
+  if (dbr_sequence_length ())
+    return FALSE;
+
+  jump_insn = next_active_insn (JUMP_LABEL (insn));
+  while (insn)
+    {
+      insn = next_active_insn (insn);
+      if (jump_insn == insn)
+       return TRUE;
+
+      /* We can't rely on the length of asms.  So, we return FALSE when
+        the branch is followed by an asm.  */
+      if (!insn
+         || GET_CODE (PATTERN (insn)) == ASM_INPUT
+         || asm_noperands (PATTERN (insn)) >= 0
+         || get_attr_length (insn) > 0)
+       break;
+    }
+
+  return FALSE;
+}
+
+/* Return TRUE if INSN, a forward jump insn, needs a nop in its delay slot.
+
+   This occurs when INSN has an unfilled delay slot and is followed
+   by an asm.  Disaster can occur if the asm is empty and the jump
+   branches into the delay slot.  So, we add a nop in the delay slot
+   when this occurs.  */
+
+static bool
+branch_needs_nop_p (rtx insn)
+{
+  rtx jump_insn;
+
+  if (dbr_sequence_length ())
+    return FALSE;
+
+  jump_insn = next_active_insn (JUMP_LABEL (insn));
+  while (insn)
+    {
+      insn = next_active_insn (insn);
+      if (!insn || jump_insn == insn)
+       return TRUE;
+
+      if (!(GET_CODE (PATTERN (insn)) == ASM_INPUT
+          || asm_noperands (PATTERN (insn)) >= 0)
+         && get_attr_length (insn) > 0)
+       break;
+    }
+
+  return FALSE;
+}
+
+/* Return TRUE if INSN, a forward jump insn, can use nullification
+   to skip the following instruction.  This avoids an extra cycle due
+   to a mis-predicted branch when we fall through.  */
+
+static bool
+use_skip_p (rtx insn)
+{
+  rtx jump_insn = next_active_insn (JUMP_LABEL (insn));
+
+  while (insn)
+    {
+      insn = next_active_insn (insn);
+
+      /* We can't rely on the length of asms, so we can't skip asms.  */
+      if (!insn
+         || GET_CODE (PATTERN (insn)) == ASM_INPUT
+         || asm_noperands (PATTERN (insn)) >= 0)
+       break;
+      if (get_attr_length (insn) == 4
+         && jump_insn == next_active_insn (insn))
+       return TRUE;
+      if (get_attr_length (insn) > 0)
+       break;
+    }
+
+  return FALSE;
+}
+
 /* This routine handles all the normal conditional branch sequences we
    might need to generate.  It handles compare immediate vs compare
    register, nullification of delay slots, varying length branches,
@@ -6099,7 +6188,7 @@ const char *
 output_cbranch (rtx *operands, int negated, rtx insn)
 {
   static char buf[100];
-  int useskip = 0;
+  bool useskip;
   int nullify = INSN_ANNULLED_BRANCH_P (insn);
   int length = get_attr_length (insn);
   int xdelay;
@@ -6113,7 +6202,7 @@ output_cbranch (rtx *operands, int negated, rtx insn)
      slot and the same branch target as this branch.  We could check
      for this but jump optimization should eliminate nop jumps.  It
      is always safe to emit a nop.  */
-  if (next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn))
+  if (branch_to_delay_slot_p (insn))
     return "nop";
 
   /* The doubleword form of the cmpib instruction doesn't have the LEU
@@ -6137,12 +6226,7 @@ output_cbranch (rtx *operands, int negated, rtx insn)
   /* A forward branch over a single nullified insn can be done with a
      comclr instruction.  This avoids a single cycle penalty due to
      mis-predicted branch if we fall through (branch not taken).  */
-  if (length == 4
-      && next_real_insn (insn) != 0
-      && get_attr_length (next_real_insn (insn)) == 4
-      && JUMP_LABEL (insn) == next_nonnote_insn (next_real_insn (insn))
-      && nullify)
-    useskip = 1;
+  useskip = (length == 4 && nullify) ? use_skip_p (insn) : FALSE;
 
   switch (length)
     {
@@ -6162,7 +6246,12 @@ output_cbranch (rtx *operands, int negated, rtx insn)
        if (useskip)
          strcat (buf, " %2,%r1,%%r0");
        else if (nullify)
-         strcat (buf, ",n %2,%r1,%0");
+         {
+           if (branch_needs_nop_p (insn))
+             strcat (buf, ",n %2,%r1,%0%#");
+           else
+             strcat (buf, ",n %2,%r1,%0");
+         }
        else
          strcat (buf, " %2,%r1,%0");
        break;
@@ -6425,7 +6514,7 @@ const char *
 output_bb (rtx *operands ATTRIBUTE_UNUSED, int negated, rtx insn, int which)
 {
   static char buf[100];
-  int useskip = 0;
+  bool useskip;
   int nullify = INSN_ANNULLED_BRANCH_P (insn);
   int length = get_attr_length (insn);
   int xdelay;
@@ -6435,7 +6524,7 @@ output_bb (rtx *operands ATTRIBUTE_UNUSED, int negated, rtx insn, int which)
      is only used when optimizing; jump optimization should eliminate the
      jump.  But be prepared just in case.  */
 
-  if (next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn))
+  if (branch_to_delay_slot_p (insn))
     return "nop";
 
   /* If this is a long branch with its delay slot unfilled, set `nullify'
@@ -6451,13 +6540,7 @@ output_bb (rtx *operands ATTRIBUTE_UNUSED, int negated, rtx insn, int which)
   /* A forward branch over a single nullified insn can be done with a
      extrs instruction.  This avoids a single cycle penalty due to
      mis-predicted branch if we fall through (branch not taken).  */
-
-  if (length == 4
-      && next_real_insn (insn) != 0
-      && get_attr_length (next_real_insn (insn)) == 4
-      && JUMP_LABEL (insn) == next_nonnote_insn (next_real_insn (insn))
-      && nullify)
-    useskip = 1;
+  useskip = (length == 4 && nullify) ? use_skip_p (insn) : FALSE;
 
   switch (length)
     {
@@ -6481,11 +6564,21 @@ output_bb (rtx *operands ATTRIBUTE_UNUSED, int negated, rtx insn, int which)
        if (useskip)
          strcat (buf, " %0,%1,1,%%r0");
        else if (nullify && negated)
-         strcat (buf, ",n %0,%1,%3");
+         {
+           if (branch_needs_nop_p (insn))
+             strcat (buf, ",n %0,%1,%3%#");
+           else
+             strcat (buf, ",n %0,%1,%3");
+         }
        else if (nullify && ! negated)
-         strcat (buf, ",n %0,%1,%2");
+         {
+           if (branch_needs_nop_p (insn))
+             strcat (buf, ",n %0,%1,%2%#");
+           else
+             strcat (buf, ",n %0,%1,%2");
+         }
        else if (! nullify && negated)
-         strcat (buf, "%0,%1,%3");
+         strcat (buf, " %0,%1,%3");
        else if (! nullify && ! negated)
          strcat (buf, " %0,%1,%2");
        break;
@@ -6606,7 +6699,7 @@ const char *
 output_bvb (rtx *operands ATTRIBUTE_UNUSED, int negated, rtx insn, int which)
 {
   static char buf[100];
-  int useskip = 0;
+  bool useskip;
   int nullify = INSN_ANNULLED_BRANCH_P (insn);
   int length = get_attr_length (insn);
   int xdelay;
@@ -6616,7 +6709,7 @@ output_bvb (rtx *operands ATTRIBUTE_UNUSED, int negated, rtx insn, int which)
      is only used when optimizing; jump optimization should eliminate the
      jump.  But be prepared just in case.  */
 
-  if (next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn))
+  if (branch_to_delay_slot_p (insn))
     return "nop";
 
   /* If this is a long branch with its delay slot unfilled, set `nullify'
@@ -6632,13 +6725,7 @@ output_bvb (rtx *operands ATTRIBUTE_UNUSED, int negated, rtx insn, int which)
   /* A forward branch over a single nullified insn can be done with a
      extrs instruction.  This avoids a single cycle penalty due to
      mis-predicted branch if we fall through (branch not taken).  */
-
-  if (length == 4
-      && next_real_insn (insn) != 0
-      && get_attr_length (next_real_insn (insn)) == 4
-      && JUMP_LABEL (insn) == next_nonnote_insn (next_real_insn (insn))
-      && nullify)
-    useskip = 1;
+  useskip = (length == 4 && nullify) ? use_skip_p (insn) : FALSE;
 
   switch (length)
     {
@@ -6662,11 +6749,21 @@ output_bvb (rtx *operands ATTRIBUTE_UNUSED, int negated, rtx insn, int which)
        if (useskip)
          strcat (buf, "{ %0,1,%%r0| %0,%%sar,1,%%r0}");
        else if (nullify && negated)
-         strcat (buf, "{,n %0,%3|,n %0,%%sar,%3}");
+         {
+           if (branch_needs_nop_p (insn))
+             strcat (buf, "{,n %0,%3%#|,n %0,%%sar,%3%#}");
+           else
+             strcat (buf, "{,n %0,%3|,n %0,%%sar,%3}");
+         }
        else if (nullify && ! negated)
-         strcat (buf, "{,n %0,%2|,n %0,%%sar,%2}");
+         {
+           if (branch_needs_nop_p (insn))
+             strcat (buf, "{,n %0,%2%#|,n %0,%%sar,%2%#}");
+           else
+             strcat (buf, "{,n %0,%2|,n %0,%%sar,%2}");
+         }
        else if (! nullify && negated)
-         strcat (buf, "{%0,%3|%0,%%sar,%3}");
+         strcat (buf, "{ %0,%3| %0,%%sar,%3}");
        else if (! nullify && ! negated)
          strcat (buf, "{ %0,%2| %0,%%sar,%2}");
        break;
@@ -6788,7 +6885,7 @@ output_dbra (rtx *operands, rtx insn, int which_alternative)
   /* A conditional branch to the following instruction (e.g. the delay slot) is
      asking for a disaster.  Be prepared!  */
 
-  if (next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn))
+  if (branch_to_delay_slot_p (insn))
     {
       if (which_alternative == 0)
        return "ldo %1(%0),%0";
@@ -6825,7 +6922,12 @@ output_dbra (rtx *operands, rtx insn, int which_alternative)
        {
        case 4:
          if (nullify)
-           return "addib,%C2,n %1,%0,%3";
+           {
+             if (branch_needs_nop_p (insn))
+               return "addib,%C2,n %1,%0,%3%#";
+             else
+               return "addib,%C2,n %1,%0,%3";
+           }
          else
            return "addib,%C2 %1,%0,%3";
       
@@ -6933,7 +7035,7 @@ output_movb (rtx *operands, rtx insn, int which_alternative,
   /* A conditional branch to the following instruction (e.g. the delay slot) is
      asking for a disaster.  Be prepared!  */
 
-  if (next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn))
+  if (branch_to_delay_slot_p (insn))
     {
       if (which_alternative == 0)
        return "copy %1,%0";
@@ -6971,7 +7073,12 @@ output_movb (rtx *operands, rtx insn, int which_alternative,
        {
        case 4:
          if (nullify)
-           return "movb,%C2,n %1,%0,%3";
+           {
+             if (branch_needs_nop_p (insn))
+               return "movb,%C2,n %1,%0,%3%#";
+             else
+               return "movb,%C2,n %1,%0,%3";
+           }
          else
            return "movb,%C2 %1,%0,%3";