This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Problem with HARD_REGNO_CALL_PART_CLOBBERED: some changes
- From: "Unruh, Erwin" <Erwin dot Unruh at fujitsu-siemens dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: "Unruh, Erwin" <Erwin dot Unruh at fujitsu-siemens dot com>
- Date: Wed, 6 Mar 2002 13:19:56 +0100
- Subject: 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