aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Henderson <rth@redhat.com>2004-07-11 10:41:52 -0700
committerRichard Henderson <rth@gcc.gnu.org>2004-07-11 10:41:52 -0700
commitfa27426eb1377c2a9e23f58424b4da5497e78c8d (patch)
tree2934106e3d3e6eaac5aa3e9c20bb96aa1aaada5f /gcc
parent71956db351f1941cf9ebaf35130163832a93478e (diff)
downloadgcc-fa27426eb1377c2a9e23f58424b4da5497e78c8d.zip
gcc-fa27426eb1377c2a9e23f58424b4da5497e78c8d.tar.gz
gcc-fa27426eb1377c2a9e23f58424b4da5497e78c8d.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/tree-sra.c67
-rw-r--r--gcc/tree-ssa-ccp.c45
-rw-r--r--gcc/tree.c45
-rw-r--r--gcc/tree.h3
5 files changed, 126 insertions, 44 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 3ab7ced..155e343 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,15 @@
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
* tree-sra.c (generate_one_element_init): New.
(generate_element_init): Use it.
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
index 1a4e558..423ee3c 100644
--- a/gcc/tree-sra.c
+++ b/gcc/tree-sra.c
@@ -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);
diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c
index 01da8f8..5b6fca6 100644
--- a/gcc/tree-ssa-ccp.c
+++ b/gcc/tree-ssa-ccp.c
@@ -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. */
-
- 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. */
- }
+ /* 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 (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:
diff --git a/gcc/tree.c b/gcc/tree.c
index 033c851..30ddcc8 100644
--- a/gcc/tree.c
+++ b/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"
diff --git a/gcc/tree.h b/gcc/tree.h
index 1daea21..baa2078 100644
--- a/gcc/tree.h
+++ b/gcc/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);