/* Data flow functions for trees.
- Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@redhat.com>
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
long num_phis;
long num_phi_args;
int max_num_phi_args;
- long num_v_may_defs;
+ long num_vdefs;
long num_vuses;
- long num_v_must_defs;
};
static tree find_vars_r (tree *, int *, void *);
-/* Global declarations. */
-
-/* Array of all variables referenced in the function. */
-htab_t referenced_vars;
-
-/* Default definition for this symbols. If set for symbol, it
- means that the first reference to this variable in the function is a
- USE or a VUSE. In those cases, the SSA renamer creates an SSA name
- for this variable with an empty defining statement. */
-htab_t default_defs;
-
-
/*---------------------------------------------------------------------------
Dataflow analysis (DFA) routines
---------------------------------------------------------------------------*/
create_var_ann (tree t)
{
var_ann_t ann;
+ struct static_var_ann_d *sann = NULL;
gcc_assert (t);
gcc_assert (DECL_P (t));
- gcc_assert (!t->common.ann || t->common.ann->common.type == VAR_ANN);
+ gcc_assert (!t->base.ann || t->base.ann->common.type == VAR_ANN);
- ann = GGC_CNEW (struct var_ann_d);
+ if (!MTAG_P (t) && (TREE_STATIC (t) || DECL_EXTERNAL (t)))
+ {
+ sann = GGC_CNEW (struct static_var_ann_d);
+ ann = &sann->ann;
+ }
+ else
+ ann = GGC_CNEW (struct var_ann_d);
ann->common.type = VAR_ANN;
- t->common.ann = (tree_ann_t) ann;
+ if (!MTAG_P (t) && (TREE_STATIC (t) || DECL_EXTERNAL (t)))
+ {
+ void **slot;
+ sann->uid = DECL_UID (t);
+ slot = htab_find_slot_with_hash (gimple_var_anns (cfun),
+ t, DECL_UID (t), INSERT);
+ gcc_assert (!*slot);
+ *slot = sann;
+ }
+ else
+ t->base.ann = (tree_ann_t) ann;
return ann;
}
gcc_assert (t);
gcc_assert (TREE_CODE (t) == FUNCTION_DECL);
- gcc_assert (!t->common.ann || t->common.ann->common.type == FUNCTION_ANN);
+ gcc_assert (!t->base.ann || t->base.ann->common.type == FUNCTION_ANN);
ann = ggc_alloc (sizeof (*ann));
memset ((void *) ann, 0, sizeof (*ann));
ann->common.type = FUNCTION_ANN;
- t->common.ann = (tree_ann_t) ann;
+ t->base.ann = (tree_ann_t) ann;
return ann;
}
stmt_ann_t ann;
gcc_assert (is_gimple_stmt (t));
- gcc_assert (!t->common.ann || t->common.ann->common.type == STMT_ANN);
+ gcc_assert (!t->base.ann || t->base.ann->common.type == STMT_ANN);
ann = GGC_CNEW (struct stmt_ann_d);
/* Since we just created the annotation, mark the statement modified. */
ann->modified = true;
- t->common.ann = (tree_ann_t) ann;
+ t->base.ann = (tree_ann_t) ann;
return ann;
}
tree_ann_common_t ann;
gcc_assert (t);
- gcc_assert (!t->common.ann || t->common.ann->common.type == TREE_ANN_COMMON);
+ gcc_assert (!t->base.ann || t->base.ann->common.type == TREE_ANN_COMMON);
ann = GGC_CNEW (struct tree_ann_common_d);
ann->type = TREE_ANN_COMMON;
- t->common.ann = (tree_ann_t) ann;
+ t->base.ann = (tree_ann_t) ann;
return ann;
}
{
tree t = create_tmp_var (type, prefix);
- if (TREE_CODE (type) == COMPLEX_TYPE)
- DECL_COMPLEX_GIMPLE_REG_P (t) = 1;
+ if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
+ || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
+ DECL_GIMPLE_REG_P (t) = 1;
- if (referenced_vars)
+ if (gimple_referenced_vars (cfun))
{
add_referenced_var (t);
mark_sym_for_renaming (t);
ann = var_ann (var);
- fprintf (file, ", UID %u", (unsigned) DECL_UID (var));
+ fprintf (file, ", UID D.%u", (unsigned) DECL_UID (var));
fprintf (file, ", ");
print_generic_expr (file, TREE_TYPE (var), dump_flags);
print_generic_expr (file, ann->symbol_mem_tag, dump_flags);
}
- if (ann && ann->is_aliased)
- fprintf (file, ", is aliased");
-
if (TREE_ADDRESSABLE (var))
fprintf (file, ", is addressable");
if (TREE_THIS_VOLATILE (var))
fprintf (file, ", is volatile");
+ if (mem_sym_stats (cfun, var))
+ {
+ mem_sym_stats_t stats = mem_sym_stats (cfun, var);
+ fprintf (file, ", direct reads: %ld", stats->num_direct_reads);
+ fprintf (file, ", direct writes: %ld", stats->num_direct_writes);
+ fprintf (file, ", indirect reads: %ld", stats->num_indirect_reads);
+ fprintf (file, ", indirect writes: %ld", stats->num_indirect_writes);
+ fprintf (file, ", read frequency: %ld", stats->frequency_reads);
+ fprintf (file, ", write frequency: %ld", stats->frequency_writes);
+ }
+
if (is_call_clobbered (var))
{
+ const char *s = "";
+ var_ann_t va = var_ann (var);
+ unsigned int escape_mask = va->escape_mask;
+
fprintf (file, ", call clobbered");
- if (dump_flags & TDF_DETAILS)
- {
- var_ann_t va = var_ann (var);
- unsigned int escape_mask = va->escape_mask;
-
- fprintf (file, " (");
- if (escape_mask & ESCAPE_STORED_IN_GLOBAL)
- fprintf (file, ", stored in global");
- if (escape_mask & ESCAPE_TO_ASM)
- fprintf (file, ", goes through ASM");
- if (escape_mask & ESCAPE_TO_CALL)
- fprintf (file, ", passed to call");
- if (escape_mask & ESCAPE_BAD_CAST)
- fprintf (file, ", bad cast");
- if (escape_mask & ESCAPE_TO_RETURN)
- fprintf (file, ", returned from func");
- if (escape_mask & ESCAPE_TO_PURE_CONST)
- fprintf (file, ", passed to pure/const");
- if (escape_mask & ESCAPE_IS_GLOBAL)
- fprintf (file, ", is global var");
- if (escape_mask & ESCAPE_IS_PARM)
- fprintf (file, ", is incoming pointer");
- if (escape_mask & ESCAPE_UNKNOWN)
- fprintf (file, ", unknown escape");
- fprintf (file, " )");
- }
+ fprintf (file, " (");
+ if (escape_mask & ESCAPE_STORED_IN_GLOBAL)
+ { fprintf (file, "%sstored in global", s); s = ", "; }
+ if (escape_mask & ESCAPE_TO_ASM)
+ { fprintf (file, "%sgoes through ASM", s); s = ", "; }
+ if (escape_mask & ESCAPE_TO_CALL)
+ { fprintf (file, "%spassed to call", s); s = ", "; }
+ if (escape_mask & ESCAPE_BAD_CAST)
+ { fprintf (file, "%sbad cast", s); s = ", "; }
+ if (escape_mask & ESCAPE_TO_RETURN)
+ { fprintf (file, "%sreturned from func", s); s = ", "; }
+ if (escape_mask & ESCAPE_TO_PURE_CONST)
+ { fprintf (file, "%spassed to pure/const", s); s = ", "; }
+ if (escape_mask & ESCAPE_IS_GLOBAL)
+ { fprintf (file, "%sis global var", s); s = ", "; }
+ if (escape_mask & ESCAPE_IS_PARM)
+ { fprintf (file, "%sis incoming pointer", s); s = ", "; }
+ if (escape_mask & ESCAPE_UNKNOWN)
+ { fprintf (file, "%sunknown escape", s); s = ", "; }
+ fprintf (file, ")");
}
- if (default_def (var))
+ if (ann->noalias_state == NO_ALIAS)
+ fprintf (file, ", NO_ALIAS (does not alias other NO_ALIAS symbols)");
+ else if (ann->noalias_state == NO_ALIAS_GLOBAL)
+ fprintf (file, ", NO_ALIAS_GLOBAL (does not alias other NO_ALIAS symbols"
+ " and global vars)");
+ else if (ann->noalias_state == NO_ALIAS_ANYTHING)
+ fprintf (file, ", NO_ALIAS_ANYTHING (does not alias any other symbols)");
+
+ if (gimple_default_def (cfun, var))
{
fprintf (file, ", default def: ");
- print_generic_expr (file, default_def (var), dump_flags);
+ print_generic_expr (file, gimple_default_def (cfun, var), dump_flags);
}
- if (may_aliases (var))
+ if (MTAG_P (var) && may_aliases (var))
{
fprintf (file, ", may aliases: ");
dump_may_aliases_for (file, var);
dump_subvars_for (file, var);
}
+ if (!is_gimple_reg (var))
+ {
+ if (memory_partition (var))
+ {
+ fprintf (file, ", belongs to partition: ");
+ print_generic_expr (file, memory_partition (var), dump_flags);
+ }
+
+ if (TREE_CODE (var) == MEMORY_PARTITION_TAG)
+ {
+ fprintf (file, ", partition symbols: ");
+ dump_decl_set (file, MPT_SYMBOLS (var));
+ }
+ }
+
fprintf (file, "\n");
}
fprintf (file, fmt_str_1, "VUSE operands", dfa_stats.num_vuses,
SCALE (size), LABEL (size));
- size = dfa_stats.num_v_may_defs * sizeof (tree *);
- total += size;
- fprintf (file, fmt_str_1, "V_MAY_DEF operands", dfa_stats.num_v_may_defs,
- SCALE (size), LABEL (size));
-
- size = dfa_stats.num_v_must_defs * sizeof (tree *);
+ size = dfa_stats.num_vdefs * sizeof (tree *);
total += size;
- fprintf (file, fmt_str_1, "V_MUST_DEF operands", dfa_stats.num_v_must_defs,
+ fprintf (file, fmt_str_1, "VDEF operands", dfa_stats.num_vdefs,
SCALE (size), LABEL (size));
size = dfa_stats.num_phis * sizeof (struct tree_phi_node);
tree t = *tp;
struct dfa_stats_d *dfa_stats_p = (struct dfa_stats_d *)data;
- if (t->common.ann)
+ if (t->base.ann)
{
- switch (ann_type (t->common.ann))
+ switch (ann_type (t->base.ann))
{
case STMT_ANN:
{
dfa_stats_p->num_stmt_anns++;
dfa_stats_p->num_defs += NUM_SSA_OPERANDS (t, SSA_OP_DEF);
dfa_stats_p->num_uses += NUM_SSA_OPERANDS (t, SSA_OP_USE);
- dfa_stats_p->num_v_may_defs += NUM_SSA_OPERANDS (t, SSA_OP_VMAYDEF);
+ dfa_stats_p->num_vdefs += NUM_SSA_OPERANDS (t, SSA_OP_VDEF);
dfa_stats_p->num_vuses += NUM_SSA_OPERANDS (t, SSA_OP_VUSE);
- dfa_stats_p->num_v_must_defs +=
- NUM_SSA_OPERANDS (t, SSA_OP_VMUSTDEF);
break;
}
tree
referenced_var_lookup (unsigned int uid)
{
- struct int_tree_map *h, in;
+ tree h;
+ struct tree_decl_minimal in;
in.uid = uid;
- h = (struct int_tree_map *) htab_find_with_hash (referenced_vars, &in, uid);
+ h = (tree) htab_find_with_hash (gimple_referenced_vars (cfun), &in, uid);
gcc_assert (h || uid == 0);
- if (h)
- return h->to;
- return NULL_TREE;
+ return h;
}
/* Check if TO is in the referenced_vars hash table and insert it if not.
Return true if it required insertion. */
-static bool
+bool
referenced_var_check_and_insert (tree to)
{
- struct int_tree_map *h, in;
- void **loc;
+ tree h, *loc;
+ struct tree_decl_minimal in;
unsigned int uid = DECL_UID (to);
in.uid = uid;
- in.to = to;
- h = (struct int_tree_map *) htab_find_with_hash (referenced_vars, &in, uid);
-
+ h = (tree) htab_find_with_hash (gimple_referenced_vars (cfun), &in, uid);
if (h)
{
/* DECL_UID has already been entered in the table. Verify that it is
the same entry as TO. See PR 27793. */
- gcc_assert (h->to == to);
+ gcc_assert (h == to);
return false;
}
- h = GGC_NEW (struct int_tree_map);
- h->uid = uid;
- h->to = to;
- loc = htab_find_slot_with_hash (referenced_vars, h, uid, INSERT);
- *(struct int_tree_map **) loc = h;
+ loc = (tree *) htab_find_slot_with_hash (gimple_referenced_vars (cfun),
+ &in, uid, INSERT);
+ *loc = to;
return true;
}
variable. */
tree
-default_def (tree var)
+gimple_default_def (struct function *fn, tree var)
{
- struct int_tree_map *h, in;
+ struct tree_decl_minimal ind;
+ struct tree_ssa_name in;
gcc_assert (SSA_VAR_P (var));
- in.uid = DECL_UID (var);
- h = (struct int_tree_map *) htab_find_with_hash (default_defs, &in,
- DECL_UID (var));
- if (h)
- return h->to;
- return NULL_TREE;
+ in.var = (tree)&ind;
+ ind.uid = DECL_UID (var);
+ return (tree) htab_find_with_hash (DEFAULT_DEFS (fn), &in, DECL_UID (var));
}
/* Insert the pair VAR's UID, DEF into the default_defs hashtable. */
void
set_default_def (tree var, tree def)
{
- struct int_tree_map in;
- struct int_tree_map *h;
+ struct tree_decl_minimal ind;
+ struct tree_ssa_name in;
void **loc;
gcc_assert (SSA_VAR_P (var));
- in.uid = DECL_UID (var);
- if (!def && default_def (var))
+ in.var = (tree)&ind;
+ ind.uid = DECL_UID (var);
+ if (!def)
{
- loc = htab_find_slot_with_hash (default_defs, &in, DECL_UID (var), INSERT);
- htab_remove_elt (default_defs, *loc);
+ loc = htab_find_slot_with_hash (DEFAULT_DEFS (cfun), &in,
+ DECL_UID (var), INSERT);
+ gcc_assert (*loc);
+ htab_remove_elt (DEFAULT_DEFS (cfun), *loc);
return;
}
- gcc_assert (TREE_CODE (def) == SSA_NAME);
- loc = htab_find_slot_with_hash (default_defs, &in, DECL_UID (var), INSERT);
+ gcc_assert (TREE_CODE (def) == SSA_NAME && SSA_NAME_VAR (def) == var);
+ loc = htab_find_slot_with_hash (DEFAULT_DEFS (cfun), &in,
+ DECL_UID (var), INSERT);
+
/* Default definition might be changed by tail call optimization. */
- if (!*loc)
- {
- h = GGC_NEW (struct int_tree_map);
- h->uid = DECL_UID (var);
- h->to = def;
- *(struct int_tree_map **) loc = h;
- }
- else
- {
- h = (struct int_tree_map *) *loc;
- h->to = def;
- }
+ if (*loc)
+ SSA_NAME_IS_DEFAULT_DEF (*(tree *) loc) = false;
+ *(tree *) loc = def;
+
+ /* Mark DEF as the default definition for VAR. */
+ SSA_NAME_IS_DEFAULT_DEF (def) = true;
}
/* Add VAR to the list of referenced variables if it isn't already there. */
/* Scan DECL_INITIAL for pointer variables as they may contain
address arithmetic referencing the address of other
- variables. */
+ variables.
+ Even non-constant intializers need to be walked, because
+ IPA passes might prove that their are invariant later on. */
if (DECL_INITIAL (var)
/* Initializers of external variables are not useful to the
optimizers. */
- && !DECL_EXTERNAL (var)
- /* It's not necessary to walk the initial value of non-constant
- variables because it cannot be propagated by the
- optimizers. */
- && (TREE_CONSTANT (var) || TREE_READONLY (var)))
+ && !DECL_EXTERNAL (var))
walk_tree (&DECL_INITIAL (var), find_vars_r, NULL, 0);
}
}
+/* Remove VAR from the list. */
+
+void
+remove_referenced_var (tree var)
+{
+ var_ann_t v_ann;
+ struct tree_decl_minimal in;
+ void **loc;
+ unsigned int uid = DECL_UID (var);
+
+ clear_call_clobbered (var);
+ v_ann = get_var_ann (var);
+ ggc_free (v_ann);
+ var->base.ann = NULL;
+ gcc_assert (DECL_P (var));
+ in.uid = uid;
+ loc = htab_find_slot_with_hash (gimple_referenced_vars (cfun), &in, uid,
+ NO_INSERT);
+ htab_clear_slot (gimple_referenced_vars (cfun), loc);
+}
+
/* Return the virtual variable associated to the non-scalar variable VAR. */
return var;
}
-/* Mark all the non-SSA variables found in STMT's operands to be
- processed by update_ssa. */
+/* Mark all the naked symbols in STMT for SSA renaming.
+
+ NOTE: This function should only be used for brand new statements.
+ If the caller is modifying an existing statement, it should use the
+ combination push_stmt_changes/pop_stmt_changes. */
void
-mark_new_vars_to_rename (tree stmt)
+mark_symbols_for_renaming (tree stmt)
{
+ tree op;
ssa_op_iter iter;
- tree val;
- bitmap vars_in_vops_to_rename;
- bool found_exposed_symbol = false;
- int v_may_defs_before, v_may_defs_after;
- int v_must_defs_before, v_must_defs_after;
-
- if (TREE_CODE (stmt) == PHI_NODE)
- return;
-
- get_stmt_ann (stmt);
- vars_in_vops_to_rename = BITMAP_ALLOC (NULL);
-
- /* Before re-scanning the statement for operands, mark the existing
- virtual operands to be renamed again. We do this because when new
- symbols are exposed, the virtual operands that were here before due to
- aliasing will probably be removed by the call to get_stmt_operand.
- Therefore, we need to flag them to be renamed beforehand.
- We flag them in a separate bitmap because we don't really want to
- rename them if there are not any newly exposed symbols in the
- statement operands. */
- v_may_defs_before = NUM_SSA_OPERANDS (stmt, SSA_OP_VMAYDEF);
- v_must_defs_before = NUM_SSA_OPERANDS (stmt, SSA_OP_VMUSTDEF);
-
- FOR_EACH_SSA_TREE_OPERAND (val, stmt, iter,
- SSA_OP_VMAYDEF | SSA_OP_VUSE | SSA_OP_VMUSTDEF)
- {
- if (!DECL_P (val))
- val = SSA_NAME_VAR (val);
- bitmap_set_bit (vars_in_vops_to_rename, DECL_UID (val));
- }
-
- /* Now force an operand re-scan on the statement and mark any newly
- exposed variables. */
update_stmt (stmt);
- v_may_defs_after = NUM_SSA_OPERANDS (stmt, SSA_OP_VMAYDEF);
- v_must_defs_after = NUM_SSA_OPERANDS (stmt, SSA_OP_VMUSTDEF);
-
- FOR_EACH_SSA_TREE_OPERAND (val, stmt, iter, SSA_OP_ALL_OPERANDS)
- if (DECL_P (val))
- {
- found_exposed_symbol = true;
- mark_sym_for_renaming (val);
- }
-
- /* If we found any newly exposed symbols, or if there are fewer VDEF
- operands in the statement, add the variables we had set in
- VARS_IN_VOPS_TO_RENAME to VARS_TO_RENAME. We need to check for
- vanishing VDEFs because in those cases, the names that were formerly
- generated by this statement are not going to be available anymore. */
- if (found_exposed_symbol
- || v_may_defs_before > v_may_defs_after
- || v_must_defs_before > v_must_defs_after)
- mark_set_for_renaming (vars_in_vops_to_rename);
-
- BITMAP_FREE (vars_in_vops_to_rename);
+ /* Mark all the operands for renaming. */
+ FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_ALL_OPERANDS)
+ if (DECL_P (op))
+ mark_sym_for_renaming (op);
}
+
/* Find all variables within the gimplified statement that were not previously
visible to the function and add them to the referenced variables list. */
}
-/* If REF is a handled component reference for a structure, return the
+/* If EXP is a handled component reference for a structure, return the
base variable. The access range is delimited by bit positions *POFFSET and
*POFFSET + *PMAX_SIZE. The access size is *PSIZE bits. If either
*PSIZE or *PMAX_SIZE is -1, they could not be determined. If *PSIZE
HOST_WIDE_INT bitsize = -1;
HOST_WIDE_INT maxsize = -1;
tree size_tree = NULL_TREE;
- tree bit_offset = bitsize_zero_node;
+ HOST_WIDE_INT bit_offset = 0;
bool seen_variable_array_ref = false;
gcc_assert (!SSA_VAR_P (exp));
switch (TREE_CODE (exp))
{
case BIT_FIELD_REF:
- bit_offset = size_binop (PLUS_EXPR, bit_offset,
- TREE_OPERAND (exp, 2));
+ bit_offset += tree_low_cst (TREE_OPERAND (exp, 2), 0);
break;
case COMPONENT_REF:
if (this_offset && TREE_CODE (this_offset) == INTEGER_CST)
{
- this_offset = size_binop (MULT_EXPR,
- fold_convert (bitsizetype,
- this_offset),
- bitsize_unit_node);
- bit_offset = size_binop (PLUS_EXPR,
- bit_offset, this_offset);
- bit_offset = size_binop (PLUS_EXPR, bit_offset,
- DECL_FIELD_BIT_OFFSET (field));
+ HOST_WIDE_INT hthis_offset = tree_low_cst (this_offset, 0);
+
+ hthis_offset *= BITS_PER_UNIT;
+ bit_offset += hthis_offset;
+ bit_offset += tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 0);
}
else
{
/* We need to adjust maxsize to the whole structure bitsize.
But we can subtract any constant offset seen sofar,
because that would get us out of the structure otherwise. */
- if (maxsize != -1
- && csize && host_integerp (csize, 1))
- {
- maxsize = (TREE_INT_CST_LOW (csize)
- - TREE_INT_CST_LOW (bit_offset));
- }
+ if (maxsize != -1 && csize && host_integerp (csize, 1))
+ maxsize = TREE_INT_CST_LOW (csize) - bit_offset;
else
maxsize = -1;
}
tree low_bound = array_ref_low_bound (exp);
tree unit_size = array_ref_element_size (exp);
- if (! integer_zerop (low_bound))
- index = fold_build2 (MINUS_EXPR, TREE_TYPE (index),
- index, low_bound);
- index = size_binop (MULT_EXPR,
- fold_convert (sizetype, index), unit_size);
- if (TREE_CODE (index) == INTEGER_CST)
+ /* If the resulting bit-offset is constant, track it. */
+ if (host_integerp (index, 0)
+ && host_integerp (low_bound, 0)
+ && host_integerp (unit_size, 1))
{
- index = size_binop (MULT_EXPR,
- fold_convert (bitsizetype, index),
- bitsize_unit_node);
- bit_offset = size_binop (PLUS_EXPR, bit_offset, index);
+ HOST_WIDE_INT hindex = tree_low_cst (index, 0);
+
+ hindex -= tree_low_cst (low_bound, 0);
+ hindex *= tree_low_cst (unit_size, 1);
+ hindex *= BITS_PER_UNIT;
+ bit_offset += hindex;
/* An array ref with a constant index up in the structure
hierarchy will constrain the size of any variable array ref
/* We need to adjust maxsize to the whole array bitsize.
But we can subtract any constant offset seen sofar,
because that would get us outside of the array otherwise. */
- if (maxsize != -1
- && asize && host_integerp (asize, 1))
- {
- maxsize = (TREE_INT_CST_LOW (asize)
- - TREE_INT_CST_LOW (bit_offset));
- }
+ if (maxsize != -1 && asize && host_integerp (asize, 1))
+ maxsize = TREE_INT_CST_LOW (asize) - bit_offset;
else
maxsize = -1;
break;
case IMAGPART_EXPR:
- bit_offset = size_binop (PLUS_EXPR, bit_offset,
- bitsize_int (bitsize));
+ bit_offset += bitsize;
break;
case VIEW_CONVERT_EXPR:
if (seen_variable_array_ref
&& maxsize != -1
&& host_integerp (TYPE_SIZE (TREE_TYPE (exp)), 1)
- && TREE_INT_CST_LOW (bit_offset) + maxsize
- == TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (exp))))
+ && bit_offset + maxsize
+ == (signed)TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (exp))))
maxsize = -1;
/* ??? Due to negative offsets in ARRAY_REF we can end up with
negative bit_offset here. We might want to store a zero offset
in this case. */
- *poffset = TREE_INT_CST_LOW (bit_offset);
+ *poffset = bit_offset;
*psize = bitsize;
*pmax_size = maxsize;
return exp;
}
+
+
+/* Return memory reference statistics for variable VAR in function FN.
+ This is computed by alias analysis, but it is not kept
+ incrementally up-to-date. So, these stats are only accurate if
+ pass_may_alias has been run recently. If no alias information
+ exists, this function returns NULL. */
+
+mem_sym_stats_t
+mem_sym_stats (struct function *fn, tree var)
+{
+ void **slot;
+ struct pointer_map_t *stats_map = gimple_mem_ref_stats (fn)->mem_sym_stats;
+
+ if (stats_map == NULL)
+ return NULL;
+
+ slot = pointer_map_contains (stats_map, var);
+ if (slot == NULL)
+ return NULL;
+
+ return (mem_sym_stats_t) *slot;
+}