This splits the TYPE_CANONICAL merging machinery from the regular merging machinery. It just gets too confusing to share code-paths as both cases require opposing conservatism (merge everything for TYPE_CANONICAL, merge nothing for regular merging).
Bootstrapped and tested on x86_64-unknown-linux-gnu, SPEC2k6 LTO tested. Next on the list is to do the same for hashing and then remove those discriminators that do not make much sense for TYPE_CANONICAL merging. Richard. 2011-05-10 Richard Guenther <rguent...@suse.de> * gimple.c (gimple_canonical_types_compatible_p): Split out from gimple_types_compatible_p and friends. Do not recurse to pointed-to types. (gimple_canonical_type_eq): Use it. Index: trunk/gcc/gimple.c =================================================================== *** trunk.orig/gcc/gimple.c 2011-05-10 11:55:52.000000000 +0200 --- trunk/gcc/gimple.c 2011-05-10 12:19:56.000000000 +0200 *************** gimple_register_type (tree t) *** 4479,4484 **** --- 4479,4840 ---- } + /* The TYPE_CANONICAL merging machinery. It should closely resemble + the middle-end types_compatible_p function. It needs to avoid + claiming types are different for types that should be treated + the same with respect to TBAA. Canonical types are also used + for IL consistency checks via the useless_type_conversion_p + predicate which does not handle all type kinds itself but falls + back to pointer-comparison of TYPE_CANONICAL for aggregates + for example. */ + + /* Return true iff T1 and T2 are structurally identical for what + TBAA is concerned. */ + + static bool + gimple_canonical_types_compatible_p (tree t1, tree t2) + { + type_pair_t p = NULL; + + /* Before starting to set up the SCC machinery handle simple cases. */ + + /* Check first for the obvious case of pointer identity. */ + if (t1 == t2) + return true; + + /* Check that we have two types to compare. */ + if (t1 == NULL_TREE || t2 == NULL_TREE) + return false; + + /* If the types have been previously registered and found equal + they still are. */ + if (TYPE_CANONICAL (t1) + && TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2)) + return true; + + /* Can't be the same type if the types don't have the same code. */ + if (TREE_CODE (t1) != TREE_CODE (t2)) + return false; + + /* Can't be the same type if they have different CV qualifiers. */ + if (TYPE_QUALS (t1) != TYPE_QUALS (t2)) + return false; + + /* Void types are always the same. */ + if (TREE_CODE (t1) == VOID_TYPE) + return true; + + /* Do some simple checks before doing three hashtable queries. */ + if (INTEGRAL_TYPE_P (t1) + || SCALAR_FLOAT_TYPE_P (t1) + || FIXED_POINT_TYPE_P (t1) + || TREE_CODE (t1) == VECTOR_TYPE + || TREE_CODE (t1) == COMPLEX_TYPE + || TREE_CODE (t1) == OFFSET_TYPE) + { + /* Can't be the same type if they have different alignment, + sign, precision or mode. */ + if (TYPE_ALIGN (t1) != TYPE_ALIGN (t2) + || TYPE_PRECISION (t1) != TYPE_PRECISION (t2) + || TYPE_MODE (t1) != TYPE_MODE (t2) + || TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2)) + return false; + + if (TREE_CODE (t1) == INTEGER_TYPE + && (TYPE_IS_SIZETYPE (t1) != TYPE_IS_SIZETYPE (t2) + || TYPE_STRING_FLAG (t1) != TYPE_STRING_FLAG (t2))) + return false; + + /* That's all we need to check for float and fixed-point types. */ + if (SCALAR_FLOAT_TYPE_P (t1) + || FIXED_POINT_TYPE_P (t1)) + return true; + + /* For integral types fall thru to more complex checks. */ + } + + else if (AGGREGATE_TYPE_P (t1) || POINTER_TYPE_P (t1)) + { + /* Can't be the same type if they have different alignment or mode. */ + if (TYPE_ALIGN (t1) != TYPE_ALIGN (t2) + || TYPE_MODE (t1) != TYPE_MODE (t2)) + return false; + } + + /* If the hash values of t1 and t2 are different the types can't + possibly be the same. This helps keeping the type-pair hashtable + small, only tracking comparisons for hash collisions. */ + if (gimple_canonical_type_hash (t1) != gimple_canonical_type_hash (t2)) + return false; + + /* If we've visited this type pair before (in the case of aggregates + with self-referential types), and we made a decision, return it. */ + p = lookup_type_pair (t1, t2, >c_visited, >c_ob); + if (p->same_p[GTC_DIAG] == 0 || p->same_p[GTC_DIAG] == 1) + { + /* We have already decided whether T1 and T2 are the + same, return the cached result. */ + return p->same_p[GTC_DIAG] == 1; + } + + gcc_assert (p->same_p[GTC_DIAG] == -2); + + /* If their attributes are not the same they can't be the same type. */ + if (!attribute_list_equal (TYPE_ATTRIBUTES (t1), TYPE_ATTRIBUTES (t2))) + goto different_types; + + /* Do type-specific comparisons. */ + switch (TREE_CODE (t1)) + { + case VECTOR_TYPE: + case COMPLEX_TYPE: + if (!gimple_canonical_types_compatible_p (TREE_TYPE (t1), TREE_TYPE (t2))) + goto different_types; + goto same_types; + + case ARRAY_TYPE: + /* Array types are the same if the element types are the same and + the number of elements are the same. */ + if (!gimple_canonical_types_compatible_p (TREE_TYPE (t1), TREE_TYPE (t2)) + || TYPE_STRING_FLAG (t1) != TYPE_STRING_FLAG (t2) + || TYPE_NONALIASED_COMPONENT (t1) != TYPE_NONALIASED_COMPONENT (t2)) + goto different_types; + else + { + tree i1 = TYPE_DOMAIN (t1); + tree i2 = TYPE_DOMAIN (t2); + + /* For an incomplete external array, the type domain can be + NULL_TREE. Check this condition also. */ + if (i1 == NULL_TREE && i2 == NULL_TREE) + goto same_types; + else if (i1 == NULL_TREE || i2 == NULL_TREE) + goto different_types; + /* If for a complete array type the possibly gimplified sizes + are different the types are different. */ + else if (((TYPE_SIZE (i1) != NULL) ^ (TYPE_SIZE (i2) != NULL)) + || (TYPE_SIZE (i1) + && TYPE_SIZE (i2) + && !operand_equal_p (TYPE_SIZE (i1), TYPE_SIZE (i2), 0))) + goto different_types; + else + { + tree min1 = TYPE_MIN_VALUE (i1); + tree min2 = TYPE_MIN_VALUE (i2); + tree max1 = TYPE_MAX_VALUE (i1); + tree max2 = TYPE_MAX_VALUE (i2); + + /* The minimum/maximum values have to be the same. */ + if ((min1 == min2 + || (min1 && min2 + && ((TREE_CODE (min1) == PLACEHOLDER_EXPR + && TREE_CODE (min2) == PLACEHOLDER_EXPR) + || operand_equal_p (min1, min2, 0)))) + && (max1 == max2 + || (max1 && max2 + && ((TREE_CODE (max1) == PLACEHOLDER_EXPR + && TREE_CODE (max2) == PLACEHOLDER_EXPR) + || operand_equal_p (max1, max2, 0))))) + goto same_types; + else + goto different_types; + } + } + + case METHOD_TYPE: + /* Method types should belong to the same class. */ + if (!gimple_canonical_types_compatible_p + (TYPE_METHOD_BASETYPE (t1), TYPE_METHOD_BASETYPE (t2))) + goto different_types; + + /* Fallthru */ + + case FUNCTION_TYPE: + /* Function types are the same if the return type and arguments types + are the same. */ + if (!gimple_compatible_complete_and_incomplete_subtype_p + (TREE_TYPE (t1), TREE_TYPE (t2)) + && !gimple_canonical_types_compatible_p + (TREE_TYPE (t1), TREE_TYPE (t2))) + goto different_types; + + if (!comp_type_attributes (t1, t2)) + goto different_types; + + if (TYPE_ARG_TYPES (t1) == TYPE_ARG_TYPES (t2)) + goto same_types; + else + { + tree parms1, parms2; + + for (parms1 = TYPE_ARG_TYPES (t1), parms2 = TYPE_ARG_TYPES (t2); + parms1 && parms2; + parms1 = TREE_CHAIN (parms1), parms2 = TREE_CHAIN (parms2)) + { + if (!gimple_compatible_complete_and_incomplete_subtype_p + (TREE_VALUE (parms1), TREE_VALUE (parms2)) + && !gimple_canonical_types_compatible_p + (TREE_VALUE (parms1), TREE_VALUE (parms2))) + goto different_types; + } + + if (parms1 || parms2) + goto different_types; + + goto same_types; + } + + case OFFSET_TYPE: + { + if (!gimple_canonical_types_compatible_p + (TREE_TYPE (t1), TREE_TYPE (t2)) + || !gimple_canonical_types_compatible_p + (TYPE_OFFSET_BASETYPE (t1), TYPE_OFFSET_BASETYPE (t2))) + goto different_types; + + goto same_types; + } + + case POINTER_TYPE: + case REFERENCE_TYPE: + { + /* If the two pointers have different ref-all attributes, + they can't be the same type. */ + if (TYPE_REF_CAN_ALIAS_ALL (t1) != TYPE_REF_CAN_ALIAS_ALL (t2)) + goto different_types; + + if (TYPE_ADDR_SPACE (TREE_TYPE (t1)) + != TYPE_ADDR_SPACE (TREE_TYPE (t2))) + goto different_types; + + if (TYPE_RESTRICT (t1) != TYPE_RESTRICT (t2)) + goto different_types; + + /* For canonical type comparisons we do not want to build SCCs + so we cannot compare pointed-to types. But we can, for now, + require the same pointed-to type kind. */ + if (TREE_CODE (TREE_TYPE (t1)) != TREE_CODE (TREE_TYPE (t2))) + goto different_types; + + goto same_types; + } + + case NULLPTR_TYPE: + /* There is only one decltype(nullptr). */ + goto same_types; + + case INTEGER_TYPE: + case BOOLEAN_TYPE: + { + tree min1 = TYPE_MIN_VALUE (t1); + tree max1 = TYPE_MAX_VALUE (t1); + tree min2 = TYPE_MIN_VALUE (t2); + tree max2 = TYPE_MAX_VALUE (t2); + bool min_equal_p = false; + bool max_equal_p = false; + + /* If either type has a minimum value, the other type must + have the same. */ + if (min1 == NULL_TREE && min2 == NULL_TREE) + min_equal_p = true; + else if (min1 && min2 && operand_equal_p (min1, min2, 0)) + min_equal_p = true; + + /* Likewise, if either type has a maximum value, the other + type must have the same. */ + if (max1 == NULL_TREE && max2 == NULL_TREE) + max_equal_p = true; + else if (max1 && max2 && operand_equal_p (max1, max2, 0)) + max_equal_p = true; + + if (!min_equal_p || !max_equal_p) + goto different_types; + + goto same_types; + } + + case ENUMERAL_TYPE: + { + /* FIXME lto, we cannot check bounds on enumeral types because + different front ends will produce different values. + In C, enumeral types are integers, while in C++ each element + will have its own symbolic value. We should decide how enums + are to be represented in GIMPLE and have each front end lower + to that. */ + tree v1, v2; + + /* For enumeral types, all the values must be the same. */ + if (TYPE_VALUES (t1) == TYPE_VALUES (t2)) + goto same_types; + + for (v1 = TYPE_VALUES (t1), v2 = TYPE_VALUES (t2); + v1 && v2; + v1 = TREE_CHAIN (v1), v2 = TREE_CHAIN (v2)) + { + tree c1 = TREE_VALUE (v1); + tree c2 = TREE_VALUE (v2); + + if (TREE_CODE (c1) == CONST_DECL) + c1 = DECL_INITIAL (c1); + + if (TREE_CODE (c2) == CONST_DECL) + c2 = DECL_INITIAL (c2); + + if (tree_int_cst_equal (c1, c2) != 1) + goto different_types; + } + + /* If one enumeration has more values than the other, they + are not the same. */ + if (v1 || v2) + goto different_types; + + goto same_types; + } + + case RECORD_TYPE: + case UNION_TYPE: + case QUAL_UNION_TYPE: + { + tree f1, f2; + + /* For aggregate types, all the fields must be the same. */ + for (f1 = TYPE_FIELDS (t1), f2 = TYPE_FIELDS (t2); + f1 && f2; + f1 = TREE_CHAIN (f1), f2 = TREE_CHAIN (f2)) + { + /* The fields must have the same name, offset and type. */ + if (DECL_NONADDRESSABLE_P (f1) != DECL_NONADDRESSABLE_P (f2) + || !gimple_compare_field_offset (f1, f2) + || !gimple_canonical_types_compatible_p + (TREE_TYPE (f1), TREE_TYPE (f2))) + goto different_types; + } + + /* If one aggregate has more fields than the other, they + are not the same. */ + if (f1 || f2) + goto different_types; + + goto same_types; + } + + default: + gcc_unreachable (); + } + + /* Common exit path for types that are not compatible. */ + different_types: + p->same_p[GTC_DIAG] = 0; + return false; + + /* Common exit path for types that are compatible. */ + same_types: + p->same_p[GTC_DIAG] = 1; + return true; + } + + /* Returns nonzero if P1 and P2 are equal. */ static int *************** gimple_canonical_type_eq (const void *p1 *** 4486,4493 **** { const_tree t1 = (const_tree) p1; const_tree t2 = (const_tree) p2; ! return gimple_types_compatible_p (CONST_CAST_TREE (t1), ! CONST_CAST_TREE (t2), GTC_DIAG); } /* Register type T in the global type table gimple_types. --- 4842,4849 ---- { const_tree t1 = (const_tree) p1; const_tree t2 = (const_tree) p2; ! return gimple_canonical_types_compatible_p (CONST_CAST_TREE (t1), ! CONST_CAST_TREE (t2)); } /* Register type T in the global type table gimple_types.