Commit 9e582b1d by Joern Rennecke Committed by Joern Rennecke

regset.h (fixed_reg_set_regset): Declare.

        * regset.h (fixed_reg_set_regset): Declare.
        * dse.c: Include regset.h .
        (struct insn_info): Add member fixed_regs_live.
        (note_add_store_info): New typedef.
        (note_add_store): New function.
        (emit_inc_dec_insn_before): Expect arg to be of type insn_info_t .
        Use gen_add3_insn / gen_move_insn.
        Check new insn for unwanted clobbers before emitting it.
        (check_for_inc_dec): Rename to...
        (check_for_inc_dec_1:) ... this.  Return bool.  Take insn_info
        parameter.  Changed all callers in file.
        (check_for_inc_dec, copy_fixed_regs): New functions.
        (scan_insn): Set fixed_regs_live field of insn_info.
        * rtl.h (check_for_inc_dec): Update prototype.
        * postreload.c (reload_cse_simplify): Take new signature of
        check_ind_dec into account.
        * reginfo.c (fixed_reg_set_regset): New variable.
        (init_reg_sets_1): Initialize it.

Co-Authored-By: Eric Botcazou <ebotcazou@adacore.com>

From-SVN: r181046
parent 57899d2f
2011-11-06 Joern Rennecke <joern.rennecke@embecosm.com>
Eric Botcazou <ebotcazou@adacore.com>
* regset.h (fixed_reg_set_regset): Declare.
* dse.c: Include regset.h .
(struct insn_info): Add member fixed_regs_live.
(note_add_store_info): New typedef.
(note_add_store): New function.
(emit_inc_dec_insn_before): Expect arg to be of type insn_info_t .
Use gen_add3_insn / gen_move_insn.
Check new insn for unwanted clobbers before emitting it.
(check_for_inc_dec): Rename to...
(check_for_inc_dec_1:) ... this. Return bool. Take insn_info
parameter. Changed all callers in file.
(check_for_inc_dec, copy_fixed_regs): New functions.
(scan_insn): Set fixed_regs_live field of insn_info.
* rtl.h (check_for_inc_dec): Update prototype.
* postreload.c (reload_cse_simplify): Take new signature of
check_ind_dec into account.
* reginfo.c (fixed_reg_set_regset): New variable.
(init_reg_sets_1): Initialize it.
2011-11-06 Jakub Jelinek <jakub@redhat.com> 2011-11-06 Jakub Jelinek <jakub@redhat.com>
* tree-cfg.c (gimple_can_merge_blocks_p): For -O0 don't remove * tree-cfg.c (gimple_can_merge_blocks_p): For -O0 don't remove
...@@ -33,6 +33,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -33,6 +33,7 @@ along with GCC; see the file COPYING3. If not see
#include "tm_p.h" #include "tm_p.h"
#include "regs.h" #include "regs.h"
#include "hard-reg-set.h" #include "hard-reg-set.h"
#include "regset.h"
#include "flags.h" #include "flags.h"
#include "df.h" #include "df.h"
#include "cselib.h" #include "cselib.h"
...@@ -377,6 +378,13 @@ struct insn_info ...@@ -377,6 +378,13 @@ struct insn_info
created. */ created. */
read_info_t read_rec; read_info_t read_rec;
/* The live fixed registers. We assume only fixed registers can
cause trouble by being clobbered from an expanded pattern;
storing only the live fixed registers (rather than all registers)
means less memory needs to be allocated / copied for the individual
stores. */
regset fixed_regs_live;
/* The prev insn in the basic block. */ /* The prev insn in the basic block. */
struct insn_info * prev_insn; struct insn_info * prev_insn;
...@@ -448,9 +456,9 @@ struct bb_info ...@@ -448,9 +456,9 @@ struct bb_info
/* The following bitvector is indexed by the reg number. It /* The following bitvector is indexed by the reg number. It
contains the set of regs that are live at the current instruction contains the set of regs that are live at the current instruction
being processed. While it contains info for all of the being processed. While it contains info for all of the
registers, only the pseudos are actually examined. It is used to registers, only the hard registers are actually examined. It is used
assure that shift sequences that are inserted do not accidently to assure that shift and/or add sequences that are inserted do not
clobber live hard regs. */ accidently clobber live hard regs. */
bitmap regs_live; bitmap regs_live;
}; };
...@@ -827,6 +835,51 @@ free_store_info (insn_info_t insn_info) ...@@ -827,6 +835,51 @@ free_store_info (insn_info_t insn_info)
insn_info->store_rec = NULL; insn_info->store_rec = NULL;
} }
typedef struct
{
rtx first, current;
regset fixed_regs_live;
bool failure;
} note_add_store_info;
/* Callback for emit_inc_dec_insn_before via note_stores.
Check if a register is clobbered which is live afterwards. */
static void
note_add_store (rtx loc, const_rtx expr ATTRIBUTE_UNUSED, void *data)
{
rtx insn;
note_add_store_info *info = (note_add_store_info *) data;
int r, n;
if (!REG_P (loc))
return;
/* If this register is referenced by the current or an earlier insn,
that's OK. E.g. this applies to the register that is being incremented
with this addition. */
for (insn = info->first;
insn != NEXT_INSN (info->current);
insn = NEXT_INSN (insn))
if (reg_referenced_p (loc, PATTERN (insn)))
return;
/* If we come here, we have a clobber of a register that's only OK
if that register is not live. If we don't have liveness information
available, fail now. */
if (!info->fixed_regs_live)
{
info->failure = true;
return;
}
/* Now check if this is a live fixed register. */
r = REGNO (loc);
n = hard_regno_nregs[r][GET_MODE (loc)];
while (--n >= 0)
if (REGNO_REG_SET_P (info->fixed_regs_live, r+n))
info->failure = true;
}
/* Callback for for_each_inc_dec that emits an INSN that sets DEST to /* Callback for for_each_inc_dec that emits an INSN that sets DEST to
SRC + SRCOFF before insn ARG. */ SRC + SRCOFF before insn ARG. */
...@@ -835,31 +888,68 @@ emit_inc_dec_insn_before (rtx mem ATTRIBUTE_UNUSED, ...@@ -835,31 +888,68 @@ emit_inc_dec_insn_before (rtx mem ATTRIBUTE_UNUSED,
rtx op ATTRIBUTE_UNUSED, rtx op ATTRIBUTE_UNUSED,
rtx dest, rtx src, rtx srcoff, void *arg) rtx dest, rtx src, rtx srcoff, void *arg)
{ {
rtx insn = (rtx)arg; insn_info_t insn_info = (insn_info_t) arg;
rtx insn = insn_info->insn, new_insn, cur;
if (srcoff) note_add_store_info info;
src = gen_rtx_PLUS (GET_MODE (src), src, srcoff);
/* We can reuse all operands without copying, because we are about /* We can reuse all operands without copying, because we are about
to delete the insn that contained it. */ to delete the insn that contained it. */
if (srcoff)
new_insn = gen_add3_insn (dest, src, srcoff);
else
new_insn = gen_move_insn (dest, src);
info.first = new_insn;
info.fixed_regs_live = insn_info->fixed_regs_live;
info.failure = false;
for (cur = new_insn; cur; cur = NEXT_INSN (cur))
{
info.current = cur;
note_stores (PATTERN (cur), note_add_store, &info);
}
emit_insn_before (gen_rtx_SET (VOIDmode, dest, src), insn); /* If a failure was flagged above, return 1 so that for_each_inc_dec will
return it immediately, communicating the failure to its caller. */
if (info.failure)
return 1;
emit_insn_before (new_insn, insn);
return -1; return -1;
} }
/* Before we delete INSN, make sure that the auto inc/dec, if it is /* Before we delete INSN_INFO->INSN, make sure that the auto inc/dec, if it
there, is split into a separate insn. */ is there, is split into a separate insn.
Return true on success (or if there was nothing to do), false on failure. */
void static bool
check_for_inc_dec (rtx insn) check_for_inc_dec_1 (insn_info_t insn_info)
{ {
rtx insn = insn_info->insn;
rtx note = find_reg_note (insn, REG_INC, NULL_RTX); rtx note = find_reg_note (insn, REG_INC, NULL_RTX);
if (note) if (note)
for_each_inc_dec (&insn, emit_inc_dec_insn_before, insn); return for_each_inc_dec (&insn, emit_inc_dec_insn_before, insn_info) == 0;
return true;
} }
/* Entry point for postreload. If you work on reload_cse, or you need this
anywhere else, consider if you can provide register liveness information
and add a parameter to this function so that it can be passed down in
insn_info.fixed_regs_live. */
bool
check_for_inc_dec (rtx insn)
{
struct insn_info insn_info;
rtx note;
insn_info.insn = insn;
insn_info.fixed_regs_live = NULL;
note = find_reg_note (insn, REG_INC, NULL_RTX);
if (note)
return for_each_inc_dec (&insn, emit_inc_dec_insn_before, &insn_info) == 0;
return true;
}
/* Delete the insn and free all of the fields inside INSN_INFO. */ /* Delete the insn and free all of the fields inside INSN_INFO. */
static void static void
...@@ -870,7 +960,8 @@ delete_dead_store_insn (insn_info_t insn_info) ...@@ -870,7 +960,8 @@ delete_dead_store_insn (insn_info_t insn_info)
if (!dbg_cnt (dse)) if (!dbg_cnt (dse))
return; return;
check_for_inc_dec (insn_info->insn); if (!check_for_inc_dec_1 (insn_info))
return;
if (dump_file) if (dump_file)
{ {
fprintf (dump_file, "Locally deleting insn %d ", fprintf (dump_file, "Locally deleting insn %d ",
...@@ -2375,6 +2466,17 @@ get_call_args (rtx call_insn, tree fn, rtx *args, int nargs) ...@@ -2375,6 +2466,17 @@ get_call_args (rtx call_insn, tree fn, rtx *args, int nargs)
return true; return true;
} }
/* Return a bitmap of the fixed registers contained in IN. */
static bitmap
copy_fixed_regs (const_bitmap in)
{
bitmap ret;
ret = ALLOC_REG_SET (NULL);
bitmap_and (ret, in, fixed_reg_set_regset);
return ret;
}
/* Apply record_store to all candidate stores in INSN. Mark INSN /* Apply record_store to all candidate stores in INSN. Mark INSN
if some part of it is not a candidate store and assigns to a if some part of it is not a candidate store and assigns to a
...@@ -2529,6 +2631,8 @@ scan_insn (bb_info_t bb_info, rtx insn) ...@@ -2529,6 +2631,8 @@ scan_insn (bb_info_t bb_info, rtx insn)
active_local_stores_len = 1; active_local_stores_len = 1;
active_local_stores = NULL; active_local_stores = NULL;
} }
insn_info->fixed_regs_live
= copy_fixed_regs (bb_info->regs_live);
insn_info->next_local_store = active_local_stores; insn_info->next_local_store = active_local_stores;
active_local_stores = insn_info; active_local_stores = insn_info;
} }
...@@ -2579,6 +2683,7 @@ scan_insn (bb_info_t bb_info, rtx insn) ...@@ -2579,6 +2683,7 @@ scan_insn (bb_info_t bb_info, rtx insn)
active_local_stores_len = 1; active_local_stores_len = 1;
active_local_stores = NULL; active_local_stores = NULL;
} }
insn_info->fixed_regs_live = copy_fixed_regs (bb_info->regs_live);
insn_info->next_local_store = active_local_stores; insn_info->next_local_store = active_local_stores;
active_local_stores = insn_info; active_local_stores = insn_info;
} }
...@@ -3622,9 +3727,9 @@ dse_step5_nospill (void) ...@@ -3622,9 +3727,9 @@ dse_step5_nospill (void)
} }
if (deleted) if (deleted)
{ {
if (dbg_cnt (dse)) if (dbg_cnt (dse)
&& check_for_inc_dec_1 (insn_info))
{ {
check_for_inc_dec (insn_info->insn);
delete_insn (insn_info->insn); delete_insn (insn_info->insn);
insn_info->insn = NULL; insn_info->insn = NULL;
globally_deleted++; globally_deleted++;
...@@ -3702,12 +3807,12 @@ dse_step5_spill (void) ...@@ -3702,12 +3807,12 @@ dse_step5_spill (void)
deleted = false; deleted = false;
store_info = store_info->next; store_info = store_info->next;
} }
if (deleted && dbg_cnt (dse)) if (deleted && dbg_cnt (dse)
&& check_for_inc_dec_1 (insn_info))
{ {
if (dump_file) if (dump_file)
fprintf (dump_file, "Spill deleting insn %d\n", fprintf (dump_file, "Spill deleting insn %d\n",
INSN_UID (insn_info->insn)); INSN_UID (insn_info->insn));
check_for_inc_dec (insn_info->insn);
delete_insn (insn_info->insn); delete_insn (insn_info->insn);
spill_deleted++; spill_deleted++;
insn_info->insn = NULL; insn_info->insn = NULL;
......
...@@ -112,8 +112,8 @@ reload_cse_simplify (rtx insn, rtx testreg) ...@@ -112,8 +112,8 @@ reload_cse_simplify (rtx insn, rtx testreg)
if (REG_P (value) if (REG_P (value)
&& ! REG_FUNCTION_VALUE_P (value)) && ! REG_FUNCTION_VALUE_P (value))
value = 0; value = 0;
check_for_inc_dec (insn); if (check_for_inc_dec (insn))
delete_insn_and_edges (insn); delete_insn_and_edges (insn);
return; return;
} }
...@@ -164,8 +164,8 @@ reload_cse_simplify (rtx insn, rtx testreg) ...@@ -164,8 +164,8 @@ reload_cse_simplify (rtx insn, rtx testreg)
if (i < 0) if (i < 0)
{ {
check_for_inc_dec (insn); if (check_for_inc_dec (insn))
delete_insn_and_edges (insn); delete_insn_and_edges (insn);
/* We're done with this insn. */ /* We're done with this insn. */
return; return;
} }
......
/* Compute different info about registers. /* Compute different info about registers.
Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996 Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996
1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
2009, 2010 Free Software Foundation, Inc. 2009, 2010, 2011 Free Software Foundation, Inc.
This file is part of GCC. This file is part of GCC.
...@@ -94,6 +94,9 @@ static tree GTY(()) global_regs_decl[FIRST_PSEUDO_REGISTER]; ...@@ -94,6 +94,9 @@ static tree GTY(()) global_regs_decl[FIRST_PSEUDO_REGISTER];
in dataflow more conveniently. */ in dataflow more conveniently. */
regset regs_invalidated_by_call_regset; regset regs_invalidated_by_call_regset;
/* Same information as FIXED_REG_SET but in regset form. */
regset fixed_reg_set_regset;
/* The bitmap_obstack is used to hold some static variables that /* The bitmap_obstack is used to hold some static variables that
should not be reset after each function is compiled. */ should not be reset after each function is compiled. */
static bitmap_obstack persistent_obstack; static bitmap_obstack persistent_obstack;
...@@ -451,6 +454,10 @@ init_reg_sets_1 (void) ...@@ -451,6 +454,10 @@ init_reg_sets_1 (void)
} }
else else
CLEAR_REG_SET (regs_invalidated_by_call_regset); CLEAR_REG_SET (regs_invalidated_by_call_regset);
if (!fixed_reg_set_regset)
fixed_reg_set_regset = ALLOC_REG_SET (&persistent_obstack);
else
CLEAR_REG_SET (fixed_reg_set_regset);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{ {
...@@ -462,7 +469,10 @@ init_reg_sets_1 (void) ...@@ -462,7 +469,10 @@ init_reg_sets_1 (void)
#endif #endif
if (fixed_regs[i]) if (fixed_regs[i])
SET_HARD_REG_BIT (fixed_reg_set, i); {
SET_HARD_REG_BIT (fixed_reg_set, i);
SET_REGNO_REG_SET (fixed_reg_set_regset, i);
}
if (call_used_regs[i]) if (call_used_regs[i])
SET_HARD_REG_BIT (call_used_reg_set, i); SET_HARD_REG_BIT (call_used_reg_set, i);
......
/* Define regsets. /* Define regsets.
Copyright (C) 1987, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, Copyright (C) 1987, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
This file is part of GCC. This file is part of GCC.
...@@ -115,6 +115,9 @@ typedef bitmap_iterator reg_set_iterator; ...@@ -115,6 +115,9 @@ typedef bitmap_iterator reg_set_iterator;
extern regset regs_invalidated_by_call_regset; extern regset regs_invalidated_by_call_regset;
/* Same information as FIXED_REG_SET but in regset form. */
extern regset fixed_reg_set_regset;
/* An obstack for regsets. */ /* An obstack for regsets. */
extern bitmap_obstack reg_obstack; extern bitmap_obstack reg_obstack;
......
...@@ -2396,7 +2396,7 @@ extern int exp_equiv_p (const_rtx, const_rtx, int, bool); ...@@ -2396,7 +2396,7 @@ extern int exp_equiv_p (const_rtx, const_rtx, int, bool);
extern unsigned hash_rtx (const_rtx x, enum machine_mode, int *, int *, bool); extern unsigned hash_rtx (const_rtx x, enum machine_mode, int *, int *, bool);
/* In dse.c */ /* In dse.c */
extern void check_for_inc_dec (rtx insn); extern bool check_for_inc_dec (rtx insn);
/* In jump.c */ /* In jump.c */
extern int comparison_dominates_p (enum rtx_code, enum rtx_code); extern int comparison_dominates_p (enum rtx_code, enum rtx_code);
......
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