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 (DECL_SIZE (temp.op0), 0))
+ temp.op0 = DECL_SIZE (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);
- temp.op2 = TREE_OPERAND (ref, 3);
+ /* Always record lower bounds and element size. */
+ temp.op1 = array_ref_low_bound (ref);
+ temp.op2 = array_ref_element_size (ref);
break;
case STRING_CST:
case INTEGER_CST:
case CONST_DECL:
case RESULT_DECL:
case SSA_NAME:
- case EXC_PTR_EXPR:
- case FILTER_EXPR:
temp.op0 = ref;
break;
case ADDR_EXPR:
}
}
-/* 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:
+ *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);
+ /* We recorded the lower bound and the element size. */
+ if (!host_integerp (op->op0, 0)
+ || !host_integerp (op->op1, 0)
+ || !host_integerp (op->op2, 0))
+ max_size = -1;
+ else
+ {
+ HOST_WIDE_INT hindex = TREE_INT_CST_LOW (op->op0);
+ hindex -= TREE_INT_CST_LOW (op->op1);
+ hindex *= TREE_INT_CST_LOW (op->op2);
+ hindex *= BITS_PER_UNIT;
+ 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
if ((dom = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (op->op0, 0))))
&& TYPE_MIN_VALUE (dom))
aref.op0 = TYPE_MIN_VALUE (dom);
- aref.op1 = NULL_TREE;
- aref.op2 = NULL_TREE;
+ aref.op1 = aref.op0;
+ aref.op2 = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (op->op0)));
VEC_safe_push (vn_reference_op_s, heap, mem, &aref);
}
copy_reference_ops_from_ref (TREE_OPERAND (op->op0, 0), &mem);
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),
copy_reference_ops_from_ref (gimple_assign_lhs (def_stmt), &lhs);
i = VEC_length (vn_reference_op_s, vr->operands) - 1;
j = VEC_length (vn_reference_op_s, lhs) - 1;
- while (j >= 0
+ while (j >= 0 && i >= 0
&& vn_reference_op_eq (VEC_index (vn_reference_op_s,
vr->operands, i),
VEC_index (vn_reference_op_s, lhs, j)))
i--;
j--;
}
+
+ VEC_free (vn_reference_op_s, heap, lhs);
/* i now points to the first additional op.
??? LHS may not be completely contained in VR, one or more
VIEW_CONVERT_EXPRs could be in its way. We could at least
try handling outermost VIEW_CONVERT_EXPRs. */
if (j != -1)
return (void *)-1;
- VEC_free (vn_reference_op_s, heap, lhs);
/* Now re-write REF to be based on the rhs of the assignment. */
copy_reference_ops_from_ref (gimple_assign_rhs1 (def_stmt), &rhs);
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;
+ /* This can happen with bitfields. */
+ if (ref->size != r.size)
return (void *)-1;
+ *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);
/* Compute and return the hash value for nary operation VBO1. */
-inline hashval_t
+hashval_t
vn_nary_op_compute_hash (const vn_nary_op_t vno1)
{
hashval_t hash = 0;
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,
bool changed = false;
tree result = vn_reference_lookup (op, gimple_vuse (stmt), true, NULL);
+ /* If we have a VCE, try looking up its operand as it might be stored in
+ a different type. */
+ if (!result && TREE_CODE (op) == VIEW_CONVERT_EXPR)
+ result = vn_reference_lookup (TREE_OPERAND (op, 0), gimple_vuse (stmt),
+ true, NULL);
+
/* We handle type-punning through unions by value-numbering based
on offset and size of the access. Be prepared to handle a
type-mismatch here via creating a VIEW_CONVERT_EXPR. */