/* Data flow functions for trees.
- Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009
+ Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@redhat.com>
#include "hashtab.h"
#include "pointer-set.h"
#include "tree.h"
-#include "rtl.h"
#include "tm_p.h"
-#include "hard-reg-set.h"
#include "basic-block.h"
#include "output.h"
#include "timevar.h"
-#include "expr.h"
#include "ggc.h"
#include "langhooks.h"
#include "flags.h"
#include "function.h"
-#include "diagnostic.h"
+#include "tree-pretty-print.h"
#include "tree-dump.h"
#include "gimple.h"
#include "tree-flow.h"
PROP_gimple_leh | PROP_cfg, /* properties_required */
PROP_referenced_vars, /* properties_provided */
0, /* properties_destroyed */
- TODO_dump_func, /* todo_flags_start */
- TODO_dump_func /* todo_flags_finish */
+ 0, /* todo_flags_start */
+ 0 /* todo_flags_finish */
}
};
var_ann_t ann;
gcc_assert (t);
- gcc_assert (DECL_P (t));
- gcc_assert (!t->base.ann || t->base.ann->common.type == VAR_ANN);
+ gcc_assert (TREE_CODE (t) == VAR_DECL
+ || TREE_CODE (t) == PARM_DECL
+ || TREE_CODE (t) == RESULT_DECL);
- ann = GGC_CNEW (struct var_ann_d);
- ann->common.type = VAR_ANN;
- t->base.ann = (tree_ann_t) ann;
+ ann = ggc_alloc_cleared_var_ann_d ();
+ *DECL_VAR_ANN_PTR (t) = ann;
return ann;
}
/* Renumber all of the gimple stmt uids. */
-void
+void
renumber_gimple_stmt_uids (void)
{
basic_block bb;
FOR_ALL_BB (bb)
{
gimple_stmt_iterator bsi;
+ for (bsi = gsi_start_phis (bb); !gsi_end_p (bsi); gsi_next (&bsi))
+ {
+ gimple stmt = gsi_stmt (bsi);
+ gimple_set_uid (stmt, inc_gimple_stmt_max_uid (cfun));
+ }
for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
{
gimple stmt = gsi_stmt (bsi);
/* Like renumber_gimple_stmt_uids, but only do work on the basic blocks
in BLOCKS, of which there are N_BLOCKS. Also renumbers PHIs. */
-void
+void
renumber_gimple_stmt_uids_in_blocks (basic_block *blocks, int n_blocks)
{
int i;
}
}
-/* Create a new annotation for a tree T. */
-
-tree_ann_common_t
-create_tree_common_ann (tree t)
-{
- tree_ann_common_t ann;
-
- gcc_assert (t);
- 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->base.ann = (tree_ann_t) ann;
-
- return ann;
-}
-
/* Build a temporary. Make sure and register it to be renamed. */
tree
make_rename_temp (tree type, const char *prefix)
{
- tree t = create_tmp_var (type, prefix);
-
- if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
- || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
- DECL_GIMPLE_REG_P (t) = 1;
+ tree t = create_tmp_reg (type, prefix);
if (gimple_referenced_vars (cfun))
{
{
tree var;
referenced_var_iterator rvi;
-
+
fprintf (file, "\nReferenced variables in %s: %u\n\n",
get_name (current_function_decl), (unsigned) num_referenced_vars);
-
- FOR_EACH_REFERENCED_VAR (var, rvi)
+
+ FOR_EACH_REFERENCED_VAR (cfun, var, rvi)
{
fprintf (file, "Variable: ");
dump_variable (file, var);
/* Dump the list of all the referenced variables to stderr. */
-void
+DEBUG_FUNCTION void
debug_referenced_vars (void)
{
dump_referenced_vars (stderr);
void
dump_variable (FILE *file, tree var)
{
- var_ann_t ann;
-
if (TREE_CODE (var) == SSA_NAME)
{
if (POINTER_TYPE_P (TREE_TYPE (var)))
print_generic_expr (file, var, dump_flags);
- ann = var_ann (var);
-
fprintf (file, ", UID D.%u", (unsigned) DECL_UID (var));
+ if (DECL_PT_UID (var) != DECL_UID (var))
+ fprintf (file, ", PT-UID D.%u", (unsigned) DECL_PT_UID (var));
fprintf (file, ", ");
print_generic_expr (file, TREE_TYPE (var), dump_flags);
if (TREE_ADDRESSABLE (var))
fprintf (file, ", is addressable");
-
+
if (is_global_var (var))
fprintf (file, ", is global");
if (TREE_THIS_VOLATILE (var))
fprintf (file, ", is volatile");
- if (is_call_clobbered (var))
- fprintf (file, ", call clobbered");
- else if (is_call_used (var))
- fprintf (file, ", call used");
-
- if (ann && ann->noalias_state == NO_ALIAS)
- fprintf (file, ", NO_ALIAS (does not alias other NO_ALIAS symbols)");
- else if (ann && ann->noalias_state == NO_ALIAS_GLOBAL)
- fprintf (file, ", NO_ALIAS_GLOBAL (does not alias other NO_ALIAS symbols"
- " and global vars)");
- else if (ann && ann->noalias_state == NO_ALIAS_ANYTHING)
- fprintf (file, ", NO_ALIAS_ANYTHING (does not alias any other symbols)");
-
if (cfun && gimple_default_def (cfun, var))
{
fprintf (file, ", default def: ");
/* Dump variable VAR and its may-aliases to stderr. */
-void
+DEBUG_FUNCTION void
debug_variable (tree var)
{
dump_variable (stderr, var);
/* Dump DFA statistics on stderr. */
-void
+DEBUG_FUNCTION void
debug_dfa_stats (void)
{
dump_dfa_stats (stderr);
memset ((void *)dfa_stats_p, 0, sizeof (struct dfa_stats_d));
/* Count all the variable annotations. */
- FOR_EACH_REFERENCED_VAR (var, vi)
+ FOR_EACH_REFERENCED_VAR (cfun, var, vi)
if (var_ann (var))
dfa_stats_p->num_var_anns++;
/* Lookup UID in the referenced_vars hashtable and return the associated
variable. */
-tree
-referenced_var_lookup (unsigned int uid)
+tree
+referenced_var_lookup (struct function *fn, unsigned int uid)
{
tree h;
struct tree_decl_minimal in;
in.uid = uid;
- h = (tree) htab_find_with_hash (gimple_referenced_vars (cfun), &in, uid);
- gcc_assert (h || uid == 0);
+ h = (tree) htab_find_with_hash (gimple_referenced_vars (fn), &in, uid);
return h;
}
-/* Check if TO is in the referenced_vars hash table and insert it if not.
+/* Check if TO is in the referenced_vars hash table and insert it if not.
Return true if it required insertion. */
bool
referenced_var_check_and_insert (tree to)
-{
+{
tree h, *loc;
struct tree_decl_minimal in;
unsigned int uid = DECL_UID (to);
/* Lookup VAR UID in the default_defs hashtable and return the associated
variable. */
-tree
+tree
gimple_default_def (struct function *fn, tree var)
{
struct tree_decl_minimal ind;
void
set_default_def (tree var, tree def)
-{
+{
struct tree_decl_minimal ind;
struct tree_ssa_name in;
void **loc;
bool
add_referenced_var (tree var)
{
- var_ann_t v_ann;
-
- v_ann = get_var_ann (var);
gcc_assert (DECL_P (var));
-
- /* Insert VAR into the referenced_vars has table if it isn't present. */
+ if (!*DECL_VAR_ANN_PTR (var))
+ create_var_ann (var);
+
+ /* Insert VAR into the referenced_vars hash table if it isn't present. */
if (referenced_var_check_and_insert (var))
{
/* Scan DECL_INITIAL for pointer variables as they may contain
&& (v_ann = var_ann (var)))
{
ggc_free (v_ann);
- var->base.ann = NULL;
+ *DECL_VAR_ANN_PTR (var) = NULL;
}
gcc_assert (DECL_P (var));
in.uid = uid;
tree size_tree = NULL_TREE;
HOST_WIDE_INT bit_offset = 0;
bool seen_variable_array_ref = false;
+ tree base_type;
/* First get the final access size from just the outermost expression. */
if (TREE_CODE (exp) == COMPONENT_REF)
and find the ultimate containing object. */
while (1)
{
+ base_type = TREE_TYPE (exp);
+
switch (TREE_CODE (exp))
{
case BIT_FIELD_REF:
&& maxsize != -1)
{
tree stype = TREE_TYPE (TREE_OPERAND (exp, 0));
- tree next = TREE_CHAIN (field);
+ tree next = DECL_CHAIN (field);
while (next && TREE_CODE (next) != FIELD_DECL)
- next = TREE_CHAIN (next);
+ next = DECL_CHAIN (next);
if (!next
|| TREE_CODE (stype) != RECORD_TYPE)
{
case VIEW_CONVERT_EXPR:
break;
+ case MEM_REF:
+ /* Hand back the decl for MEM[&decl, off]. */
+ if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR)
+ {
+ if (integer_zerop (TREE_OPERAND (exp, 1)))
+ exp = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+ else
+ {
+ double_int off = mem_ref_offset (exp);
+ off = double_int_lshift (off,
+ BITS_PER_UNIT == 8
+ ? 3 : exact_log2 (BITS_PER_UNIT),
+ HOST_BITS_PER_DOUBLE_INT, true);
+ off = double_int_add (off, shwi_to_double_int (bit_offset));
+ if (double_int_fits_in_shwi_p (off))
+ {
+ bit_offset = double_int_to_shwi (off);
+ exp = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+ }
+ }
+ }
+ goto done;
+
+ case TARGET_MEM_REF:
+ /* Hand back the decl for MEM[&decl, off]. */
+ if (TREE_CODE (TMR_BASE (exp)) == ADDR_EXPR)
+ {
+ /* Via the variable index or index2 we can reach the
+ whole object. */
+ if (TMR_INDEX (exp) || TMR_INDEX2 (exp))
+ {
+ exp = TREE_OPERAND (TMR_BASE (exp), 0);
+ bit_offset = 0;
+ maxsize = -1;
+ goto done;
+ }
+ if (integer_zerop (TMR_OFFSET (exp)))
+ exp = TREE_OPERAND (TMR_BASE (exp), 0);
+ else
+ {
+ double_int off = mem_ref_offset (exp);
+ off = double_int_lshift (off,
+ BITS_PER_UNIT == 8
+ ? 3 : exact_log2 (BITS_PER_UNIT),
+ HOST_BITS_PER_DOUBLE_INT, true);
+ off = double_int_add (off, shwi_to_double_int (bit_offset));
+ if (double_int_fits_in_shwi_p (off))
+ {
+ bit_offset = double_int_to_shwi (off);
+ exp = TREE_OPERAND (TMR_BASE (exp), 0);
+ }
+ }
+ }
+ goto done;
+
default:
goto done;
}
the array. The simplest way to conservatively deal with this
is to punt in the case that offset + maxsize reaches the
base type boundary. This needs to include possible trailing padding
- that is there for alignment purposes.
+ that is there for alignment purposes. */
+
+ if (seen_variable_array_ref
+ && maxsize != -1
+ && (!host_integerp (TYPE_SIZE (base_type), 1)
+ || (bit_offset + maxsize
+ == (signed) TREE_INT_CST_LOW (TYPE_SIZE (base_type)))))
+ maxsize = -1;
- That is of course only true if the base object is not a decl. */
+ /* In case of a decl or constant base object we can do better. */
if (DECL_P (exp))
{
&& host_integerp (DECL_SIZE (exp), 1))
maxsize = TREE_INT_CST_LOW (DECL_SIZE (exp)) - bit_offset;
}
- else if (seen_variable_array_ref
- && maxsize != -1
- && (!host_integerp (TYPE_SIZE (TREE_TYPE (exp)), 1)
- || (bit_offset + maxsize
- == (signed) TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (exp))))))
- maxsize = -1;
+ else if (CONSTANT_CLASS_P (exp))
+ {
+ /* If maxsize is unknown adjust it according to the size of the
+ base type constant. */
+ if (maxsize == -1
+ && host_integerp (TYPE_SIZE (TREE_TYPE (exp)), 1))
+ maxsize = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (exp))) - bit_offset;
+ }
/* ??? Due to negative offsets in ARRAY_REF we can end up with
negative bit_offset here. We might want to store a zero offset
return exp;
}
+/* Returns the base object and a constant BITS_PER_UNIT offset in *POFFSET that
+ denotes the starting address of the memory access EXP.
+ Returns NULL_TREE if the offset is not constant or any component
+ is not BITS_PER_UNIT-aligned. */
+
+tree
+get_addr_base_and_unit_offset (tree exp, HOST_WIDE_INT *poffset)
+{
+ return get_addr_base_and_unit_offset_1 (exp, poffset, NULL);
+}
+
/* Returns true if STMT references an SSA_NAME that has
SSA_NAME_OCCURS_IN_ABNORMAL_PHI set, otherwise false. */
return false;
}
-