/* Variable tracking routines for the GNU compiler.
- Copyright (C) 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008
+ Free Software Foundation, Inc.
This file is part of GCC.
insn_stack_adjust_offset_pre_post (rtx insn, HOST_WIDE_INT *pre,
HOST_WIDE_INT *post)
{
+ rtx pattern;
+
*pre = 0;
*post = 0;
- if (GET_CODE (PATTERN (insn)) == SET)
- stack_adjust_offset_pre_post (PATTERN (insn), pre, post);
- else if (GET_CODE (PATTERN (insn)) == PARALLEL
- || GET_CODE (PATTERN (insn)) == SEQUENCE)
+ pattern = PATTERN (insn);
+ if (RTX_FRAME_RELATED_P (insn))
+ {
+ rtx expr = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX);
+ if (expr)
+ pattern = XEXP (expr, 0);
+ }
+
+ if (GET_CODE (pattern) == SET)
+ stack_adjust_offset_pre_post (pattern, pre, post);
+ else if (GET_CODE (pattern) == PARALLEL
+ || GET_CODE (pattern) == SEQUENCE)
{
int i;
/* There may be stack adjustments inside compound insns. Search
for them. */
- for ( i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
- if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET)
- stack_adjust_offset_pre_post (XVECEXP (PATTERN (insn), 0, i),
- pre, post);
+ for ( i = XVECLEN (pattern, 0) - 1; i >= 0; i--)
+ if (GET_CODE (XVECEXP (pattern, 0, i)) == SET)
+ stack_adjust_offset_pre_post (XVECEXP (pattern, 0, i), pre, post);
}
}
{
attrs list;
- list = pool_alloc (attrs_pool);
+ list = (attrs) pool_alloc (attrs_pool);
list->loc = loc;
list->decl = decl;
list->offset = offset;
attrs_list_clear (dstp);
for (; src; src = src->next)
{
- n = pool_alloc (attrs_pool);
+ n = (attrs) pool_alloc (attrs_pool);
n->loc = src->loc;
n->decl = src->decl;
n->offset = src->offset;
variable new_var;
int i;
- new_var = pool_alloc (var_pool);
+ new_var = (variable) pool_alloc (var_pool);
new_var->decl = var->decl;
new_var->refcount = 1;
var->refcount--;
{
location_chain new_lc;
- new_lc = pool_alloc (loc_chain_pool);
+ new_lc = (location_chain) pool_alloc (loc_chain_pool);
new_lc->next = NULL;
if (node->init > initialized)
new_lc->init = node->init;
static int
variable_union_info_cmp_pos (const void *n1, const void *n2)
{
- const struct variable_union_info *i1 = n1;
- const struct variable_union_info *i2 = n2;
+ const struct variable_union_info *const i1 =
+ (const struct variable_union_info *) n1;
+ const struct variable_union_info *const i2 =
+ ( const struct variable_union_info *) n2;
if (i1->pos != i2->pos)
return i1->pos - i2->pos;
location_chain new_node;
/* Copy the location from SRC. */
- new_node = pool_alloc (loc_chain_pool);
+ new_node = (location_chain) pool_alloc (loc_chain_pool);
new_node->loc = node->loc;
new_node->init = node->init;
if (!node->set_src || MEM_P (node->set_src))
{
location_chain new_lc;
- new_lc = pool_alloc (loc_chain_pool);
+ new_lc = (location_chain) pool_alloc (loc_chain_pool);
new_lc->next = NULL;
new_lc->init = node->init;
if (!node->set_src || MEM_P (node->set_src))
variable var1, var2;
var1 = *(variable *) slot;
- var2 = htab_find_with_hash (htab, var1->decl,
+ var2 = (variable) htab_find_with_hash (htab, var1->decl,
VARIABLE_HASH_VAL (var1->decl));
if (!var2)
{
variable var1, var2;
var1 = *(variable *) slot;
- var2 = htab_find_with_hash (htab, var1->decl,
+ var2 = (variable) htab_find_with_hash (htab, var1->decl,
VARIABLE_HASH_VAL (var1->decl));
if (!var2)
{
return 1;
}
-/* Return true if OFFSET is a valid offset for a register or memory
- access we want to track. This is used to reject out-of-bounds
- accesses that can cause assertions to fail later. Note that we
- don't reject negative offsets because they can be generated for
- paradoxical subregs on big-endian architectures. */
-
-static inline bool
-offset_valid_for_tracked_p (HOST_WIDE_INT offset)
-{
- return (-MAX_VAR_PARTS < offset) && (offset < MAX_VAR_PARTS);
-}
-
/* Determine whether a given LOC refers to the same variable part as
EXPR+OFFSET. */
return (expr == expr2 && offset == offset2);
}
-/* REG is a register we want to track. If not all of REG contains useful
- information, return the mode of the lowpart that does contain useful
- information, otherwise return the mode of REG.
+/* LOC is a REG or MEM that we would like to track if possible.
+ If EXPR is null, we don't know what expression LOC refers to,
+ otherwise it refers to EXPR + OFFSET. STORE_REG_P is true if
+ LOC is an lvalue register.
- If REG was a paradoxical subreg, its REG_ATTRS will describe the
- whole subreg, but only the old inner part is really relevant. */
+ Return true if EXPR is nonnull and if LOC, or some lowpart of it,
+ is something we can track. When returning true, store the mode of
+ the lowpart we can track in *MODE_OUT (if nonnull) and its offset
+ from EXPR in *OFFSET_OUT (if nonnull). */
-static enum machine_mode
-mode_for_reg_attrs (rtx reg)
+static bool
+track_loc_p (rtx loc, tree expr, HOST_WIDE_INT offset, bool store_reg_p,
+ enum machine_mode *mode_out, HOST_WIDE_INT *offset_out)
{
enum machine_mode mode;
- mode = GET_MODE (reg);
- if (!HARD_REGISTER_NUM_P (ORIGINAL_REGNO (reg)))
+ if (expr == NULL || !track_expr_p (expr))
+ return false;
+
+ /* If REG was a paradoxical subreg, its REG_ATTRS will describe the
+ whole subreg, but only the old inner part is really relevant. */
+ mode = GET_MODE (loc);
+ if (REG_P (loc) && !HARD_REGISTER_NUM_P (ORIGINAL_REGNO (loc)))
{
enum machine_mode pseudo_mode;
- pseudo_mode = PSEUDO_REGNO_MODE (ORIGINAL_REGNO (reg));
+ pseudo_mode = PSEUDO_REGNO_MODE (ORIGINAL_REGNO (loc));
if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (pseudo_mode))
- mode = pseudo_mode;
+ {
+ offset += byte_lowpart_offset (pseudo_mode, mode);
+ mode = pseudo_mode;
+ }
}
- return mode;
+
+ /* If LOC is a paradoxical lowpart of EXPR, refer to EXPR itself.
+ Do the same if we are storing to a register and EXPR occupies
+ the whole of register LOC; in that case, the whole of EXPR is
+ being changed. We exclude complex modes from the second case
+ because the real and imaginary parts are represented as separate
+ pseudo registers, even if the whole complex value fits into one
+ hard register. */
+ if ((GET_MODE_SIZE (mode) > GET_MODE_SIZE (DECL_MODE (expr))
+ || (store_reg_p
+ && !COMPLEX_MODE_P (DECL_MODE (expr))
+ && hard_regno_nregs[REGNO (loc)][DECL_MODE (expr)] == 1))
+ && offset + byte_lowpart_offset (DECL_MODE (expr), mode) == 0)
+ {
+ mode = DECL_MODE (expr);
+ offset = 0;
+ }
+
+ if (offset < 0 || offset >= MAX_VAR_PARTS)
+ return false;
+
+ if (mode_out)
+ *mode_out = mode;
+ if (offset_out)
+ *offset_out = offset;
+ return true;
}
/* Return the MODE lowpart of LOC, or null if LOC is not something we
static rtx
var_lowpart (enum machine_mode mode, rtx loc)
{
- unsigned int offset, regno;
+ unsigned int offset, reg_offset, regno;
if (!REG_P (loc) && !MEM_P (loc))
return NULL;
if (GET_MODE (loc) == mode)
return loc;
- offset = subreg_lowpart_offset (mode, GET_MODE (loc));
+ offset = byte_lowpart_offset (mode, GET_MODE (loc));
if (MEM_P (loc))
return adjust_address_nv (loc, mode, offset);
+ reg_offset = subreg_lowpart_offset (mode, GET_MODE (loc));
regno = REGNO (loc) + subreg_regno_offset (REGNO (loc), GET_MODE (loc),
- offset, mode);
+ reg_offset, mode);
return gen_rtx_REG_offset (loc, mode, regno, offset);
}
VTI (bb)->n_mos++;
}
else if (MEM_P (*loc)
- && MEM_EXPR (*loc)
- && track_expr_p (MEM_EXPR (*loc))
- && offset_valid_for_tracked_p (INT_MEM_OFFSET (*loc)))
+ && track_loc_p (*loc, MEM_EXPR (*loc), INT_MEM_OFFSET (*loc),
+ false, NULL, NULL))
{
VTI (bb)->n_mos++;
}
static int
add_uses (rtx *loc, void *insn)
{
+ enum machine_mode mode;
+
if (REG_P (*loc))
{
basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
- if (REG_EXPR (*loc)
- && track_expr_p (REG_EXPR (*loc))
- && offset_valid_for_tracked_p (REG_OFFSET (*loc)))
+ if (track_loc_p (*loc, REG_EXPR (*loc), REG_OFFSET (*loc),
+ false, &mode, NULL))
{
mo->type = MO_USE;
- mo->u.loc = var_lowpart (mode_for_reg_attrs (*loc), *loc);
+ mo->u.loc = var_lowpart (mode, *loc);
}
else
{
mo->insn = (rtx) insn;
}
else if (MEM_P (*loc)
- && MEM_EXPR (*loc)
- && track_expr_p (MEM_EXPR (*loc))
- && offset_valid_for_tracked_p (INT_MEM_OFFSET (*loc)))
+ && track_loc_p (*loc, MEM_EXPR (*loc), INT_MEM_OFFSET (*loc),
+ false, &mode, NULL))
{
basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
mo->type = MO_USE;
- mo->u.loc = *loc;
+ mo->u.loc = var_lowpart (mode, *loc);
mo->insn = (rtx) insn;
}
static void
add_stores (rtx loc, const_rtx expr, void *insn)
{
+ enum machine_mode mode;
+
if (REG_P (loc))
{
basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
if (GET_CODE (expr) == CLOBBER
- || !(REG_EXPR (loc)
- && track_expr_p (REG_EXPR (loc))
- && offset_valid_for_tracked_p (REG_OFFSET (loc))))
+ || !track_loc_p (loc, REG_EXPR (loc), REG_OFFSET (loc),
+ true, &mode, NULL))
{
mo->type = MO_CLOBBER;
mo->u.loc = loc;
}
else
{
- enum machine_mode mode = mode_for_reg_attrs (loc);
rtx src = NULL;
if (GET_CODE (expr) == SET && SET_DEST (expr) == loc)
mo->insn = (rtx) insn;
}
else if (MEM_P (loc)
- && MEM_EXPR (loc)
- && track_expr_p (MEM_EXPR (loc))
- && offset_valid_for_tracked_p (INT_MEM_OFFSET (loc)))
+ && track_loc_p (loc, MEM_EXPR (loc), INT_MEM_OFFSET (loc),
+ false, &mode, NULL))
{
basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
if (GET_CODE (expr) == CLOBBER)
{
mo->type = MO_CLOBBER;
- mo->u.loc = loc;
+ mo->u.loc = var_lowpart (mode, loc);
}
else
{
rtx src = NULL;
if (GET_CODE (expr) == SET && SET_DEST (expr) == loc)
- src = var_lowpart (GET_MODE (loc), SET_SRC (expr));
+ src = var_lowpart (mode, SET_SRC (expr));
+ loc = var_lowpart (mode, loc);
if (src == NULL)
{
}
else
{
+ if (SET_SRC (expr) != src)
+ expr = gen_rtx_SET (VOIDmode, loc, src);
if (same_variable_part_p (SET_SRC (expr),
MEM_EXPR (loc),
INT_MEM_OFFSET (loc)))
while (!fibheap_empty (worklist))
{
- bb = fibheap_extract_min (worklist);
+ bb = (basic_block) fibheap_extract_min (worklist);
RESET_BIT (in_worklist, bb->index);
if (!TEST_BIT (visited, bb->index))
{
variable empty_var;
void **old;
- empty_var = pool_alloc (var_pool);
+ empty_var = (variable) pool_alloc (var_pool);
empty_var->decl = var->decl;
empty_var->refcount = 1;
empty_var->n_var_parts = 0;
if (!*slot)
{
/* Create new variable information. */
- var = pool_alloc (var_pool);
+ var = (variable) pool_alloc (var_pool);
var->decl = decl;
var->refcount = 1;
var->n_var_parts = 1;
}
/* Add the location to the beginning. */
- node = pool_alloc (loc_chain_pool);
+ node = (location_chain) pool_alloc (loc_chain_pool);
node->loc = loc;
node->init = initialized;
node->set_src = set_src;
pool_free (attrs_pool, anode);
*anextp = anext;
}
+ else
+ anextp = &anode->next;
}
}
variable old_var, new_var;
old_var = *(variable *) slot;
- new_var = htab_find_with_hash (new_vars, old_var->decl,
+ new_var = (variable) htab_find_with_hash (new_vars, old_var->decl,
VARIABLE_HASH_VAL (old_var->decl));
if (!new_var)
/* Variable has disappeared. */
variable empty_var;
- empty_var = pool_alloc (var_pool);
+ empty_var = (variable) pool_alloc (var_pool);
empty_var->decl = old_var->decl;
empty_var->refcount = 1;
empty_var->n_var_parts = 0;
variable old_var, new_var;
new_var = *(variable *) slot;
- old_var = htab_find_with_hash (old_vars, new_var->decl,
+ old_var = (variable) htab_find_with_hash (old_vars, new_var->decl,
VARIABLE_HASH_VAL (new_var->decl));
if (!old_var)
{
rtx decl_rtl = DECL_RTL_IF_SET (parm);
rtx incoming = DECL_INCOMING_RTL (parm);
tree decl;
+ enum machine_mode mode;
HOST_WIDE_INT offset;
dataflow_set *out;
continue;
if (!vt_get_decl_and_offset (incoming, &decl, &offset))
- if (!vt_get_decl_and_offset (decl_rtl, &decl, &offset))
- continue;
+ {
+ if (!vt_get_decl_and_offset (decl_rtl, &decl, &offset))
+ continue;
+ offset += byte_lowpart_offset (GET_MODE (incoming),
+ GET_MODE (decl_rtl));
+ }
if (!decl)
continue;
- gcc_assert (parm == decl);
+ if (parm != decl)
+ {
+ /* Assume that DECL_RTL was a pseudo that got spilled to
+ memory. The spill slot sharing code will force the
+ memory to reference spill_slot_decl (%sfp), so we don't
+ match above. That's ok, the pseudo must have referenced
+ the entire parameter, so just reset OFFSET. */
+ gcc_assert (decl == get_spill_slot_decl (false));
+ offset = 0;
+ }
+
+ if (!track_loc_p (incoming, parm, offset, false, &mode, &offset))
+ continue;
out = &VTI (ENTRY_BLOCK_PTR)->out;
if (REG_P (incoming))
{
+ incoming = var_lowpart (mode, incoming);
gcc_assert (REGNO (incoming) < FIRST_PSEUDO_REGISTER);
attrs_list_insert (&out->regs[REGNO (incoming)],
parm, offset, incoming);
NULL);
}
else if (MEM_P (incoming))
- set_variable_part (out, incoming, parm, offset, VAR_INIT_STATUS_INITIALIZED,
- NULL);
+ {
+ incoming = var_lowpart (mode, incoming);
+ set_variable_part (out, incoming, parm, offset,
+ VAR_INIT_STATUS_INITIALIZED, NULL);
+ }
}
}
-struct tree_opt_pass pass_variable_tracking =
+struct rtl_opt_pass pass_variable_tracking =
{
+ {
+ RTL_PASS,
"vartrack", /* name */
gate_handle_var_tracking, /* gate */
variable_tracking_main, /* execute */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_func | TODO_verify_rtl_sharing,/* todo_flags_finish */
- 'V' /* letter */
+ TODO_dump_func | TODO_verify_rtl_sharing/* todo_flags_finish */
+ }
};