This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Re: More SJLJ exception breakage


I wrote:

> In any case, I now understand the problem a bit better.  Fundamentally,
> this is about the assumption in sjlj_emit_function_exit that the place
> where to insert the unregister call -that was announced (from function.c)
> via the sjlj_emit_function_exit_after routine- is located within the
> last basic block, i.e. the one with a fall-through edge to EXIT.

The patch below fixes the problem for me.  It changes sjlj_emit_function_exit
to always respect the location announced via sjlj_emit_function_exit_after.

The current code seems to be intended to cope with the case where that
location is "after" the last basic block.  However, expand_function_end
will in fact always announce the location of the "return_label" ... I
don't quite see how a label (which starts a new basic block anyway) can
ever be outside a basic block.  (In particular as the various CFG cleanup
before EH processing is no longer performed now ...)

Thus it seems to me it should be OK to simply always insert the call to
the unregister function at that location, and remove the "insert on edge"
code path.

This fixes nearly all instances of exception-related problems on SPU.
However, there is one case where it appears a pre-existing problem is
exposed: in the case of a return by fall-through at the end of a 
function without explict return statement, expand_function_end
generates a branch bypassing the "return_label" and going directly
to the "naked_return_label".

Now that sjlj_emit_function_exit in fact always places the unregister
call at the return_label, this causes that call to now by bypassed as
well in this case.

However, I don't quite understand why the return label is bypassed
anyway; in the semantically identical situation where a "return;"
is the last statement of the function, the return_label is *not*
bypassed.

The patch below therefore changes expand_function_end to omit that
extra branch, and have the fall-through function end case also go
through the return_label.  (The only remaining case where the
naked_return_label is used is __builtin_return.)

The patch fixes all C++ test suite regressions, without introducing
any new regressions on the SPU.

OK for mainline?

Bye,
Ulrich


ChangeLog:

	* function.c (expand_function_end): Do not emit a jump to the "naked"
	return label for fall-through returns.
	* except.c (sjlj_emit_function_exit): Always place the call to the
	unregister function at the location installed by expand_function_end.


Index: gcc/function.c
===================================================================
*** gcc/function.c	(revision 146246)
--- gcc/function.c	(working copy)
*************** expand_function_end (void)
*** 4804,4810 ****
  
      start_sequence ();
      clobber_return_register ();
-     expand_naked_return ();
      seq = get_insns ();
      end_sequence ();
  
--- 4804,4809 ----
*************** expand_function_end (void)
*** 4812,4818 ****
    }
  
    /* Output the label for the naked return from the function.  */
!   emit_label (naked_return_label);
  
    /* @@@ This is a kludge.  We want to ensure that instructions that
       may trap are not moved into the epilogue by scheduling, because
--- 4811,4818 ----
    }
  
    /* Output the label for the naked return from the function.  */
!   if (naked_return_label)
!     emit_label (naked_return_label);
  
    /* @@@ This is a kludge.  We want to ensure that instructions that
       may trap are not moved into the epilogue by scheduling, because
Index: gcc/except.c
===================================================================
*** gcc/except.c	(revision 146246)
--- gcc/except.c	(working copy)
*************** sjlj_emit_function_exit_after (rtx after
*** 2072,2080 ****
  static void
  sjlj_emit_function_exit (void)
  {
!   rtx seq;
!   edge e;
!   edge_iterator ei;
  
    start_sequence ();
  
--- 2072,2078 ----
  static void
  sjlj_emit_function_exit (void)
  {
!   rtx seq, insn;
  
    start_sequence ();
  
*************** sjlj_emit_function_exit (void)
*** 2088,2118 ****
       post-dominates all can_throw_internal instructions.  This is
       the last possible moment.  */
  
!   FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
!     if (e->flags & EDGE_FALLTHRU)
!       break;
!   if (e)
!     {
!       rtx insn;
  
!       /* Figure out whether the place we are supposed to insert libcall
!          is inside the last basic block or after it.  In the other case
!          we need to emit to edge.  */
!       gcc_assert (e->src->next_bb == EXIT_BLOCK_PTR);
!       for (insn = BB_HEAD (e->src); ; insn = NEXT_INSN (insn))
! 	{
! 	  if (insn == crtl->eh.sjlj_exit_after)
! 	    {
! 	      if (LABEL_P (insn))
! 		insn = NEXT_INSN (insn);
! 	      emit_insn_after (seq, insn);
! 	      return;
! 	    }
! 	  if (insn == BB_END (e->src))
! 	    break;
! 	}
!       insert_insn_on_edge (seq, e);
!     }
  }
  
  static void
--- 2086,2096 ----
       post-dominates all can_throw_internal instructions.  This is
       the last possible moment.  */
  
!   insn = crtl->eh.sjlj_exit_after;
!   if (LABEL_P (insn))
!     insn = NEXT_INSN (insn);
  
!   emit_insn_after (seq, insn);
  }
  
  static void


-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]