aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJohn David Anglin <dave.anglin@nrc-cnrc.gc.ca>2010-12-18 17:10:34 +0000
committerJohn David Anglin <danglin@gcc.gnu.org>2010-12-18 17:10:34 +0000
commit16923e7bf333db732aed3686972b40ac2e458109 (patch)
tree1e81f7c53d72184586caf1560f886f5fa2696c0d /gcc
parentc50ebc7332db306b3b7e122fb5251605db3bcd96 (diff)
downloadgcc-16923e7bf333db732aed3686972b40ac2e458109.zip
gcc-16923e7bf333db732aed3686972b40ac2e458109.tar.gz
gcc-16923e7bf333db732aed3686972b40ac2e458109.tar.bz2
re PR target/46915 (Wrong code is generated for conditional branch followed by zero length asm)
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. From-SVN: r168026
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog11
-rw-r--r--gcc/config/pa/pa.c106
2 files changed, 84 insertions, 33 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 5b7241e..9536e0a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,14 @@
+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.
+
2010-12-18 Kai Tietz <kai.tietz@onevision.com>
PR target/36834
diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c
index ab54e4b..89f7e50 100644
--- a/gcc/config/pa/pa.c
+++ b/gcc/config/pa/pa.c
@@ -6188,35 +6188,92 @@ pa_scalar_mode_supported_p (enum machine_mode mode)
}
/* Return TRUE if INSN, a jump insn, has an unfilled delay slot and
- it branches to the next real instruction. Otherwise, return FALSE. */
+ 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;
- return next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn);
+ 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
+ || extract_asm_operands (PATTERN (insn)) != NULL_RTX
+ || get_attr_length (insn) > 0)
+ break;
+ }
+
+ return FALSE;
}
-/* Return TRUE if INSN, a jump insn, needs a nop in its delay slot.
+/* 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_INPUT. Disaster can occur if the ASM_INPUT is empty and
- the jump branches into the delay slot. So, we add a nop in the delay
- slot just to be safe. This messes up our instruction count, but we
- don't know how big the ASM_INPUT insn is anyway. */
+ 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 next_insn;
+ rtx jump_insn;
if (dbr_sequence_length ())
return FALSE;
- next_insn = next_real_insn (insn);
- return GET_CODE (PATTERN (next_insn)) == ASM_INPUT;
+ 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
+ || extract_asm_operands (PATTERN (insn)) != NULL_RTX)
+ && 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
+ || extract_asm_operands (PATTERN (insn)) != NULL_RTX)
+ 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
@@ -6230,7 +6287,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;
@@ -6268,12 +6325,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)
{
@@ -6561,7 +6613,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;
@@ -6587,13 +6639,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)
{
@@ -6752,7 +6798,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;
@@ -6778,13 +6824,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)
{