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]

RFA: disparage CLASS_LIKELY_SPILLED reloads for fully used register classes; fixes sh-elf build failure


The function return value register issue rears its ugly head again,
causing a build failure for newlib (vfprintf.c -m4-single-only) on sh-elf.

The failure occurs for this insn:

(insn:HI 1216 1215 6852 126 ../../../../../../srcw/newlib/libc/stdio/vfprintf.c:1269 (set (reg:SI 147 t)
        (eq:SI (reg/v:SI 163 [ ch ])
            (const_int 103 [0x67]))) 1 {cmpeqsi_t} (insn_list:REG_DEP_OUTPUT 1211 (nil))
    (nil))

r0 is live because it is set by a function call shortly before this function,
and copied into another register shortly afterwards.

This is the cmpeqsi_t pattern:

(define_insn "cmpeqsi_t"
  [(set (reg:SI T_REG)
        (eq:SI (match_operand:SI 0 "arith_reg_operand" "r,z,r")
               (match_operand:SI 1 "arith_operand" "N,rI08,r")))]
  "TARGET_SH1"
  "@
        tst     %0,%0
        cmp/eq  %1,%0
        cmp/eq  %1,%0"
   [(set_attr "type" "mt_group")])

That is, we could use the r/r alternative, but it is mentioned after z/I08
because in general, using the alternative using r0 and an immediate is
preferrable.  If r/r came first/ z/I08 would almost never be used.

The following patch fixes the problem by disparaging reloads that need
CLASS_LIKELY_SPILLED registers of a class that is already fully used;
bootstrapping / regtesting on i686-pc-linux-gnu native /
i686-pc-linux-gnu X sh-elf .

2004-03-01  J"orn Rennecke <joern.rennecke@superh.com>

	* reload.h (find_reloads): Declare in insn_chain block.  First
	argument is a struct insn_chain *.  Changed all callers.
	* reload.c (no_free_reg): New function.
	(find_reloads): First argument is a struct insn_chain *.
	For CLASS_LIKLY_SPILLED_P registers, disparage win_reg strategy if
	there is no free register available.

Index: reload.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/reload.h,v
retrieving revision 1.45
diff -p -r1.45 reload.h
*** reload.h	6 Jul 2003 09:56:07 -0000	1.45
--- reload.h	1 Mar 2004 20:32:17 -0000
*************** extern struct insn_chain *reload_insn_ch
*** 250,255 ****
--- 250,260 ----
  extern struct insn_chain *new_insn_chain (void);
  
  extern void compute_use_by_pseudos (HARD_REG_SET *, regset);
+ 
+ /* Search the body of INSN for values that need reloading and record them
+    with push_reload.  REPLACE nonzero means record also where the values occur
+    so that subst_reloads can be used.  */
+ extern int find_reloads (struct insn_chain *, int, int, int, short *);
  #endif
  
  /* Functions from reload.c:  */
*************** extern int operands_match_p (rtx, rtx);
*** 279,289 ****
  
  /* Return 1 if altering OP will not modify the value of CLOBBER.  */
  extern int safe_from_earlyclobber (rtx, rtx);
- 
- /* Search the body of INSN for values that need reloading and record them
-    with push_reload.  REPLACE nonzero means record also where the values occur
-    so that subst_reloads can be used.  */
- extern int find_reloads (rtx, int, int, int, short *);
  
  /* Compute the sum of X and Y, making canonicalizations assumed in an
     address, namely: sum constant integers, surround the sum of two
--- 284,289 ----
Index: reload1.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/reload1.c,v
retrieving revision 1.430
diff -p -r1.430 reload1.c
*** reload1.c	25 Feb 2004 12:42:26 -0000	1.430
--- reload1.c	1 Mar 2004 20:32:17 -0000
*************** calculate_needs_all_insns (int global)
*** 1458,1464 ****
  	    did_elimination = eliminate_regs_in_insn (insn, 0);
  
  	  /* Analyze the instruction.  */
! 	  operands_changed = find_reloads (insn, 0, spill_indirect_levels,
  					   global, spill_reg_order);
  
  	  /* If a no-op set needs more than one reload, this is likely
--- 1458,1464 ----
  	    did_elimination = eliminate_regs_in_insn (insn, 0);
  
  	  /* Analyze the instruction.  */
! 	  operands_changed = find_reloads (chain, 0, spill_indirect_levels,
  					   global, spill_reg_order);
  
  	  /* If a no-op set needs more than one reload, this is likely
*************** reload_as_needed (int live_known)
*** 3858,3864 ****
  	      memset (reg_has_output_reload, 0, max_regno);
  	      CLEAR_HARD_REG_SET (reg_is_output_reload);
  
! 	      find_reloads (insn, 1, spill_indirect_levels, live_known,
  			    spill_reg_order);
  	    }
  
--- 3858,3864 ----
  	      memset (reg_has_output_reload, 0, max_regno);
  	      CLEAR_HARD_REG_SET (reg_is_output_reload);
  
! 	      find_reloads (chain, 1, spill_indirect_levels, live_known,
  			    spill_reg_order);
  	    }
  
Index: reload.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/reload.c,v
retrieving revision 1.238
diff -p -r1.238 reload.c
*** reload.c	24 Feb 2004 16:58:35 -0000	1.238
--- reload.c	1 Mar 2004 20:32:17 -0000
*************** a register with any other reload.  */
*** 96,104 ****
  #include "expr.h"
  #include "optabs.h"
  #include "recog.h"
- #include "reload.h"
  #include "regs.h"
  #include "hard-reg-set.h"
  #include "flags.h"
  #include "real.h"
  #include "output.h"
--- 96,105 ----
  #include "expr.h"
  #include "optabs.h"
  #include "recog.h"
  #include "regs.h"
  #include "hard-reg-set.h"
+ #include "basic-block.h"
+ #include "reload.h"
  #include "flags.h"
  #include "real.h"
  #include "output.h"
*************** safe_from_earlyclobber (rtx op, rtx clob
*** 2448,2453 ****
--- 2449,2473 ----
    early_data = decompose (clobber);
    return immune_p (op, clobber, early_data);
  }
+ 
+ /* Check if there are no registers in CLASS that is not marked as live in
+    *CACHE_LIVE.  If *CHAIN is nonzero, first calculate *CACHE_LIVE from
+    (*CHAIN)->life_throughout, and zero *CHAIN.
+   Return nonzero if there is no free register, 0 if there is.  */
+ static int
+ no_free_reg (enum reg_class class, struct insn_chain **chain,
+ 	      HARD_REG_SET *cache_live)
+ {
+   if (*chain)
+     {
+       REG_SET_TO_HARD_REG_SET (*cache_live, &(*chain)->live_throughout);
+       *chain = 0;
+     }
+   GO_IF_HARD_REG_SUBSET (reg_class_contents[class], *cache_live, loose);
+   return 0;
+  loose:
+   return 1;
+ }
  
  /* Main entry point of this file: search the body of INSN
     for values that need reloading and record them with push_reload.
*************** safe_from_earlyclobber (rtx op, rtx clob
*** 2472,2480 ****
     commutative operands, reg_equiv_address substitution, or whatever.  */
  
  int
! find_reloads (rtx insn, int replace, int ind_levels, int live_known,
! 	      short *reload_reg_p)
  {
    int insn_code_number;
    int i, j;
    int noperands;
--- 2492,2501 ----
     commutative operands, reg_equiv_address substitution, or whatever.  */
  
  int
! find_reloads (struct insn_chain *chain, int replace, int ind_levels,
! 	      int live_known, short *reload_reg_p)
  {
+   rtx insn = chain->insn;
    int insn_code_number;
    int i, j;
    int noperands;
*************** find_reloads (rtx insn, int replace, int
*** 2524,2529 ****
--- 2545,2551 ----
    int goal_earlyclobber = 0, this_earlyclobber;
    enum machine_mode operand_mode[MAX_RECOG_OPERANDS];
    int retval = 0;
+   HARD_REG_SET cache_live;
  
    this_insn = insn;
    n_reloads = 0;
*************** find_reloads (rtx insn, int replace, int
*** 2712,2718 ****
  		  || GET_CODE (recog_data.operand[i]) == PLUS))
  	    {
  	      INSN_CODE (insn) = -1;
! 	      retval = find_reloads (insn, replace, ind_levels, live_known,
  				     reload_reg_p);
  	      return retval;
  	    }
--- 2734,2740 ----
  		  || GET_CODE (recog_data.operand[i]) == PLUS))
  	    {
  	      INSN_CODE (insn) = -1;
! 	      retval = find_reloads (chain, replace, ind_levels, live_known,
  				     reload_reg_p);
  	      return retval;
  	    }
*************** find_reloads (rtx insn, int replace, int
*** 3348,3355 ****
  
  	  /* If this operand could be handled with a reg,
  	     and some reg is allowed, then this operand can be handled.  */
! 	  if (winreg && this_alternative[i] != (int) NO_REGS)
! 	    badop = 0;
  
  	  /* Record which operands fit this alternative.  */
  	  this_alternative_earlyclobber[i] = earlyclobber;
--- 3370,3390 ----
  
  	  /* If this operand could be handled with a reg,
  	     and some reg is allowed, then this operand can be handled.  */
! 	  if (winreg && this_alternative[i] != (int) NO_REGS && badop)
! 	    {
! 	      badop = 0;
! 	      /* If all registers in the register class are already taken
! 		 by hard registers, then we can't reload this at all.
! 		 This can happen for R0_REGS on the SH when a function
! 		 return value is live.  On the other hand, if we just happen
! 		 to have used up all the registers with non-essential variable
! 		 assignments, we could still win if we kick out one of these
! 		 variables, and there might be no other alternative.  So
! 		 we just disparage this alternative.  */
! 	      if (CLASS_LIKELY_SPILLED_P (this_alternative[i])
! 		  && no_free_reg (this_alternative[i], &chain, &cache_live))
! 		losers += 2;
! 	    }
  
  	  /* Record which operands fit this alternative.  */
  	  this_alternative_earlyclobber[i] = earlyclobber;


Ironically, though, after sched2 the original problem turns out to have been
caused by unfortunate scheduling of the copy of the return value:

        mov.l   .L841,r0
        jsr     @r0
        fmov    fr12,fr4
        mov.w   .L852,r7
        mov     #103,r1
        mov     r0,r5
        add     r14,r7
        mov.l   @(0,r7),r7
        cmp/eq  r1,r7
        mov     #-1,r1
        negc    r1,r2
        mov     r7,r0
        cmp/eq  #71,r0

However, it don't think that an approach based on this is as robust as
preferring an alternative that doesn't use a CLASS_LIKELY_SPILLED
class that is already fully used.


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