From fa27426eb1377c2a9e23f58424b4da5497e78c8d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 11 Jul 2004 10:41:52 -0700 Subject: [PATCH] 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 --- gcc/ChangeLog | 10 +++++++ gcc/tree-sra.c | 67 +++++++++++++++++++++++++++++++++++++--------- gcc/tree-ssa-ccp.c | 45 +++++++++---------------------- gcc/tree.c | 45 +++++++++++++++++++++++++++++++ gcc/tree.h | 3 +++ 5 files changed, 126 insertions(+), 44 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3ab7cedeadb..155e3436738 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2004-07-11 Richard Henderson + + 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 PR tree-opt/16422 diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c index 1a4e5586c4f..423ee3ca498 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 01da8f88e07..5b6fca62653 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 033c851ea74..30ddcc895a5 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 1daea216559..baa20781eef 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); -- 2.30.2