Commit 4554e20d by Jeff Law

caller-save.c (insert_save_restore): Break this function up into new functions insert_restore...

�
	* caller-save.c (insert_save_restore): Break this function up
	into new functions insert_restore, insert_save and insert_one_insn.
	All callers changed.
	(insert_restore): New function, mostly broken out of
	insert_save_restore.
	(insert_save): Likewise.
	(insert_one_insn): Likewise.
	(restore_referenced_regs): New argument BLOCK.  All callers changed.
	(save_call_clobbered_regs): Don't keep track of basic block boundaries
	in this function, do it in insert_one_insn instead.

From-SVN: r22754
parent f670c074
...@@ -82,9 +82,14 @@ int n_regs_saved; ...@@ -82,9 +82,14 @@ int n_regs_saved;
static void set_reg_live PROTO((rtx, rtx)); static void set_reg_live PROTO((rtx, rtx));
static void clear_reg_live PROTO((rtx)); static void clear_reg_live PROTO((rtx));
static void restore_referenced_regs PROTO((rtx, rtx, enum machine_mode)); static void restore_referenced_regs PROTO((rtx, rtx, enum machine_mode,
static int insert_save_restore PROTO((rtx, int, int, int));
static int insert_restore PROTO((rtx, int, int,
enum machine_mode, int, int));
static int insert_save PROTO((rtx, int, int,
enum machine_mode, int)); enum machine_mode, int));
static void insert_one_insn PROTO((rtx, int, enum rtx_code,
enum machine_mode, rtx, int));
/* Initialize for caller-save. /* Initialize for caller-save.
...@@ -358,7 +363,6 @@ save_call_clobbered_regs (insn_mode) ...@@ -358,7 +363,6 @@ save_call_clobbered_regs (insn_mode)
for (b = 0; b < n_basic_blocks; b++) for (b = 0; b < n_basic_blocks; b++)
{ {
regset regs_live = basic_block_live_at_start[b]; regset regs_live = basic_block_live_at_start[b];
rtx prev_block_last = PREV_INSN (basic_block_head[b]);
int i, j; int i, j;
int regno; int regno;
...@@ -399,7 +403,7 @@ save_call_clobbered_regs (insn_mode) ...@@ -399,7 +403,7 @@ save_call_clobbered_regs (insn_mode)
any of them. We must restore them before the insn if so. */ any of them. We must restore them before the insn if so. */
if (n_regs_saved) if (n_regs_saved)
restore_referenced_regs (PATTERN (insn), insn, insn_mode); restore_referenced_regs (PATTERN (insn), insn, insn_mode, b);
/* NB: the normal procedure is to first enliven any /* NB: the normal procedure is to first enliven any
registers set by insn, then deaden any registers that registers set by insn, then deaden any registers that
...@@ -449,8 +453,7 @@ save_call_clobbered_regs (insn_mode) ...@@ -449,8 +453,7 @@ save_call_clobbered_regs (insn_mode)
/* It must not be set by this instruction. */ /* It must not be set by this instruction. */
&& ! TEST_HARD_REG_BIT (this_call_sets, regno) && ! TEST_HARD_REG_BIT (this_call_sets, regno)
&& ! TEST_HARD_REG_BIT (hard_regs_saved, regno)) && ! TEST_HARD_REG_BIT (hard_regs_saved, regno))
regno += insert_save_restore (insn, 1, regno, regno += insert_save (insn, 1, regno, insn_mode, b);
insn_mode, 0);
/* Put the information for this CALL_INSN on top of what /* Put the information for this CALL_INSN on top of what
we already had. */ we already had. */
...@@ -489,13 +492,9 @@ save_call_clobbered_regs (insn_mode) ...@@ -489,13 +492,9 @@ save_call_clobbered_regs (insn_mode)
if (n_regs_saved) if (n_regs_saved)
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (TEST_HARD_REG_BIT (hard_regs_need_restore, regno)) if (TEST_HARD_REG_BIT (hard_regs_need_restore, regno))
regno += insert_save_restore ((GET_CODE (insn) == JUMP_INSN regno += insert_restore (insn, GET_CODE (insn) == JUMP_INSN,
? insn : NEXT_INSN (insn)), 0, regno, insn_mode,
regno, insn_mode, MOVE_MAX / UNITS_PER_WORD); MOVE_MAX / UNITS_PER_WORD, b);
/* If we added any insns at the start of the block, update the start
of the block to point at those insns. */
basic_block_head[b] = NEXT_INSN (prev_block_last);
} }
} }
...@@ -562,10 +561,11 @@ clear_reg_live (reg) ...@@ -562,10 +561,11 @@ clear_reg_live (reg)
INSN_MODE is the mode to assign to any insns that we add. */ INSN_MODE is the mode to assign to any insns that we add. */
static void static void
restore_referenced_regs (x, insn, insn_mode) restore_referenced_regs (x, insn, insn_mode, block)
rtx x; rtx x;
rtx insn; rtx insn;
enum machine_mode insn_mode; enum machine_mode insn_mode;
int block;
{ {
enum rtx_code code = GET_CODE (x); enum rtx_code code = GET_CODE (x);
char *fmt; char *fmt;
...@@ -584,11 +584,11 @@ restore_referenced_regs (x, insn, insn_mode) ...@@ -584,11 +584,11 @@ restore_referenced_regs (x, insn, insn_mode)
if (regno >= FIRST_PSEUDO_REGISTER if (regno >= FIRST_PSEUDO_REGISTER
&& reg_equiv_mem[regno] != 0) && reg_equiv_mem[regno] != 0)
restore_referenced_regs (XEXP (reg_equiv_mem[regno], 0), restore_referenced_regs (XEXP (reg_equiv_mem[regno], 0),
insn, insn_mode); insn, insn_mode, block);
else if (regno >= FIRST_PSEUDO_REGISTER else if (regno >= FIRST_PSEUDO_REGISTER
&& reg_equiv_address[regno] != 0) && reg_equiv_address[regno] != 0)
restore_referenced_regs (reg_equiv_address[regno], restore_referenced_regs (reg_equiv_address[regno],
insn, insn_mode); insn, insn_mode, block);
/* Otherwise if this is a hard register, restore any piece of it that /* Otherwise if this is a hard register, restore any piece of it that
is currently saved. */ is currently saved. */
...@@ -597,13 +597,13 @@ restore_referenced_regs (x, insn, insn_mode) ...@@ -597,13 +597,13 @@ restore_referenced_regs (x, insn, insn_mode)
{ {
int numregs = HARD_REGNO_NREGS (regno, GET_MODE (x)); int numregs = HARD_REGNO_NREGS (regno, GET_MODE (x));
/* Save at most SAVEREGS at a time. This can not be larger than /* Save at most SAVEREGS at a time. This can not be larger than
MOVE_MAX, because that causes insert_save_restore to fail. */ MOVE_MAX, because that causes insert_restore to fail. */
int saveregs = MIN (numregs, MOVE_MAX / UNITS_PER_WORD); int saveregs = MIN (numregs, MOVE_MAX / UNITS_PER_WORD);
int endregno = regno + numregs; int endregno = regno + numregs;
for (i = regno; i < endregno; i++) for (i = regno; i < endregno; i++)
if (TEST_HARD_REG_BIT (hard_regs_need_restore, i)) if (TEST_HARD_REG_BIT (hard_regs_need_restore, i))
i += insert_save_restore (insn, 0, i, insn_mode, saveregs); i += insert_restore (insn, 1, i, insn_mode, saveregs, block);
} }
return; return;
...@@ -613,18 +613,18 @@ restore_referenced_regs (x, insn, insn_mode) ...@@ -613,18 +613,18 @@ restore_referenced_regs (x, insn, insn_mode)
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{ {
if (fmt[i] == 'e') if (fmt[i] == 'e')
restore_referenced_regs (XEXP (x, i), insn, insn_mode); restore_referenced_regs (XEXP (x, i), insn, insn_mode, block);
else if (fmt[i] == 'E') else if (fmt[i] == 'E')
for (j = XVECLEN (x, i) - 1; j >= 0; j--) for (j = XVECLEN (x, i) - 1; j >= 0; j--)
restore_referenced_regs (XVECEXP (x, i, j), insn, insn_mode); restore_referenced_regs (XVECEXP (x, i, j), insn, insn_mode, block);
} }
} }
/* Insert a sequence of insns to save or restore, SAVE_P says which, /* Insert a sequence of insns to restore REGNO. Place these insns in front
REGNO. Place these insns in front of INSN. INSN_MODE is the mode of or after INSN (determined by BEFORE_P). INSN_MODE is the mode
to assign to these insns. MAXRESTORE is the maximum number of registers to assign to these insns. MAXRESTORE is the maximum number of registers
which should be restored during this call (when SAVE_P == 0). It should which should be restored during this call. It should never be less than
never be less than 1 since we only work with entire registers. 1 since we only work with entire registers.
Note that we have verified in init_caller_save that we can do this Note that we have verified in init_caller_save that we can do this
with a simple SET, so use it. Set INSN_CODE to what we save there with a simple SET, so use it. Set INSN_CODE to what we save there
...@@ -635,16 +635,19 @@ restore_referenced_regs (x, insn, insn_mode) ...@@ -635,16 +635,19 @@ restore_referenced_regs (x, insn, insn_mode)
Return the extra number of registers saved. */ Return the extra number of registers saved. */
static int static int
insert_save_restore (insn, save_p, regno, insn_mode, maxrestore) insert_restore (insn, before_p, regno, insn_mode, maxrestore, block)
rtx insn; rtx insn;
int save_p; int before_p;
int regno; int regno;
enum machine_mode insn_mode; enum machine_mode insn_mode;
int maxrestore; int maxrestore;
int block;
{ {
rtx pat = NULL_RTX; rtx pat = NULL_RTX;
enum insn_code code = CODE_FOR_nothing; enum insn_code code = CODE_FOR_nothing;
int numregs = 0; int numregs = 0;
int i, j, k;
int ok;
/* A common failure mode if register status is not correct in the RTL /* A common failure mode if register status is not correct in the RTL
is for this routine to be called with a REGNO we didn't expect to is for this routine to be called with a REGNO we didn't expect to
...@@ -656,108 +659,159 @@ insert_save_restore (insn, save_p, regno, insn_mode, maxrestore) ...@@ -656,108 +659,159 @@ insert_save_restore (insn, save_p, regno, insn_mode, maxrestore)
if (regno_save_mem[regno][1] == 0) if (regno_save_mem[regno][1] == 0)
abort (); abort ();
#ifdef HAVE_cc0
/* If INSN references CC0, put our insns in front of the insn that sets
CC0. This is always safe, since the only way we could be passed an
insn that references CC0 is for a restore, and doing a restore earlier
isn't a problem. We do, however, assume here that CALL_INSNs don't
reference CC0. Guard against non-INSN's like CODE_LABEL. */
if ((GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)
&& reg_referenced_p (cc0_rtx, PATTERN (insn)))
insn = prev_nonnote_insn (insn);
#endif
/* Get the pattern to emit and update our status. */ /* Get the pattern to emit and update our status. */
if (save_p)
/* See if we can restore `maxrestore' registers at once. Work
backwards to the single register case. */
for (i = maxrestore; i > 0; i--)
{ {
int i, j, k; ok = 1;
int ok; if (regno_save_mem[regno][i])
for (j = 0; j < i; j++)
{
if (! TEST_HARD_REG_BIT (hard_regs_need_restore, regno + j))
ok = 0;
}
else
continue;
/* Must do this one restore at a time */
if (! ok)
continue;
pat = gen_rtx_SET (VOIDmode,
gen_rtx_REG (GET_MODE (regno_save_mem[regno][i]),
regno),
regno_save_mem[regno][i]);
code = reg_restore_code[regno][i];
/* See if we can save several registers with a single instruction. /* Clear status for all registers we restored. */
Work backwards to the single register case. */ for (k = 0; k < i; k++)
for (i = MOVE_MAX / UNITS_PER_WORD; i > 0; i--)
{ {
ok = 1; CLEAR_HARD_REG_BIT (hard_regs_need_restore, regno + k);
if (regno_save_mem[regno][i] != 0) n_regs_saved--;
for (j = 0; j < i; j++) }
{
if (! call_used_regs[regno + j] || call_fixed_regs[regno + j]
|| ! TEST_HARD_REG_BIT (hard_regs_live, regno + j)
|| TEST_HARD_REG_BIT (hard_regs_saved, regno + j))
ok = 0;
}
else
continue;
/* Must do this one save at a time */ numregs = i;
if (! ok) break;
continue; }
pat = gen_rtx_SET (VOIDmode, regno_save_mem[regno][i], insert_one_insn (insn, before_p, code, insn_mode, pat, block);
gen_rtx_REG (GET_MODE (regno_save_mem[regno][i]),
regno));
code = reg_save_code[regno][i];
/* Set hard_regs_saved for all the registers we saved. */ /* Tell our callers how many extra registers we saved/restored */
for (k = 0; k < i; k++) return numregs - 1;
{ }
SET_HARD_REG_BIT (hard_regs_saved, regno + k);
SET_HARD_REG_BIT (hard_regs_need_restore, regno + k);
n_regs_saved++;
}
numregs = i; /* Like insert_restore, but emit code to save REGNO. */
break; static int
} insert_save (insn, before_p, regno, insn_mode, block)
} rtx insn;
else int before_p;
{ int regno;
int i, j, k; enum machine_mode insn_mode;
int ok; int block;
{
rtx pat = NULL_RTX;
enum insn_code code = CODE_FOR_nothing;
int numregs = 0;
int i, j, k;
int ok;
/* See if we can restore `maxrestore' registers at once. Work /* A common failure mode if register status is not correct in the RTL
backwards to the single register case. */ is for this routine to be called with a REGNO we didn't expect to
for (i = maxrestore; i > 0; i--) save. That will cause us to write an insn with a (nil) SET_DEST
{ or SET_SRC. Instead of doing so and causing a crash later, check
ok = 1; for this common case and abort here instead. This will remove one
if (regno_save_mem[regno][i]) step in debugging such problems. */
for (j = 0; j < i; j++)
{
if (! TEST_HARD_REG_BIT (hard_regs_need_restore, regno + j))
ok = 0;
}
else
continue;
/* Must do this one restore at a time */ if (regno_save_mem[regno][1] == 0)
if (! ok) abort ();
continue;
pat = gen_rtx_SET (VOIDmode,
gen_rtx_REG (GET_MODE (regno_save_mem[regno][i]),
regno),
regno_save_mem[regno][i]);
code = reg_restore_code[regno][i];
/* Get the pattern to emit and update our status. */
/* Clear status for all registers we restored. */ /* See if we can save several registers with a single instruction.
for (k = 0; k < i; k++) Work backwards to the single register case. */
{ for (i = MOVE_MAX / UNITS_PER_WORD; i > 0; i--)
CLEAR_HARD_REG_BIT (hard_regs_need_restore, regno + k); {
n_regs_saved--; ok = 1;
} if (regno_save_mem[regno][i] != 0)
for (j = 0; j < i; j++)
{
if (! call_used_regs[regno + j] || call_fixed_regs[regno + j]
|| ! TEST_HARD_REG_BIT (hard_regs_live, regno + j)
|| TEST_HARD_REG_BIT (hard_regs_saved, regno + j))
ok = 0;
}
else
continue;
numregs = i; /* Must do this one save at a time */
break; if (! ok)
} continue;
pat = gen_rtx_SET (VOIDmode, regno_save_mem[regno][i],
gen_rtx_REG (GET_MODE (regno_save_mem[regno][i]),
regno));
code = reg_save_code[regno][i];
/* Set hard_regs_saved for all the registers we saved. */
for (k = 0; k < i; k++)
{
SET_HARD_REG_BIT (hard_regs_saved, regno + k);
SET_HARD_REG_BIT (hard_regs_need_restore, regno + k);
n_regs_saved++;
}
numregs = i;
break;
} }
/* Emit the insn and set the code and mode. */
insn = emit_insn_before (pat, insn); insert_one_insn (insn, before_p, code, insn_mode, pat, block);
PUT_MODE (insn, insn_mode);
INSN_CODE (insn) = code;
/* Tell our callers how many extra registers we saved/restored */ /* Tell our callers how many extra registers we saved/restored */
return numregs - 1; return numregs - 1;
} }
/* Emit one insn, set the code and mode, and update basic block
boundaries. */
static void
insert_one_insn (insn, before_p, code, mode, pat, block)
rtx insn;
int before_p;
enum rtx_code code;
enum machine_mode mode;
rtx pat;
int block;
{
rtx insert_point = insn;
rtx new;
#ifdef HAVE_cc0
/* If INSN references CC0, put our insns in front of the insn that sets
CC0. This is always safe, since the only way we could be passed an
insn that references CC0 is for a restore, and doing a restore earlier
isn't a problem. We do, however, assume here that CALL_INSNs don't
reference CC0. Guard against non-INSN's like CODE_LABEL. */
if ((GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)
&& before_p
&& reg_referenced_p (cc0_rtx, PATTERN (insn)))
insert_point = prev_nonnote_insn (insn);
#endif
if (before_p)
{
new = emit_insn_before (pat, insert_point);
if (insert_point == basic_block_head[block])
basic_block_head[block] = new;
}
else
{
new = emit_insn_after (pat, insert_point);
if (insert_point == basic_block_end[block])
basic_block_end[block] = new;
}
PUT_MODE (new, mode);
INSN_CODE (new) = code;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment