+2009-05-28 Richard Guenther <rguenther@suse.de>
+
+ * tree-ssa-alias.c (ao_ref_init): New function.
+ (ao_ref_base): Likewise.
+ (ao_ref_base_alias_set): Likewise.
+ (ao_ref_alias_set): Likewise.
+ (refs_may_alias_p_1): Change signature.
+ (refs_may_alias_p): Adjust.
+ (refs_anti_dependent_p): Likewise.
+ (refs_output_dependent_p): Likewise.
+ (call_may_clobber_ref_p_1): Change signature.
+ (call_may_clobber_ref_p): Adjust.
+ (stmt_may_clobber_ref_p_1): New function split out from ...
+ (stmt_may_clobber_ref_p): ... here.
+ (maybe_skip_until): Adjust signature.
+ (get_continuation_for_phi): Likewise.
+ (walk_non_aliased_vuses): Likewise.
+ * tree-ssa-alias.h (struct ao_ref_s): New structure type.
+ (ao_ref_init): Declare.
+ (ao_ref_base): Likewise.
+ (ao_ref_alias_set): Likewise.
+ (stmt_may_clobber_ref_p_1): Likewise.
+ (walk_non_aliased_vuses): Adjust.
+ * tree-ssa-sccvn.c (ao_ref_init_from_vn_reference): New function.
+ (get_ref_from_reference_ops): remove.
+ (vn_reference_lookup_2): Adjust signature.
+ (vn_reference_lookup_3): Do not re-build trees. Handle unions.
+ (vn_reference_lookup_pieces): Adjust signature, do not re-build
+ trees.
+ (vn_reference_lookup): Adjust.
+ (vn_reference_insert): Likewise.
+ (vn_reference_insert_pieces): Adjust signature.
+ (visit_reference_op_call): Adjust.
+ * tree-ssa-pre.c (get_expr_type): Simplify.
+ (phi_translate_1): Adjust.
+ (compute_avail): Likewise.
+ (translate_vuse_through_block): Do not re-build trees.
+ (value_dies_in_block_x): Likewise.
+ * tree-ssa-sccvn.h (struct vn_reference_s): Add type and alias-set
+ fields.
+ (vn_reference_lookup_pieces): Adjust declaration.
+ (vn_reference_insert_pieces): Likewise.
+
2009-05-28 Benjamin Kosnik <bkoz@redhat.com>
* tree-ssa-copy.c (replace_exp_1): Move op for warning-free use
+2009-05-28 Richard Guenther <rguenther@suse.de>
+
+ * gcc.dg/tree-ssa/ssa-fre-26.c: New testcase.
+ * gcc.c-torture/execute/20090527-1.c: Likewise.
+
2009-05-28 Dodji Seketeli <dodji@redhat.com>
PR c++/39754
--- /dev/null
+typedef enum { POSITION_ASIS, POSITION_UNSPECIFIED } unit_position;
+
+typedef enum { STATUS_UNKNOWN, STATUS_UNSPECIFIED } unit_status;
+
+typedef struct
+{
+ unit_position position;
+ unit_status status;
+} unit_flags;
+
+extern void abort (void);
+
+void
+new_unit (unit_flags * flags)
+{
+ if (flags->status == STATUS_UNSPECIFIED)
+ flags->status = STATUS_UNKNOWN;
+
+ if (flags->position == POSITION_UNSPECIFIED)
+ flags->position = POSITION_ASIS;
+
+ switch (flags->status)
+ {
+ case STATUS_UNKNOWN:
+ break;
+
+ default:
+ abort ();
+ }
+}
+
+int main()
+{
+ unit_flags f;
+ f.status = STATUS_UNSPECIFIED;
+ new_unit (&f);
+ return 0;
+}
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O -fno-tree-sra -fdump-tree-fre-details" } */
+
+union U {
+ float f;
+ int i;
+};
+
+int foo (union U *p)
+{
+ union U u;
+ p->f = 0.0;
+ u = *p;
+ return u.i;
+}
+
+/* { dg-final { scan-tree-dump "Replaced u.i with 0 in" "fre" } } */
+/* { dg-final { cleanup-tree-dump "fre" } } */
dump_points_to_info_for (stderr, var);
}
+
+/* Initializes the alias-oracle reference representation *R from REF. */
+
+void
+ao_ref_init (ao_ref *r, tree ref)
+{
+ r->ref = ref;
+ r->base = NULL_TREE;
+ r->offset = 0;
+ r->size = -1;
+ r->max_size = -1;
+ r->ref_alias_set = -1;
+ r->base_alias_set = -1;
+}
+
+/* Returns the base object of the memory reference *REF. */
+
+tree
+ao_ref_base (ao_ref *ref)
+{
+ if (ref->base)
+ return ref->base;
+ ref->base = get_ref_base_and_extent (ref->ref, &ref->offset, &ref->size,
+ &ref->max_size);
+ return ref->base;
+}
+
+/* Returns the base object alias set of the memory reference *REF. */
+
+static alias_set_type ATTRIBUTE_UNUSED
+ao_ref_base_alias_set (ao_ref *ref)
+{
+ if (ref->base_alias_set != -1)
+ return ref->base_alias_set;
+ ref->base_alias_set = get_alias_set (ao_ref_base (ref));
+ return ref->base_alias_set;
+}
+
+/* Returns the reference alias set of the memory reference *REF. */
+
+alias_set_type
+ao_ref_alias_set (ao_ref *ref)
+{
+ if (ref->ref_alias_set != -1)
+ return ref->ref_alias_set;
+ ref->ref_alias_set = get_alias_set (ref->ref);
+ return ref->ref_alias_set;
+}
+
/* Return 1 if TYPE1 and TYPE2 are to be considered equivalent for the
purpose of TBAA. Return 0 if they are distinct and -1 if we cannot
decide. */
/* Return true, if the two memory references REF1 and REF2 may alias. */
static bool
-refs_may_alias_p_1 (tree ref1, tree ref2, bool tbaa_p)
+refs_may_alias_p_1 (ao_ref *ref1, ao_ref *ref2, bool tbaa_p)
{
tree base1, base2;
HOST_WIDE_INT offset1 = 0, offset2 = 0;
bool var1_p, var2_p, ind1_p, ind2_p;
alias_set_type set;
- gcc_assert ((SSA_VAR_P (ref1)
- || handled_component_p (ref1)
- || INDIRECT_REF_P (ref1)
- || TREE_CODE (ref1) == TARGET_MEM_REF)
- && (SSA_VAR_P (ref2)
- || handled_component_p (ref2)
- || INDIRECT_REF_P (ref2)
- || TREE_CODE (ref2) == TARGET_MEM_REF));
+ gcc_assert ((!ref1->ref
+ || SSA_VAR_P (ref1->ref)
+ || handled_component_p (ref1->ref)
+ || INDIRECT_REF_P (ref1->ref)
+ || TREE_CODE (ref1->ref) == TARGET_MEM_REF)
+ && (!ref2->ref
+ || SSA_VAR_P (ref2->ref)
+ || handled_component_p (ref2->ref)
+ || INDIRECT_REF_P (ref2->ref)
+ || TREE_CODE (ref2->ref) == TARGET_MEM_REF));
/* Decompose the references into their base objects and the access. */
- base1 = get_ref_base_and_extent (ref1, &offset1, &size1, &max_size1);
- base2 = get_ref_base_and_extent (ref2, &offset2, &size2, &max_size2);
+ base1 = ao_ref_base (ref1);
+ offset1 = ref1->offset;
+ size1 = ref1->size;
+ max_size1 = ref1->max_size;
+ base2 = ao_ref_base (ref2);
+ offset2 = ref2->offset;
+ size2 = ref2->size;
+ max_size2 = ref2->max_size;
/* We can end up with registers or constants as bases for example from
*D.1663_44 = VIEW_CONVERT_EXPR<struct DB_LSN>(__tmp$B0F64_59);
/* First defer to TBAA if possible. */
if (tbaa_p
&& flag_strict_aliasing
- && !alias_sets_conflict_p (get_alias_set (ref1), get_alias_set (ref2)))
+ && !alias_sets_conflict_p (ao_ref_alias_set (ref1),
+ ao_ref_alias_set (ref2)))
return false;
/* If one reference is a TARGET_MEM_REF weird things are allowed. Still
TBAA disambiguation based on the access type is possible, so bail
out only after that check. */
- if (TREE_CODE (ref1) == TARGET_MEM_REF
- || TREE_CODE (ref2) == TARGET_MEM_REF)
+ if ((ref1->ref && TREE_CODE (ref1->ref) == TARGET_MEM_REF)
+ || (ref2->ref && TREE_CODE (ref2->ref) == TARGET_MEM_REF))
return true;
/* Dispatch to the pointer-vs-decl or pointer-vs-pointer disambiguators. */
ind2_p = INDIRECT_REF_P (base2);
set = tbaa_p ? -1 : 0;
if (var1_p && ind2_p)
- return indirect_ref_may_alias_decl_p (ref2, TREE_OPERAND (base2, 0),
+ return indirect_ref_may_alias_decl_p (ref2->ref, TREE_OPERAND (base2, 0),
offset2, max_size2, set,
- ref1, base1,
+ ref1->ref, base1,
offset1, max_size1, set);
else if (ind1_p && var2_p)
- return indirect_ref_may_alias_decl_p (ref1, TREE_OPERAND (base1, 0),
+ return indirect_ref_may_alias_decl_p (ref1->ref, TREE_OPERAND (base1, 0),
offset1, max_size1, set,
- ref2, base2,
+ ref2->ref, base2,
offset2, max_size2, set);
else if (ind1_p && ind2_p)
- return indirect_refs_may_alias_p (ref1, TREE_OPERAND (base1, 0),
+ return indirect_refs_may_alias_p (ref1->ref, TREE_OPERAND (base1, 0),
offset1, max_size1, set,
- ref2, TREE_OPERAND (base2, 0),
+ ref2->ref, TREE_OPERAND (base2, 0),
offset2, max_size2, set);
gcc_unreachable ();
bool
refs_may_alias_p (tree ref1, tree ref2)
{
- bool res = refs_may_alias_p_1 (ref1, ref2, true);
+ ao_ref r1, r2;
+ bool res;
+ ao_ref_init (&r1, ref1);
+ ao_ref_init (&r2, ref2);
+ res = refs_may_alias_p_1 (&r1, &r2, true);
if (res)
++alias_stats.refs_may_alias_p_may_alias;
else
bool
refs_anti_dependent_p (tree load, tree store)
{
- return refs_may_alias_p_1 (load, store, false);
+ ao_ref r1, r2;
+ ao_ref_init (&r1, load);
+ ao_ref_init (&r2, store);
+ return refs_may_alias_p_1 (&r1, &r2, false);
}
/* Returns true if there is a output dependence for the stores
bool
refs_output_dependent_p (tree store1, tree store2)
{
- return refs_may_alias_p_1 (store1, store2, false);
+ ao_ref r1, r2;
+ ao_ref_init (&r1, store1);
+ ao_ref_init (&r2, store2);
+ return refs_may_alias_p_1 (&r1, &r2, false);
}
/* If the call CALL may use the memory reference REF return true,
return true, otherwise return false. */
static bool
-call_may_clobber_ref_p_1 (gimple call, tree ref)
+call_may_clobber_ref_p_1 (gimple call, ao_ref *ref)
{
tree base;
& (ECF_PURE|ECF_CONST|ECF_LOOPING_CONST_OR_PURE|ECF_NOVOPS))
return false;
- base = get_base_address (ref);
+ base = ao_ref_base (ref);
if (!base)
return true;
return true;
}
-static bool
+static bool ATTRIBUTE_UNUSED
call_may_clobber_ref_p (gimple call, tree ref)
{
- bool res = call_may_clobber_ref_p_1 (call, ref);
+ bool res;
+ ao_ref r;
+ ao_ref_init (&r, ref);
+ res = call_may_clobber_ref_p_1 (call, &r);
if (res)
++alias_stats.call_may_clobber_ref_p_may_alias;
else
otherwise return false. */
bool
-stmt_may_clobber_ref_p (gimple stmt, tree ref)
+stmt_may_clobber_ref_p_1 (gimple stmt, ao_ref *ref)
{
if (is_gimple_call (stmt))
{
tree lhs = gimple_call_lhs (stmt);
if (lhs
- && !is_gimple_reg (lhs)
- && refs_may_alias_p (ref, lhs))
- return true;
+ && !is_gimple_reg (lhs))
+ {
+ ao_ref r;
+ ao_ref_init (&r, lhs);
+ if (refs_may_alias_p_1 (ref, &r, true))
+ return true;
+ }
- return call_may_clobber_ref_p (stmt, ref);
+ return call_may_clobber_ref_p_1 (stmt, ref);
}
else if (is_gimple_assign (stmt))
- return refs_may_alias_p (ref, gimple_assign_lhs (stmt));
+ {
+ ao_ref r;
+ ao_ref_init (&r, gimple_assign_lhs (stmt));
+ return refs_may_alias_p_1 (ref, &r, true);
+ }
else if (gimple_code (stmt) == GIMPLE_ASM)
return true;
return false;
}
-static tree get_continuation_for_phi (gimple, tree, bitmap *);
+bool
+stmt_may_clobber_ref_p (gimple stmt, tree ref)
+{
+ ao_ref r;
+ ao_ref_init (&r, ref);
+ return stmt_may_clobber_ref_p_1 (stmt, &r);
+}
+
+
+static tree get_continuation_for_phi (gimple, ao_ref *, bitmap *);
/* Walk the virtual use-def chain of VUSE until hitting the virtual operand
TARGET or a statement clobbering the memory reference REF in which
case false is returned. The walk starts with VUSE, one argument of PHI. */
static bool
-maybe_skip_until (gimple phi, tree target, tree ref, tree vuse, bitmap *visited)
+maybe_skip_until (gimple phi, tree target, ao_ref *ref,
+ tree vuse, bitmap *visited)
{
if (!*visited)
*visited = BITMAP_ALLOC (NULL);
}
/* A clobbering statement or the end of the IL ends it failing. */
else if (gimple_nop_p (def_stmt)
- || stmt_may_clobber_ref_p (def_stmt, ref))
+ || stmt_may_clobber_ref_p_1 (def_stmt, ref))
return false;
vuse = gimple_vuse (def_stmt);
}
be found. */
static tree
-get_continuation_for_phi (gimple phi, tree ref, bitmap *visited)
+get_continuation_for_phi (gimple phi, ao_ref *ref, bitmap *visited)
{
unsigned nargs = gimple_phi_num_args (phi);
TODO: Cache the vector of equivalent vuses per ref, vuse pair. */
void *
-walk_non_aliased_vuses (tree ref, tree vuse,
- void *(*walker)(tree, tree, void *),
- void *(*translate)(tree *, tree, void *),void *data)
+walk_non_aliased_vuses (ao_ref *ref, tree vuse,
+ void *(*walker)(ao_ref *, tree, void *),
+ void *(*translate)(ao_ref *, tree, void *), void *data)
{
bitmap visited = NULL;
void *res;
vuse = get_continuation_for_phi (def_stmt, ref, &visited);
else
{
- if (stmt_may_clobber_ref_p (def_stmt, ref))
+ if (stmt_may_clobber_ref_p_1 (def_stmt, ref))
{
if (!translate)
break;
- res = (*translate) (&ref, vuse, data);
+ res = (*translate) (ref, vuse, data);
/* Failed lookup and translation. */
if (res == (void *)-1)
{
};
+/* Simplified and cached information about a memory reference tree.
+ Used by the alias-oracle internally and externally in alternate
+ interfaces. */
+typedef struct ao_ref_s
+{
+ /* The original full memory reference tree or NULL_TREE if that is
+ not available. */
+ tree ref;
+
+ /* The following fields are the decomposed reference as returned
+ by get_ref_base_and_extent. */
+ /* The base object of the memory reference or NULL_TREE if all of
+ the following fields are not yet computed. */
+ tree base;
+ /* The offset relative to the base. */
+ HOST_WIDE_INT offset;
+ /* The size of the access. */
+ HOST_WIDE_INT size;
+ /* The maximum possible extent of the access or -1 if unconstrained. */
+ HOST_WIDE_INT max_size;
+
+ /* The alias set of the access or -1 if not yet computed. */
+ alias_set_type ref_alias_set;
+
+ /* The alias set of the base object or -1 if not yet computed. */
+ alias_set_type base_alias_set;
+} ao_ref;
+
+
/* In tree-ssa-alias.c */
+extern void ao_ref_init (ao_ref *, tree);
+extern tree ao_ref_base (ao_ref *);
+extern alias_set_type ao_ref_alias_set (ao_ref *);
extern enum escape_type is_escape_site (gimple);
extern bool ptr_deref_may_alias_global_p (tree);
extern bool refs_may_alias_p (tree, tree);
extern bool refs_output_dependent_p (tree, tree);
extern bool ref_maybe_used_by_stmt_p (gimple, tree);
extern bool stmt_may_clobber_ref_p (gimple, tree);
-extern void *walk_non_aliased_vuses (tree, tree,
- void *(*)(tree, tree, void *),
- void *(*)(tree *, tree, void *), void *);
+extern bool stmt_may_clobber_ref_p_1 (gimple, ao_ref *);
+extern void *walk_non_aliased_vuses (ao_ref *, tree,
+ void *(*)(ao_ref *, tree, void *),
+ void *(*)(ao_ref *, tree, void *), void *);
extern unsigned int walk_aliased_vdefs (tree, tree,
bool (*)(tree, tree, void *), void *,
bitmap *);
static tree
translate_vuse_through_block (VEC (vn_reference_op_s, heap) *operands,
- tree vuse,
+ alias_set_type set, tree type, tree vuse,
basic_block phiblock,
basic_block block)
{
gimple phi = SSA_NAME_DEF_STMT (vuse);
- tree ref;
+ ao_ref ref;
if (gimple_bb (phi) != phiblock)
return vuse;
return PHI_ARG_DEF (phi, e->dest_idx);
}
- if (!(ref = get_ref_from_reference_ops (operands)))
+ if (!ao_ref_init_from_vn_reference (&ref, set, type, operands))
return NULL_TREE;
/* Use the alias-oracle to find either the PHI node in this block,
the first VUSE used in this block that is equivalent to vuse or
the first VUSE which definition in this block kills the value. */
- while (!stmt_may_clobber_ref_p (phi, ref))
+ while (!stmt_may_clobber_ref_p_1 (phi, &ref))
{
vuse = gimple_vuse (phi);
phi = SSA_NAME_DEF_STMT (vuse);
case CONSTANT:
return TREE_TYPE (PRE_EXPR_CONSTANT (e));
case REFERENCE:
- {
- vn_reference_op_t vro;
-
- gcc_assert (PRE_EXPR_REFERENCE (e)->operands);
- vro = VEC_index (vn_reference_op_s,
- PRE_EXPR_REFERENCE (e)->operands,
- 0);
- /* We don't store type along with COMPONENT_REF because it is
- always the same as FIELD_DECL's type. */
- if (!vro->type)
- {
- gcc_assert (vro->opcode == COMPONENT_REF);
- return TREE_TYPE (vro->op0);
- }
- return vro->type;
- }
-
+ return PRE_EXPR_REFERENCE (e)->type;
case NARY:
return PRE_EXPR_NARY (e)->type;
}
if (vuse)
{
newvuse = translate_vuse_through_block (newoperands,
+ ref->set, ref->type,
vuse, phiblock, pred);
if (newvuse == NULL_TREE)
{
unsigned int new_val_id;
pre_expr constant;
- tree result = vn_reference_lookup_pieces (newvuse,
+ tree result = vn_reference_lookup_pieces (newvuse, ref->set,
+ ref->type,
newoperands,
&newref, true);
if (newref)
new_val_id = get_next_value_id ();
VEC_safe_grow_cleared (bitmap_set_t, heap, value_expressions,
get_max_value_id() + 1);
- newref = vn_reference_insert_pieces (newvuse,
+ newref = vn_reference_insert_pieces (newvuse, ref->set,
+ ref->type,
newoperands,
result, new_val_id);
newoperands = NULL;
tree vuse = PRE_EXPR_REFERENCE (expr)->vuse;
vn_reference_t refx = PRE_EXPR_REFERENCE (expr);
gimple def;
- tree ref = NULL_TREE;
gimple_stmt_iterator gsi;
unsigned id = get_expression_id (expr);
bool res = false;
+ ao_ref ref;
if (!vuse)
return false;
top of the basic block, a statement uses VUSE there can be no kill
inbetween that use and the original statement that loaded {e, VUSE},
so we can stop walking. */
+ ref.base = NULL_TREE;
for (gsi = gsi_start_bb (block); !gsi_end_p (gsi); gsi_next (&gsi))
{
tree def_vuse, def_vdef;
}
/* Init ref only if we really need it. */
- if (ref == NULL_TREE)
+ if (ref.base == NULL_TREE
+ && !ao_ref_init_from_vn_reference (&ref, refx->set, refx->type,
+ refx->operands))
{
- if (!(ref = get_ref_from_reference_ops (refx->operands)))
- {
- res = true;
- break;
- }
+ res = true;
+ break;
}
/* If the statement may clobber expr, it dies. */
- if (stmt_may_clobber_ref_p (def, ref))
+ if (stmt_may_clobber_ref_p_1 (def, &ref))
{
res = true;
break;
continue;
copy_reference_ops_from_call (stmt, &ops);
- vn_reference_lookup_pieces (gimple_vuse (stmt),
+ vn_reference_lookup_pieces (gimple_vuse (stmt), 0,
+ gimple_expr_type (stmt),
ops, &ref, false);
VEC_free (vn_reference_op_s, heap, ops);
if (!ref)
a matching type is not necessary and a mismatching type
is always a spurious difference. */
temp.type = NULL_TREE;
+ temp.op0 = TREE_OPERAND (ref, 1);
+ temp.op1 = TREE_OPERAND (ref, 2);
/* If this is a reference to a union member, record the union
member size as operand. Do so only if we are doing
expression insertion (during FRE), as PRE currently gets
confused with this. */
if (may_insert
- && TREE_OPERAND (ref, 2) == NULL_TREE
- && TREE_CODE (DECL_CONTEXT (TREE_OPERAND (ref, 1))) == UNION_TYPE
- && integer_zerop (DECL_FIELD_OFFSET (TREE_OPERAND (ref, 1)))
- && integer_zerop (DECL_FIELD_BIT_OFFSET (TREE_OPERAND (ref, 1))))
- temp.op0 = TYPE_SIZE (TREE_TYPE (TREE_OPERAND (ref, 1)));
- else
- {
- /* Record field as operand. */
- temp.op0 = TREE_OPERAND (ref, 1);
- temp.op1 = TREE_OPERAND (ref, 2);
- }
+ && temp.op1 == NULL_TREE
+ && TREE_CODE (DECL_CONTEXT (temp.op0)) == UNION_TYPE
+ && integer_zerop (DECL_FIELD_OFFSET (temp.op0))
+ && integer_zerop (DECL_FIELD_BIT_OFFSET (temp.op0))
+ && host_integerp (TYPE_SIZE (TREE_TYPE (temp.op0)), 0))
+ temp.op0 = TYPE_SIZE (TREE_TYPE (temp.op0));
break;
case ARRAY_RANGE_REF:
case ARRAY_REF:
/* Record index as operand. */
temp.op0 = TREE_OPERAND (ref, 1);
- temp.op1 = TREE_OPERAND (ref, 2);
+ /* Record even constant lower bounds. */
+ if (TREE_OPERAND (ref, 2))
+ temp.op1 = TREE_OPERAND (ref, 2);
+ else
+ {
+ tree domain = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (ref, 0)));
+ if (domain
+ && TYPE_MIN_VALUE (domain)
+ && !integer_zerop (TYPE_MIN_VALUE (domain)))
+ temp.op1 = TYPE_MIN_VALUE (domain);
+ }
temp.op2 = TREE_OPERAND (ref, 3);
break;
case STRING_CST:
}
}
-/* Re-create a reference tree from the reference ops OPS.
- Returns NULL_TREE if the ops were not handled.
- This routine needs to be kept in sync with copy_reference_ops_from_ref. */
+/* Build a alias-oracle reference abstraction in *REF from the vn_reference
+ operands in *OPS, the reference alias set SET and the reference type TYPE.
+ Return true if something useful was produced. */
-tree
-get_ref_from_reference_ops (VEC(vn_reference_op_s, heap) *ops)
+bool
+ao_ref_init_from_vn_reference (ao_ref *ref,
+ alias_set_type set, tree type,
+ VEC (vn_reference_op_s, heap) *ops)
{
vn_reference_op_t op;
unsigned i;
- tree ref, *op0_p = &ref;
+ tree base = NULL_TREE;
+ tree *op0_p = &base;
+ HOST_WIDE_INT offset = 0;
+ HOST_WIDE_INT max_size;
+ HOST_WIDE_INT size = -1;
+ tree size_tree = NULL_TREE;
+
+ /* First get the final access size from just the outermost expression. */
+ op = VEC_index (vn_reference_op_s, ops, 0);
+ if (op->opcode == COMPONENT_REF)
+ {
+ if (TREE_CODE (op->op0) == INTEGER_CST)
+ size_tree = op->op0;
+ else
+ size_tree = DECL_SIZE (op->op0);
+ }
+ else if (op->opcode == BIT_FIELD_REF)
+ size_tree = op->op0;
+ else
+ {
+ enum machine_mode mode = TYPE_MODE (type);
+ if (mode == BLKmode)
+ size_tree = TYPE_SIZE (type);
+ else
+ size = GET_MODE_BITSIZE (mode);
+ }
+ if (size_tree != NULL_TREE)
+ {
+ if (!host_integerp (size_tree, 1))
+ size = -1;
+ else
+ size = TREE_INT_CST_LOW (size_tree);
+ }
+ /* Initially, maxsize is the same as the accessed element size.
+ In the following it will only grow (or become -1). */
+ max_size = size;
+
+ /* Compute cumulative bit-offset for nested component-refs and array-refs,
+ and find the ultimate containing object. */
for (i = 0; VEC_iterate (vn_reference_op_s, ops, i, op); ++i)
{
switch (op->opcode)
{
+ /* These may be in the reference ops, but we cannot do anything
+ sensible with them here. */
case CALL_EXPR:
- return NULL_TREE;
+ case ADDR_EXPR:
+ return false;
+ /* Record the base objects. */
case ALIGN_INDIRECT_REF:
case INDIRECT_REF:
*op0_p = build1 (op->opcode, op->type, NULL_TREE);
op0_p = &TREE_OPERAND (*op0_p, 0);
break;
+ case VAR_DECL:
+ case PARM_DECL:
+ case RESULT_DECL:
+ case SSA_NAME:
+ case FILTER_EXPR:
+ case EXC_PTR_EXPR:
+ *op0_p = op->op0;
+ break;
+
+ /* And now the usual component-reference style ops. */
case BIT_FIELD_REF:
- *op0_p = build3 (BIT_FIELD_REF, op->type, NULL_TREE,
- op->op0, op->op1);
- op0_p = &TREE_OPERAND (*op0_p, 0);
+ offset += tree_low_cst (op->op1, 0);
break;
case COMPONENT_REF:
- /* We cannot re-construct our fancy union reference handling. */
- if (TREE_CODE (op->op0) == INTEGER_CST)
- return NULL_TREE;
- *op0_p = build3 (COMPONENT_REF, TREE_TYPE (op->op0), NULL_TREE,
- op->op0, op->op1);
- op0_p = &TREE_OPERAND (*op0_p, 0);
- break;
+ {
+ tree field = op->op0;
+ /* We do not have a complete COMPONENT_REF tree here so we
+ cannot use component_ref_field_offset. Do the interesting
+ parts manually. */
+
+ /* Our union trick, done for offset zero only. */
+ if (TREE_CODE (field) == INTEGER_CST)
+ ;
+ else if (op->op1
+ || !host_integerp (DECL_FIELD_OFFSET (field), 1))
+ max_size = -1;
+ else
+ {
+ offset += (TREE_INT_CST_LOW (DECL_FIELD_OFFSET (field))
+ * BITS_PER_UNIT);
+ offset += TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field));
+ }
+ break;
+ }
case ARRAY_RANGE_REF:
case ARRAY_REF:
- *op0_p = build4 (op->opcode, op->type, NULL_TREE,
- op->op0, op->op1, op->op2);
- op0_p = &TREE_OPERAND (*op0_p, 0);
+ /* Same for ARRAY_REFs. We do not have access to the array
+ type here, but we recorded the lower bound in op1. */
+ if (op->op2
+ || !host_integerp (op->op0, 0)
+ || (op->op1 && !host_integerp (op->op1, 0))
+ || !host_integerp (TYPE_SIZE (op->type), 1))
+ max_size = -1;
+ else
+ {
+ HOST_WIDE_INT hindex = TREE_INT_CST_LOW (op->op0);
+ if (op->op1)
+ hindex -= TREE_INT_CST_LOW (op->op1);
+ hindex *= TREE_INT_CST_LOW (TYPE_SIZE (op->type));
+ offset += hindex;
+ }
+ break;
+
+ case REALPART_EXPR:
+ break;
+
+ case IMAGPART_EXPR:
+ offset += size;
+ break;
+
+ case VIEW_CONVERT_EXPR:
break;
case STRING_CST:
case VECTOR_CST:
case REAL_CST:
case CONSTRUCTOR:
- case VAR_DECL:
- case PARM_DECL:
case CONST_DECL:
- case RESULT_DECL:
- case SSA_NAME:
- case FILTER_EXPR:
- case EXC_PTR_EXPR:
- *op0_p = op->op0;
- break;
-
- case ADDR_EXPR:
- if (op->op0 != NULL_TREE)
- {
- gcc_assert (is_gimple_min_invariant (op->op0));
- *op0_p = op->op0;
- break;
- }
- /* Fallthrough. */
- case IMAGPART_EXPR:
- case REALPART_EXPR:
- case VIEW_CONVERT_EXPR:
- *op0_p = build1 (op->opcode, op->type, NULL_TREE);
- op0_p = &TREE_OPERAND (*op0_p, 0);
- break;
+ return false;
default:
- return NULL_TREE;
+ return false;
}
}
- return ref;
+ if (base == NULL_TREE)
+ return false;
+
+ ref->ref = NULL_TREE;
+ ref->base = base;
+ ref->offset = offset;
+ ref->size = size;
+ ref->max_size = max_size;
+ ref->ref_alias_set = set;
+ ref->base_alias_set = -1;
+
+ return true;
}
/* Copy the operations present in load/store/call REF into RESULT, a vector of
with the current VUSE and performs the expression lookup. */
static void *
-vn_reference_lookup_2 (tree op ATTRIBUTE_UNUSED, tree vuse, void *vr_)
+vn_reference_lookup_2 (ao_ref *op ATTRIBUTE_UNUSED, tree vuse, void *vr_)
{
vn_reference_t vr = (vn_reference_t)vr_;
void **slot;
of VUSE. */
static void *
-vn_reference_lookup_3 (tree *refp, tree vuse, void *vr_)
+vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *vr_)
{
vn_reference_t vr = (vn_reference_t)vr_;
gimple def_stmt = SSA_NAME_DEF_STMT (vuse);
tree fndecl;
- tree ref = *refp;
tree base;
HOST_WIDE_INT offset, size, maxsize;
- base = get_ref_base_and_extent (ref, &offset, &size, &maxsize);
+ base = ao_ref_base (ref);
+ offset = ref->offset;
+ size = ref->size;
+ maxsize = ref->max_size;
/* If we cannot constrain the size of the reference we cannot
test if anything kills it. */
/* def_stmt may-defs *ref. See if we can derive a value for *ref
from that defintion.
1) Memset. */
- if (is_gimple_reg_type (TREE_TYPE (ref))
+ if (is_gimple_reg_type (vr->type)
&& is_gimple_call (def_stmt)
&& (fndecl = gimple_call_fndecl (def_stmt))
&& DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
&& operand_equal_p (base, base2, 0)
&& offset2 <= offset
&& offset2 + size2 >= offset + maxsize)
- return vn_reference_insert (ref,
- fold_convert (TREE_TYPE (ref),
- integer_zero_node), vuse);
+ {
+ tree val = fold_convert (vr->type, integer_zero_node);
+ unsigned int value_id = get_or_alloc_constant_value_id (val);
+ return vn_reference_insert_pieces (vuse, vr->set, vr->type,
+ VEC_copy (vn_reference_op_s,
+ heap, vr->operands),
+ val, value_id);
+ }
}
/* 2) Assignment from an empty CONSTRUCTOR. */
- else if (is_gimple_reg_type (TREE_TYPE (ref))
+ else if (is_gimple_reg_type (vr->type)
&& gimple_assign_single_p (def_stmt)
&& gimple_assign_rhs_code (def_stmt) == CONSTRUCTOR
&& CONSTRUCTOR_NELTS (gimple_assign_rhs1 (def_stmt)) == 0)
if (operand_equal_p (base, base2, 0)
&& offset2 <= offset
&& offset2 + size2 >= offset + maxsize)
- return vn_reference_insert (ref,
- fold_convert (TREE_TYPE (ref),
- integer_zero_node), vuse);
+ {
+ tree val = fold_convert (vr->type, integer_zero_node);
+ unsigned int value_id = get_or_alloc_constant_value_id (val);
+ return vn_reference_insert_pieces (vuse, vr->set, vr->type,
+ VEC_copy (vn_reference_op_s,
+ heap, vr->operands),
+ val, value_id);
+ }
}
/* For aggregate copies translate the reference through them if
int i, j;
VEC (vn_reference_op_s, heap) *lhs = NULL, *rhs = NULL;
vn_reference_op_t vro;
+ ao_ref r;
/* See if the assignment kills REF. */
base2 = get_ref_base_and_extent (gimple_assign_lhs (def_stmt),
VEC_replace (vn_reference_op_s, vr->operands, i + 1 + j, vro);
VEC_free (vn_reference_op_s, heap, rhs);
vr->hashcode = vn_reference_compute_hash (vr);
- *refp = get_ref_from_reference_ops (vr->operands);
- if (!*refp)
+
+ /* Adjust *ref from the new operands. */
+ if (!ao_ref_init_from_vn_reference (&r, vr->set, vr->type, vr->operands))
return (void *)-1;
+ gcc_assert (ref->size == r.size);
+ *ref = r;
/* Keep looking for the adjusted *REF / VR pair. */
return NULL;
vn_reference_t stored in the hashtable if something is found. */
tree
-vn_reference_lookup_pieces (tree vuse,
+vn_reference_lookup_pieces (tree vuse, alias_set_type set, tree type,
VEC (vn_reference_op_s, heap) *operands,
vn_reference_t *vnresult, bool maywalk)
{
* VEC_length (vn_reference_op_s, operands));
vr1.operands = operands = shared_lookup_references
= valueize_refs (shared_lookup_references);
+ vr1.type = type;
+ vr1.set = set;
vr1.hashcode = vn_reference_compute_hash (&vr1);
vn_reference_lookup_1 (&vr1, vnresult);
&& maywalk
&& vr1.vuse)
{
- tree ref = get_ref_from_reference_ops (operands);
- if (ref)
+ ao_ref r;
+ if (ao_ref_init_from_vn_reference (&r, set, type, vr1.operands))
*vnresult =
- (vn_reference_t)walk_non_aliased_vuses (ref, vr1.vuse,
+ (vn_reference_t)walk_non_aliased_vuses (&r, vr1.vuse,
vn_reference_lookup_2,
vn_reference_lookup_3, &vr1);
if (vr1.operands != operands)
vr1.vuse = vuse ? SSA_VAL (vuse) : NULL_TREE;
vr1.operands = operands = valueize_shared_reference_ops_from_ref (op);
+ vr1.type = TREE_TYPE (op);
+ vr1.set = get_alias_set (op);
vr1.hashcode = vn_reference_compute_hash (&vr1);
if (maywalk
&& vr1.vuse)
{
vn_reference_t wvnresult;
+ ao_ref r;
+ ao_ref_init (&r, op);
wvnresult =
- (vn_reference_t)walk_non_aliased_vuses (op, vr1.vuse,
+ (vn_reference_t)walk_non_aliased_vuses (&r, vr1.vuse,
vn_reference_lookup_2,
vn_reference_lookup_3, &vr1);
if (vr1.operands != operands)
vr1->value_id = get_or_alloc_constant_value_id (result);
vr1->vuse = vuse ? SSA_VAL (vuse) : NULL_TREE;
vr1->operands = valueize_refs (create_reference_ops_from_ref (op));
+ vr1->type = TREE_TYPE (op);
+ vr1->set = get_alias_set (op);
vr1->hashcode = vn_reference_compute_hash (vr1);
vr1->result = TREE_CODE (result) == SSA_NAME ? SSA_VAL (result) : result;
structure we created. */
vn_reference_t
-vn_reference_insert_pieces (tree vuse,
+vn_reference_insert_pieces (tree vuse, alias_set_type set, tree type,
VEC (vn_reference_op_s, heap) *operands,
tree result, unsigned int value_id)
vr1->value_id = value_id;
vr1->vuse = vuse ? SSA_VAL (vuse) : NULL_TREE;
vr1->operands = valueize_refs (operands);
+ vr1->type = type;
+ vr1->set = set;
vr1->hashcode = vn_reference_compute_hash (vr1);
if (result && TREE_CODE (result) == SSA_NAME)
result = SSA_VAL (result);
vr1.vuse = vuse ? SSA_VAL (vuse) : NULL_TREE;
vr1.operands = valueize_shared_reference_ops_from_call (stmt);
+ vr1.type = gimple_expr_type (stmt);
+ vr1.set = 0;
vr1.hashcode = vn_reference_compute_hash (&vr1);
result = vn_reference_lookup_1 (&vr1, NULL);
if (result)
vr2 = (vn_reference_t) pool_alloc (current_info->references_pool);
vr2->vuse = vr1.vuse;
vr2->operands = valueize_refs (create_reference_ops_from_call (stmt));
+ vr2->type = vr1.type;
+ vr2->set = vr1.set;
vr2->hashcode = vr1.hashcode;
vr2->result = lhs;
slot = htab_find_slot_with_hash (current_info->references,
unsigned int value_id;
hashval_t hashcode;
tree vuse;
+ alias_set_type set;
+ tree type;
VEC (vn_reference_op_s, heap) *operands;
tree result;
} *vn_reference_t;
unsigned int *);
void copy_reference_ops_from_ref (tree, VEC(vn_reference_op_s, heap) **);
void copy_reference_ops_from_call (gimple, VEC(vn_reference_op_s, heap) **);
-tree get_ref_from_reference_ops (VEC(vn_reference_op_s, heap) *ops);
-tree vn_reference_lookup_pieces (tree,
+bool ao_ref_init_from_vn_reference (ao_ref *, alias_set_type, tree,
+ VEC (vn_reference_op_s, heap) *);
+tree vn_reference_lookup_pieces (tree, alias_set_type, tree,
VEC (vn_reference_op_s, heap) *,
vn_reference_t *, bool);
tree vn_reference_lookup (tree, tree, bool, vn_reference_t *);
vn_reference_t vn_reference_insert (tree, tree, tree);
-vn_reference_t vn_reference_insert_pieces (tree,
+vn_reference_t vn_reference_insert_pieces (tree, alias_set_type, tree,
VEC (vn_reference_op_s, heap) *,
tree, unsigned int);