diff options
author | rguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-10-14 12:06:38 +0000 |
---|---|---|
committer | rguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-10-14 12:06:38 +0000 |
commit | 700d6a0bc1754dbf6ad6c98e1484195cce30575d (patch) | |
tree | 5851ead175606fe8c897bc8ed1b707d4f2d9d845 /gcc | |
parent | ebeb88c0b40390184bc642bf2dc0dcc96b07c5f5 (diff) | |
download | gcc-700d6a0bc1754dbf6ad6c98e1484195cce30575d.tar.gz |
2013-10-14 Richard Biener <rguenther@suse.de>
* gimple.c (gimple_canonical_types, canonical_type_hash_cache,
iterative_hash_canonical_type, gimple_canonical_type_hash,
gimple_canonical_types_compatible_p, gimple_canonical_type_eq,
gimple_register_canonical_type, print_gimple_types_stats,
free_gimple_type_tables): Move to lto/lto.c
(gt-gimple.h): Do not include.
* gimple.h (gimple_register_canonical_type,
print_gimple_types_stats, free_gimple_type_tables): Remove.
* Makefile.in (GTFILES): Remove gimple.c.
lto/
* lto-lang.c (lto_init): Do not re-init canonical types here.
(lto_register_canonical_types): Move to ...
* lto.c (lto_register_canonical_types): ... here.
(gimple_canonical_types, canonical_type_hash_cache,
iterative_hash_canonical_type, gimple_canonical_type_hash,
gimple_canonical_types_compatible_p, gimple_canonical_type_eq,
gimple_register_canonical_type): Add canonical type merging machinery
moved from gimple.c.
(read_cgraph_and_symbols): Init and free canonical type tables
here.
(print_lto_report_1): Report canonical type table stats here.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@203521 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 12 | ||||
-rw-r--r-- | gcc/Makefile.in | 2 | ||||
-rw-r--r-- | gcc/gimple.c | 459 | ||||
-rw-r--r-- | gcc/gimple.h | 3 | ||||
-rw-r--r-- | gcc/lto/ChangeLog | 14 | ||||
-rw-r--r-- | gcc/lto/lto-lang.c | 31 | ||||
-rw-r--r-- | gcc/lto/lto.c | 456 |
7 files changed, 481 insertions, 496 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 08c99309870..0a03d3ccb81 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2013-10-14 Richard Biener <rguenther@suse.de> + + * gimple.c (gimple_canonical_types, canonical_type_hash_cache, + iterative_hash_canonical_type, gimple_canonical_type_hash, + gimple_canonical_types_compatible_p, gimple_canonical_type_eq, + gimple_register_canonical_type, print_gimple_types_stats, + free_gimple_type_tables): Move to lto/lto.c + (gt-gimple.h): Do not include. + * gimple.h (gimple_register_canonical_type, + print_gimple_types_stats, free_gimple_type_tables): Remove. + * Makefile.in (GTFILES): Remove gimple.c. + 2013-10-14 Travis Snoozy <quandary@remstate.com> PR target/58716 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 4e396aab9d9..24c8fed8a64 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -2240,7 +2240,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \ $(srcdir)/reg-stack.c $(srcdir)/cfgrtl.c \ $(srcdir)/sdbout.c $(srcdir)/stor-layout.c \ $(srcdir)/stringpool.c $(srcdir)/tree.c $(srcdir)/varasm.c \ - $(srcdir)/gimple.h $(srcdir)/gimple.c \ + $(srcdir)/gimple.h \ $(srcdir)/tree-mudflap.c $(srcdir)/gimple-ssa.h \ $(srcdir)/tree-ssanames.c $(srcdir)/tree-eh.c $(srcdir)/tree-ssa-address.c \ $(srcdir)/tree-cfg.c \ diff --git a/gcc/gimple.c b/gcc/gimple.c index e0cc4ef92d1..a12dd67a118 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -37,11 +37,6 @@ along with GCC; see the file COPYING3. If not see #include "demangle.h" #include "langhooks.h" -/* Global canonical type table. */ -static GTY((if_marked ("ggc_marked_p"), param_is (union tree_node))) - htab_t gimple_canonical_types; -static GTY((if_marked ("tree_int_map_marked_p"), param_is (struct tree_int_map))) - htab_t canonical_type_hash_cache; /* All the tuples have their operand vector (if present) at the very bottom of the structure. Therefore, the offset required to find the @@ -3099,458 +3094,6 @@ gimple_compare_field_offset (tree f1, tree f2) return false; } -/* 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, NO_INSERT))) - return iterative_hash_hashval_t (((struct tree_int_map *) *slot)->to, val); - - /* 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 (TREE_ADDRESSABLE (type), v); - v = iterative_hash_hashval_t (TYPE_ALIGN (type), v); - v = iterative_hash_hashval_t (TYPE_MODE (type), v); - - /* Incorporate common features of numerical types. */ - if (INTEGRAL_TYPE_P (type) - || SCALAR_FLOAT_TYPE_P (type) - || FIXED_POINT_TYPE_P (type) - || TREE_CODE (type) == OFFSET_TYPE - || POINTER_TYPE_P (type)) - { - v = iterative_hash_hashval_t (TYPE_PRECISION (type), v); - v = iterative_hash_hashval_t (TYPE_UNSIGNED (type), v); - } - - if (VECTOR_TYPE_P (type)) - { - v = iterative_hash_hashval_t (TYPE_VECTOR_SUBPARTS (type), v); - v = iterative_hash_hashval_t (TYPE_UNSIGNED (type), v); - } - - if (TREE_CODE (type) == COMPLEX_TYPE) - 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 (TYPE_ADDR_SPACE (TREE_TYPE (type)), v); - v = iterative_hash_hashval_t (TYPE_RESTRICT (type), v); - v = iterative_hash_hashval_t (TREE_CODE (TREE_TYPE (type)), v); - } - - /* For integer types hash only the string flag. */ - if (TREE_CODE (type) == INTEGER_TYPE) - v = iterative_hash_hashval_t (TYPE_STRING_FLAG (type), v); - - /* For array types hash the domain bounds and the string flag. */ - if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type)) - { - v = iterative_hash_hashval_t (TYPE_STRING_FLAG (type), v); - /* OMP lowering can introduce error_mark_node in place of - random local decls in types. */ - if (TYPE_MIN_VALUE (TYPE_DOMAIN (type)) != error_mark_node) - v = iterative_hash_expr (TYPE_MIN_VALUE (TYPE_DOMAIN (type)), v); - if (TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != error_mark_node) - v = iterative_hash_expr (TYPE_MAX_VALUE (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); - - v = iterative_hash_canonical_type (TREE_TYPE (type), v); - - for (p = TYPE_ARG_TYPES (type), na = 0; p; p = TREE_CHAIN (p)) - { - v = iterative_hash_canonical_type (TREE_VALUE (p), v); - na++; - } - - v = iterative_hash_hashval_t (na, v); - } - - if (RECORD_OR_UNION_TYPE_P (type)) - { - unsigned nf; - tree f; - - for (f = TYPE_FIELDS (type), nf = 0; f; f = TREE_CHAIN (f)) - if (TREE_CODE (f) == FIELD_DECL) - { - 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; - /* As we recurse the hashtable may expand between looking up the - cached value (and not finding one) and here, so we have to - re-lookup the slot. */ - slot = htab_find_slot (canonical_type_hash_cache, &m, INSERT); - *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); -} - - - - -/* 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) -{ - /* 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; - - if (TREE_ADDRESSABLE (t1) != TREE_ADDRESSABLE (t2)) - return false; - - /* Qualifiers do not matter for canonical type comparison purposes. */ - - /* Void types and nullptr types are always the same. */ - if (TREE_CODE (t1) == VOID_TYPE - || TREE_CODE (t1) == NULLPTR_TYPE) - return true; - - /* 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; - - /* Non-aggregate types can be handled cheaply. */ - 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 - || POINTER_TYPE_P (t1)) - { - /* Can't be the same type if they have different sign or precision. */ - if (TYPE_PRECISION (t1) != TYPE_PRECISION (t2) - || TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2)) - return false; - - if (TREE_CODE (t1) == INTEGER_TYPE - && TYPE_STRING_FLAG (t1) != TYPE_STRING_FLAG (t2)) - return false; - - /* 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 and match what - useless_type_conversion_p would do. */ - if (POINTER_TYPE_P (t1)) - { - /* 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)) - return false; - - if (TYPE_ADDR_SPACE (TREE_TYPE (t1)) - != TYPE_ADDR_SPACE (TREE_TYPE (t2))) - return false; - - if (TYPE_RESTRICT (t1) != TYPE_RESTRICT (t2)) - return false; - - if (TREE_CODE (TREE_TYPE (t1)) != TREE_CODE (TREE_TYPE (t2))) - return false; - } - - /* Tail-recurse to components. */ - if (TREE_CODE (t1) == VECTOR_TYPE - || TREE_CODE (t1) == COMPLEX_TYPE) - return gimple_canonical_types_compatible_p (TREE_TYPE (t1), - TREE_TYPE (t2)); - - return true; - } - - /* Do type-specific comparisons. */ - switch (TREE_CODE (t1)) - { - 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)) - return false; - 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) - return true; - else if (i1 == NULL_TREE || i2 == NULL_TREE) - return false; - 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))))) - return true; - else - return false; - } - } - - case METHOD_TYPE: - case FUNCTION_TYPE: - /* Function types are the same if the return type and arguments types - are the same. */ - if (!gimple_canonical_types_compatible_p (TREE_TYPE (t1), TREE_TYPE (t2))) - return false; - - if (!comp_type_attributes (t1, t2)) - return false; - - if (TYPE_ARG_TYPES (t1) == TYPE_ARG_TYPES (t2)) - return true; - 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_canonical_types_compatible_p - (TREE_VALUE (parms1), TREE_VALUE (parms2))) - return false; - } - - if (parms1 || parms2) - return false; - - return true; - } - - 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)) - { - /* Skip non-fields. */ - while (f1 && TREE_CODE (f1) != FIELD_DECL) - f1 = TREE_CHAIN (f1); - while (f2 && TREE_CODE (f2) != FIELD_DECL) - f2 = TREE_CHAIN (f2); - if (!f1 || !f2) - break; - /* 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))) - return false; - } - - /* If one aggregate has more fields than the other, they - are not the same. */ - if (f1 || f2) - return false; - - return true; - } - - default: - gcc_unreachable (); - } -} - - -/* Returns nonzero if P1 and P2 are equal. */ - -static int -gimple_canonical_type_eq (const void *p1, const void *p2) -{ - 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. - If another type T', compatible with T, already existed in - gimple_types then return T', otherwise return T. This is used by - LTO to merge identical types read from different TUs. - - ??? This merging does not exactly match how the tree.c middle-end - functions will assign TYPE_CANONICAL when new types are created - during optimization (which at least happens for pointer and array - types). */ - -tree -gimple_register_canonical_type (tree t) -{ - void **slot; - - gcc_assert (TYPE_P (t)); - - if (TYPE_CANONICAL (t)) - return TYPE_CANONICAL (t); - - if (gimple_canonical_types == NULL) - gimple_canonical_types = htab_create_ggc (16381, gimple_canonical_type_hash, - gimple_canonical_type_eq, 0); - - slot = htab_find_slot (gimple_canonical_types, t, INSERT); - if (*slot - && *(tree *)slot != t) - { - tree new_type = (tree) *((tree *) slot); - - TYPE_CANONICAL (t) = new_type; - t = new_type; - } - else - { - TYPE_CANONICAL (t) = t; - *slot = (void *) t; - } - - return t; -} - - -/* Show statistics on references to the global type table gimple_types. */ - -void -print_gimple_types_stats (const char *pfx) -{ - if (gimple_canonical_types) - fprintf (stderr, "[%s] GIMPLE canonical type table: size %ld, " - "%ld elements, %ld searches, %ld collisions (ratio: %f)\n", pfx, - (long) htab_size (gimple_canonical_types), - (long) htab_elements (gimple_canonical_types), - (long) gimple_canonical_types->searches, - (long) gimple_canonical_types->collisions, - htab_collisions (gimple_canonical_types)); - else - fprintf (stderr, "[%s] GIMPLE canonical type table is empty\n", pfx); - if (canonical_type_hash_cache) - fprintf (stderr, "[%s] GIMPLE canonical type hash table: size %ld, " - "%ld elements, %ld searches, %ld collisions (ratio: %f)\n", pfx, - (long) htab_size (canonical_type_hash_cache), - (long) htab_elements (canonical_type_hash_cache), - (long) canonical_type_hash_cache->searches, - (long) canonical_type_hash_cache->collisions, - htab_collisions (canonical_type_hash_cache)); - else - fprintf (stderr, "[%s] GIMPLE canonical type hash table is empty\n", pfx); -} - -/* Free the gimple type hashtables used for LTO type merging. */ - -void -free_gimple_type_tables (void) -{ - if (gimple_canonical_types) - { - htab_delete (gimple_canonical_types); - gimple_canonical_types = NULL; - } - if (canonical_type_hash_cache) - { - htab_delete (canonical_type_hash_cache); - canonical_type_hash_cache = NULL; - } -} - /* Return a type the same as TYPE except unsigned or signed according to UNSIGNEDP. */ @@ -4520,5 +4063,3 @@ nonfreeing_call_p (gimple call) return false; } - -#include "gt-gimple.h" diff --git a/gcc/gimple.h b/gcc/gimple.h index 822274a29f0..c0c19ce995a 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -891,9 +891,6 @@ extern bool is_gimple_builtin_call (gimple stmt); extern void recalculate_side_effects (tree); extern bool gimple_compare_field_offset (tree, tree); -extern tree gimple_register_canonical_type (tree); -extern void print_gimple_types_stats (const char *); -extern void free_gimple_type_tables (void); extern tree gimple_unsigned_type (tree); extern tree gimple_signed_type (tree); extern alias_set_type gimple_get_alias_set (tree); diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog index eaa69306f67..58474af57ca 100644 --- a/gcc/lto/ChangeLog +++ b/gcc/lto/ChangeLog @@ -1,3 +1,17 @@ +2013-10-14 Richard Biener <rguenther@suse.de> + + * lto-lang.c (lto_init): Do not re-init canonical types here. + (lto_register_canonical_types): Move to ... + * lto.c (lto_register_canonical_types): ... here. + (gimple_canonical_types, canonical_type_hash_cache, + iterative_hash_canonical_type, gimple_canonical_type_hash, + gimple_canonical_types_compatible_p, gimple_canonical_type_eq, + gimple_register_canonical_type): Add canonical type merging machinery + moved from gimple.c. + (read_cgraph_and_symbols): Init and free canonical type tables + here. + (print_lto_report_1): Report canonical type table stats here. + 2013-10-11 Jakub Jelinek <jakub@redhat.com> * lto-lang.c (DEF_FUNCTION_TYPE_8): Define. diff --git a/gcc/lto/lto-lang.c b/gcc/lto/lto-lang.c index 79cc5609994..0fa0fc9a438 100644 --- a/gcc/lto/lto-lang.c +++ b/gcc/lto/lto-lang.c @@ -1134,31 +1134,11 @@ lto_build_c_type_nodes (void) pid_type_node = integer_type_node; } -/* Re-compute TYPE_CANONICAL for NODE and related types. */ - -static void -lto_register_canonical_types (tree node) -{ - if (!node - || !TYPE_P (node)) - return; - - TYPE_CANONICAL (node) = NULL_TREE; - TYPE_CANONICAL (node) = gimple_register_canonical_type (node); - - if (POINTER_TYPE_P (node) - || TREE_CODE (node) == COMPLEX_TYPE - || TREE_CODE (node) == ARRAY_TYPE) - lto_register_canonical_types (TREE_TYPE (node)); -} - /* Perform LTO-specific initialization. */ static bool lto_init (void) { - unsigned i; - /* We need to generate LTO if running in WPA mode. */ flag_generate_lto = flag_wpa; @@ -1226,17 +1206,6 @@ lto_init (void) NAME_TYPE (boolean_type_node, "bool"); #undef NAME_TYPE - /* Register the common node types with the canonical type machinery so - we properly share alias-sets across languages and TUs. Do not - expose the common nodes as type merge target - those that should be - are already exposed so by pre-loading the LTO streamer caches. */ - for (i = 0; i < itk_none; ++i) - lto_register_canonical_types (integer_types[i]); - /* The sizetypes are not used to access data so we do not need to - do anything about them. */ - for (i = 0; i < TI_MAX; ++i) - lto_register_canonical_types (global_trees[i]); - /* Initialize LTO-specific data structures. */ vec_alloc (lto_global_var_decls, 256); in_lto_p = true; diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c index 470f3c1d7a7..f01b37521fd 100644 --- a/gcc/lto/lto.c +++ b/gcc/lto/lto.c @@ -254,6 +254,427 @@ lto_read_in_decl_state (struct data_in *data_in, const uint32_t *data, } +/* Global canonical type table. */ +static GTY((if_marked ("ggc_marked_p"), param_is (union tree_node))) + htab_t gimple_canonical_types; +static GTY((if_marked ("tree_int_map_marked_p"), param_is (struct tree_int_map))) + htab_t canonical_type_hash_cache; + +/* 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, NO_INSERT))) + return iterative_hash_hashval_t (((struct tree_int_map *) *slot)->to, val); + + /* 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 (TREE_ADDRESSABLE (type), v); + v = iterative_hash_hashval_t (TYPE_ALIGN (type), v); + v = iterative_hash_hashval_t (TYPE_MODE (type), v); + + /* Incorporate common features of numerical types. */ + if (INTEGRAL_TYPE_P (type) + || SCALAR_FLOAT_TYPE_P (type) + || FIXED_POINT_TYPE_P (type) + || TREE_CODE (type) == OFFSET_TYPE + || POINTER_TYPE_P (type)) + { + v = iterative_hash_hashval_t (TYPE_PRECISION (type), v); + v = iterative_hash_hashval_t (TYPE_UNSIGNED (type), v); + } + + if (VECTOR_TYPE_P (type)) + { + v = iterative_hash_hashval_t (TYPE_VECTOR_SUBPARTS (type), v); + v = iterative_hash_hashval_t (TYPE_UNSIGNED (type), v); + } + + if (TREE_CODE (type) == COMPLEX_TYPE) + 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 (TYPE_ADDR_SPACE (TREE_TYPE (type)), v); + v = iterative_hash_hashval_t (TYPE_RESTRICT (type), v); + v = iterative_hash_hashval_t (TREE_CODE (TREE_TYPE (type)), v); + } + + /* For integer types hash only the string flag. */ + if (TREE_CODE (type) == INTEGER_TYPE) + v = iterative_hash_hashval_t (TYPE_STRING_FLAG (type), v); + + /* For array types hash the domain bounds and the string flag. */ + if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type)) + { + v = iterative_hash_hashval_t (TYPE_STRING_FLAG (type), v); + /* OMP lowering can introduce error_mark_node in place of + random local decls in types. */ + if (TYPE_MIN_VALUE (TYPE_DOMAIN (type)) != error_mark_node) + v = iterative_hash_expr (TYPE_MIN_VALUE (TYPE_DOMAIN (type)), v); + if (TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != error_mark_node) + v = iterative_hash_expr (TYPE_MAX_VALUE (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); + + v = iterative_hash_canonical_type (TREE_TYPE (type), v); + + for (p = TYPE_ARG_TYPES (type), na = 0; p; p = TREE_CHAIN (p)) + { + v = iterative_hash_canonical_type (TREE_VALUE (p), v); + na++; + } + + v = iterative_hash_hashval_t (na, v); + } + + if (RECORD_OR_UNION_TYPE_P (type)) + { + unsigned nf; + tree f; + + for (f = TYPE_FIELDS (type), nf = 0; f; f = TREE_CHAIN (f)) + if (TREE_CODE (f) == FIELD_DECL) + { + 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; + /* As we recurse the hashtable may expand between looking up the + cached value (and not finding one) and here, so we have to + re-lookup the slot. */ + slot = htab_find_slot (canonical_type_hash_cache, &m, INSERT); + *slot = (void *) mp; + + return iterative_hash_hashval_t (v, val); +} + +static hashval_t +gimple_canonical_type_hash (const void *p) +{ + return iterative_hash_canonical_type (CONST_CAST_TREE ((const_tree) p), 0); +} + + +/* 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) +{ + /* 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; + + if (TREE_ADDRESSABLE (t1) != TREE_ADDRESSABLE (t2)) + return false; + + /* Qualifiers do not matter for canonical type comparison purposes. */ + + /* Void types and nullptr types are always the same. */ + if (TREE_CODE (t1) == VOID_TYPE + || TREE_CODE (t1) == NULLPTR_TYPE) + return true; + + /* 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; + + /* Non-aggregate types can be handled cheaply. */ + 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 + || POINTER_TYPE_P (t1)) + { + /* Can't be the same type if they have different sign or precision. */ + if (TYPE_PRECISION (t1) != TYPE_PRECISION (t2) + || TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2)) + return false; + + if (TREE_CODE (t1) == INTEGER_TYPE + && TYPE_STRING_FLAG (t1) != TYPE_STRING_FLAG (t2)) + return false; + + /* 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 and match what + useless_type_conversion_p would do. */ + if (POINTER_TYPE_P (t1)) + { + /* 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)) + return false; + + if (TYPE_ADDR_SPACE (TREE_TYPE (t1)) + != TYPE_ADDR_SPACE (TREE_TYPE (t2))) + return false; + + if (TYPE_RESTRICT (t1) != TYPE_RESTRICT (t2)) + return false; + + if (TREE_CODE (TREE_TYPE (t1)) != TREE_CODE (TREE_TYPE (t2))) + return false; + } + + /* Tail-recurse to components. */ + if (TREE_CODE (t1) == VECTOR_TYPE + || TREE_CODE (t1) == COMPLEX_TYPE) + return gimple_canonical_types_compatible_p (TREE_TYPE (t1), + TREE_TYPE (t2)); + + return true; + } + + /* Do type-specific comparisons. */ + switch (TREE_CODE (t1)) + { + 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)) + return false; + 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) + return true; + else if (i1 == NULL_TREE || i2 == NULL_TREE) + return false; + 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))))) + return true; + else + return false; + } + } + + case METHOD_TYPE: + case FUNCTION_TYPE: + /* Function types are the same if the return type and arguments types + are the same. */ + if (!gimple_canonical_types_compatible_p (TREE_TYPE (t1), TREE_TYPE (t2))) + return false; + + if (!comp_type_attributes (t1, t2)) + return false; + + if (TYPE_ARG_TYPES (t1) == TYPE_ARG_TYPES (t2)) + return true; + 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_canonical_types_compatible_p + (TREE_VALUE (parms1), TREE_VALUE (parms2))) + return false; + } + + if (parms1 || parms2) + return false; + + return true; + } + + 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)) + { + /* Skip non-fields. */ + while (f1 && TREE_CODE (f1) != FIELD_DECL) + f1 = TREE_CHAIN (f1); + while (f2 && TREE_CODE (f2) != FIELD_DECL) + f2 = TREE_CHAIN (f2); + if (!f1 || !f2) + break; + /* 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))) + return false; + } + + /* If one aggregate has more fields than the other, they + are not the same. */ + if (f1 || f2) + return false; + + return true; + } + + default: + gcc_unreachable (); + } +} + + +/* Returns nonzero if P1 and P2 are equal. */ + +static int +gimple_canonical_type_eq (const void *p1, const void *p2) +{ + 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. + If another type T', compatible with T, already existed in + gimple_types then return T', otherwise return T. This is used by + LTO to merge identical types read from different TUs. + + ??? This merging does not exactly match how the tree.c middle-end + functions will assign TYPE_CANONICAL when new types are created + during optimization (which at least happens for pointer and array + types). */ + +static tree +gimple_register_canonical_type (tree t) +{ + void **slot; + + gcc_assert (TYPE_P (t)); + + if (TYPE_CANONICAL (t)) + return TYPE_CANONICAL (t); + + slot = htab_find_slot (gimple_canonical_types, t, INSERT); + if (*slot + && *(tree *)slot != t) + { + tree new_type = (tree) *((tree *) slot); + + TYPE_CANONICAL (t) = new_type; + t = new_type; + } + else + { + TYPE_CANONICAL (t) = t; + *slot = (void *) t; + } + + return t; +} + +/* Re-compute TYPE_CANONICAL for NODE and related types. */ + +static void +lto_register_canonical_types (tree node) +{ + if (!node + || !TYPE_P (node)) + return; + + TYPE_CANONICAL (node) = NULL_TREE; + TYPE_CANONICAL (node) = gimple_register_canonical_type (node); + + if (POINTER_TYPE_P (node) + || TREE_CODE (node) == COMPLEX_TYPE + || TREE_CODE (node) == ARRAY_TYPE) + lto_register_canonical_types (TREE_TYPE (node)); +} + /* ??? Old hashing and merging code follows, we keep it for statistics purposes for now. */ @@ -3398,6 +3819,10 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames) } cgraph_state = CGRAPH_LTO_STREAMING; + canonical_type_hash_cache = htab_create_ggc (512, tree_int_map_hash, + tree_int_map_eq, NULL); + gimple_canonical_types = htab_create_ggc (16381, gimple_canonical_type_hash, + gimple_canonical_type_eq, 0); type_hash_cache = htab_create_ggc (512, tree_int_map_hash, tree_int_map_eq, NULL); type_pair_cache = XCNEWVEC (struct type_pair_d, GIMPLE_TYPE_PAIR_SIZE); @@ -3405,6 +3830,17 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames) gcc_obstack_init (&tree_scc_hash_obstack); tree_scc_hash.create (4096); + /* Register the common node types with the canonical type machinery so + we properly share alias-sets across languages and TUs. Do not + expose the common nodes as type merge target - those that should be + are already exposed so by pre-loading the LTO streamer caches. */ + for (i = 0; i < itk_none; ++i) + lto_register_canonical_types (integer_types[i]); + /* The sizetypes are not used to access data so we do not need to + do anything about them. */ + for (i = 0; i < TI_MAX; ++i) + lto_register_canonical_types (global_trees[i]); + if (!quiet_flag) fprintf (stderr, "Reading object files:"); @@ -3459,7 +3895,10 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames) type_pair_cache = NULL; tree_scc_hash.dispose (); obstack_free (&tree_scc_hash_obstack, NULL); - free_gimple_type_tables (); + htab_delete (gimple_canonical_types); + gimple_canonical_types = NULL; + htab_delete (canonical_type_hash_cache); + canonical_type_hash_cache = NULL; ggc_collect (); /* Set the hooks so that all of the ipa passes can read in their data. */ @@ -3663,9 +4102,22 @@ print_lto_report_1 (void) pfx, num_not_merged_types, num_not_merged_types_in_same_scc, num_not_merged_types_trees, num_not_merged_types_in_same_scc_trees); + fprintf (stderr, "[%s] GIMPLE canonical type table: size %ld, " + "%ld elements, %ld searches, %ld collisions (ratio: %f)\n", pfx, + (long) htab_size (gimple_canonical_types), + (long) htab_elements (gimple_canonical_types), + (long) gimple_canonical_types->searches, + (long) gimple_canonical_types->collisions, + htab_collisions (gimple_canonical_types)); + fprintf (stderr, "[%s] GIMPLE canonical type hash table: size %ld, " + "%ld elements, %ld searches, %ld collisions (ratio: %f)\n", pfx, + (long) htab_size (canonical_type_hash_cache), + (long) htab_elements (canonical_type_hash_cache), + (long) canonical_type_hash_cache->searches, + (long) canonical_type_hash_cache->collisions, + htab_collisions (canonical_type_hash_cache)); } - print_gimple_types_stats (pfx); print_lto_report (pfx); } |