/* Perform branch target register load optimizations.
- Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of GCC.
#include "system.h"
#include "coretypes.h"
#include "tm.h"
-#include "bitmap.h"
-#include "sbitmap.h"
#include "rtl.h"
#include "hard-reg-set.h"
-#include "basic-block.h"
#include "regs.h"
-#include "obstack.h"
#include "fibheap.h"
#include "output.h"
#include "target.h"
as appropriate. */
char other_btr_uses_before_def;
char other_btr_uses_after_use;
+ /* We set own_end when we have moved a definition into a dominator.
+ Thus, when a later combination removes this definition again, we know
+ to clear out trs_live_at_end again. */
+ char own_end;
bitmap live_range;
} *btr_def;
static void build_btr_def_use_webs (fibheap_t);
static int block_at_edge_of_live_range_p (int, btr_def);
static void clear_btr_from_live_range (btr_def def);
-static void add_btr_to_live_range (btr_def);
+static void add_btr_to_live_range (btr_def, int);
static void augment_live_range (bitmap, HARD_REG_SET *, basic_block,
- basic_block);
+ basic_block, int);
static int choose_btr (HARD_REG_SET);
static void combine_btr_defs (btr_def, HARD_REG_SET *);
static void btr_def_live_range (btr_def, HARD_REG_SET *);
{
rtx set;
- if (GET_CODE (insn) == INSN
+ if (NONJUMP_INSN_P (insn)
&& (set = single_set (insn)))
{
rtx dest = SET_DEST (set);
if (REG_P (dest)
&& TEST_HARD_REG_BIT (all_btrs, REGNO (dest)))
{
- if (btr_referenced_p (src, NULL))
- abort();
+ gcc_assert (!btr_referenced_p (src, NULL));
+
if (!check_const || CONSTANT_P (src))
{
if (regno)
SET_BIT (btr_defset[regno - first_btr], insn_uid);
note_other_use_this_block (regno, info.users_this_bb);
}
+ /* Check for the blockage emitted by expand_nl_goto_receiver. */
+ else if (current_function_has_nonlocal_label
+ && GET_CODE (PATTERN (insn)) == ASM_INPUT)
+ {
+ btr_user user;
+
+ /* Do the equivalent of calling note_other_use_this_block
+ for every target register. */
+ for (user = info.users_this_bb; user != NULL;
+ user = user->next)
+ if (user->use)
+ user->other_use_this_block = 1;
+ IOR_HARD_REG_SET (info.btrs_written_in_block, all_btrs);
+ IOR_HARD_REG_SET (info.btrs_live_in_block, all_btrs);
+ sbitmap_zero (info.bb_gen);
+ }
else
{
if (btr_referenced_p (PATTERN (insn), NULL))
user->next = info.users_this_bb;
info.users_this_bb = user;
}
- if (GET_CODE (insn) == CALL_INSN)
+ if (CALL_P (insn))
{
HARD_REG_SET *clobbered = &call_used_reg_set;
HARD_REG_SET call_saved;
IOR_HARD_REG_SET (btrs_live_at_end[i], tmp);
can_throw = 1;
}
- if (can_throw || GET_CODE (insn) == JUMP_INSN)
+ if (can_throw || JUMP_P (insn))
{
int regno;
{
/* Find all the reaching defs for this use. */
sbitmap reaching_defs_of_reg = sbitmap_alloc(max_uid);
- int uid;
+ unsigned int uid;
+ sbitmap_iterator sbi;
if (user->use)
sbitmap_a_and_b (
reaching_defs,
btr_defset[reg - first_btr]);
}
- EXECUTE_IF_SET_IN_SBITMAP (reaching_defs_of_reg, 0, uid,
+ EXECUTE_IF_SET_IN_SBITMAP (reaching_defs_of_reg, 0, uid, sbi)
{
btr_def def = def_array[uid];
def->other_btr_uses_after_use = 1;
user->next = def->uses;
def->uses = user;
- });
+ }
sbitmap_free (reaching_defs_of_reg);
}
- if (GET_CODE (insn) == CALL_INSN)
+ if (CALL_P (insn))
{
int regno;
static void
clear_btr_from_live_range (btr_def def)
{
- int bb;
-
- EXECUTE_IF_SET_IN_BITMAP
- (def->live_range, 0, bb,
- {
- if ((!def->other_btr_uses_before_def
- && !def->other_btr_uses_after_use)
- || !block_at_edge_of_live_range_p (bb, def))
- {
- CLEAR_HARD_REG_BIT (btrs_live[bb], def->btr);
- CLEAR_HARD_REG_BIT (btrs_live_at_end[bb], def->btr);
- if (dump_file)
- dump_btrs_live (bb);
- }
- });
+ unsigned bb;
+ bitmap_iterator bi;
+
+ EXECUTE_IF_SET_IN_BITMAP (def->live_range, 0, bb, bi)
+ {
+ if ((!def->other_btr_uses_before_def
+ && !def->other_btr_uses_after_use)
+ || !block_at_edge_of_live_range_p (bb, def))
+ {
+ CLEAR_HARD_REG_BIT (btrs_live[bb], def->btr);
+ CLEAR_HARD_REG_BIT (btrs_live_at_end[bb], def->btr);
+ if (dump_file)
+ dump_btrs_live (bb);
+ }
+ }
+ if (def->own_end)
+ CLEAR_HARD_REG_BIT (btrs_live_at_end[def->bb->index], def->btr);
}
/* We are adding the def/use web DEF. Add the target register used
in this web to the live set of all of the basic blocks that contain
- the live range of the web. */
+ the live range of the web.
+ If OWN_END is set, also show that the register is live from our
+ definitions at the end of the basic block where it is defined. */
static void
-add_btr_to_live_range (btr_def def)
+add_btr_to_live_range (btr_def def, int own_end)
{
- int bb;
- EXECUTE_IF_SET_IN_BITMAP
- (def->live_range, 0, bb,
- {
- SET_HARD_REG_BIT (btrs_live[bb], def->btr);
- SET_HARD_REG_BIT (btrs_live_at_end[bb], def->btr);
- if (dump_file)
- dump_btrs_live (bb);
- });
+ unsigned bb;
+ bitmap_iterator bi;
+
+ EXECUTE_IF_SET_IN_BITMAP (def->live_range, 0, bb, bi)
+ {
+ SET_HARD_REG_BIT (btrs_live[bb], def->btr);
+ SET_HARD_REG_BIT (btrs_live_at_end[bb], def->btr);
+ if (dump_file)
+ dump_btrs_live (bb);
+ }
+ if (own_end)
+ {
+ SET_HARD_REG_BIT (btrs_live_at_end[def->bb->index], def->btr);
+ def->own_end = 1;
+ }
}
/* Update a live range to contain the basic block NEW_BLOCK, and all
all other blocks in the existing live range.
Also add to the set BTRS_LIVE_IN_RANGE all target registers that
are live in the blocks that we add to the live range.
+ If FULL_RANGE is set, include the full live range of NEW_BB;
+ otherwise, if NEW_BB dominates HEAD_BB, only add registers that
+ are life at the end of NEW_BB for NEW_BB itself.
It is a precondition that either NEW_BLOCK dominates HEAD,or
HEAD dom NEW_BLOCK. This is used to speed up the
implementation of this function. */
static void
augment_live_range (bitmap live_range, HARD_REG_SET *btrs_live_in_range,
- basic_block head_bb, basic_block new_bb)
+ basic_block head_bb, basic_block new_bb, int full_range)
{
basic_block *worklist, *tos;
tos = worklist = xmalloc (sizeof (basic_block) * (n_basic_blocks + 1));
if (dominated_by_p (CDI_DOMINATORS, new_bb, head_bb))
- *tos++ = new_bb;
- else if (dominated_by_p (CDI_DOMINATORS, head_bb, new_bb))
+ {
+ if (new_bb == head_bb)
+ {
+ if (full_range)
+ IOR_HARD_REG_SET (*btrs_live_in_range, btrs_live[new_bb->index]);
+ return;
+ }
+ *tos++ = new_bb;
+ }
+ else
{
edge e;
+ edge_iterator ei;
int new_block = new_bb->index;
+ gcc_assert (dominated_by_p (CDI_DOMINATORS, head_bb, new_bb));
+
+ IOR_HARD_REG_SET (*btrs_live_in_range, btrs_live[head_bb->index]);
bitmap_set_bit (live_range, new_block);
- if (flag_btr_bb_exclusive)
+ /* A previous btr migration could have caused a register to be
+ live just at the end of new_block which we need in full, so
+ use trs_live_at_end even if full_range is set. */
+ IOR_HARD_REG_SET (*btrs_live_in_range, btrs_live_at_end[new_block]);
+ if (full_range)
IOR_HARD_REG_SET (*btrs_live_in_range, btrs_live[new_block]);
- else
- {
- IOR_HARD_REG_SET (*btrs_live_in_range, btrs_live_at_end[new_block]);
- IOR_HARD_REG_SET (*btrs_live_in_range, btrs_live[head_bb->index]);
- }
if (dump_file)
{
fprintf (dump_file,
dump_hard_reg_set (*btrs_live_in_range);
fprintf (dump_file, "\n");
}
- for (e = head_bb->pred; e; e = e->pred_next)
+ FOR_EACH_EDGE (e, ei, head_bb->preds)
*tos++ = e->src;
}
- else
- abort();
while (tos != worklist)
{
if (!bitmap_bit_p (live_range, bb->index))
{
edge e;
+ edge_iterator ei;
bitmap_set_bit (live_range, bb->index);
IOR_HARD_REG_SET (*btrs_live_in_range,
btrs_live[bb->index]);
+ /* A previous btr migration could have caused a register to be
+ live just at the end of a block which we need in full. */
+ IOR_HARD_REG_SET (*btrs_live_in_range,
+ btrs_live_at_end[bb->index]);
if (dump_file)
{
fprintf (dump_file,
fprintf (dump_file, "\n");
}
- for (e = bb->pred; e != NULL; e = e->pred_next)
+ FOR_EACH_EDGE (e, ei, bb->preds)
{
basic_block pred = e->src;
if (!bitmap_bit_p (live_range, pred->index))
{
btr_user user;
- def->live_range = BITMAP_XMALLOC ();
+ def->live_range = BITMAP_ALLOC (NULL);
bitmap_set_bit (def->live_range, def->bb->index);
- if (flag_btr_bb_exclusive)
- COPY_HARD_REG_SET (*btrs_live_in_range, btrs_live[def->bb->index]);
- else
- COPY_HARD_REG_SET (*btrs_live_in_range,
- btrs_live_at_end[def->bb->index]);
+ COPY_HARD_REG_SET (*btrs_live_in_range,
+ (flag_btr_bb_exclusive
+ ? btrs_live : btrs_live_at_end)[def->bb->index]);
for (user = def->uses; user != NULL; user = user->next)
augment_live_range (def->live_range, btrs_live_in_range,
- def->bb, user->bb);
+ def->bb, user->bb,
+ (flag_btr_bb_exclusive
+ || user->insn != BB_END (def->bb)
+ || !JUMP_P (user->insn)));
}
else
{
the set of target registers live over it, because migration
of other PT instructions may have affected it.
*/
- int bb;
- int def_bb = def->bb->index;
+ unsigned bb;
+ unsigned def_bb = flag_btr_bb_exclusive ? -1 : def->bb->index;
+ bitmap_iterator bi;
CLEAR_HARD_REG_SET (*btrs_live_in_range);
- if (flag_btr_bb_exclusive)
- EXECUTE_IF_SET_IN_BITMAP
- (def->live_range, 0, bb,
- {
- IOR_HARD_REG_SET (*btrs_live_in_range, btrs_live[bb]);
- });
- else
- EXECUTE_IF_SET_IN_BITMAP
- (def->live_range, 0, bb,
- {
- IOR_HARD_REG_SET (*btrs_live_in_range,
- (def_bb == bb
- ? btrs_live_at_end : btrs_live) [bb]);
- });
+ EXECUTE_IF_SET_IN_BITMAP (def->live_range, 0, bb, bi)
+ {
+ IOR_HARD_REG_SET (*btrs_live_in_range,
+ (def_bb == bb
+ ? btrs_live_at_end : btrs_live) [bb]);
+ }
}
if (!def->other_btr_uses_before_def &&
!def->other_btr_uses_after_use)
target registers live over the merged range. */
int btr;
HARD_REG_SET combined_btrs_live;
- bitmap combined_live_range = BITMAP_XMALLOC ();
+ bitmap combined_live_range = BITMAP_ALLOC (NULL);
btr_user user;
if (other_def->live_range == NULL)
for (user = other_def->uses; user != NULL; user = user->next)
augment_live_range (combined_live_range, &combined_btrs_live,
- def->bb, user->bb);
+ def->bb, user->bb,
+ (flag_btr_bb_exclusive
+ || user->insn != BB_END (def->bb)
+ || !JUMP_P (user->insn)));
btr = choose_btr (combined_btrs_live);
if (btr != -1)
clear_btr_from_live_range (other_def);
other_def->uses = NULL;
bitmap_copy (def->live_range, combined_live_range);
- if (other_def->other_btr_uses_after_use)
+ if (other_def->btr == btr && other_def->other_btr_uses_after_use)
def->other_btr_uses_after_use = 1;
COPY_HARD_REG_SET (*btrs_live_in_range, combined_btrs_live);
delete_insn (other_def->insn);
}
- BITMAP_XFREE (combined_live_range);
+ BITMAP_FREE (combined_live_range);
}
}
}
def->bb = new_def_bb;
def->luid = 0;
def->cost = basic_block_freq (new_def_bb);
- def->other_btr_uses_before_def
- = TEST_HARD_REG_BIT (btrs_live[b->index], btr) ? 1 : 0;
bitmap_copy (def->live_range, live_range);
combine_btr_defs (def, btrs_live_in_range);
btr = def->btr;
- add_btr_to_live_range (def);
- if (GET_CODE (insp) == CODE_LABEL)
+ def->other_btr_uses_before_def
+ = TEST_HARD_REG_BIT (btrs_live[b->index], btr) ? 1 : 0;
+ add_btr_to_live_range (def, 1);
+ if (LABEL_P (insp))
insp = NEXT_INSN (insp);
/* N.B.: insp is expected to be NOTE_INSN_BASIC_BLOCK now. Some
optimizations can result in insp being both first and last insn of
{
insp = BB_END (b);
for (insp = BB_END (b); ! INSN_P (insp); insp = PREV_INSN (insp))
- if (insp == BB_HEAD (b))
- abort ();
- if (GET_CODE (insp) == JUMP_INSN || can_throw_internal (insp))
+ gcc_assert (insp != BB_HEAD (b));
+
+ if (JUMP_P (insp) || can_throw_internal (insp))
insp = PREV_INSN (insp);
}
int give_up = 0;
int def_moved = 0;
btr_user user;
- int def_latency = 1;
+ int def_latency;
if (dump_file)
fprintf (dump_file,
}
btr_def_live_range (def, &btrs_live_in_range);
- live_range = BITMAP_XMALLOC ();
+ live_range = BITMAP_ALLOC (NULL);
bitmap_copy (live_range, def->live_range);
#ifdef INSN_SCHEDULING
- if (targetm.sched.use_dfa_pipeline_interface ())
- def_latency = insn_default_latency (def->insn);
- else
- def_latency = result_ready_cost (def->insn);
+ def_latency = insn_default_latency (def->insn) * issue_rate;
+#else
+ def_latency = issue_rate;
#endif
- def_latency *= issue_rate;
-
for (user = def->uses; user != NULL; user = user->next)
{
if (user->bb == def->bb
|| (try_freq == def_basic_block_freq && btr_used_near_def))
{
int btr;
- augment_live_range (live_range, &btrs_live_in_range, def->bb, try);
+ augment_live_range (live_range, &btrs_live_in_range, def->bb, try,
+ flag_btr_bb_exclusive);
if (dump_file)
{
fprintf (dump_file, "Now btrs live in range are: ");
if (dump_file)
fprintf (dump_file, "failed to move\n");
}
- BITMAP_XFREE (live_range);
+ BITMAP_FREE (live_range);
return !give_up;
}
}
}
else
- {
- if (def->live_range)
- BITMAP_XFREE (def->live_range);
- }
+ BITMAP_FREE (def->live_range);
}
free (btrs_live);