summaryrefslogtreecommitdiff
path: root/gcc/config/sh/sh.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/sh/sh.c')
-rw-r--r--gcc/config/sh/sh.c233
1 files changed, 119 insertions, 114 deletions
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index d8825d05ce6..4ca2d5c1a81 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -1,6 +1,6 @@
/* Output routines for GCC for Renesas / SuperH SH.
Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+ 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
Contributed by Steve Chamberlain (sac@cygnus.com).
Improved by Jim Wilson (wilson@cygnus.com).
@@ -47,6 +47,7 @@ Boston, MA 02110-1301, USA. */
#include "real.h"
#include "langhooks.h"
#include "basic-block.h"
+#include "df.h"
#include "cfglayout.h"
#include "intl.h"
#include "sched-int.h"
@@ -88,6 +89,9 @@ static short *regmode_weight[2];
/* Total SFmode and SImode weights of scheduled insns. */
static int curr_regmode_pressure[2];
+/* Number of r0 life regions. */
+static int r0_life_regions;
+
/* If true, skip cycles for Q -> R movement. */
static int skip_cycles = 0;
@@ -195,6 +199,7 @@ static int sh_dfa_new_cycle (FILE *, int, rtx, int, int, int *sort_p);
static short find_set_regmode_weight (rtx, enum machine_mode);
static short find_insn_regmode_weight (rtx, enum machine_mode);
static void find_regmode_weight (basic_block, enum machine_mode);
+static int find_r0_life_regions (basic_block);
static void sh_md_init_global (FILE *, int, int);
static void sh_md_finish_global (FILE *, int);
static int rank_for_reorder (const void *, const void *);
@@ -4757,51 +4762,25 @@ sh_reorg (void)
if (GET_CODE (reg) != REG)
continue;
- /* This is a function call via REG. If the only uses of REG
- between the time that it is set and the time that it dies
- are in function calls, then we can associate all the
- function calls with the setting of REG. */
-
- for (link = LOG_LINKS (insn); link; link = XEXP (link, 1))
- {
- rtx linked_insn;
-
- if (REG_NOTE_KIND (link) != 0)
- continue;
- linked_insn = XEXP (link, 0);
- set = single_set (linked_insn);
- if (set
- && rtx_equal_p (reg, SET_DEST (set))
- && ! INSN_DELETED_P (linked_insn))
- {
- link = linked_insn;
- break;
- }
- }
-
- if (! link)
+ /* Try scanning backward to find where the register is set. */
+ link = NULL;
+ for (scan = PREV_INSN (insn);
+ scan && GET_CODE (scan) != CODE_LABEL;
+ scan = PREV_INSN (scan))
{
- /* ??? Sometimes global register allocation will have
- deleted the insn pointed to by LOG_LINKS. Try
- scanning backward to find where the register is set. */
- for (scan = PREV_INSN (insn);
- scan && GET_CODE (scan) != CODE_LABEL;
- scan = PREV_INSN (scan))
- {
- if (! INSN_P (scan))
- continue;
+ if (! INSN_P (scan))
+ continue;
- if (! reg_mentioned_p (reg, scan))
- continue;
+ if (! reg_mentioned_p (reg, scan))
+ continue;
- if (noncall_uses_reg (reg, scan, &set))
- break;
+ if (noncall_uses_reg (reg, scan, &set))
+ break;
- if (set)
- {
- link = scan;
- break;
- }
+ if (set)
+ {
+ link = scan;
+ break;
}
}
@@ -4833,7 +4812,7 @@ sh_reorg (void)
/* Don't try to trace forward past a CODE_LABEL if we haven't
seen INSN yet. Ordinarily, we will only find the setting insn
- in LOG_LINKS if it is in the same basic block. However,
+ if it is in the same basic block. However,
cross-jumping can insert code labels in between the load and
the call, and can result in situations where a single call
insn may have two targets depending on where we came from. */
@@ -4880,11 +4859,8 @@ sh_reorg (void)
later insn. */
/* ??? We shouldn't have to use FOUNDINSN here.
- However, the LOG_LINKS fields are apparently not
- entirely reliable around libcalls;
- newlib/libm/math/e_pow.c is a test case. Sometimes
- an insn will appear in LOG_LINKS even though it is
- not the most recent insn which sets the register. */
+ This dates back to when we used LOG_LINKS to find
+ the most recent insn which sets the register. */
if (foundinsn
&& (scanset
@@ -5849,12 +5825,12 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
CLEAR_HARD_REG_SET (*live_regs_mask);
if ((TARGET_SH4 || TARGET_SH2A_DOUBLE) && TARGET_FMOVD && interrupt_handler
- && regs_ever_live[FPSCR_REG])
+ && df_regs_ever_live_p (FPSCR_REG))
target_flags &= ~MASK_FPU_SINGLE;
/* If we can save a lot of saves by switching to double mode, do that. */
else if ((TARGET_SH4 || TARGET_SH2A_DOUBLE) && TARGET_FMOVD && TARGET_FPU_SINGLE)
for (count = 0, reg = FIRST_FP_REG; reg <= LAST_FP_REG; reg += 2)
- if (regs_ever_live[reg] && regs_ever_live[reg+1]
+ if (df_regs_ever_live_p (reg) && df_regs_ever_live_p (reg+1)
&& (! call_really_used_regs[reg]
|| interrupt_handler)
&& ++count > 2)
@@ -5876,11 +5852,11 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
pr_live = (pr_initial
? (GET_CODE (pr_initial) != REG
|| REGNO (pr_initial) != (PR_REG))
- : regs_ever_live[PR_REG]);
+ : df_regs_ever_live_p (PR_REG));
/* For Shcompact, if not optimizing, we end up with a memory reference
using the return address pointer for __builtin_return_address even
though there is no actual need to put the PR register on the stack. */
- pr_live |= regs_ever_live[RETURN_ADDRESS_POINTER_REGNUM];
+ pr_live |= df_regs_ever_live_p (RETURN_ADDRESS_POINTER_REGNUM);
}
/* Force PR to be live if the prologue has to call the SHmedia
argument decoder or register saver. */
@@ -5896,7 +5872,7 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
? pr_live
: interrupt_handler
? (/* Need to save all the regs ever live. */
- (regs_ever_live[reg]
+ (df_regs_ever_live_p (reg)
|| (call_really_used_regs[reg]
&& (! fixed_regs[reg] || reg == MACH_REG || reg == MACL_REG
|| reg == PIC_OFFSET_TABLE_REGNUM)
@@ -5914,7 +5890,7 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
&& flag_pic
&& current_function_args_info.call_cookie
&& reg == PIC_OFFSET_TABLE_REGNUM)
- || (regs_ever_live[reg]
+ || (df_regs_ever_live_p (reg)
&& (!call_really_used_regs[reg]
|| (trapa_handler && reg == FPSCR_REG && TARGET_FPU_ANY)))
|| (current_function_calls_eh_return
@@ -5923,7 +5899,7 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
|| reg == EH_RETURN_DATA_REGNO (2)
|| reg == EH_RETURN_DATA_REGNO (3)))
|| ((reg == MACL_REG || reg == MACH_REG)
- && regs_ever_live[reg]
+ && df_regs_ever_live_p (reg)
&& sh_cfun_attr_renesas_p ())
))
{
@@ -5935,7 +5911,7 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
{
if (FP_REGISTER_P (reg))
{
- if (! TARGET_FPU_SINGLE && ! regs_ever_live[reg ^ 1])
+ if (! TARGET_FPU_SINGLE && ! df_regs_ever_live_p (reg ^ 1))
{
SET_HARD_REG_BIT (*live_regs_mask, (reg ^ 1));
count += GET_MODE_SIZE (REGISTER_NATURAL_MODE (reg ^ 1));
@@ -6012,10 +5988,10 @@ sh_media_register_for_return (void)
if (sh_cfun_interrupt_handler_p ())
return -1;
- tr0_used = flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM];
+ tr0_used = flag_pic && df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM);
for (regno = FIRST_TARGET_REG + tr0_used; regno <= LAST_TARGET_REG; regno++)
- if (call_really_used_regs[regno] && ! regs_ever_live[regno])
+ if (call_really_used_regs[regno] && ! df_regs_ever_live_p (regno))
return regno;
return -1;
@@ -6174,7 +6150,7 @@ sh_expand_prologue (void)
incoming-argument decoder and/or of the return trampoline from
the GOT, so make sure the PIC register is preserved and
initialized. */
- regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
+ df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
if (TARGET_SHCOMPACT
&& (current_function_args_info.call_cookie & ~ CALL_COOKIE_RET_TRAMP(1)))
@@ -6207,19 +6183,8 @@ sh_expand_prologue (void)
int tr = sh_media_register_for_return ();
if (tr >= 0)
- {
- rtx insn = emit_move_insn (gen_rtx_REG (DImode, tr),
- gen_rtx_REG (DImode, PR_MEDIA_REG));
-
- /* ??? We should suppress saving pr when we don't need it, but this
- is tricky because of builtin_return_address. */
-
- /* If this function only exits with sibcalls, this copy
- will be flagged as dead. */
- REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD,
- const0_rtx,
- REG_NOTES (insn));
- }
+ emit_move_insn (gen_rtx_REG (DImode, tr),
+ gen_rtx_REG (DImode, PR_MEDIA_REG));
}
/* Emit the code for SETUP_VARARGS. */
@@ -6467,24 +6432,8 @@ sh_expand_prologue (void)
else
push_regs (&live_regs_mask, current_function_interrupt);
- if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
- {
- rtx insn = get_last_insn ();
- rtx last = emit_insn (gen_GOTaddr2picreg ());
-
- /* Mark these insns as possibly dead. Sometimes, flow2 may
- delete all uses of the PIC register. In this case, let it
- delete the initialization too. */
- do
- {
- insn = NEXT_INSN (insn);
-
- REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD,
- const0_rtx,
- REG_NOTES (insn));
- }
- while (insn != last);
- }
+ if (flag_pic && df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM))
+ emit_insn (gen_GOTaddr2picreg ());
if (SHMEDIA_REGS_STACK_ADJUST ())
{
@@ -6499,16 +6448,7 @@ sh_expand_prologue (void)
}
if (target_flags != save_flags && ! current_function_interrupt)
- {
- rtx insn = emit_insn (gen_toggle_sz ());
-
- /* If we're lucky, a mode switch in the function body will
- overwrite fpscr, turning this insn dead. Tell flow this
- insn is ok to delete. */
- REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD,
- const0_rtx,
- REG_NOTES (insn));
- }
+ emit_insn (gen_toggle_sz ());
target_flags = save_flags;
@@ -6729,11 +6669,6 @@ sh_expand_epilogue (bool sibcall_p)
}
insn = emit_move_insn (reg_rtx, mem_rtx);
- if (reg == PR_MEDIA_REG && sh_media_register_for_return () >= 0)
- /* This is dead, unless we return with a sibcall. */
- REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD,
- const0_rtx,
- REG_NOTES (insn));
}
gcc_assert (entry->offset + offset_base == d + d_rounding);
@@ -6742,7 +6677,11 @@ sh_expand_epilogue (bool sibcall_p)
{
save_size = 0;
if (TEST_HARD_REG_BIT (live_regs_mask, PR_REG))
- pop (PR_REG);
+ {
+ if (!frame_pointer_needed)
+ emit_insn (gen_blockage ());
+ pop (PR_REG);
+ }
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
int j = (FIRST_PSEUDO_REGISTER - 1) - i;
@@ -8799,7 +8738,7 @@ sh_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED,
saved by the prologue, even if they would normally be
call-clobbered. */
- if (sh_cfun_interrupt_handler_p () && !regs_ever_live[new_reg])
+ if (sh_cfun_interrupt_handler_p () && !df_regs_ever_live_p (new_reg))
return 0;
return 1;
@@ -9039,7 +8978,7 @@ flow_dependent_p_1 (rtx x, rtx pat ATTRIBUTE_UNUSED, void *data)
static int
sh_pr_n_sets (void)
{
- return REG_N_SETS (TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG);
+ return DF_REG_DEF_COUNT (TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG);
}
/* Return where to allocate pseudo for a given hard register initial
@@ -9206,6 +9145,56 @@ ready_reorder (rtx *ready, int nready)
SCHED_REORDER (ready, nready);
}
+/* Count life regions of r0 for a block. */
+static int
+find_r0_life_regions (basic_block b)
+{
+ rtx end, insn;
+ rtx pset;
+ rtx r0_reg;
+ int live;
+ int set;
+ int death = 0;
+
+ if (REGNO_REG_SET_P (DF_LIVE_IN (b), R0_REG))
+ {
+ set = 1;
+ live = 1;
+ }
+ else
+ {
+ set = 0;
+ live = 0;
+ }
+
+ insn = BB_HEAD (b);
+ end = BB_END (b);
+ r0_reg = gen_rtx_REG (SImode, R0_REG);
+ while (1)
+ {
+ if (INSN_P (insn))
+ {
+ if (find_regno_note (insn, REG_DEAD, R0_REG))
+ {
+ death++;
+ live = 0;
+ }
+ if (!live
+ && (pset = single_set (insn))
+ && reg_overlap_mentioned_p (r0_reg, SET_DEST (pset))
+ && !find_regno_note (insn, REG_UNUSED, R0_REG))
+ {
+ set++;
+ live = 1;
+ }
+ }
+ if (insn == end)
+ break;
+ insn = NEXT_INSN (insn);
+ }
+ return set - death;
+}
+
/* Calculate regmode weights for all insns of all basic block. */
static void
sh_md_init_global (FILE *dump ATTRIBUTE_UNUSED,
@@ -9216,11 +9205,14 @@ sh_md_init_global (FILE *dump ATTRIBUTE_UNUSED,
regmode_weight[0] = (short *) xcalloc (old_max_uid, sizeof (short));
regmode_weight[1] = (short *) xcalloc (old_max_uid, sizeof (short));
+ r0_life_regions = 0;
FOR_EACH_BB_REVERSE (b)
{
find_regmode_weight (b, SImode);
find_regmode_weight (b, SFmode);
+ if (!reload_completed)
+ r0_life_regions += find_r0_life_regions (b);
}
CURR_REGMODE_PRESSURE (SImode) = 0;
@@ -9281,7 +9273,6 @@ sh_md_init (FILE *dump ATTRIBUTE_UNUSED,
/* Pressure on register r0 can lead to spill failures. so avoid sched1 for
functions that already have high pressure on r0. */
#define R0_MAX_LIFE_REGIONS 2
-#define R0_MAX_LIVE_LENGTH 12
/* Register Pressure thresholds for SImode and SFmode registers. */
#define SIMODE_MAX_WEIGHT 5
#define SFMODE_MAX_WEIGHT 10
@@ -9292,9 +9283,8 @@ high_pressure (enum machine_mode mode)
{
/* Pressure on register r0 can lead to spill failures. so avoid sched1 for
functions that already have high pressure on r0. */
- if ((REG_N_SETS (0) - REG_N_DEATHS (0)) >= R0_MAX_LIFE_REGIONS
- && REG_LIVE_LENGTH (0) >= R0_MAX_LIVE_LENGTH)
- return 1;
+ if (r0_life_regions >= R0_MAX_LIFE_REGIONS)
+ return 1;
if (mode == SFmode)
return (CURR_REGMODE_PRESSURE (SFmode) > SFMODE_MAX_WEIGHT);
@@ -10275,6 +10265,7 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
insn_locators_alloc ();
insns = get_insns ();
+#if 0
if (optimize > 0)
{
/* Initialize the bitmap obstacks. */
@@ -10301,6 +10292,14 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
else if (flag_pic)
split_all_insns_noflow ();
}
+#else
+ if (optimize > 0)
+ {
+ if (! cfun->cfg)
+ init_flow ();
+ split_all_insns_noflow ();
+ }
+#endif
sh_reorg ();
@@ -10312,15 +10311,21 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
final (insns, file, 1);
final_end_function ();
+#if 0
if (optimize > 0)
{
- /* Release all memory allocated by flow. */
- free_basic_block_vars ();
+ /* Release all memory allocated by df. */
+ if (rtl_df)
+ {
+ df_finish (rtl_df);
+ rtl_df = NULL;
+ }
/* Release the bitmap obstacks. */
bitmap_obstack_release (&reg_obstack);
bitmap_obstack_release (NULL);
}
+#endif
reload_completed = 0;
epilogue_completed = 0;