Commit c13fde05 by Richard Henderson Committed by Richard Henderson

function.c (diddle_return_value): Rework to use a callback function.

        * function.c (diddle_return_value): Rework to use a callback function.
        Use current_function_return_rtx if it's been set up.
        (do_clobber_return_reg, clobber_return_register): New.
        (do_use_return_reg, use_return_register): New.
        (expand_function_end): Use them.
        * stmt.c (expand_null_return): Likewise.
        * function.h: Declare them.
        * flow.c (mark_regs_live_at_end): Use diddle_return_value.
        (mark_reg): Change arguments as appropriate for callback.
        * integrate.c (expand_inline_function): Revert 19 Jan change.

From-SVN: r31791
parent facc279f
2000-02-04 Richard Henderson <rth@cygnus.com>
* function.c (diddle_return_value): Rework to use a callback function.
Use current_function_return_rtx if it's been set up.
(do_clobber_return_reg, clobber_return_register): New.
(do_use_return_reg, use_return_register): New.
(expand_function_end): Use them.
* stmt.c (expand_null_return): Likewise.
* function.h: Declare them.
* flow.c (mark_regs_live_at_end): Use diddle_return_value.
(mark_reg): Change arguments as appropriate for callback.
* integrate.c (expand_inline_function): Revert 19 Jan change.
Fri Feb 4 20:25:42 2000 Hans-Peter Nilsson <hp@bitrange.com> Fri Feb 4 20:25:42 2000 Hans-Peter Nilsson <hp@bitrange.com>
* tm.texi (Values in Registers): Fix typo: "fo" "for". * tm.texi (Values in Registers): Fix typo: "fo" "for".
......
...@@ -320,7 +320,7 @@ static int set_noop_p PARAMS ((rtx)); ...@@ -320,7 +320,7 @@ static int set_noop_p PARAMS ((rtx));
static int noop_move_p PARAMS ((rtx)); static int noop_move_p PARAMS ((rtx));
static void notice_stack_pointer_modification PARAMS ((rtx, rtx, void *)); static void notice_stack_pointer_modification PARAMS ((rtx, rtx, void *));
static void record_volatile_insns PARAMS ((rtx)); static void record_volatile_insns PARAMS ((rtx));
static void mark_reg PARAMS ((regset, rtx)); static void mark_reg PARAMS ((rtx, void *));
static void mark_regs_live_at_end PARAMS ((regset)); static void mark_regs_live_at_end PARAMS ((regset));
static void life_analysis_1 PARAMS ((rtx, int, int)); static void life_analysis_1 PARAMS ((rtx, int, int));
static void calculate_global_regs_live PARAMS ((sbitmap, sbitmap, int)); static void calculate_global_regs_live PARAMS ((sbitmap, sbitmap, int));
...@@ -2788,12 +2788,16 @@ record_volatile_insns (f) ...@@ -2788,12 +2788,16 @@ record_volatile_insns (f)
/* Mark a register in SET. Hard registers in large modes get all /* Mark a register in SET. Hard registers in large modes get all
of their component registers set as well. */ of their component registers set as well. */
static void static void
mark_reg (set, reg) mark_reg (reg, xset)
regset set;
rtx reg; rtx reg;
void *xset;
{ {
regset set = (regset) xset;
int regno = REGNO (reg); int regno = REGNO (reg);
if (GET_MODE (reg) == BLKmode)
abort ();
SET_REGNO_REG_SET (set, regno); SET_REGNO_REG_SET (set, regno);
if (regno < FIRST_PSEUDO_REGISTER) if (regno < FIRST_PSEUDO_REGISTER)
{ {
...@@ -2867,44 +2871,7 @@ mark_regs_live_at_end (set) ...@@ -2867,44 +2871,7 @@ mark_regs_live_at_end (set)
} }
/* Mark function return value. */ /* Mark function return value. */
diddle_return_value (mark_reg, set);
result = DECL_RESULT (current_function_decl);
type = TREE_TYPE (result);
if (type != void_type_node)
{
rtx outgoing;
/* ??? Share this code with expand_function_end. */
#ifdef FUNCTION_OUTGOING_VALUE
outgoing = FUNCTION_OUTGOING_VALUE (type, current_function_decl);
#else
outgoing = FUNCTION_VALUE (type, current_function_decl);
#endif
/* If this is a BLKmode structure being returned in registers,
then use the mode computed in expand_return. */
if (GET_MODE (outgoing) == BLKmode)
PUT_MODE (outgoing, GET_MODE (DECL_RTL (result)));
if (GET_CODE (outgoing) == REG)
mark_reg (set, outgoing);
else if (GET_CODE (outgoing) == PARALLEL)
{
int len = XVECLEN (outgoing, 0);
/* Check for a NULL entry, used to indicate that the parameter
goes on the stack and in registers. */
i = (XEXP (XVECEXP (outgoing, 0, 0), 0) ? 0 : 1);
for ( ; i < len; ++i)
{
rtx r = XVECEXP (outgoing, 0, i);
if (GET_CODE (r) == REG)
mark_reg (set, r);
}
}
else
abort ();
}
} }
/* Determine which registers are live at the start of each /* Determine which registers are live at the start of each
......
...@@ -286,7 +286,8 @@ static void mark_temp_slot PARAMS ((struct temp_slot *)); ...@@ -286,7 +286,8 @@ static void mark_temp_slot PARAMS ((struct temp_slot *));
static void mark_function_status PARAMS ((struct function *)); static void mark_function_status PARAMS ((struct function *));
static void mark_function_chain PARAMS ((void *)); static void mark_function_chain PARAMS ((void *));
static void prepare_function_start PARAMS ((void)); static void prepare_function_start PARAMS ((void));
static void do_clobber_return_reg PARAMS ((rtx, void *));
static void do_use_return_reg PARAMS ((rtx, void *));
/* Pointer to chain of `struct function' for containing functions. */ /* Pointer to chain of `struct function' for containing functions. */
struct function *outer_function_chain; struct function *outer_function_chain;
...@@ -6120,44 +6121,79 @@ expand_dummy_function_end () ...@@ -6120,44 +6121,79 @@ expand_dummy_function_end ()
cfun = 0; cfun = 0;
} }
/* Emit CODE for each register of the return value. Useful values for /* Call DOIT for each hard register used as a return value from
code are USE and CLOBBER. */ the current function. */
void void
diddle_return_value (code) diddle_return_value (doit, arg)
enum rtx_code code; void (*doit) PARAMS ((rtx, void *));
void *arg;
{ {
tree decl_result = DECL_RESULT (current_function_decl); rtx outgoing = current_function_return_rtx;
rtx return_reg = DECL_RTL (decl_result);
if (return_reg) if (! outgoing)
return;
if (GET_CODE (outgoing) == REG
&& REGNO (outgoing) >= FIRST_PSEUDO_REGISTER)
{ {
if (GET_CODE (return_reg) == REG tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
&& REGNO (return_reg) < FIRST_PSEUDO_REGISTER) #ifdef FUNCTION_OUTGOING_VALUE
{ outgoing = FUNCTION_OUTGOING_VALUE (type, current_function_decl);
/* Use hard_function_value to avoid creating a reference to a BLKmode #else
register in the USE/CLOBBER insn. */ outgoing = FUNCTION_VALUE (type, current_function_decl);
return_reg = hard_function_value (TREE_TYPE (decl_result), #endif
current_function_decl, 1); /* If this is a BLKmode structure being returned in registers, then use
REG_FUNCTION_VALUE_P (return_reg) = 1; the mode computed in expand_return. */
emit_insn (gen_rtx_fmt_e (code, VOIDmode, return_reg)); if (GET_MODE (outgoing) == BLKmode)
} PUT_MODE (outgoing,
else if (GET_CODE (return_reg) == PARALLEL) GET_MODE (DECL_RTL (DECL_RESULT (current_function_decl))));
{ }
int i;
for (i = 0; i < XVECLEN (return_reg, 0); i++) if (GET_CODE (outgoing) == REG)
{ (*doit) (outgoing, arg);
rtx x = XEXP (XVECEXP (return_reg, 0, i), 0); else if (GET_CODE (outgoing) == PARALLEL)
{
int i;
if (GET_CODE (x) == REG for (i = 0; i < XVECLEN (outgoing, 0); i++)
&& REGNO (x) < FIRST_PSEUDO_REGISTER) {
emit_insn (gen_rtx_fmt_e (code, VOIDmode, x)); rtx x = XEXP (XVECEXP (outgoing, 0, i), 0);
}
if (GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
(*doit) (x, arg);
} }
} }
} }
static void
do_clobber_return_reg (reg, arg)
rtx reg;
void *arg ATTRIBUTE_UNUSED;
{
emit_insn (gen_rtx_CLOBBER (VOIDmode, reg));
}
void
clobber_return_register ()
{
diddle_return_value (do_clobber_return_reg, NULL);
}
static void
do_use_return_reg (reg, arg)
rtx reg;
void *arg ATTRIBUTE_UNUSED;
{
emit_insn (gen_rtx_USE (VOIDmode, reg));
}
void
use_return_register ()
{
diddle_return_value (do_use_return_reg, NULL);
}
/* Generate RTL for the end of the current function. /* Generate RTL for the end of the current function.
FILENAME and LINE are the current position in the source file. FILENAME and LINE are the current position in the source file.
...@@ -6324,7 +6360,7 @@ expand_function_end (filename, line, end_bindings) ...@@ -6324,7 +6360,7 @@ expand_function_end (filename, line, end_bindings)
can only happen with functions that drop through; if there had can only happen with functions that drop through; if there had
been a return statement, there would have either been a return been a return statement, there would have either been a return
rtx, or a jump to the return label. */ rtx, or a jump to the return label. */
diddle_return_value (CLOBBER); clobber_return_register ();
emit_label (return_label); emit_label (return_label);
} }
...@@ -6444,6 +6480,12 @@ expand_function_end (filename, line, end_bindings) ...@@ -6444,6 +6480,12 @@ expand_function_end (filename, line, end_bindings)
emit_move_insn (outgoing, value_address); emit_move_insn (outgoing, value_address);
} }
/* ??? This should no longer be necessary since stupid is no longer with
us, but there are some parts of the compiler (eg reload_combine, and
sh mach_dep_reorg) that still try and compute their own lifetime info
instead of using the general framework. */
use_return_register ();
/* If this is an implementation of __throw, do what's necessary to /* If this is an implementation of __throw, do what's necessary to
communicate between __builtin_eh_return and the epilogue. */ communicate between __builtin_eh_return and the epilogue. */
expand_eh_return (); expand_eh_return ();
......
...@@ -585,7 +585,9 @@ extern void free_expr_status PARAMS ((struct function *)); ...@@ -585,7 +585,9 @@ extern void free_expr_status PARAMS ((struct function *));
extern rtx get_first_block_beg PARAMS ((void)); extern rtx get_first_block_beg PARAMS ((void));
#ifdef RTX_CODE #ifdef RTX_CODE
extern void diddle_return_value PARAMS ((enum rtx_code)); extern void diddle_return_value PARAMS ((void (*)(rtx, void*), void*));
extern void clobber_return_register PARAMS ((void));
extern void use_return_register PARAMS ((void));
#endif #endif
extern void init_virtual_regs PARAMS ((struct emit_status *)); extern void init_virtual_regs PARAMS ((struct emit_status *));
......
...@@ -1099,6 +1099,13 @@ expand_inline_function (fndecl, parms, target, ignore, type, ...@@ -1099,6 +1099,13 @@ expand_inline_function (fndecl, parms, target, ignore, type,
pattern = PATTERN (insn); pattern = PATTERN (insn);
set = single_set (insn); set = single_set (insn);
copy = 0; copy = 0;
if (GET_CODE (pattern) == USE
&& GET_CODE (XEXP (pattern, 0)) == REG
&& REG_FUNCTION_VALUE_P (XEXP (pattern, 0)))
/* The (USE (REG n)) at return from the function should
be ignored since we are changing (REG n) into
inline_target. */
break;
/* If the inline fn needs eh context, make sure that /* If the inline fn needs eh context, make sure that
the current fn has one. */ the current fn has one. */
......
...@@ -2676,11 +2676,9 @@ expand_null_return () ...@@ -2676,11 +2676,9 @@ expand_null_return ()
/* If this function was declared to return a value, but we /* If this function was declared to return a value, but we
didn't, clobber the return registers so that they are not didn't, clobber the return registers so that they are not
propogated live to the rest of the function. */ propogated live to the rest of the function. */
clobber_return_register ();
diddle_return_value (CLOBBER);
/* Does any pending block have cleanups? */ /* Does any pending block have cleanups? */
while (block && block->data.block.cleanups == 0) while (block && block->data.block.cleanups == 0)
block = block->next; block = block->next;
......
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