re PR tree-optimization/16383 (internal compiler error: in generate_element_copy, at tree-sra.c:1466)
PR tree-opt/16383 * tree-ssa-ccp.c (fold_stmt_r): Split out... * tree.c (fields_compatible_p, find_compatible_field): ... new. * tree.h (fields_compatible_p, find_compatible_field): Declare. * tree-sra.c (sra_hash_tree): Hash fields by offset. (sra_elt_eq): Use fields_compatible_p. (generate_one_element_ref): Use find_compatible_field. From-SVN: r84524
This commit is contained in:
parent
71956db351
commit
fa27426eb1
@ -1,3 +1,13 @@
|
||||
2004-07-11 Richard Henderson <rth@redhat.com>
|
||||
|
||||
PR tree-opt/16383
|
||||
* tree-ssa-ccp.c (fold_stmt_r): Split out...
|
||||
* tree.c (fields_compatible_p, find_compatible_field): ... new.
|
||||
* tree.h (fields_compatible_p, find_compatible_field): Declare.
|
||||
* tree-sra.c (sra_hash_tree): Hash fields by offset.
|
||||
(sra_elt_eq): Use fields_compatible_p.
|
||||
(generate_one_element_ref): Use find_compatible_field.
|
||||
|
||||
2004-07-11 Richard Henderson <rth@redhat.com>
|
||||
|
||||
PR tree-opt/16422
|
||||
|
@ -357,18 +357,32 @@ can_completely_scalarize_p (struct sra_elt *elt)
|
||||
static hashval_t
|
||||
sra_hash_tree (tree t)
|
||||
{
|
||||
hashval_t h;
|
||||
|
||||
switch (TREE_CODE (t))
|
||||
{
|
||||
case VAR_DECL:
|
||||
case PARM_DECL:
|
||||
case RESULT_DECL:
|
||||
case FIELD_DECL:
|
||||
return DECL_UID (t);
|
||||
h = DECL_UID (t);
|
||||
break;
|
||||
|
||||
case INTEGER_CST:
|
||||
return TREE_INT_CST_LOW (t) ^ TREE_INT_CST_HIGH (t);
|
||||
h = TREE_INT_CST_LOW (t) ^ TREE_INT_CST_HIGH (t);
|
||||
break;
|
||||
|
||||
case FIELD_DECL:
|
||||
/* We can have types that are compatible, but have different member
|
||||
lists, so we can't hash fields by ID. Use offsets instead. */
|
||||
h = iterative_hash_expr (DECL_FIELD_OFFSET (t), 0);
|
||||
h = iterative_hash_expr (DECL_FIELD_BIT_OFFSET (t), h);
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
/* Hash function for type SRA_PAIR. */
|
||||
@ -399,20 +413,41 @@ sra_elt_eq (const void *x, const void *y)
|
||||
{
|
||||
const struct sra_elt *a = x;
|
||||
const struct sra_elt *b = y;
|
||||
tree ae, be;
|
||||
|
||||
if (a->parent != b->parent)
|
||||
return false;
|
||||
|
||||
/* All the field/decl stuff is unique. */
|
||||
if (a->element == b->element)
|
||||
return true;
|
||||
ae = a->element;
|
||||
be = b->element;
|
||||
|
||||
/* The only thing left is integer equality. */
|
||||
if (TREE_CODE (a->element) == INTEGER_CST
|
||||
&& TREE_CODE (b->element) == INTEGER_CST)
|
||||
return tree_int_cst_equal (a->element, b->element);
|
||||
else
|
||||
if (ae == be)
|
||||
return true;
|
||||
if (TREE_CODE (ae) != TREE_CODE (be))
|
||||
return false;
|
||||
|
||||
switch (TREE_CODE (ae))
|
||||
{
|
||||
case VAR_DECL:
|
||||
case PARM_DECL:
|
||||
case RESULT_DECL:
|
||||
/* These are all pointer unique. */
|
||||
return false;
|
||||
|
||||
case INTEGER_CST:
|
||||
/* Integers are not pointer unique, so compare their values. */
|
||||
return tree_int_cst_equal (ae, be);
|
||||
|
||||
case FIELD_DECL:
|
||||
/* Fields are unique within a record, but not between
|
||||
compatible records. */
|
||||
if (DECL_FIELD_CONTEXT (ae) == DECL_FIELD_CONTEXT (be))
|
||||
return false;
|
||||
return fields_compatible_p (ae, be);
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Create or return the SRA_ELT structure for CHILD in PARENT. PARENT
|
||||
@ -1392,7 +1427,15 @@ generate_one_element_ref (struct sra_elt *elt, tree base)
|
||||
switch (TREE_CODE (TREE_TYPE (base)))
|
||||
{
|
||||
case RECORD_TYPE:
|
||||
return build (COMPONENT_REF, elt->type, base, elt->element, NULL);
|
||||
{
|
||||
tree field = elt->element;
|
||||
|
||||
/* Watch out for compatible records with differing field lists. */
|
||||
if (DECL_FIELD_CONTEXT (field) != TYPE_MAIN_VARIANT (TREE_TYPE (base)))
|
||||
field = find_compatible_field (TREE_TYPE (base), field);
|
||||
|
||||
return build (COMPONENT_REF, elt->type, base, field, NULL);
|
||||
}
|
||||
|
||||
case ARRAY_TYPE:
|
||||
return build (ARRAY_REF, elt->type, base, elt->element, NULL, NULL);
|
||||
|
@ -1962,38 +1962,19 @@ fold_stmt_r (tree *expr_p, int *walk_subtrees, void *data)
|
||||
return t;
|
||||
*walk_subtrees = 0;
|
||||
|
||||
/* Make sure the FIELD_DECL is actually a field in the type on
|
||||
the lhs. In cases with IMA it is possible that it came
|
||||
from another, equivalent type at this point. We have
|
||||
already checked the equivalence in this case.
|
||||
Match on type plus offset, to allow for unnamed fields.
|
||||
We won't necessarily get the corresponding field for
|
||||
unions; this is believed to be harmless. */
|
||||
/* Make sure the FIELD_DECL is actually a field in the type on the lhs.
|
||||
We've already checked that the records are compatible, so we should
|
||||
come up with a set of compatible fields. */
|
||||
{
|
||||
tree expr_record = TREE_TYPE (TREE_OPERAND (expr, 0));
|
||||
tree expr_field = TREE_OPERAND (expr, 1);
|
||||
|
||||
if ((current_file_decl && TREE_CHAIN (current_file_decl))
|
||||
&& (DECL_FIELD_CONTEXT (TREE_OPERAND (expr, 1)) !=
|
||||
TREE_TYPE (TREE_OPERAND (expr, 0))))
|
||||
{
|
||||
tree f;
|
||||
tree orig_field = TREE_OPERAND (expr, 1);
|
||||
tree orig_type = TREE_TYPE (orig_field);
|
||||
for (f = TYPE_FIELDS (TREE_TYPE (TREE_OPERAND (expr, 0)));
|
||||
f; f = TREE_CHAIN (f))
|
||||
{
|
||||
if (lang_hooks.types_compatible_p (TREE_TYPE (f), orig_type)
|
||||
&& tree_int_cst_compare (DECL_FIELD_BIT_OFFSET (f),
|
||||
DECL_FIELD_BIT_OFFSET (orig_field))
|
||||
== 0
|
||||
&& tree_int_cst_compare (DECL_FIELD_OFFSET (f),
|
||||
DECL_FIELD_OFFSET (orig_field))
|
||||
== 0)
|
||||
{
|
||||
TREE_OPERAND (expr, 1) = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Fall through is an error; it will be detected in tree-sra. */
|
||||
}
|
||||
if (DECL_FIELD_CONTEXT (expr_field) != TYPE_MAIN_VARIANT (expr_record))
|
||||
{
|
||||
expr_field = find_compatible_field (expr_record, expr_field);
|
||||
TREE_OPERAND (expr, 1) = expr_field;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
45
gcc/tree.c
45
gcc/tree.c
@ -5693,4 +5693,49 @@ needs_to_live_in_memory (tree t)
|
||||
|| decl_function_context (t) != current_function_decl);
|
||||
}
|
||||
|
||||
/* There are situations in which a language considers record types
|
||||
compatible which have different field lists. Decide if two fields
|
||||
are compatible. It is assumed that the parent records are compatible. */
|
||||
|
||||
bool
|
||||
fields_compatible_p (tree f1, tree f2)
|
||||
{
|
||||
if (!operand_equal_p (DECL_FIELD_BIT_OFFSET (f1),
|
||||
DECL_FIELD_BIT_OFFSET (f2), OEP_ONLY_CONST))
|
||||
return false;
|
||||
|
||||
if (!operand_equal_p (DECL_FIELD_OFFSET (f1),
|
||||
DECL_FIELD_OFFSET (f2), OEP_ONLY_CONST))
|
||||
return false;
|
||||
|
||||
if (!lang_hooks.types_compatible_p (TREE_TYPE (f1), TREE_TYPE (f2)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Locate within RECORD a field that is compatible with ORIG_FIELD. */
|
||||
|
||||
tree
|
||||
find_compatible_field (tree record, tree orig_field)
|
||||
{
|
||||
tree f;
|
||||
|
||||
for (f = TYPE_FIELDS (record); f ; f = TREE_CHAIN (f))
|
||||
if (TREE_CODE (f) == FIELD_DECL
|
||||
&& fields_compatible_p (f, orig_field))
|
||||
return f;
|
||||
|
||||
/* ??? Why isn't this on the main fields list? */
|
||||
f = TYPE_VFIELD (record);
|
||||
if (f && TREE_CODE (f) == FIELD_DECL
|
||||
&& fields_compatible_p (f, orig_field))
|
||||
return f;
|
||||
|
||||
/* ??? We should abort here, but Java appears to do Bad Things
|
||||
with inherited fields. */
|
||||
return orig_field;
|
||||
}
|
||||
|
||||
|
||||
#include "gt-tree.h"
|
||||
|
@ -3481,6 +3481,9 @@ extern void build_common_tree_nodes_2 (int);
|
||||
extern tree build_nonstandard_integer_type (unsigned HOST_WIDE_INT, int);
|
||||
extern tree build_range_type (tree, tree, tree);
|
||||
|
||||
extern bool fields_compatible_p (tree, tree);
|
||||
extern tree find_compatible_field (tree, tree);
|
||||
|
||||
/* In function.c */
|
||||
extern void expand_main_function (void);
|
||||
extern void init_dummy_function_start (void);
|
||||
|
Loading…
x
Reference in New Issue
Block a user