This is the mail archive of the gcc@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]

Bug fix for combinable_i3pat


While testing the d10v port (that's one to be submitted) in egcs,
I found a problem with my combinable_i3pat patch from December.

When there is a function call that receives several arguments in
hard registers, and combine combines a somewhat complex insn with
any but the first argument register setting insns, reload might
allocate a spill register for the combined insn in one of the
argument registers that have been previously set.
This had been covered by the previous check, even though this
was not documented and presumably not even anticipated.

Note that when we allow the first arguemnt register setting insn for
a call to be combined, it might end up as a part of a PARALLEL with multiple
SETs, while following non-combined argument register setting insns should
have only a single SET.

Here is a patch:

Tue Oct 21 15:02:58 1997  J"orn Rennecke <amylaar@cygnus.co.uk>

	* combine.c (sets_function_arg_p): New function.
	(combinable_i3pat): Check if combining with any but the first
	argument register setting insn for a function call.

*** combine.c-971021	Wed Oct 22 11:21:11 1997
--- combine.c	Wed Oct 22 11:37:33 1997
*************** can_combine_p (insn, i3, pred, succ, pde
*** 1048,1053 ****
--- 1048,1090 ----
    return 1;
  }
  
+ /* Check if PAT is an insn - or a part of it - used to set up an
+    argument for a function in a hard register.  */
+ 
+ static int
+ sets_function_arg_p (pat)
+      rtx pat;
+ {
+   for (;;)
+     switch (GET_CODE (pat))
+       {
+       case INSN:
+ 	pat = PATTERN (pat);
+ 	continue;
+       case PARALLEL:
+ 	{
+ 	  int i;
+ 	  for (i = XVECLEN (pat, 0); --i >= 0;)
+ 	    if (sets_function_arg_p (XVECEXP (pat, 0, i)))
+ 	      return 1;
+ 	  return 0;
+ 	}
+       case SET:
+ 	{
+ 	  rtx inner_dest = SET_DEST (pat);
+ 	  while (GET_CODE (inner_dest) == STRICT_LOW_PART
+ 		 || GET_CODE (inner_dest) == SUBREG
+ 		 || GET_CODE (inner_dest) == ZERO_EXTRACT)
+ 	    inner_dest = XEXP (inner_dest, 0);
+ 	  return (GET_CODE (inner_dest) == REG
+ 		  && REGNO (inner_dest) < FIRST_PSEUDO_REGISTER
+ 		  && FUNCTION_ARG_REGNO_P (REGNO (inner_dest)));
+ 	}
+       default:
+ 	return 0;
+       }
+ }
+ 
  /* LOC is the location within I3 that contains its pattern or the component
     of a PARALLEL of the pattern.  We validate that it is valid for combining.
  
*************** combinable_i3pat (i3, loc, i2dest, i1des
*** 1149,1161 ****
  	     Moreover, we can't test all_adjacent; we don't have to, since
  	     this instruction will stay in place, thus we are not considering
  	     to increase the lifetime of INNER_DEST.  */
  	  || (GET_CODE (inner_dest) == REG
  	      && REGNO (inner_dest) < FIRST_PSEUDO_REGISTER
  	      && (! HARD_REGNO_MODE_OK (REGNO (inner_dest),
  					GET_MODE (inner_dest))
  		 || (SMALL_REGISTER_CLASSES && GET_CODE (src) != CALL
  		     && ! REG_USERVAR_P (inner_dest)
! 		     && FUNCTION_VALUE_REGNO_P (REGNO (inner_dest)))))
  	  || (i1_not_in_src && reg_overlap_mentioned_p (i1dest, src)))
  	return 0;
  
--- 1186,1208 ----
  	     Moreover, we can't test all_adjacent; we don't have to, since
  	     this instruction will stay in place, thus we are not considering
  	     to increase the lifetime of INNER_DEST.  */
+ 	  /* However, there is another problem we have to look out for:
+ 	     if this insn sets a function argument, combining it with
+ 	     something that might need a spill could clobber a previous
+ 	     function argument; the all_adjacent test in can_combine_p
+ 	     also checks this; here, we do a more specific test for
+ 	     this case.  */
+ 	     
  	  || (GET_CODE (inner_dest) == REG
  	      && REGNO (inner_dest) < FIRST_PSEUDO_REGISTER
  	      && (! HARD_REGNO_MODE_OK (REGNO (inner_dest),
  					GET_MODE (inner_dest))
  		 || (SMALL_REGISTER_CLASSES && GET_CODE (src) != CALL
  		     && ! REG_USERVAR_P (inner_dest)
! 		     && (FUNCTION_VALUE_REGNO_P (REGNO (inner_dest))
! 			 || (FUNCTION_ARG_REGNO_P (REGNO (inner_dest))
! 			     && i3 && single_set (i3)
! 			     && sets_function_arg_p (prev_nonnote_insn (i3)))))))
  	  || (i1_not_in_src && reg_overlap_mentioned_p (i1dest, src)))
  	return 0;
  


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