This is the second half of splitting TYPE_CANONICAL handling away from the rest of the machinery. The following patch introduces a simplified, non-SCC based hashing for TYPE_CANONICAL - it still hashes things it shouldn't, but the patch is supposed to be functional equivalent apart from the pointer-following case.
Bootstrapped on x86_64-unknown-linux-gnu, testing and SPEC2k6 LTO building in progress. I plan to commit both pieces together tomorrow, if the testing succeeded. A followup will then remove dead codepaths from the other half of the machinery, followed by a patch to simplify both hashing and comparing TYPE_CANONICALs a tad bid. Richard. 2011-05-10 Richard Guenther <rguent...@suse.de> * gimple.c (iterative_hash_canonical_type): Split out from iterative_hash_gimple_type and friends. Do not recurse to pointed-to types. (gimple_canonical_type_hash): Use it, allocate the hash here. Index: trunk/gcc/gimple.c =================================================================== *** trunk.orig/gcc/gimple.c 2011-05-10 13:45:13.000000000 +0200 --- trunk/gcc/gimple.c 2011-05-10 17:02:07.000000000 +0200 *************** gimple_type_hash (const void *p) *** 4344,4353 **** return gimple_type_hash_1 (p, GTC_MERGE); } static hashval_t gimple_canonical_type_hash (const void *p) { ! return gimple_type_hash_1 (p, GTC_DIAG); } --- 4344,4491 ---- return gimple_type_hash_1 (p, GTC_MERGE); } + /* Returning a hash value for gimple type TYPE combined with VAL. + + The hash value returned is equal for types considered compatible + by gimple_canonical_types_compatible_p. */ + + static hashval_t + iterative_hash_canonical_type (tree type, hashval_t val) + { + hashval_t v; + void **slot; + struct tree_int_map *mp, m; + + m.base.from = type; + if ((slot = htab_find_slot (canonical_type_hash_cache, &m, INSERT)) + && *slot) + return iterative_hash_hashval_t (((struct tree_int_map *) *slot)->to, 0); + + /* Combine a few common features of types so that types are grouped into + smaller sets; when searching for existing matching types to merge, + only existing types having the same features as the new type will be + checked. */ + v = iterative_hash_hashval_t (TREE_CODE (type), 0); + v = iterative_hash_hashval_t (TYPE_QUALS (type), v); + v = iterative_hash_hashval_t (TREE_ADDRESSABLE (type), v); + + /* Do not hash the types size as this will cause differences in + hash values for the complete vs. the incomplete type variant. */ + + /* Incorporate common features of numerical types. */ + if (INTEGRAL_TYPE_P (type) + || SCALAR_FLOAT_TYPE_P (type) + || FIXED_POINT_TYPE_P (type)) + { + v = iterative_hash_hashval_t (TYPE_PRECISION (type), v); + v = iterative_hash_hashval_t (TYPE_MODE (type), v); + v = iterative_hash_hashval_t (TYPE_UNSIGNED (type), v); + } + + /* For pointer and reference types, fold in information about the type + pointed to but do not recurse to the pointed-to type. */ + if (POINTER_TYPE_P (type)) + { + v = iterative_hash_hashval_t (TYPE_REF_CAN_ALIAS_ALL (type), v); + v = iterative_hash_hashval_t (TREE_CODE (TREE_TYPE (type)), v); + } + + /* For integer types hash the types min/max values and the string flag. */ + if (TREE_CODE (type) == INTEGER_TYPE) + { + /* OMP lowering can introduce error_mark_node in place of + random local decls in types. */ + if (TYPE_MIN_VALUE (type) != error_mark_node) + v = iterative_hash_expr (TYPE_MIN_VALUE (type), v); + if (TYPE_MAX_VALUE (type) != error_mark_node) + v = iterative_hash_expr (TYPE_MAX_VALUE (type), v); + v = iterative_hash_hashval_t (TYPE_STRING_FLAG (type), v); + } + + /* For array types hash their domain and the string flag. */ + if (TREE_CODE (type) == ARRAY_TYPE + && TYPE_DOMAIN (type)) + { + v = iterative_hash_hashval_t (TYPE_STRING_FLAG (type), v); + v = iterative_hash_canonical_type (TYPE_DOMAIN (type), v); + } + + /* Recurse for aggregates with a single element type. */ + if (TREE_CODE (type) == ARRAY_TYPE + || TREE_CODE (type) == COMPLEX_TYPE + || TREE_CODE (type) == VECTOR_TYPE) + v = iterative_hash_canonical_type (TREE_TYPE (type), v); + + /* Incorporate function return and argument types. */ + if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE) + { + unsigned na; + tree p; + + /* For method types also incorporate their parent class. */ + if (TREE_CODE (type) == METHOD_TYPE) + v = iterative_hash_canonical_type (TYPE_METHOD_BASETYPE (type), v); + + /* For result types allow mismatch in completeness. */ + if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type))) + { + v = iterative_hash_hashval_t (TREE_CODE (TREE_TYPE (type)), v); + v = iterative_hash_name + (TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (type))), v); + } + else + v = iterative_hash_canonical_type (TREE_TYPE (type), v); + + for (p = TYPE_ARG_TYPES (type), na = 0; p; p = TREE_CHAIN (p)) + { + /* For argument types allow mismatch in completeness. */ + if (RECORD_OR_UNION_TYPE_P (TREE_VALUE (p))) + { + v = iterative_hash_hashval_t (TREE_CODE (TREE_VALUE (p)), v); + v = iterative_hash_name + (TYPE_NAME (TYPE_MAIN_VARIANT (TREE_VALUE (p))), v); + } + else + v = iterative_hash_canonical_type (TREE_VALUE (p), v); + na++; + } + + v = iterative_hash_hashval_t (na, v); + } + + if (TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE + || TREE_CODE (type) == QUAL_UNION_TYPE) + { + unsigned nf; + tree f; + + for (f = TYPE_FIELDS (type), nf = 0; f; f = TREE_CHAIN (f)) + { + v = iterative_hash_canonical_type (TREE_TYPE (f), v); + nf++; + } + + v = iterative_hash_hashval_t (nf, v); + } + + /* Cache the just computed hash value. */ + mp = ggc_alloc_cleared_tree_int_map (); + mp->base.from = type; + mp->to = v; + *slot = (void *) mp; + + return iterative_hash_hashval_t (v, val); + } + static hashval_t gimple_canonical_type_hash (const void *p) { ! if (canonical_type_hash_cache == NULL) ! canonical_type_hash_cache = htab_create_ggc (512, tree_int_map_hash, ! tree_int_map_eq, NULL); ! ! return iterative_hash_canonical_type (CONST_CAST_TREE ((const_tree) p), 0); }