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]

loop vs exceptions


The following fixes an ia64 miscompilation of __cxa_vec_ctor.

There are a couple of problems here.

One, since the existing loop code doesn't use the CFG, it didn't
actually know about the exit from the loop via the exception edge.
Thus it decided that it was possible to reverse the loop and fix
up the live BIVs at loop exit.

Two, ia64 uses schedule_ebbs for post-reload scheduling, which means
that insns in a fallthru basic block are given the opportunity to be
scheduled into the preceeding basic block.  Which allowed the BIV
increment to be scheduled before the call.

Unfortunately, this doesn't completely fix g++.abi/cxa_vec.C, but we
do get farther, and what is remaining is some kind of unwind problem.

Tested on alphaev6 and ia64 linux.


r~


        * loop.c (prescan_loop): Set has_multiple_exit_targets for exception
        edges.  Rearrange jump interpretation code to use pc_set.
        (check_dbra_loop): Examine has_multiple_exit_targets not exit_count.

        * sched-deps.c (sched_analyze_insn): Set scheduling barrier for
        all insns that can throw, not just if flag_non_call_exceptions.

        * g++.dg/eh/loop1.C: New.

Index: loop.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/loop.c,v
retrieving revision 1.373
diff -c -p -d -r1.373 loop.c
*** loop.c	2001/12/23 02:16:02	1.373
--- loop.c	2001/12/29 18:41:35
*************** prescan_loop (loop)
*** 2450,2457 ****
    for (insn = NEXT_INSN (start); insn != NEXT_INSN (end);
         insn = NEXT_INSN (insn))
      {
!       if (GET_CODE (insn) == NOTE)
  	{
  	  if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
  	    {
  	      ++level;
--- 2450,2458 ----
    for (insn = NEXT_INSN (start); insn != NEXT_INSN (end);
         insn = NEXT_INSN (insn))
      {
!       switch (GET_CODE (insn))
  	{
+ 	case NOTE:
  	  if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
  	    {
  	      ++level;
*************** prescan_loop (loop)
*** 2459,2482 ****
  	      loop->level++;
  	    }
  	  else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
! 	    {
! 	      --level;
! 	    }
! 	}
!       else if (GET_CODE (insn) == CALL_INSN)
! 	{
  	  if (! CONST_OR_PURE_CALL_P (insn))
  	    {
  	      loop_info->unknown_address_altered = 1;
  	      loop_info->has_nonconst_call = 1;
  	    }
  	  loop_info->has_call = 1;
! 	}
!       else if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)
! 	{
! 	  rtx label1 = NULL_RTX;
! 	  rtx label2 = NULL_RTX;
  
  	  if (volatile_refs_p (PATTERN (insn)))
  	    loop_info->has_volatile = 1;
  
--- 2460,2532 ----
  	      loop->level++;
  	    }
  	  else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
! 	    --level;
! 	  break;
! 
! 	case CALL_INSN:
  	  if (! CONST_OR_PURE_CALL_P (insn))
  	    {
  	      loop_info->unknown_address_altered = 1;
  	      loop_info->has_nonconst_call = 1;
  	    }
  	  loop_info->has_call = 1;
! 	  if (can_throw_internal (insn))
! 	    loop_info->has_multiple_exit_targets = 1;
! 	  break;
! 
! 	case JUMP_INSN:
! 	  if (! loop_info->has_multiple_exit_targets)
! 	    {
! 	      rtx set = pc_set (insn);
! 
! 	      if (set)
! 		{
! 		  rtx label1, label2;
! 
! 		  if (GET_CODE (SET_SRC (set)) == IF_THEN_ELSE)
! 		    {
! 		      label1 = XEXP (SET_SRC (set), 1);
! 		      label2 = XEXP (SET_SRC (set), 2);
! 		    }
! 		  else
! 		    {
! 		      label1 = SET_SRC (PATTERN (insn));
! 		      label2 = NULL_RTX;
! 		    }
! 
! 		  do
! 		    {
! 		      if (label1 && label1 != pc_rtx)
! 			{
! 			  if (GET_CODE (label1) != LABEL_REF)
! 			    {
! 			      /* Something tricky.  */
! 			      loop_info->has_multiple_exit_targets = 1;
! 			      break;
! 			    }
! 			  else if (XEXP (label1, 0) != exit_target
! 				   && LABEL_OUTSIDE_LOOP_P (label1))
! 			    {
! 			      /* A jump outside the current loop.  */
! 			      loop_info->has_multiple_exit_targets = 1;
! 			      break;
! 			    }
! 			}
  
+ 		      label1 = label2;
+ 		      label2 = NULL_RTX;
+ 		    }
+ 		  while (label1);
+ 		}
+ 	      else
+ 		{
+ 		  /* A return, or something tricky.  */
+ 		  loop_info->has_multiple_exit_targets = 1;
+ 		}
+ 	    }
+ 	  /* FALLTHRU */
+ 
+ 	case INSN:
  	  if (volatile_refs_p (PATTERN (insn)))
  	    loop_info->has_volatile = 1;
  
*************** prescan_loop (loop)
*** 2488,2536 ****
  	  note_stores (PATTERN (insn), note_addr_stored, loop_info);
  	  if (! loop_info->first_loop_store_insn && loop_info->store_mems)
  	    loop_info->first_loop_store_insn = insn;
- 
- 	  if (! loop_info->has_multiple_exit_targets
- 	      && GET_CODE (insn) == JUMP_INSN
- 	      && GET_CODE (PATTERN (insn)) == SET
- 	      && SET_DEST (PATTERN (insn)) == pc_rtx)
- 	    {
- 	      if (GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE)
- 		{
- 		  label1 = XEXP (SET_SRC (PATTERN (insn)), 1);
- 		  label2 = XEXP (SET_SRC (PATTERN (insn)), 2);
- 		}
- 	      else
- 		{
- 		  label1 = SET_SRC (PATTERN (insn));
- 		}
  
! 	      do
! 		{
! 		  if (label1 && label1 != pc_rtx)
! 		    {
! 		      if (GET_CODE (label1) != LABEL_REF)
! 			{
! 			  /* Something tricky.  */
! 			  loop_info->has_multiple_exit_targets = 1;
! 			  break;
! 			}
! 		      else if (XEXP (label1, 0) != exit_target
! 			       && LABEL_OUTSIDE_LOOP_P (label1))
! 			{
! 			  /* A jump outside the current loop.  */
! 			  loop_info->has_multiple_exit_targets = 1;
! 			  break;
! 			}
! 		    }
  
! 		  label1 = label2;
! 		  label2 = NULL_RTX;
! 		}
! 	      while (label1);
! 	    }
  	}
-       else if (GET_CODE (insn) == RETURN)
- 	loop_info->has_multiple_exit_targets = 1;
      }
  
    /* Now, rescan the loop, setting up the LOOP_MEMS array.  */
--- 2538,2551 ----
  	  note_stores (PATTERN (insn), note_addr_stored, loop_info);
  	  if (! loop_info->first_loop_store_insn && loop_info->store_mems)
  	    loop_info->first_loop_store_insn = insn;
  
! 	  if (flag_non_call_exceptions && can_throw_internal (insn))
! 	    loop_info->has_multiple_exit_targets = 1;
! 	  break;
  
! 	default:
! 	  break;
  	}
      }
  
    /* Now, rescan the loop, setting up the LOOP_MEMS array.  */
*************** check_dbra_loop (loop, insn_count)
*** 7962,7968 ****
  	 which is reversible.  */
        int reversible_mem_store = 1;
  
!       if (bl->giv_count == 0 && ! loop->exit_count)
  	{
  	  rtx bivreg = regno_reg_rtx[bl->regno];
  	  struct iv_class *blt;
--- 7977,7983 ----
  	 which is reversible.  */
        int reversible_mem_store = 1;
  
!       if (bl->giv_count == 0 && ! loop_info->has_multiple_exit_targets)
  	{
  	  rtx bivreg = regno_reg_rtx[bl->regno];
  	  struct iv_class *blt;
*************** check_dbra_loop (loop, insn_count)
*** 8003,8011 ****
  		  }
  	      }
  
! 	  /* A biv has uses besides counting if it is used to set another biv.  */
  	  for (blt = ivs->list; blt; blt = blt->next)
! 	    if (blt->init_set && reg_mentioned_p (bivreg, SET_SRC (blt->init_set)))
  	      {
  		no_use_except_counting = 0;
  		break;
--- 8018,8028 ----
  		  }
  	      }
  
! 	  /* A biv has uses besides counting if it is used to set
! 	     another biv.  */
  	  for (blt = ivs->list; blt; blt = blt->next)
! 	    if (blt->init_set
! 		&& reg_mentioned_p (bivreg, SET_SRC (blt->init_set)))
  	      {
  		no_use_except_counting = 0;
  		break;
Index: sched-deps.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/sched-deps.c,v
retrieving revision 1.28
diff -c -p -d -r1.28 sched-deps.c
*** sched-deps.c	2001/10/28 20:09:15	1.28
--- sched-deps.c	2001/12/29 18:41:35
*************** sched_analyze_insn (deps, x, insn, loop_
*** 1141,1147 ****
    /* If this instruction can throw an exception, then moving it changes
       where block boundaries fall.  This is mighty confusing elsewhere. 
       Therefore, prevent such an instruction from being moved.  */
!   if (flag_non_call_exceptions && can_throw_internal (insn))
      schedule_barrier_found = 1;
  
    /* Add dependencies if a scheduling barrier was found.  */
--- 1141,1147 ----
    /* If this instruction can throw an exception, then moving it changes
       where block boundaries fall.  This is mighty confusing elsewhere. 
       Therefore, prevent such an instruction from being moved.  */
!   if (can_throw_internal (insn))
      schedule_barrier_found = 1;
  
    /* Add dependencies if a scheduling barrier was found.  */
Index: g++.dg/eh/loop1.C
===================================================================
RCS file: loop1.C
diff -N loop1.C
*** /dev/null	Tue May  5 13:32:27 1998
--- loop1.C	Sat Dec 29 10:56:01 2001
***************
*** 0 ****
--- 1,30 ----
+ // Verify that loop optimization takes into account the exception edge
+ // and does not increment I before the call.
+ // { dg-do run }
+ // { dg-options "-O2" }
+ 
+ extern "C" void abort();
+ static void bar(char *);
+ 
+ static void foo(unsigned long element_count, char *ptr)
+ {
+   unsigned long i;
+   try {
+     for (i = 0; i != element_count; i++, ptr += 8)
+       bar (ptr);
+   }
+   catch (...) {
+     if (i)
+       abort ();
+   }
+ }
+ 
+ static void bar(char *)
+ {
+   throw 1;
+ }
+ 
+ int main()
+ {
+   foo(2, 0);
+ }


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