This is the failure of ACATS c94007a at -O2 on SPARC64/Solaris: the compiler generates wrong code because of a delay slot scheduling (reorg.c) bug. This is a regression on the 4.6 branch (4.5 branch and mainline are clean).
fill_simple_delay_slots decides to fill the delay slot of a call insn with another insn that is located about one hundred insns downstream(!); this is a long sequence of call insns that can throw with handlers that fall thru, a typical pattern of ACATS tests, without any intervening jumps or labels. The problem is that fill_simple_delay_slots hoists the insn above such a call that throws and whose handler falls thru, which makes it effectively a jump with edges in the CFG. The code handles the regular jump case: /* Stop our search when seeing an unconditional jump. */ if (JUMP_P (trial_delay)) break; but overlooks this special jump case. This is a known pattern, whose solution has been factored into stop_search_p: /* Return TRUE if this insn should stop the search for insn to fill delay slots. LABELS_P indicates that labels should terminate the search. In all cases, jumps terminate the search. */ static int stop_search_p (rtx insn, int labels_p) { if (insn == 0) return 1; /* If the insn can throw an exception that is caught within the function, it may effectively perform a jump from the viewpoint of the function. Therefore act like for a jump. */ if (can_throw_internal (insn)) return 1; fill_simple_delay_slots already uses stop_search_p for the backward scan. The fix is simply to make it use stop_search_p for the forward scan as well. Bootstrappeg/regtested on SPARC/Solaris and SPARC64/Solaris. 2011-06-21 Eric Botcazou <ebotca...@adacore.com> * reorg.c (fill_simple_delay_slots): Use stop_search_p to stop the forward scan as well. -- Eric Botcazou
Index: reorg.c =================================================================== --- reorg.c (revision 175090) +++ reorg.c (working copy) @@ -2152,7 +2152,7 @@ fill_simple_delay_slots (int non_jumps_p /* This must be an INSN or CALL_INSN. */ pat = PATTERN (trial); - /* USE and CLOBBER at this level was just for flow; ignore it. */ + /* Stand-alone USE and CLOBBER are just for flow. */ if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER) continue; @@ -2271,15 +2271,12 @@ fill_simple_delay_slots (int non_jumps_p } if (target == 0) - for (trial = next_nonnote_insn (insn); trial; trial = next_trial) + for (trial = next_nonnote_insn (insn); !stop_search_p (trial, 1); + trial = next_trial) { next_trial = next_nonnote_insn (trial); - if (LABEL_P (trial) - || BARRIER_P (trial)) - break; - - /* We must have an INSN, JUMP_INSN, or CALL_INSN. */ + /* This must be an INSN or CALL_INSN. */ pat = PATTERN (trial); /* Stand-alone USE and CLOBBER are just for flow. */ @@ -2293,7 +2290,7 @@ fill_simple_delay_slots (int non_jumps_p else trial_delay = trial; - /* Stop our search when seeing an unconditional jump. */ + /* Stop our search when seeing a jump. */ if (JUMP_P (trial_delay)) break;