/* Definitions for computing resource usage of specific insns.
- Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
- Free Software Foundation, Inc.
+ Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+ 2009, 2010 Free Software Foundation, Inc.
This file is part of GCC.
#include "system.h"
#include "coretypes.h"
#include "tm.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
#include "rtl.h"
#include "tm_p.h"
#include "hard-reg-set.h"
static int
find_basic_block (rtx insn, int search_limit)
{
- basic_block bb;
-
/* Scan backwards to the previous BARRIER. Then see if we can find a
label that starts a basic block. Return the basic block number. */
for (insn = prev_nonnote_insn (insn);
for (insn = next_nonnote_insn (insn);
insn && LABEL_P (insn);
insn = next_nonnote_insn (insn))
- {
- FOR_EACH_BB (bb)
- if (insn == BB_HEAD (bb))
- return bb->index;
- }
+ if (BLOCK_FOR_INSN (insn))
+ return BLOCK_FOR_INSN (insn)->index;
return -1;
}
{
/* If INSN is an annulled branch, skip any insns from the target
of the branch. */
- if (INSN_P (insn)
+ if (JUMP_P (insn)
&& INSN_ANNULLED_BRANCH_P (insn)
&& NEXT_INSN (PREV_INSN (insn)) != insn)
{
void
mark_referenced_resources (rtx x, struct resources *res,
- int include_delayed_effects)
+ bool include_delayed_effects)
{
enum rtx_code code = GET_CODE (x);
int i, j;
case SUBREG:
if (!REG_P (SUBREG_REG (x)))
- mark_referenced_resources (SUBREG_REG (x), res, 0);
+ mark_referenced_resources (SUBREG_REG (x), res, false);
else
{
unsigned int regno = subreg_regno (x);
res->volatil |= MEM_VOLATILE_P (x);
/* Mark registers used to access memory. */
- mark_referenced_resources (XEXP (x, 0), res, 0);
+ mark_referenced_resources (XEXP (x, 0), res, false);
return;
case CC0:
traditional asms unlike their normal usage. */
for (i = 0; i < ASM_OPERANDS_INPUT_LENGTH (x); i++)
- mark_referenced_resources (ASM_OPERANDS_INPUT (x, i), res, 0);
+ mark_referenced_resources (ASM_OPERANDS_INPUT (x, i), res, false);
return;
case CALL:
/* The first operand will be a (MEM (xxx)) but doesn't really reference
memory. The second operand may be referenced, though. */
- mark_referenced_resources (XEXP (XEXP (x, 0), 0), res, 0);
- mark_referenced_resources (XEXP (x, 1), res, 0);
+ mark_referenced_resources (XEXP (XEXP (x, 0), 0), res, false);
+ mark_referenced_resources (XEXP (x, 1), res, false);
return;
case SET:
registers used to access memory are referenced. SET_DEST is
also referenced if it is a ZERO_EXTRACT. */
- mark_referenced_resources (SET_SRC (x), res, 0);
+ mark_referenced_resources (SET_SRC (x), res, false);
x = SET_DEST (x);
if (GET_CODE (x) == ZERO_EXTRACT
|| GET_CODE (x) == STRICT_LOW_PART)
- mark_referenced_resources (x, res, 0);
+ mark_referenced_resources (x, res, false);
else if (GET_CODE (x) == SUBREG)
x = SUBREG_REG (x);
if (MEM_P (x))
- mark_referenced_resources (XEXP (x, 0), res, 0);
+ mark_referenced_resources (XEXP (x, 0), res, false);
return;
case CLOBBER:
if (frame_pointer_needed)
{
SET_HARD_REG_BIT (res->regs, FRAME_POINTER_REGNUM);
-#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+#if !HARD_FRAME_POINTER_IS_FRAME_POINTER
SET_HARD_REG_BIT (res->regs, HARD_FRAME_POINTER_REGNUM);
#endif
}
}
if (i >= seq_size)
mark_referenced_resources (XEXP (XEXP (link, 0), 0),
- res, 0);
+ res, false);
}
}
}
if (jump_count++ < 10)
{
if (any_uncondjump_p (this_jump_insn)
- || GET_CODE (PATTERN (this_jump_insn)) == RETURN)
+ || ANY_RETURN_P (PATTERN (this_jump_insn)))
{
next = JUMP_LABEL (this_jump_insn);
+ if (ANY_RETURN_P (next))
+ next = NULL_RTX;
if (jump_insn == 0)
{
jump_insn = insn;
if (jump_count >= 10)
break;
- mark_referenced_resources (insn, &needed, 1);
+ mark_referenced_resources (insn, &needed, true);
/* For an annulled branch, mark_set_resources ignores slots
filled by instructions from the target. This is correct
AND_COMPL_HARD_REG_SET (scratch, needed.regs);
AND_COMPL_HARD_REG_SET (fallthrough_res.regs, scratch);
- find_dead_or_set_registers (JUMP_LABEL (this_jump_insn),
- &target_res, 0, jump_count,
- target_set, needed);
+ if (!ANY_RETURN_P (JUMP_LABEL (this_jump_insn)))
+ find_dead_or_set_registers (JUMP_LABEL (this_jump_insn),
+ &target_res, 0, jump_count,
+ target_set, needed);
find_dead_or_set_registers (next,
&fallthrough_res, 0, jump_count,
set, needed);
}
}
- mark_referenced_resources (insn, &needed, 1);
+ mark_referenced_resources (insn, &needed, true);
mark_set_resources (insn, &set, 0, MARK_SRC_DEST_CALL);
COPY_HARD_REG_SET (scratch, set.regs);
return;
case SEQUENCE:
- for (i = 0; i < XVECLEN (x, 0); i++)
- if (! (INSN_ANNULLED_BRANCH_P (XVECEXP (x, 0, 0))
- && INSN_FROM_TARGET_P (XVECEXP (x, 0, i))))
- mark_set_resources (XVECEXP (x, 0, i), res, 0, mark_type);
+ {
+ rtx control = XVECEXP (x, 0, 0);
+ bool annul_p = JUMP_P (control) && INSN_ANNULLED_BRANCH_P (control);
+
+ mark_set_resources (control, res, 0, mark_type);
+ for (i = XVECLEN (x, 0) - 1; i >= 0; --i)
+ {
+ rtx elt = XVECEXP (x, 0, i);
+ if (!annul_p && INSN_FROM_TARGET_P (elt))
+ mark_set_resources (elt, res, 0, mark_type);
+ }
+ }
return;
case POST_INC:
static bool
return_insn_p (const_rtx insn)
{
- if (JUMP_P (insn) && GET_CODE (PATTERN (insn)) == RETURN)
+ if (JUMP_P (insn) && ANY_RETURN_P (PATTERN (insn)))
return true;
if (NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE)
(with no intervening active insns) to see if any of them start a basic
block. If we hit the start of the function first, we use block 0.
- Once we have found a basic block and a corresponding first insns, we can
- accurately compute the live status from basic_block_live_regs and
- reg_renumber. (By starting at a label following a BARRIER, we are immune
- to actions taken by reload and jump.) Then we scan all insns between
- that point and our target. For each CLOBBER (or for call-clobbered regs
- when we pass a CALL_INSN), mark the appropriate registers are dead. For
- a SET, mark them as live.
+ Once we have found a basic block and a corresponding first insn, we can
+ accurately compute the live status (by starting at a label following a
+ BARRIER, we are immune to actions taken by reload and jump.) Then we
+ scan all insns between that point and our target. For each CLOBBER (or
+ for call-clobbered regs when we pass a CALL_INSN), mark the appropriate
+ registers are dead. For a SET, mark them as live.
We have to be careful when using REG_DEAD notes because they are not
updated by such things as find_equiv_reg. So keep track of registers
struct resources set, needed;
/* Handle end of function. */
- if (target == 0)
+ if (target == 0 || ANY_RETURN_P (target))
{
*res = end_of_function_needs;
return;
else if (return_insn_p (target))
{
*res = end_of_function_needs;
- mark_referenced_resources (target, res, 0);
+ mark_referenced_resources (target, res, false);
return;
}
/* If we found a basic block, get the live registers from it and update
them with anything set or killed between its start and the insn before
- TARGET. Otherwise, we must assume everything is live. */
+ TARGET; this custom life analysis is really about registers so we need
+ to use the LR problem. Otherwise, we must assume everything is live. */
if (b != -1)
{
regset regs_live = DF_LR_IN (BASIC_BLOCK (b));
rtx start_insn, stop_insn;
- /* Compute hard regs live at start of block -- this is the real hard regs
- marked live, plus live pseudo regs that have been renumbered to
- hard regs. */
-
+ /* Compute hard regs live at start of block. */
REG_SET_TO_HARD_REG_SET (current_live_regs, regs_live);
/* Get starting and ending insn, handling the case where each might
be a SEQUENCE. */
- start_insn = (b == ENTRY_BLOCK_PTR->next_bb->index ?
+ start_insn = (b == ENTRY_BLOCK_PTR->next_bb->index ?
insns : BB_HEAD (BASIC_BLOCK (b)));
stop_insn = target;
rtx real_insn = insn;
enum rtx_code code = GET_CODE (insn);
+ if (DEBUG_INSN_P (insn))
+ continue;
+
/* If this insn is from the target of a branch, it isn't going to
be used in the sequel. If it is used in both cases, this
test will not be true. */
else if (LABEL_P (real_insn))
{
+ basic_block bb;
+
/* A label clobbers the pending dead registers since neither
reload nor jump will propagate a value across a label. */
AND_COMPL_HARD_REG_SET (current_live_regs, pending_dead_regs);
CLEAR_HARD_REG_SET (pending_dead_regs);
+
+ /* We must conservatively assume that all registers that used
+ to be live here still are. The fallthrough edge may have
+ left a live register uninitialized. */
+ bb = BLOCK_FOR_INSN (real_insn);
+ if (bb)
+ {
+ HARD_REG_SET extra_live;
+
+ REG_SET_TO_HARD_REG_SET (extra_live, DF_LR_IN (bb));
+ IOR_HARD_REG_SET (current_live_regs, extra_live);
+ }
}
/* The beginning of the epilogue corresponds to the end of the
struct resources new_resources;
rtx stop_insn = next_active_insn (jump_insn);
- mark_target_live_regs (insns, next_active_insn (jump_target),
- &new_resources);
+ if (!ANY_RETURN_P (jump_target))
+ jump_target = next_active_insn (jump_target);
+ mark_target_live_regs (insns, jump_target, &new_resources);
CLEAR_RESOURCE (&set);
CLEAR_RESOURCE (&needed);
/* Include JUMP_INSN in the needed registers. */
for (insn = target; insn != stop_insn; insn = next_active_insn (insn))
{
- mark_referenced_resources (insn, &needed, 1);
+ mark_referenced_resources (insn, &needed, true);
COPY_HARD_REG_SET (scratch, needed.regs);
AND_COMPL_HARD_REG_SET (scratch, set.regs);
init_resource_info (rtx epilogue_insn)
{
int i;
+ basic_block bb;
/* Indicate what resources are required to be valid at the end of the current
function. The condition code never is and memory always is. If the
if (frame_pointer_needed)
{
SET_HARD_REG_BIT (end_of_function_needs.regs, FRAME_POINTER_REGNUM);
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+#if !HARD_FRAME_POINTER_IS_FRAME_POINTER
SET_HARD_REG_BIT (end_of_function_needs.regs, HARD_FRAME_POINTER_REGNUM);
#endif
if (! EXIT_IGNORE_STACK
if (crtl->return_rtx != 0)
mark_referenced_resources (crtl->return_rtx,
- &end_of_function_needs, 1);
+ &end_of_function_needs, true);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (global_regs[i]
/* Allocate and initialize the tables used by mark_target_live_regs. */
target_hash_table = XCNEWVEC (struct target_info *, TARGET_HASH_PRIME);
bb_ticks = XCNEWVEC (int, last_basic_block);
+
+ /* Set the BLOCK_FOR_INSN of each label that starts a basic block. */
+ FOR_EACH_BB (bb)
+ if (LABEL_P (BB_HEAD (bb)))
+ BLOCK_FOR_INSN (BB_HEAD (bb)) = bb;
}
\f
/* Free up the resources allocated to mark_target_live_regs (). This
void
free_resource_info (void)
{
+ basic_block bb;
+
if (target_hash_table != NULL)
{
int i;
free (bb_ticks);
bb_ticks = NULL;
}
+
+ FOR_EACH_BB (bb)
+ if (LABEL_P (BB_HEAD (bb)))
+ BLOCK_FOR_INSN (BB_HEAD (bb)) = NULL;
}
\f
/* Clear any hashed information that we have stored for INSN. */
/* Add TRIAL to the set of resources used at the end of the current
function. */
void
-mark_end_of_function_resources (rtx trial, int include_delayed_effects)
+mark_end_of_function_resources (rtx trial, bool include_delayed_effects)
{
mark_referenced_resources (trial, &end_of_function_needs,
include_delayed_effects);