From: John David Anglin Date: Wed, 22 Dec 2010 18:49:24 +0000 (+0000) Subject: backport: re PR target/46915 (Wrong code is generated for conditional branch followed... X-Git-Tag: releases/gcc-4.3.6~240 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8b21bb77b6dc89cdd04744fea8219e6bb98579f0;p=thirdparty%2Fgcc.git backport: re PR target/46915 (Wrong code is generated for conditional branch followed by zero length asm) Backport from mainline: 2010-12-18 John David Anglin 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 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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0bc1f19216bc..d895a58a3823 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,24 @@ +2010-12-22 John David Anglin + + Backport from mainline: + 2010-12-18 John David Anglin + + 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 + + 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 Ira Rosen diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c index af09dcbf7a39..3ee7841108e7 100644 --- a/gcc/config/pa/pa.c +++ b/gcc/config/pa/pa.c @@ -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";