#include "flags.h"
#include "alias.h"
#include "demangle.h"
+#include "langhooks.h"
/* Global type table. FIXME lto, it should be possible to re-use some
of the type hashing routines in tree.c (type_hash_canon, type_hash_lookup,
etc), but those assume that types were built with the various
build_*_type routines which is not the case with the streamer. */
-static htab_t gimple_types;
-static struct pointer_map_t *type_hash_cache;
+static GTY((if_marked ("ggc_marked_p"), param_is (union tree_node)))
+ htab_t gimple_types;
+static GTY((if_marked ("tree_int_map_marked_p"), param_is (struct tree_int_map)))
+ htab_t type_hash_cache;
-/* Global type comparison cache. */
+/* Global type comparison cache. This is by TYPE_UID for space efficiency
+ and thus cannot use and does not need GC. */
static htab_t gtc_visited;
static struct obstack gtc_ob;
-static htab_t gtc_visited2;
-static struct obstack gtc_ob2;
/* All the tuples have their operand vector (if present) at the very bottom
of the structure. Therefore, the offset required to find the
return false;
}
-
/* Helper for gimple_could_trap_p and gimple_assign_rhs_could_trap_p.
- Return true if S can trap. If INCLUDE_LHS is true and S is a
- GIMPLE_ASSIGN, the LHS of the assignment is also checked.
- Otherwise, only the RHS of the assignment is checked. */
+ Return true if S can trap. When INCLUDE_MEM is true, check whether
+ the memory operations could trap. When INCLUDE_STORES is true and
+ S is a GIMPLE_ASSIGN, the LHS of the assignment is also checked. */
-static bool
-gimple_could_trap_p_1 (gimple s, bool include_lhs)
+bool
+gimple_could_trap_p_1 (gimple s, bool include_mem, bool include_stores)
{
- unsigned i, start;
tree t, div = NULL_TREE;
enum tree_code op;
- start = (is_gimple_assign (s) && !include_lhs) ? 1 : 0;
+ if (include_mem)
+ {
+ unsigned i, start = (is_gimple_assign (s) && !include_stores) ? 1 : 0;
- for (i = start; i < gimple_num_ops (s); i++)
- if (tree_could_trap_p (gimple_op (s, i)))
- return true;
+ for (i = start; i < gimple_num_ops (s); i++)
+ if (tree_could_trap_p (gimple_op (s, i)))
+ return true;
+ }
switch (gimple_code (s))
{
}
return false;
-
}
-
/* Return true if statement S can trap. */
bool
gimple_could_trap_p (gimple s)
{
- return gimple_could_trap_p_1 (s, true);
+ return gimple_could_trap_p_1 (s, true, true);
}
-
/* Return true if RHS of a GIMPLE_ASSIGN S can trap. */
bool
gimple_assign_rhs_could_trap_p (gimple s)
{
gcc_assert (is_gimple_assign (s));
- return gimple_could_trap_p_1 (s, false);
+ return gimple_could_trap_p_1 (s, true, false);
}
while (handled_component_p (t))
t = TREE_OPERAND (t, 0);
- if (TREE_CODE (t) == MEM_REF
+ if ((TREE_CODE (t) == MEM_REF
+ || TREE_CODE (t) == TARGET_MEM_REF)
&& TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR)
t = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
- if (SSA_VAR_P (t)
+ if (TREE_CODE (t) == SSA_NAME
+ || DECL_P (t)
|| TREE_CODE (t) == STRING_CST
|| TREE_CODE (t) == CONSTRUCTOR
|| INDIRECT_REF_P (t)
- || TREE_CODE (t) == MEM_REF)
+ || TREE_CODE (t) == MEM_REF
+ || TREE_CODE (t) == TARGET_MEM_REF)
return t;
else
return NULL_TREE;
/* Structure used to maintain a cache of some type pairs compared by
gimple_types_compatible_p when comparing aggregate types. There are
- four possible values for SAME_P:
+ three possible values for SAME_P:
-2: The pair (T1, T2) has just been inserted in the table.
- -1: The pair (T1, T2) is currently being compared.
0: T1 and T2 are different types.
1: T1 and T2 are the same type.
- This table is only used when comparing aggregate types to avoid
- infinite recursion due to self-referential types. */
+ The two elements in the SAME_P array are indexed by the comparison
+ mode gtc_mode. */
+
struct type_pair_d
{
unsigned int uid1;
unsigned int uid2;
- int same_p;
+ signed char same_p[2];
};
typedef struct type_pair_d *type_pair_t;
p = XOBNEW (ob_p, struct type_pair_d);
p->uid1 = TYPE_UID (t1);
p->uid2 = TYPE_UID (t2);
- p->same_p = -2;
+ p->same_p[0] = -2;
+ p->same_p[1] = -2;
*slot = (void *) p;
}
bool on_sccstack;
union {
hashval_t hash;
- int same_p;
+ signed char same_p;
} u;
};
}
static bool
-gimple_types_compatible_p_1 (tree, tree, bool, VEC(type_pair_t, heap) **,
+gimple_types_compatible_p_1 (tree, tree, enum gtc_mode, type_pair_t,
+ VEC(type_pair_t, heap) **,
struct pointer_map_t *, struct obstack *);
/* DFS visit the edge from the callers type pair with state *STATE to
SCCSTACK, SCCSTATE and SCCSTATE_OBSTACK are state for the DFS walk done. */
static bool
-gtc_visit (tree t1, tree t2, bool for_merging_p,
+gtc_visit (tree t1, tree t2, enum gtc_mode mode,
struct sccs *state,
VEC(type_pair_t, heap) **sccstack,
struct pointer_map_t *sccstate,
return false;
/* Allocate a new cache entry for this comparison. */
- p = lookup_type_pair (t1, t2,
- for_merging_p ? >c_visited : >c_visited2,
- for_merging_p ? >c_ob : >c_ob2);
- if (p->same_p == 0 || p->same_p == 1)
+ p = lookup_type_pair (t1, t2, >c_visited, >c_ob);
+ if (p->same_p[mode] == 0 || p->same_p[mode] == 1)
{
/* We have already decided whether T1 and T2 are the
same, return the cached result. */
- return p->same_p == 1;
+ return p->same_p[mode] == 1;
}
- gcc_assert (p->same_p == -2);
-
if ((slot = pointer_map_contains (sccstate, p)) != NULL)
cstate = (struct sccs *)*slot;
if (!cstate)
{
bool res;
/* Not yet visited. DFS recurse. */
- res = gimple_types_compatible_p_1 (t1, t2, for_merging_p,
+ res = gimple_types_compatible_p_1 (t1, t2, mode, p,
sccstack, sccstate, sccstate_obstack);
if (!cstate)
cstate = (struct sccs *)* pointer_map_contains (sccstate, p);
state->low = MIN (state->low, cstate->low);
/* If the type is no longer on the SCC stack and thus is not part
- of the parents SCC mix in its hash value. Otherwise we will
- ignore the type for hashing purposes and return the unaltered
- hash value. */
+ of the parents SCC, return its state. Otherwise we will
+ ignore this pair and assume equality. */
if (!cstate->on_sccstack)
return res;
}
SCCSTACK, SCCSTATE and SCCSTATE_OBSTACK are state for the DFS walk done. */
static bool
-gimple_types_compatible_p_1 (tree t1, tree t2, bool for_merging_p,
+gimple_types_compatible_p_1 (tree t1, tree t2, enum gtc_mode mode,
+ type_pair_t p,
VEC(type_pair_t, heap) **sccstack,
struct pointer_map_t *sccstate,
struct obstack *sccstate_obstack)
{
- type_pair_t p;
struct sccs *state;
- /* Allocate a new cache entry for this comparison. */
- p = lookup_type_pair (t1, t2,
- for_merging_p ? >c_visited : >c_visited2,
- for_merging_p ? >c_ob : >c_ob2);
- gcc_assert (p->same_p == -2);
+ gcc_assert (p->same_p[mode] == -2);
state = XOBNEW (sccstate_obstack, struct sccs);
*pointer_map_insert (sccstate, p) = state;
{
case VECTOR_TYPE:
case COMPLEX_TYPE:
- if (!gtc_visit (TREE_TYPE (t1), TREE_TYPE (t2), for_merging_p,
+ if (!gtc_visit (TREE_TYPE (t1), TREE_TYPE (t2), mode,
state, sccstack, sccstate, sccstate_obstack))
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 (!gtc_visit (TREE_TYPE (t1), TREE_TYPE (t2), for_merging_p,
+ if (!gtc_visit (TREE_TYPE (t1), TREE_TYPE (t2), mode,
state, sccstack, sccstate, sccstate_obstack)
|| TYPE_STRING_FLAG (t1) != TYPE_STRING_FLAG (t2)
|| TYPE_NONALIASED_COMPONENT (t1) != TYPE_NONALIASED_COMPONENT (t2))
case METHOD_TYPE:
/* Method types should belong to the same class. */
if (!gtc_visit (TYPE_METHOD_BASETYPE (t1), TYPE_METHOD_BASETYPE (t2),
- for_merging_p,
- state, sccstack, sccstate, sccstate_obstack))
+ mode, state, sccstack, sccstate, sccstate_obstack))
goto different_types;
/* Fallthru */
case FUNCTION_TYPE:
/* Function types are the same if the return type and arguments types
are the same. */
- if ((for_merging_p
+ if ((mode != GTC_DIAG
|| !gimple_compatible_complete_and_incomplete_subtype_p
(TREE_TYPE (t1), TREE_TYPE (t2)))
- && !gtc_visit (TREE_TYPE (t1), TREE_TYPE (t2), for_merging_p,
+ && !gtc_visit (TREE_TYPE (t1), TREE_TYPE (t2), mode,
state, sccstack, sccstate, sccstate_obstack))
goto different_types;
parms1 && parms2;
parms1 = TREE_CHAIN (parms1), parms2 = TREE_CHAIN (parms2))
{
- if ((for_merging_p
+ if ((mode == GTC_MERGE
|| !gimple_compatible_complete_and_incomplete_subtype_p
(TREE_VALUE (parms1), TREE_VALUE (parms2)))
- && !gtc_visit (TREE_VALUE (parms1), TREE_VALUE (parms2),
- for_merging_p,
+ && !gtc_visit (TREE_VALUE (parms1), TREE_VALUE (parms2), mode,
state, sccstack, sccstate, sccstate_obstack))
goto different_types;
}
case OFFSET_TYPE:
{
- if (!gtc_visit (TREE_TYPE (t1), TREE_TYPE (t2), for_merging_p,
+ if (!gtc_visit (TREE_TYPE (t1), TREE_TYPE (t2), mode,
state, sccstack, sccstate, sccstate_obstack)
|| !gtc_visit (TYPE_OFFSET_BASETYPE (t1),
- TYPE_OFFSET_BASETYPE (t2), for_merging_p,
+ TYPE_OFFSET_BASETYPE (t2), mode,
state, sccstack, sccstate, sccstate_obstack))
goto different_types;
/* If one pointer points to an incomplete type variant of
the other pointed-to type they are the same. */
- if (!for_merging_p
+ if (mode == GTC_DIAG
&& gimple_compatible_complete_and_incomplete_subtype_p
(TREE_TYPE (t1), TREE_TYPE (t2)))
goto same_types;
/* Otherwise, pointer and reference types are the same if the
pointed-to types are the same. */
- if (gtc_visit (TREE_TYPE (t1), TREE_TYPE (t2), for_merging_p,
+ if (gtc_visit (TREE_TYPE (t1), TREE_TYPE (t2), mode,
state, sccstack, sccstate, sccstate_obstack))
goto same_types;
goto different_types;
}
+ case NULLPTR_TYPE:
+ /* There is only one decltype(nullptr). */
+ goto same_types;
+
case INTEGER_TYPE:
case BOOLEAN_TYPE:
{
if (DECL_NAME (f1) != DECL_NAME (f2)
|| DECL_NONADDRESSABLE_P (f1) != DECL_NONADDRESSABLE_P (f2)
|| !gimple_compare_field_offset (f1, f2)
- || !gtc_visit (TREE_TYPE (f1), TREE_TYPE (f2), for_merging_p,
+ || !gtc_visit (TREE_TYPE (f1), TREE_TYPE (f2), mode,
state, sccstack, sccstate, sccstate_obstack))
goto different_types;
}
x = VEC_pop (type_pair_t, *sccstack);
cstate = (struct sccs *)*pointer_map_contains (sccstate, x);
cstate->on_sccstack = false;
- x->same_p = cstate->u.same_p;
+ x->same_p[mode] = cstate->u.same_p;
}
while (x != p);
}
are considered different, otherwise they are considered compatible. */
bool
-gimple_types_compatible_p (tree t1, tree t2, bool for_merging_p)
+gimple_types_compatible_p (tree t1, tree t2, enum gtc_mode mode)
{
VEC(type_pair_t, heap) *sccstack = NULL;
struct pointer_map_t *sccstate;
/* 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,
- for_merging_p ? >c_visited : >c_visited2,
- for_merging_p ? >c_ob : >c_ob2);
- if (p->same_p == 0 || p->same_p == 1)
+ p = lookup_type_pair (t1, t2, >c_visited, >c_ob);
+ if (p->same_p[mode] == 0 || p->same_p[mode] == 1)
{
/* We have already decided whether T1 and T2 are the
same, return the cached result. */
- return p->same_p == 1;
+ return p->same_p[mode] == 1;
}
/* Now set up the SCC machinery for the comparison. */
gtc_next_dfs_num = 1;
sccstate = pointer_map_create ();
gcc_obstack_init (&sccstate_obstack);
- res = gimple_types_compatible_p_1 (t1, t2, for_merging_p,
+ res = gimple_types_compatible_p_1 (t1, t2, mode, p,
&sccstack, sccstate, &sccstate_obstack);
VEC_free (type_pair_t, heap, sccstack);
pointer_map_destroy (sccstate);
struct obstack *sccstate_obstack)
{
struct sccs *cstate = NULL;
+ struct tree_int_map m;
void **slot;
/* If there is a hash value recorded for this type then it can't
possibly be part of our parent SCC. Simply mix in its hash. */
- if ((slot = pointer_map_contains (type_hash_cache, t)))
- return iterative_hash_hashval_t ((hashval_t) (size_t) *slot, v);
+ m.base.from = t;
+ if ((slot = htab_find_slot (type_hash_cache, &m, NO_INSERT))
+ && *slot)
+ return iterative_hash_hashval_t (((struct tree_int_map *) *slot)->to, v);
if ((slot = pointer_map_contains (sccstate, t)) != NULL)
cstate = (struct sccs *)*slot;
struct sccs *state;
#ifdef ENABLE_CHECKING
- /* Not visited during this DFS walk nor during previous walks. */
- gcc_assert (!pointer_map_contains (type_hash_cache, type)
- && !pointer_map_contains (sccstate, type));
+ /* Not visited during this DFS walk. */
+ gcc_assert (!pointer_map_contains (sccstate, type));
#endif
state = XOBNEW (sccstate_obstack, struct sccs);
*pointer_map_insert (sccstate, type) = state;
do
{
struct sccs *cstate;
+ struct tree_int_map *m = ggc_alloc_cleared_tree_int_map ();
x = VEC_pop (tree, *sccstack);
- gcc_assert (!pointer_map_contains (type_hash_cache, x));
cstate = (struct sccs *)*pointer_map_contains (sccstate, x);
cstate->on_sccstack = false;
- slot = pointer_map_insert (type_hash_cache, x);
- *slot = (void *) (size_t) cstate->u.hash;
+ m->base.from = x;
+ m->to = cstate->u.hash;
+ slot = htab_find_slot (type_hash_cache, m, INSERT);
+ gcc_assert (!*slot);
+ *slot = (void *) m;
}
while (x != type);
}
struct obstack sccstate_obstack;
hashval_t val;
void **slot;
+ struct tree_int_map m;
if (type_hash_cache == NULL)
- type_hash_cache = pointer_map_create ();
+ type_hash_cache = htab_create_ggc (512, tree_int_map_hash,
+ tree_int_map_eq, NULL);
- if ((slot = pointer_map_contains (type_hash_cache, p)) != NULL)
- return iterative_hash_hashval_t ((hashval_t) (size_t) *slot, 0);
+ m.base.from = CONST_CAST_TREE (t);
+ if ((slot = htab_find_slot (type_hash_cache, &m, NO_INSERT))
+ && *slot)
+ return iterative_hash_hashval_t (((struct tree_int_map *) *slot)->to, 0);
/* Perform a DFS walk and pre-hash all reachable types. */
next_dfs_num = 1;
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), true);
+ CONST_CAST_TREE (t2), GTC_MERGE);
}
gcc_assert (TYPE_P (t));
/* In TYPE_CANONICAL we cache the result of gimple_register_type.
- It is initially set to NULL during LTO streaming. */
- if (TYPE_CANONICAL (t))
+ It is initially set to NULL during LTO streaming.
+ But do not mess with TYPE_CANONICAL when not in WPA or link phase. */
+ if (in_lto_p && TYPE_CANONICAL (t))
return TYPE_CANONICAL (t);
/* Always register the main variant first. This is important so we
gimple_register_type (TYPE_MAIN_VARIANT (t));
if (gimple_types == NULL)
- gimple_types = htab_create (16381, gimple_type_hash, gimple_type_eq, 0);
+ gimple_types = htab_create_ggc (16381, gimple_type_hash, gimple_type_eq, 0);
slot = htab_find_slot (gimple_types, t, INSERT);
if (*slot
TYPE_NEXT_REF_TO (t) = NULL_TREE;
}
- TYPE_CANONICAL (t) = new_type;
+ if (in_lto_p)
+ TYPE_CANONICAL (t) = new_type;
t = new_type;
}
else
{
- TYPE_CANONICAL (t) = t;
+ if (in_lto_p)
+ TYPE_CANONICAL (t) = t;
*slot = (void *) t;
}
htab_collisions (gimple_types));
else
fprintf (stderr, "GIMPLE type table is empty\n");
+ if (type_hash_cache)
+ fprintf (stderr, "GIMPLE type hash table: size %ld, %ld elements, "
+ "%ld searches, %ld collisions (ratio: %f)\n",
+ (long) htab_size (type_hash_cache),
+ (long) htab_elements (type_hash_cache),
+ (long) type_hash_cache->searches,
+ (long) type_hash_cache->collisions,
+ htab_collisions (type_hash_cache));
+ else
+ fprintf (stderr, "GIMPLE type hash table is empty\n");
if (gtc_visited)
- fprintf (stderr, "GIMPLE type merging comparison table: size %ld, %ld "
+ fprintf (stderr, "GIMPLE type comparison table: size %ld, %ld "
"elements, %ld searches, %ld collisions (ratio: %f)\n",
(long) htab_size (gtc_visited),
(long) htab_elements (gtc_visited),
(long) gtc_visited->collisions,
htab_collisions (gtc_visited));
else
- fprintf (stderr, "GIMPLE type merging comparison table is empty\n");
- if (gtc_visited2)
- fprintf (stderr, "GIMPLE type comparison table: size %ld, %ld "
- "elements, %ld searches, %ld collisions (ratio: %f)\n",
- (long) htab_size (gtc_visited2),
- (long) htab_elements (gtc_visited2),
- (long) gtc_visited2->searches,
- (long) gtc_visited2->collisions,
- htab_collisions (gtc_visited2));
- else
fprintf (stderr, "GIMPLE type comparison table is empty\n");
}
}
if (type_hash_cache)
{
- pointer_map_destroy (type_hash_cache);
+ htab_delete (type_hash_cache);
type_hash_cache = NULL;
}
if (gtc_visited)
obstack_free (>c_ob, NULL);
gtc_visited = NULL;
}
- if (gtc_visited2)
- {
- htab_delete (gtc_visited2);
- obstack_free (>c_ob2, NULL);
- gtc_visited2 = NULL;
- }
}
if (t1 != t)
return get_alias_set (t1);
}
- else if (POINTER_TYPE_P (t))
- {
- /* From the common C and C++ langhook implementation:
-
- Unfortunately, there is no canonical form of a pointer type.
- In particular, if we have `typedef int I', then `int *', and
- `I *' are different types. So, we have to pick a canonical
- representative. We do this below.
-
- Technically, this approach is actually more conservative that
- it needs to be. In particular, `const int *' and `int *'
- should be in different alias sets, according to the C and C++
- standard, since their types are not the same, and so,
- technically, an `int **' and `const int **' cannot point at
- the same thing.
-
- But, the standard is wrong. In particular, this code is
- legal C++:
-
- int *ip;
- int **ipp = &ip;
- const int* const* cipp = ipp;
- And, it doesn't make sense for that to be legal unless you
- can dereference IPP and CIPP. So, we ignore cv-qualifiers on
- the pointed-to types. This issue has been reported to the
- C++ committee. */
-
- /* In addition to the above canonicalization issue with LTO
- we should also canonicalize `T (*)[]' to `T *' avoiding
- alias issues with pointer-to element types and pointer-to
- array types.
-
- Likewise we need to deal with the situation of incomplete
- pointed-to types and make `*(struct X **)&a' and
- `*(struct X {} **)&a' alias. Otherwise we will have to
- guarantee that all pointer-to incomplete type variants
- will be replaced by pointer-to complete type variants if
- they are available.
-
- With LTO the convenient situation of using `void *' to
- access and store any pointer type will also become
- more apparent (and `void *' is just another pointer-to
- incomplete type). Assigning alias-set zero to `void *'
- and all pointer-to incomplete types is a not appealing
- solution. Assigning an effective alias-set zero only
- affecting pointers might be - by recording proper subset
- relationships of all pointer alias-sets.
-
- Pointer-to function types are another grey area which
- needs caution. Globbing them all into one alias-set
- or the above effective zero set would work. */
-
- /* For now just assign the same alias-set to all pointers.
- That's simple and avoids all the above problems. */
- if (t != ptr_type_node)
- return get_alias_set (ptr_type_node);
- }
return -1;
}
if (TREE_CODE (rhs) == ADDR_EXPR)
ret |= visit_addr (stmt, TREE_OPERAND (rhs, 0), data);
else if (TREE_CODE (rhs) == TARGET_MEM_REF
- && TMR_BASE (rhs) != NULL_TREE
&& TREE_CODE (TMR_BASE (rhs)) == ADDR_EXPR)
ret |= visit_addr (stmt, TREE_OPERAND (TMR_BASE (rhs), 0), data);
else if (TREE_CODE (rhs) == OBJ_TYPE_REF
0), data);
lhs = gimple_assign_lhs (stmt);
if (TREE_CODE (lhs) == TARGET_MEM_REF
- && TMR_BASE (lhs) != NULL_TREE
&& TREE_CODE (TMR_BASE (lhs)) == ADDR_EXPR)
ret |= visit_addr (stmt, TREE_OPERAND (TMR_BASE (lhs), 0), data);
}