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]

Problem with HARD_REGNO_CALL_PART_CLOBBERED: some changes


Hello,

I did some work on the HARD_REGNO_CALL_PART_CLOBBERED macro. The original
implementation was incomplete and faulty. I did correct it (partly).

I do not have direct access to the main CVS, so someone else has to review
and/or commit these changes.

I did:
- take CPP 3.0.2 as base.
- decided not to use the clobbered parts for caller-save registers.
- assumed that no instruction pattern generates those hard registers before
  register allocation.
- looked at every use of call_used_regs / call_used_reg_set to decide whether to
  check for partially clobbered regs.

Here are the results:
- a short description on why I did or did not add a check in a certain function.
  Here 'Check' means I added a check, 'No check' means that no check should be
  done. 'No check needed' means that in this phase no such hard register should
  exist.
- a set of patches for some files

If you have any comment or question, feel free to contact me.

        Erwin

All usages of call_used_regs / call_used_reg_set and why I did or did not add
'call_part_used_regs' or 'call_part_used_reg_set'

caller-save.c: init_caller_save
        No check. This checks for registers which are saveable.
caller-save.c: setup_save_areas
        Check. Add a slot for this register, if it is partly clobbered.
        Added abort for problem case instead.
caller-save.c: save_call_clobbered_regs
        Check. Add code to save the register.
        No need. Avoided allocating partly clobbered regs across call.
combine.c: record_dead_and_set_regs
        No check needed. Combine is done before register allocation. There
        should not be a hard register with a wrong mode at this place.
cse.c: cse_main
        No check needed. CSE is done before register allocation. There
        should not be a hard register with a wrong mode at this place.
except.c: dw2_build_landing_pads
        No check. We must consider the EH registers as being clobbered.
explow.c: find_next_ref
        This function appears to be unused. A check would be sensible.
final.c: final_start_function
        No check. Trigger saving of callee saved regs on function entry.
flow.c: mark_regs_live_at_end 
        No check. Marking call saved registers should also mark partially saved
        regs.
flow.c: calculate_global_regs_live
        No check needed. Data flow analysis is done before register allocation.
        There should not be a hard register with a wrong mode at this place.
flow.c: propagate_one_insn
        Check. Used during peephole2 optimization, which is very late.
function.c: aggregate_value_p
        No check. We should not use partially clobbered regs for return values.
gcse.c: compute_hash_table
        No check needed. GCSE is done before register allocation. There
        should not be a hard register with a wrong mode at this place.
gcse.c: compute_kill_rd
        No check needed. GCSE is done before register allocation. There
        should not be a hard register with a wrong mode at this place.
global.c: global_alloc
        No check. This heuristic is good as it is.
global.c: prune_preferences
        No Check. This is only a heuristic. It does influence correctness of
        code.
global.c: find_reg 
        No check for previous use of call_used_reg_set. We have a correct check
        for HARD_REGNO_CALL_PART_CLOBBERED. 
        Added code to avoid assigning partly call clobbered regs across call.
jump.c: thread_jumps
        No check needed. Jump threading is done before register allocation.
        There should not be a hard register with a wrong mode at this place.
local-alloc.c: find_free_reg
        No check. This heuristics is good.
        Added code to avoid assigning partly call clobbered regs across call.
loop.c: loop_invariant_p
        No check needed. Loop optimization is done before register allocation.
        There should not be a hard register with a wrong mode at this place.
loop.c: valid_initial_value_p
        No check needed. Loop optimization is done before register allocation.
        There should not be a hard register with a wrong mode at this place.
recog.c: peep2_find_free_register
        No check. It is ok not to use a call-saved reg.
regmove.c: fixup_match_2
        No check needed. This pass is done before register allocation.
        There should not be a hard register with a wrong mode at this place.
regrename.c: regrename_optimize (normal + regset)
        Check. There was a check added in GCC 3.1.
reload.c: find_equiv_reg 2x
        Check. We cannot move the use of a register across a call clobbering
        part of it.
reload1.c: reload
        No check. Function needs to save the call-saved regs in case of
        non-local label.
reload1.c: reload
        No check. Function needs to save the call-saved regs in case of a setjmp
        call.
reload1.c: reload
        No check. Here we cannot exactly calculate the frame size. Maybe we
        should move this check to another place where the frame size is known
        exactly.  Since I did not allow caller-saving partly clobbered regs, the
        calculation is correct.
reload1.c: find_reg 2x
        No check. This is just a preference.
reload1.c: reload_as_needed (regset)
        Check. Reload reg not valid after function call, if partially clobbered.
        Since information was lost on labels, I did not see harm to lose some
        more information.
reload1.c: reload_combine
        Check. Do not use partly clobbered reg across call. Mark this place as
        "unknown use" because we may both a read or a write access after the
        call.  */
reload1.c: reload_cse_move2add
        Check. Reloading cannot use partly clobbered regs across a call.
        This case was checking whether we can re-use an already
        calculated value. Since information was lost on labels, I did not see
        harm to lose some more information.
resource.c: mark_set_resources
        Check. Done by delayed branch scheduling, which is after register
        allocation.
        Since a setjmp is considered to potentially set all registers, there is
        no harm in assuming partly clobbered regs being set at a normal call.
resource.c: mark_target_live_regs
        No check. The partly clobbered registers have the same status as
        call-saved registers. They remain live at a function call, since part of
        their bits don't change. They do not become live because the caller
        should not have knowledge about the clobbered part of the register.
sched-deps.c: sched_analyze_1
        Check. INSN touching a partly clobbered reg should not be moved across
        a function call.
sched-deps.c: sched_analyze_2
        Check. INSN touching a partly clobbered reg should not be moved across
        a function call.
sched-deps.c: sched_analyze
        Check. INSN touching a partly clobbered reg should not be moved across
        a function call.
        Setting reg_pending_clobbers is acceptable as it only sets some more
        dependency notes.
simplify-rtx.c: cselib_process_insn
        Check. This also done during reload where we must be careful.


Index: basic-block.h
===================================================================
RCS file: /usr/local/cvscpp/archive/gcc/gcc/basic-block.h,v
retrieving revision 1.1.1.2
diff -u -r1.1.1.2 basic-block.h
--- basic-block.h	2001/06/19 12:21:16	1.1.1.2
+++ basic-block.h	2002/03/04 11:12:42
@@ -479,6 +479,9 @@
 #define PROP_SCAN_DEAD_CODE	16	/* Scan for dead code.  */
 #define PROP_AUTOINC		32	/* Create autoinc mem references.  */
 #define PROP_FINAL		63	/* All of the above.  */
+/* This Flag is used to mark partially clobbered registers at a function call.
+   It is used at only one call and will not be stored in a pbi. */
+#define PROP_PART_CLOBBERED	64	
 
 /* Flags for loop discovery.  */
 
Index: caller-save.c
===================================================================
RCS file: /usr/local/cvscpp/archive/gcc/gcc/caller-save.c,v
retrieving revision 1.2
diff -u -r1.2 caller-save.c
--- caller-save.c	2002/02/08 14:58:23	1.2
+++ caller-save.c	2002/03/01 08:25:32
@@ -265,13 +265,19 @@
   for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
     if (reg_renumber[i] >= 0 && REG_N_CALLS_CROSSED (i) > 0)
       {
+	enum machine_mode mode = GET_MODE (regno_reg_rtx[i]);
 	unsigned int regno = reg_renumber[i];
 	unsigned int endregno 
-	  = regno + HARD_REGNO_NREGS (regno, GET_MODE (regno_reg_rtx[i]));
+	  = regno + HARD_REGNO_NREGS (regno, mode);
 
 	for (r = regno; r < endregno; r++)
 	  if (call_used_regs[r])
 	    SET_HARD_REG_BIT (hard_regs_used, r);
+
+	/* Be sure that no partly call clobbered register was allocated across
+	   a call.  */
+	if (HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))
+	  abort();
       }
 
   /* Now run through all the call-used hard-registers and allocate
Index: flow.c
===================================================================
RCS file: /usr/local/cvscpp/archive/gcc/gcc/flow.c,v
retrieving revision 1.2
diff -u -r1.2 flow.c
--- flow.c	2002/02/08 14:58:23	1.2
+++ flow.c	2002/03/06 11:37:48
@@ -3757,6 +3757,16 @@
 			    cond, insn,
 			    pbi->flags & ~(PROP_DEATH_NOTES | PROP_REG_INFO));
 	      }
+	  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+	    if (call_part_used_regs[i] && ! global_regs[i]
+		&& ! fixed_regs[i])
+	      {
+		/* We do not want REG_UNUSED notes for these registers.  */
+		mark_set_1 (pbi, CLOBBER, gen_rtx_REG (reg_raw_mode[i], i),
+			    cond, insn,
+			    ((pbi->flags & ~(PROP_DEATH_NOTES | PROP_REG_INFO))
+			     || PROP_PART_CLOBBERED));
+	      }
 	}
 
       /* If an insn doesn't use CC0, it becomes dead since we assume
@@ -4548,6 +4558,9 @@
       /* Fall through.  */
 
     case REG:
+      if (flags & PROP_PART_CLOBBERED)
+	not_dead |= (unsigned long) REGNO_REG_SET_P (pbi->reg_live, 
+						     REGNO (reg));
       regno_last = regno_first = REGNO (reg);
       if (regno_first < FIRST_PSEUDO_REGISTER)
 	regno_last += HARD_REGNO_NREGS (regno_first, GET_MODE (reg)) - 1;
Index: global.c
===================================================================
RCS file: /usr/local/cvscpp/archive/gcc/gcc/global.c,v
retrieving revision 1.2
diff -u -r1.2 global.c
--- global.c	2002/02/08 14:58:24	1.2
+++ global.c	2002/03/01 13:20:02
@@ -986,7 +986,12 @@
   enum machine_mode mode = PSEUDO_REGNO_MODE (allocno[num].reg);
 
   if (accept_call_clobbered)
-    COPY_HARD_REG_SET (used1, call_fixed_reg_set);
+    {
+      COPY_HARD_REG_SET (used1, call_fixed_reg_set);
+      /* Avoid using register which are partly clobbered. We have problems
+	 in saving their value across a call. */
+      IOR_HARD_REG_SET (used1, call_part_used_reg_set);
+    }	    
   else if (allocno[num].calls_crossed == 0)
     COPY_HARD_REG_SET (used1, fixed_reg_set);
   else
@@ -1076,6 +1081,9 @@
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
 	if (TEST_HARD_REG_BIT (allocno[num].hard_reg_copy_preferences, i)
 	    && HARD_REGNO_MODE_OK (i, mode)
+	    && (allocno[num].calls_crossed == 0
+		|| accept_call_clobbered
+		|| ! HARD_REGNO_CALL_PART_CLOBBERED (i, mode))
 	    && (REGNO_REG_CLASS (i) == REGNO_REG_CLASS (best_reg)
 		|| reg_class_subset_p (REGNO_REG_CLASS (i),
 				       REGNO_REG_CLASS (best_reg))
@@ -1112,6 +1120,9 @@
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
 	if (TEST_HARD_REG_BIT (allocno[num].hard_reg_preferences, i)
 	    && HARD_REGNO_MODE_OK (i, mode)
+	    && (allocno[num].calls_crossed == 0
+		|| accept_call_clobbered
+		|| ! HARD_REGNO_CALL_PART_CLOBBERED (i, mode))
 	    && (REGNO_REG_CLASS (i) == REGNO_REG_CLASS (best_reg)
 		|| reg_class_subset_p (REGNO_REG_CLASS (i),
 				       REGNO_REG_CLASS (best_reg))
@@ -1192,6 +1203,9 @@
 	      /* Don't use a reg no good for this pseudo.  */
 	      && ! TEST_HARD_REG_BIT (used2, regno)
 	      && HARD_REGNO_MODE_OK (regno, mode)
+	      && (allocno[num].calls_crossed == 0
+		  || accept_call_clobbered
+		  || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))
 #ifdef CLASS_CANNOT_CHANGE_MODE
 	      && ! (REG_CHANGES_MODE (allocno[num].reg)
 		    && (TEST_HARD_REG_BIT
Index: hard-reg-set.h
===================================================================
RCS file: /usr/local/cvscpp/archive/gcc/gcc/hard-reg-set.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 hard-reg-set.h
--- hard-reg-set.h	2001/03/28 08:57:10	1.1.1.1
+++ hard-reg-set.h	2002/03/01 13:18:21
@@ -409,6 +409,17 @@
 
 extern HARD_REG_SET call_used_reg_set;
   
+/* Indexed by hard register number, contains 1 if the register could be
+   call-clobbered in one mode. Only set for registers not set in call_used_regs.
+   This array will be calculated from the HARD_REGNO_CALL_PART_CLOBBERED macro.
+   */
+
+extern char call_part_used_regs[FIRST_PSEUDO_REGISTER];
+
+/* The same info as a HARD_REG_SET.  */
+
+extern HARD_REG_SET call_part_used_reg_set;
+  
 /* Registers that we don't want to caller save.  */
 extern HARD_REG_SET losing_caller_save_reg_set;
 
Index: local-alloc.c
===================================================================
RCS file: /usr/local/cvscpp/archive/gcc/gcc/local-alloc.c,v
retrieving revision 1.3
diff -u -r1.3 local-alloc.c
--- local-alloc.c	2002/02/08 14:58:24	1.3
+++ local-alloc.c	2002/03/01 13:20:38
@@ -2182,7 +2182,12 @@
     return -1;
 
   if (accept_call_clobbered)
-    COPY_HARD_REG_SET (used, call_fixed_reg_set);
+    {
+      COPY_HARD_REG_SET (used, call_fixed_reg_set);
+      /* Avoid using register which are partly clobbered. We have problems
+	 in saving their value across a call. */
+      IOR_HARD_REG_SET (used, call_part_used_reg_set);
+    }
   else if (qty[qtyno].n_calls_crossed == 0)
     COPY_HARD_REG_SET (used, fixed_reg_set);
   else
Index: regclass.c
===================================================================
RCS file: /usr/local/cvscpp/archive/gcc/gcc/regclass.c,v
retrieving revision 1.1.1.2
diff -u -r1.1.1.2 regclass.c
--- regclass.c	2001/08/23 10:19:45	1.1.1.2
+++ regclass.c	2002/03/01 13:31:39
@@ -87,6 +87,17 @@
 
 HARD_REG_SET call_used_reg_set;
 
+/* Indexed by hard register number, contains 1 if the register could be
+   call-clobbered in one mode. Only set for registers not set in call_used_regs.
+   This array will be calculated from the HARD_REGNO_CALL_PART_CLOBBERED macro.
+   */
+
+char call_part_used_regs[FIRST_PSEUDO_REGISTER];
+
+/* The same info as a HARD_REG_SET.  */
+
+HARD_REG_SET call_part_used_reg_set;
+  
 /* HARD_REG_SET of registers we want to avoid caller saving.  */
 HARD_REG_SET losing_caller_save_reg_set;
 
@@ -408,6 +419,7 @@
 
   CLEAR_HARD_REG_SET (fixed_reg_set);
   CLEAR_HARD_REG_SET (call_used_reg_set);
+  CLEAR_HARD_REG_SET (call_part_used_reg_set);
   CLEAR_HARD_REG_SET (call_fixed_reg_set);
 
   memcpy (call_fixed_regs, fixed_regs, sizeof call_fixed_regs);
@@ -423,6 +435,15 @@
 
       if (call_used_regs[i])
 	SET_HARD_REG_BIT (call_used_reg_set, i);
+      else
+	for (m = 0; m < (unsigned int) MAX_MACHINE_MODE; m++)
+	  if (HARD_REGNO_CALL_PART_CLOBBERED (i, m))
+	    {
+	      call_part_used_regs[i] = 1;
+	      SET_HARD_REG_BIT (call_part_used_reg_set, i);
+	      break;
+	    }
+
       if (call_fixed_regs[i])
 	SET_HARD_REG_BIT (call_fixed_reg_set, i);
       if (CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (i)))
@@ -744,6 +765,7 @@
 
   SET_HARD_REG_BIT (fixed_reg_set, i);
   SET_HARD_REG_BIT (call_used_reg_set, i);
+  CLEAR_HARD_REG_BIT (call_part_used_reg_set, i);
   SET_HARD_REG_BIT (call_fixed_reg_set, i);
 }
  
Index: regrename.c
===================================================================
RCS file: /usr/local/cvscpp/archive/gcc/gcc/regrename.c,v
retrieving revision 1.1.1.4
diff -u -r1.1.1.4 regrename.c
--- regrename.c	2001/10/26 08:32:47	1.1.1.4
+++ regrename.c	2002/03/01 08:40:41
@@ -324,7 +324,12 @@
 	      /* See whether it accepts all modes that occur in
 		 definition and uses.  */
 	      for (tmp = this; tmp; tmp = tmp->next_use)
-		if (! HARD_REGNO_MODE_OK (new_reg, GET_MODE (*tmp->loc)))
+		if (! HARD_REGNO_MODE_OK (new_reg, GET_MODE (*tmp->loc))
+		    || (tmp->need_caller_save_reg
+			&& ! (HARD_REGNO_CALL_PART_CLOBBERED
+			      (reg, GET_MODE (*tmp->loc)))
+			&& (HARD_REGNO_CALL_PART_CLOBBERED
+			    (new_reg, GET_MODE (*tmp->loc)))))
 		  break;
 	      if (! tmp)
 		{
Index: reload.c
===================================================================
RCS file: /usr/local/cvscpp/archive/gcc/gcc/reload.c,v
retrieving revision 1.5
diff -u -r1.5 reload.c
--- reload.c	2002/02/08 14:58:25	1.5
+++ reload.c	2002/03/01 08:44:29
@@ -6429,12 +6429,14 @@
 
 	  if (regno >= 0 && regno < FIRST_PSEUDO_REGISTER)
 	    for (i = 0; i < nregs; ++i)
-	      if (call_used_regs[regno + i])
+	      if (call_used_regs[regno + i]
+		  || HARD_REGNO_CALL_PART_CLOBBERED( regno + i, mode))
 		return 0;
 
 	  if (valueno >= 0 && valueno < FIRST_PSEUDO_REGISTER)
 	    for (i = 0; i < valuenregs; ++i)
-	      if (call_used_regs[valueno + i])
+	      if (call_used_regs[valueno + i]
+		  || HARD_REGNO_CALL_PART_CLOBBERED( valueno + i, mode))
 		return 0;
 	}
 
Index: reload1.c
===================================================================
RCS file: /usr/local/cvscpp/archive/gcc/gcc/reload1.c,v
retrieving revision 1.4
diff -u -r1.4 reload1.c
--- reload1.c	2002/02/08 14:58:25	1.4
+++ reload1.c	2002/03/01 15:13:35
@@ -4076,7 +4076,10 @@
       /* Don't assume a reload reg is still good after a call insn
 	 if it is a call-used reg.  */
       else if (GET_CODE (insn) == CALL_INSN)
-	AND_COMPL_HARD_REG_SET(reg_reloaded_valid, call_used_reg_set);
+	{
+	  AND_COMPL_HARD_REG_SET(reg_reloaded_valid, call_used_reg_set);
+	  AND_COMPL_HARD_REG_SET(reg_reloaded_valid, call_part_used_reg_set);
+	}
     }
 
   /* Clean up.  */
@@ -8838,6 +8841,14 @@
 		reg_state[r].store_ruid = reload_combine_ruid;
 	      }
 
+	  for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
+	    if (call_part_used_regs[r])
+	      {
+		/* Partly clobbered registers: mark as 'unknown use'.  */
+		reg_state[r].use_index = -1;
+		reg_state[r].store_ruid = reload_combine_ruid;
+	      }
+
 	  for (link = CALL_INSN_FUNCTION_USAGE (insn); link;
 	       link = XEXP (link, 1))
 	    {
@@ -9286,7 +9297,7 @@
 	{
 	  for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)
 	    {
-	      if (call_used_regs[i])
+	      if (call_used_regs[i] || call_part_used_regs[i])
 		/* Reset the information about this register.  */
 		reg_set_luid[i] = 0;
 	    }
Index: resource.c
===================================================================
RCS file: /usr/local/cvscpp/archive/gcc/gcc/resource.c,v
retrieving revision 1.2
diff -u -r1.2 resource.c
--- resource.c	2002/02/08 14:58:25	1.2
+++ resource.c	2002/03/04 08:17:21
@@ -673,7 +673,7 @@
 
 	  res->cc = res->memory = 1;
 	  for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
-	    if (call_used_regs[r] || global_regs[r])
+	    if (call_used_regs[r] || call_part_used_regs[r] || global_regs[r])
 	      SET_HARD_REG_BIT (res->regs, r);
 
 	  /* If X is part of a delay slot sequence, then NEXT should be
Index: sched-deps.c
===================================================================
RCS file: /usr/local/cvscpp/archive/gcc/gcc/sched-deps.c,v
retrieving revision 1.1.1.3
diff -u -r1.1.1.3 sched-deps.c
--- sched-deps.c	2001/08/23 10:19:49	1.1.1.3
+++ sched-deps.c	2002/03/04 12:04:42
@@ -618,7 +618,9 @@
 		SET_REGNO_REG_SET (reg_pending_clobbers, r);
 
 	      /* Function calls clobber all call_used regs.  */
-	      if (global_regs[r] || (code == SET && call_used_regs[r]))
+	      if (global_regs[r] 
+		  || (code == SET 
+		      && (call_used_regs[r] || call_part_used_regs[r])))
 		for (u = deps->last_function_call; u; u = XEXP (u, 1))
 		  add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
 	    }
@@ -783,7 +785,8 @@
 		for (u = deps->reg_last[r].clobbers; u; u = XEXP (u, 1))
 		  add_dependence (insn, XEXP (u, 0), 0);
 
-		if (call_used_regs[r] || global_regs[r])
+		if (call_used_regs[r] || call_part_used_regs[r] 
+		    || global_regs[r])
 		  /* Function calls clobber all call_used regs.  */
 		  for (u = deps->last_function_call; u; u = XEXP (u, 1))
 		    add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
@@ -1311,7 +1314,8 @@
 	  else
 	    {
 	      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-		if (call_used_regs[i] || global_regs[i])
+		if (call_used_regs[i] || call_part_used_regs[i] 
+		    || global_regs[i])
 		  {
 		    for (u = deps->reg_last[i].uses; u; u = XEXP (u, 1))
 		      add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
Index: simplify-rtx.c
===================================================================
RCS file: /usr/local/cvscpp/archive/gcc/gcc/simplify-rtx.c,v
retrieving revision 1.1.1.2
diff -u -r1.1.1.2 simplify-rtx.c
--- simplify-rtx.c	2001/06/19 12:22:04	1.1.1.2
+++ simplify-rtx.c	2002/03/01 11:52:34
@@ -3354,7 +3354,7 @@
   if (GET_CODE (insn) == CALL_INSN)
     {
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-	if (call_used_regs[i])
+	if (call_used_regs[i] || call_part_used_regs[i])
 	  cselib_invalidate_regno (i, VOIDmode);
 
       if (! CONST_CALL_P (insn))



Erwin Unruh, Fujitsu Siemens Computers, C/C++ compiler group


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