}
}
+/* 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,
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;
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
/* 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)
{
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;
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;
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'
/* 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)
{
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;
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;
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'
/* 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)
{
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;
/* 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";
{
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";
/* 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";
{
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";