function.c (diddle_return_value): New.
* function.c (diddle_return_value): New. (expand_function_end): Use it. * stmt.c (expand_null_return): Likewise. (expand_value_return): Likewise. * reg-stack.c (subst_stack_regs_pat): Handle clobbers at top-level. * reload1.c (reload): Don't remove return value clobbers. From-SVN: r30401
This commit is contained in:
parent
49886fe1ce
commit
bd695e1e9d
@ -1,3 +1,14 @@
|
||||
Fri Nov 5 19:38:14 1999 Richard Henderson <rth@cygnus.com>
|
||||
|
||||
* function.c (diddle_return_value): New.
|
||||
(expand_function_end): Use it.
|
||||
* stmt.c (expand_null_return): Likewise.
|
||||
(expand_value_return): Likewise.
|
||||
|
||||
* reg-stack.c (subst_stack_regs_pat): Handle clobbers at top-level.
|
||||
|
||||
* reload1.c (reload): Don't remove return value clobbers.
|
||||
|
||||
Thu Nov 4 13:33:46 1999 Richard Henderson <rth@cygnus.com>
|
||||
|
||||
* rtl.c (read_rtx): Use fatal_with_file_and_line not fatal.
|
||||
|
@ -6150,6 +6150,36 @@ expand_dummy_function_end ()
|
||||
current_function = 0;
|
||||
}
|
||||
|
||||
/* Emit CODE for each register of the return value. Useful values for
|
||||
code are USE and CLOBBER. */
|
||||
|
||||
void
|
||||
diddle_return_value (code)
|
||||
enum rtx_code code;
|
||||
{
|
||||
rtx return_reg = DECL_RTL (DECL_RESULT (current_function_decl));
|
||||
|
||||
if (return_reg)
|
||||
{
|
||||
if (GET_CODE (return_reg) == REG
|
||||
&& REGNO (return_reg) < FIRST_PSEUDO_REGISTER)
|
||||
emit_insn (gen_rtx_fmt_e (code, VOIDmode, return_reg));
|
||||
else if (GET_CODE (return_reg) == PARALLEL)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < XVECLEN (return_reg, 0); i++)
|
||||
{
|
||||
rtx x = XEXP (XVECEXP (return_reg, 0, i), 0);
|
||||
|
||||
if (GET_CODE (x) == REG
|
||||
&& REGNO (x) < FIRST_PSEUDO_REGISTER)
|
||||
emit_insn (gen_rtx_fmt_e (code, VOIDmode, x));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate RTL for the end of the current function.
|
||||
FILENAME and LINE are the current position in the source file.
|
||||
|
||||
@ -6332,7 +6362,16 @@ expand_function_end (filename, line, end_bindings)
|
||||
structure returning. */
|
||||
|
||||
if (return_label)
|
||||
{
|
||||
/* Before the return label, clobber the return registers so that
|
||||
they are not propogated live to the rest of the function. This
|
||||
can only happen with functions that drop through; if there had
|
||||
been a return statement, there would have either been a return
|
||||
rtx, or a jump to the return label. */
|
||||
diddle_return_value (CLOBBER);
|
||||
|
||||
emit_label (return_label);
|
||||
}
|
||||
|
||||
/* C++ uses this. */
|
||||
if (end_bindings)
|
||||
|
@ -578,6 +578,10 @@ extern void free_expr_status PROTO((struct function *));
|
||||
|
||||
extern rtx get_first_block_beg PROTO((void));
|
||||
|
||||
#ifdef RTX_CODE
|
||||
extern void diddle_return_value PROTO((enum rtx_code));
|
||||
#endif
|
||||
|
||||
extern void init_virtual_regs PROTO((struct emit_status *));
|
||||
|
||||
/* Called once, at initialization, to initialize function.c. */
|
||||
|
@ -1394,16 +1394,20 @@ subst_stack_regs_pat (insn, regstack, pat)
|
||||
{
|
||||
rtx note;
|
||||
|
||||
/* The fix_truncdi_1 pattern wants to be able to allocate it's
|
||||
own scratch register. It does this by clobbering an fp reg
|
||||
so that it is assured of an empty reg-stack register.
|
||||
If the register is live, kill it now. Remove the DEAD/UNUSED
|
||||
note so we don't try to kill it later too. */
|
||||
|
||||
dest = get_true_reg (&XEXP (pat, 0));
|
||||
if (STACK_REG_P (*dest))
|
||||
{
|
||||
note = find_reg_note (insn, REG_DEAD, *dest);
|
||||
|
||||
if (pat != PATTERN (insn))
|
||||
{
|
||||
/* The fix_truncdi_1 pattern wants to be able to allocate
|
||||
it's own scratch register. It does this by clobbering
|
||||
an fp reg so that it is assured of an empty reg-stack
|
||||
register. If the register is live, kill it now.
|
||||
Remove the DEAD/UNUSED note so we don't try to kill it
|
||||
later too. */
|
||||
|
||||
if (note)
|
||||
emit_pop_insn (insn, regstack, *dest, EMIT_BEFORE);
|
||||
else
|
||||
@ -1412,10 +1416,27 @@ subst_stack_regs_pat (insn, regstack, pat)
|
||||
if (!note)
|
||||
abort ();
|
||||
}
|
||||
|
||||
remove_note (insn, note);
|
||||
replace_reg (dest, LAST_STACK_REG);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* A top-level clobber with no REG_DEAD, and no hard-regnum
|
||||
indicates an uninitialized value. Because reload removed
|
||||
all other clobbers, this must be due to a function
|
||||
returning without a value. Load up a NaN. */
|
||||
|
||||
if (! note
|
||||
&& get_hard_regnum (regstack, *dest) == -1)
|
||||
{
|
||||
pat = gen_rtx_SET (VOIDmode,
|
||||
FP_MODE_REG (REGNO (*dest), SFmode),
|
||||
nan);
|
||||
PATTERN (insn) = pat;
|
||||
move_for_stack_reg (insn, regstack, pat);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1106,13 +1106,12 @@ reload (first, global, dumpfile)
|
||||
which are only valid during and after reload. */
|
||||
reload_completed = 1;
|
||||
|
||||
/* Make a pass over all the insns and delete all USEs which we
|
||||
inserted only to tag a REG_EQUAL note on them. Remove all
|
||||
REG_DEAD and REG_UNUSED notes. Delete all CLOBBER insns and
|
||||
simplify (subreg (reg)) operands. Also remove all REG_RETVAL and
|
||||
REG_LIBCALL notes since they are no longer useful or accurate.
|
||||
Strip and regenerate REG_INC notes that may have been moved
|
||||
around. */
|
||||
/* Make a pass over all the insns and delete all USEs which we inserted
|
||||
only to tag a REG_EQUAL note on them. Remove all REG_DEAD and REG_UNUSED
|
||||
notes. Delete all CLOBBER insns that don't refer to the return value
|
||||
and simplify (subreg (reg)) operands. Also remove all REG_RETVAL and
|
||||
REG_LIBCALL notes since they are no longer useful or accurate. Strip
|
||||
and regenerate REG_INC notes that may have been moved around. */
|
||||
|
||||
for (insn = first; insn; insn = NEXT_INSN (insn))
|
||||
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
|
||||
@ -1121,7 +1120,9 @@ reload (first, global, dumpfile)
|
||||
|
||||
if ((GET_CODE (PATTERN (insn)) == USE
|
||||
&& find_reg_note (insn, REG_EQUAL, NULL_RTX))
|
||||
|| GET_CODE (PATTERN (insn)) == CLOBBER)
|
||||
|| (GET_CODE (PATTERN (insn)) == CLOBBER
|
||||
&& (GET_CODE (XEXP (PATTERN (insn), 0)) != REG
|
||||
|| ! REG_FUNCTION_VALUE_P (XEXP (PATTERN (insn), 0)))))
|
||||
{
|
||||
PUT_CODE (insn, NOTE);
|
||||
NOTE_SOURCE_FILE (insn) = 0;
|
||||
|
28
gcc/stmt.c
28
gcc/stmt.c
@ -2665,7 +2665,13 @@ void
|
||||
expand_null_return ()
|
||||
{
|
||||
struct nesting *block = block_stack;
|
||||
rtx last_insn = 0;
|
||||
rtx last_insn = get_last_insn ();
|
||||
|
||||
/* If this function was declared to return a value, but we
|
||||
didn't, clobber the return registers so that they are not
|
||||
propogated live to the rest of the function. */
|
||||
|
||||
diddle_return_value (CLOBBER);
|
||||
|
||||
/* Does any pending block have cleanups? */
|
||||
|
||||
@ -2710,25 +2716,7 @@ expand_value_return (val)
|
||||
emit_move_insn (return_reg, val);
|
||||
}
|
||||
|
||||
if (GET_CODE (return_reg) == REG
|
||||
&& REGNO (return_reg) < FIRST_PSEUDO_REGISTER)
|
||||
emit_insn (gen_rtx_USE (VOIDmode, return_reg));
|
||||
|
||||
/* Handle calls that return values in multiple non-contiguous locations.
|
||||
The Irix 6 ABI has examples of this. */
|
||||
else if (GET_CODE (return_reg) == PARALLEL)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < XVECLEN (return_reg, 0); i++)
|
||||
{
|
||||
rtx x = XEXP (XVECEXP (return_reg, 0, i), 0);
|
||||
|
||||
if (GET_CODE (x) == REG
|
||||
&& REGNO (x) < FIRST_PSEUDO_REGISTER)
|
||||
emit_insn (gen_rtx_USE (VOIDmode, x));
|
||||
}
|
||||
}
|
||||
diddle_return_value (USE);
|
||||
|
||||
/* Does any pending block have cleanups? */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user