Commit 27c07cc5 by Radovan Obradovic Committed by Tom de Vries

-fuse-caller-save - Collect register usage information

2014-05-28  Radovan Obradovic  <robradovic@mips.com>
            Tom de Vries  <tom@codesourcery.com>

	* cgraph.h (struct cgraph_rtl_info): Add function_used_regs
	and function_used_regs_valid fields.
	* final.c: Move include of hard-reg-set.h to before rtl.h to declare
	find_all_hard_reg_sets.
	(collect_fn_hard_reg_usage, get_call_fndecl, get_call_cgraph_rtl_info)
	(get_call_reg_set_usage): New function.
	(rest_of_handle_final): Use collect_fn_hard_reg_usage.
	* regs.h (get_call_reg_set_usage): Declare.

Co-Authored-By: Tom de Vries <tom@codesourcery.com>

From-SVN: r211006
parent ca48e5ef
2014-05-28 Radovan Obradovic <robradovic@mips.com>
Tom de Vries <tom@codesourcery.com>
* cgraph.h (struct cgraph_rtl_info): Add function_used_regs
and function_used_regs_valid fields.
* final.c: Move include of hard-reg-set.h to before rtl.h to declare
find_all_hard_reg_sets.
(collect_fn_hard_reg_usage, get_call_fndecl, get_call_cgraph_rtl_info)
(get_call_reg_set_usage): New function.
(rest_of_handle_final): Use collect_fn_hard_reg_usage.
* regs.h (get_call_reg_set_usage): Declare.
2014-05-28 Georg-Johann Lay <avr@gjlay.de>
PR libgcc/61152
......
......@@ -249,6 +249,13 @@ struct GTY(()) cgraph_global_info {
struct GTY(()) cgraph_rtl_info {
unsigned int preferred_incoming_stack_boundary;
/* Call unsaved hard registers really used by the corresponding
function (including ones used by functions called by the
function). */
HARD_REG_SET function_used_regs;
/* Set if function_used_regs is valid. */
unsigned function_used_regs_valid: 1;
};
/* Represent which DECL tree (or reference to such tree)
......
......@@ -49,6 +49,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree.h"
#include "varasm.h"
#include "hard-reg-set.h"
#include "rtl.h"
#include "tm_p.h"
#include "regs.h"
......@@ -57,7 +58,6 @@ along with GCC; see the file COPYING3. If not see
#include "recog.h"
#include "conditions.h"
#include "flags.h"
#include "hard-reg-set.h"
#include "output.h"
#include "except.h"
#include "function.h"
......@@ -224,6 +224,7 @@ static int alter_cond (rtx);
static int final_addr_vec_align (rtx);
#endif
static int align_fuzz (rtx, rtx, int, unsigned);
static void collect_fn_hard_reg_usage (void);
/* Initialize data in final at the beginning of a compilation. */
......@@ -4442,6 +4443,8 @@ rest_of_handle_final (void)
assemble_start_function (current_function_decl, fnname);
final_start_function (get_insns (), asm_out_file, optimize);
final (get_insns (), asm_out_file, optimize);
if (flag_use_caller_save)
collect_fn_hard_reg_usage ();
final_end_function ();
/* The IA-64 ".handlerdata" directive must be issued before the ".endp"
......@@ -4740,3 +4743,115 @@ make_pass_clean_state (gcc::context *ctxt)
{
return new pass_clean_state (ctxt);
}
/* Collect hard register usage for the current function. */
static void
collect_fn_hard_reg_usage (void)
{
rtx insn;
int i;
struct cgraph_rtl_info *node;
/* ??? To be removed when all the ports have been fixed. */
if (!targetm.call_fusage_contains_non_callee_clobbers)
return;
node = cgraph_rtl_info (current_function_decl);
gcc_assert (node != NULL);
for (insn = get_insns (); insn != NULL_RTX; insn = next_insn (insn))
{
HARD_REG_SET insn_used_regs;
if (!NONDEBUG_INSN_P (insn))
continue;
find_all_hard_reg_sets (insn, &insn_used_regs, false);
if (CALL_P (insn)
&& !get_call_reg_set_usage (insn, &insn_used_regs, call_used_reg_set))
{
CLEAR_HARD_REG_SET (node->function_used_regs);
return;
}
IOR_HARD_REG_SET (node->function_used_regs, insn_used_regs);
}
/* Be conservative - mark fixed and global registers as used. */
IOR_HARD_REG_SET (node->function_used_regs, fixed_reg_set);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (global_regs[i])
SET_HARD_REG_BIT (node->function_used_regs, i);
#ifdef STACK_REGS
/* Handle STACK_REGS conservatively, since the df-framework does not
provide accurate information for them. */
for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
SET_HARD_REG_BIT (node->function_used_regs, i);
#endif
node->function_used_regs_valid = 1;
}
/* Get the declaration of the function called by INSN. */
static tree
get_call_fndecl (rtx insn)
{
rtx note, datum;
note = find_reg_note (insn, REG_CALL_DECL, NULL_RTX);
if (note == NULL_RTX)
return NULL_TREE;
datum = XEXP (note, 0);
if (datum != NULL_RTX)
return SYMBOL_REF_DECL (datum);
return NULL_TREE;
}
/* Return the cgraph_rtl_info of the function called by INSN. Returns NULL for
call targets that can be overwritten. */
static struct cgraph_rtl_info *
get_call_cgraph_rtl_info (rtx insn)
{
tree fndecl;
if (insn == NULL_RTX)
return NULL;
fndecl = get_call_fndecl (insn);
if (fndecl == NULL_TREE
|| !decl_binds_to_current_def_p (fndecl))
return NULL;
return cgraph_rtl_info (fndecl);
}
/* Find hard registers used by function call instruction INSN, and return them
in REG_SET. Return DEFAULT_SET in REG_SET if not found. */
bool
get_call_reg_set_usage (rtx insn, HARD_REG_SET *reg_set,
HARD_REG_SET default_set)
{
if (flag_use_caller_save)
{
struct cgraph_rtl_info *node = get_call_cgraph_rtl_info (insn);
if (node != NULL
&& node->function_used_regs_valid)
{
COPY_HARD_REG_SET (*reg_set, node->function_used_regs);
AND_HARD_REG_SET (*reg_set, default_set);
return true;
}
}
COPY_HARD_REG_SET (*reg_set, default_set);
return false;
}
......@@ -419,4 +419,8 @@ range_in_hard_reg_set_p (const HARD_REG_SET set, unsigned regno, int nregs)
return true;
}
/* Get registers used by given function call instruction. */
extern bool get_call_reg_set_usage (rtx insn, HARD_REG_SET *reg_set,
HARD_REG_SET default_set);
#endif /* GCC_REGS_H */
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