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>
* tm.texi (Values in Registers): Fix typo: "fo" "for".
......
......@@ -320,7 +320,7 @@ static int set_noop_p PARAMS ((rtx));
static int noop_move_p PARAMS ((rtx));
static void notice_stack_pointer_modification PARAMS ((rtx, rtx, void *));
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 life_analysis_1 PARAMS ((rtx, int, int));
static void calculate_global_regs_live PARAMS ((sbitmap, sbitmap, int));
......@@ -2788,12 +2788,16 @@ record_volatile_insns (f)
/* Mark a register in SET. Hard registers in large modes get all
of their component registers set as well. */
static void
mark_reg (set, reg)
regset set;
mark_reg (reg, xset)
rtx reg;
void *xset;
{
regset set = (regset) xset;
int regno = REGNO (reg);
if (GET_MODE (reg) == BLKmode)
abort ();
SET_REGNO_REG_SET (set, regno);
if (regno < FIRST_PSEUDO_REGISTER)
{
......@@ -2867,44 +2871,7 @@ mark_regs_live_at_end (set)
}
/* Mark function return value. */
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 ();
}
diddle_return_value (mark_reg, set);
}
/* Determine which registers are live at the start of each
......
......@@ -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_chain 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. */
struct function *outer_function_chain;
......@@ -6120,44 +6121,79 @@ expand_dummy_function_end ()
cfun = 0;
}
/* Emit CODE for each register of the return value. Useful values for
code are USE and CLOBBER. */
/* Call DOIT for each hard register used as a return value from
the current function. */
void
diddle_return_value (code)
enum rtx_code code;
diddle_return_value (doit, arg)
void (*doit) PARAMS ((rtx, void *));
void *arg;
{
tree decl_result = DECL_RESULT (current_function_decl);
rtx return_reg = DECL_RTL (decl_result);
rtx outgoing = current_function_return_rtx;
if (return_reg)
if (! outgoing)
return;
if (GET_CODE (outgoing) == REG
&& REGNO (outgoing) >= FIRST_PSEUDO_REGISTER)
{
if (GET_CODE (return_reg) == REG
&& REGNO (return_reg) < FIRST_PSEUDO_REGISTER)
{
/* Use hard_function_value to avoid creating a reference to a BLKmode
register in the USE/CLOBBER insn. */
return_reg = hard_function_value (TREE_TYPE (decl_result),
current_function_decl, 1);
REG_FUNCTION_VALUE_P (return_reg) = 1;
emit_insn (gen_rtx_fmt_e (code, VOIDmode, return_reg));
}
else if (GET_CODE (return_reg) == PARALLEL)
{
int i;
tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
#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 (DECL_RESULT (current_function_decl))));
}
for (i = 0; i < XVECLEN (return_reg, 0); i++)
{
rtx x = XEXP (XVECEXP (return_reg, 0, i), 0);
if (GET_CODE (outgoing) == REG)
(*doit) (outgoing, arg);
else if (GET_CODE (outgoing) == PARALLEL)
{
int i;
if (GET_CODE (x) == REG
&& REGNO (x) < FIRST_PSEUDO_REGISTER)
emit_insn (gen_rtx_fmt_e (code, VOIDmode, x));
}
for (i = 0; i < XVECLEN (outgoing, 0); i++)
{
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.
FILENAME and LINE are the current position in the source file.
......@@ -6324,7 +6360,7 @@ expand_function_end (filename, line, end_bindings)
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);
clobber_return_register ();
emit_label (return_label);
}
......@@ -6444,6 +6480,12 @@ expand_function_end (filename, line, end_bindings)
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
communicate between __builtin_eh_return and the epilogue. */
expand_eh_return ();
......
......@@ -585,7 +585,9 @@ extern void free_expr_status PARAMS ((struct function *));
extern rtx get_first_block_beg PARAMS ((void));
#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
extern void init_virtual_regs PARAMS ((struct emit_status *));
......
......@@ -1099,6 +1099,13 @@ expand_inline_function (fndecl, parms, target, ignore, type,
pattern = PATTERN (insn);
set = single_set (insn);
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
the current fn has one. */
......
......@@ -2676,11 +2676,9 @@ expand_null_return ()
/* 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);
clobber_return_register ();
/* Does any pending block have cleanups? */
while (block && block->data.block.cleanups == 0)
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