This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Patch to mark return values in mark_regs_live_at_end instead of using USE insns
- To: egcs-patches at egcs dot cygnus dot com
- Subject: Patch to mark return values in mark_regs_live_at_end instead of using USE insns
- From: Jan Hubicka <hubicka at atrey dot karlin dot mff dot cuni dot cz>
- Date: Wed, 11 Aug 1999 01:55:02 +0200
Hi
This is patch to change mark_regs_live_at_end to mark return values of
functions. The resulting flowgraph is now closer to what actually happends
and it fixes possible problems with find_free_register and friends
clobbering return register in epilogue code and also fixes (I hope) last
important kludge in my reg-stack flow rewrite that prevents it from
applying...
I've changed the return code expanders to not expand uses when return
value is live and to expand clobbers when function declared to return
something don't return it. This is required to avoid register lifetimes
from bloat and regstack from complaining.
After reload this clobbers are removed, so lifetimes are enlarged, but this
happends only in at least partially bad code and hurts only find_free_register.
On the other hand this change seems to result in better dead code eliminations
because some branches becomes useless. So overall the resulting code is slightly
better (about 0.5% of the compiler size)
Tue Aug 10 19:55:53 EDT 1999 Jan Hubicka <hubicka@freesoft.cz>
* builtins.c (expand_builtin_return): Do not emit USEs, call
expand_nonnull_return instead of call_null_return.
* flow.c: Include tree.h
(mark_regs_live_at_end): Mark function return registers.
* function.c (expand_function_end): Clobber return value
(thread_prologue_and_epilogue_insns): Do not move the USE insns.
* stmt.c (expand_null_return): Rename to expand_nonnull_return.
(expand_null_return_1): Rename to expand_nonnull_return_1.
(expand_null_return): New function to clobber return value.
(expand_value_return): Do not emit USE insns.
* rtl.h (expand_nonnull_return): Declare.
* tree.h (expand_nonnull_return): Declare.
*** builtins.c.nore Tue Aug 10 17:25:49 1999
--- builtins.c Tue Aug 10 19:08:31 1999
*************** expand_builtin_return (result)
*** 1035,1041 ****
}
#endif
! /* Restore the return value and note that each value is used. */
size = 0;
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if ((mode = apply_result_mode[regno]) != VOIDmode)
--- 1035,1041 ----
}
#endif
! /* Restore the return value. */
size = 0;
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if ((mode = apply_result_mode[regno]) != VOIDmode)
*************** expand_builtin_return (result)
*** 1050,1067 ****
size)));
push_to_sequence (call_fusage);
- emit_insn (gen_rtx_USE (VOIDmode, reg));
call_fusage = get_insns ();
end_sequence ();
size += GET_MODE_SIZE (mode);
}
! /* Put the USE insns before the return. */
emit_insns (call_fusage);
/* Return whatever values was restored by jumping directly to the end
of the function. */
! expand_null_return ();
}
/* Expand a call to __builtin_classify_type with arguments found in
--- 1050,1066 ----
size)));
push_to_sequence (call_fusage);
call_fusage = get_insns ();
end_sequence ();
size += GET_MODE_SIZE (mode);
}
! /* Put the move insns before the return. */
emit_insns (call_fusage);
/* Return whatever values was restored by jumping directly to the end
of the function. */
! expand_nonnull_return ();
}
/* Expand a call to __builtin_classify_type with arguments found in
*** flow.c.nore Tue Aug 10 18:01:45 1999
--- flow.c Tue Aug 10 19:15:15 1999
*************** Boston, MA 02111-1307, USA. */
*** 132,137 ****
--- 132,138 ----
#include "recog.h"
#include "insn-flags.h"
#include "resource.h"
+ #include "tree.h"
#include "obstack.h"
#define obstack_chunk_alloc xmalloc
*************** mark_regs_live_at_end (set)
*** 2265,2270 ****
--- 2266,2272 ----
regset set;
{
int i;
+ rtx result = DECL_RTL ( DECL_RESULT (current_function_decl));
/* If exiting needs the right stack value, consider the stack pointer
live at the end of the function. */
*************** mark_regs_live_at_end (set)
*** 2301,2307 ****
)
SET_REGNO_REG_SET (set, i);
! /* ??? Mark function return value here rather than as uses. */
}
/* Determine which registers are live at the start of each
--- 2303,2329 ----
)
SET_REGNO_REG_SET (set, i);
! /* Mark function return value here.
! ??? remove uses? */
!
! if (result && GET_CODE (result) == REG)
! {
! SET_REGNO_REG_SET (set, REGNO (result));
! }
! /* Handle calls that return values in multiple non-contiguous locations.
! The Irix 6 ABI has examples of this. */
! else if (result && GET_CODE (result) == PARALLEL)
! {
! int i;
!
! for (i = 0; i < XVECLEN (result, 0); i++)
! {
! rtx x = XEXP (XVECEXP (result, 0, i), 0);
!
! if (GET_CODE (x) == REG)
! SET_REGNO_REG_SET (set, REGNO (x));
! }
! }
}
/* Determine which registers are live at the start of each
*** function.c.nore Tue Aug 10 17:59:12 1999
--- function.c Tue Aug 10 19:11:32 1999
*************** expand_function_end (filename, line, end
*** 6325,6330 ****
--- 6325,6331 ----
int end_bindings;
{
register int i;
+ rtx return_reg = DECL_RTL (DECL_RESULT (current_function_decl));
tree link;
#ifdef TRAMPOLINE_TEMPLATE
*************** expand_function_end (filename, line, end
*** 6466,6471 ****
--- 6467,6495 ----
clear_pending_stack_adjust ();
do_pending_stack_adjust ();
+ /* Clobber return value to keep lifetimes consistent. */
+ if (return_reg && GET_CODE (return_reg) == REG
+ && REGNO (return_reg) < FIRST_PSEUDO_REGISTER)
+ {
+ emit_insn (gen_rtx_CLOBBER (VOIDmode, return_reg));
+ }
+ /* Handle calls that return values in multiple non-contiguous locations.
+ The Irix 6 ABI has examples of this. */
+ else if (return_reg && 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_CLOBBER (VOIDmode, x));
+ }
+ }
+
+
/* Mark the end of the function body.
If control reaches this insn, the function can drop through
without returning a value. */
*************** thread_prologue_and_epilogue_insns (f)
*** 6792,6843 ****
/* FALLTHRU */
case 0:
{
! rtx prev, seq, first_use;
- /* Move the USE insns at the end of a function onto a list. */
prev = tail;
if (GET_CODE (prev) == BARRIER
|| GET_CODE (prev) == NOTE)
prev = prev_nonnote_insn (prev);
- first_use = 0;
- if (prev
- && GET_CODE (prev) == INSN
- && GET_CODE (PATTERN (prev)) == USE)
- {
- /* If the end of the block is the use, grab hold of something
- else so that we emit barriers etc in the right place. */
- if (prev == tail)
- {
- do
- tail = PREV_INSN (tail);
- while (GET_CODE (tail) == INSN
- && GET_CODE (PATTERN (tail)) == USE);
- }
-
- do
- {
- rtx use = prev;
- prev = prev_nonnote_insn (prev);
-
- remove_insn (use);
- if (first_use)
- {
- NEXT_INSN (use) = first_use;
- PREV_INSN (first_use) = use;
- }
- else
- NEXT_INSN (use) = NULL_RTX;
- first_use = use;
- }
- while (prev
- && GET_CODE (prev) == INSN
- && GET_CODE (PATTERN (prev)) == USE);
- }
-
/* The last basic block ends with a NOTE_INSN_EPILOGUE_BEG, the
! epilogue insns, the USE insns at the end of a function,
! the jump insn that returns, and then a BARRIER. */
if (GET_CODE (tail) != BARRIER)
{
--- 6816,6831 ----
/* FALLTHRU */
case 0:
{
! rtx prev, seq;
prev = tail;
if (GET_CODE (prev) == BARRIER
|| GET_CODE (prev) == NOTE)
prev = prev_nonnote_insn (prev);
/* The last basic block ends with a NOTE_INSN_EPILOGUE_BEG, the
! epilogue insns, the jump insn that returns, and then
! a BARRIER. */
if (GET_CODE (tail) != BARRIER)
{
*************** thread_prologue_and_epilogue_insns (f)
*** 6850,6859 ****
prev = tail;
tail = emit_jump_insn_after (seq, tail);
- /* Insert the USE insns immediately before the return insn, which
- must be the last instruction emitted in the sequence. */
- if (first_use)
- emit_insns_before (first_use, tail);
emit_note_after (NOTE_INSN_EPILOGUE_BEG, prev);
/* Update the tail of the basic block. */
--- 6838,6843 ----
*** rtl.h.nore Tue Aug 10 17:22:32 1999
--- rtl.h Tue Aug 10 17:23:11 1999
*************** extern int safe_from_earlyclobber PROTO
*** 1474,1479 ****
--- 1474,1480 ----
/* In stmt.c */
extern void expand_null_return PROTO((void));
+ extern void expand_nonnull_return PROTO((void));
extern void emit_jump PROTO ((rtx));
extern int preserve_subexpressions_p PROTO ((void));
*** stmt.c.nore Tue Aug 10 17:14:34 1999
--- stmt.c Tue Aug 10 19:11:14 1999
*************** static void expand_nl_goto_receiver PROT
*** 394,400 ****
static void expand_nl_goto_receivers PROTO((struct nesting *));
static void fixup_gotos PROTO((struct nesting *, rtx, tree,
rtx, int));
! static void expand_null_return_1 PROTO((rtx, int));
static void expand_value_return PROTO((rtx));
static int tail_recursion_args PROTO((tree, tree));
static void expand_cleanups PROTO((tree, tree, int, int));
--- 394,400 ----
static void expand_nl_goto_receivers PROTO((struct nesting *));
static void fixup_gotos PROTO((struct nesting *, rtx, tree,
rtx, int));
! static void expand_nonnull_return_1 PROTO((rtx, int));
static void expand_value_return PROTO((rtx));
static int tail_recursion_args PROTO((tree, tree));
static void expand_cleanups PROTO((tree, tree, int, int));
*************** expand_exit_something ()
*** 2474,2484 ****
return 0;
}
! /* Generate RTL to return from the current function, with no value.
! (That is, we do not do anything about returning any value.) */
void
! expand_null_return ()
{
struct nesting *block = block_stack;
rtx last_insn = 0;
--- 2474,2484 ----
return 0;
}
! /* Generate RTL to return from the current function.
! (we do not do anything about returning value.) */
void
! expand_nonnull_return ()
{
struct nesting *block = block_stack;
rtx last_insn = 0;
*************** expand_null_return ()
*** 2490,2496 ****
/* If yes, use a goto to return, since that runs cleanups. */
! expand_null_return_1 (last_insn, block != 0);
}
/* Generate RTL to return from the current function, with value VAL. */
--- 2490,2527 ----
/* If yes, use a goto to return, since that runs cleanups. */
! expand_nonnull_return_1 (last_insn, block != 0);
! }
!
! /* Generate RTL to return from the current function, with no value.
! (That is, we do clobber the return value to keep lifetimes consistent.) */
!
! void
! expand_null_return ()
! {
! rtx return_reg = DECL_RTL (DECL_RESULT (current_function_decl));
!
! if (return_reg && GET_CODE (return_reg) == REG
! && REGNO (return_reg) < FIRST_PSEUDO_REGISTER)
! {
! emit_insn (gen_rtx_CLOBBER (VOIDmode, return_reg));
! }
! /* Handle calls that return values in multiple non-contiguous locations.
! The Irix 6 ABI has examples of this. */
! else if (return_reg && 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_CLOBBER (VOIDmode, x));
! }
! }
! expand_nonnull_return ();
}
/* Generate RTL to return from the current function, with value VAL. */
*************** expand_value_return (val)
*** 2521,2544 ****
#endif
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));
- }
- }
/* Does any pending block have cleanups? */
--- 2552,2557 ----
*************** expand_value_return (val)
*** 2548,2554 ****
/* If yes, use a goto to return, since that runs cleanups.
Use LAST_INSN to put cleanups *before* the move insn emitted above. */
! expand_null_return_1 (last_insn, block != 0);
}
/* Output a return with no value. If LAST_INSN is nonzero,
--- 2561,2567 ----
/* If yes, use a goto to return, since that runs cleanups.
Use LAST_INSN to put cleanups *before* the move insn emitted above. */
! expand_nonnull_return_1 (last_insn, block != 0);
}
/* Output a return with no value. If LAST_INSN is nonzero,
*************** expand_value_return (val)
*** 2558,2564 ****
of pending blocks to be executed normally. */
static void
! expand_null_return_1 (last_insn, use_goto)
rtx last_insn;
int use_goto;
{
--- 2571,2577 ----
of pending blocks to be executed normally. */
static void
! expand_nonnull_return_1 (last_insn, use_goto)
rtx last_insn;
int use_goto;
{
*** tree.h.nore Tue Aug 10 17:22:54 1999
--- tree.h Tue Aug 10 17:23:30 1999
*************** extern int expand_exit_loop_if_false PR
*** 1954,1959 ****
--- 1954,1960 ----
extern int expand_exit_something PROTO((void));
extern void expand_null_return PROTO((void));
+ extern void expand_nonnull_return PROTO((void));
extern void expand_return PROTO((tree));
extern int optimize_tail_recursion PROTO((tree, struct rtx_def *));
extern void expand_start_bindings PROTO((int));