@@ -1200,41 +1200,6 @@ public:
unsigned calls_comdat_local : 1;
};
-/* A cgraph node set is a collection of cgraph nodes. A cgraph node
- can appear in multiple sets. */
-struct cgraph_node_set_def
-{
- struct pointer_map_t *map;
- vec<cgraph_node *> nodes;
-};
-
-typedef cgraph_node_set_def *cgraph_node_set;
-typedef struct varpool_node_set_def *varpool_node_set;
-
-class varpool_node;
-
-/* A varpool node set is a collection of varpool nodes. A varpool node
- can appear in multiple sets. */
-struct varpool_node_set_def
-{
- struct pointer_map_t * map;
- vec<varpool_node *> nodes;
-};
-
-/* Iterator structure for cgraph node sets. */
-struct cgraph_node_set_iterator
-{
- cgraph_node_set set;
- unsigned index;
-};
-
-/* Iterator structure for varpool node sets. */
-struct varpool_node_set_iterator
-{
- varpool_node_set set;
- unsigned index;
-};
-
/* Structure containing additional information about an indirect call. */
struct GTY(()) cgraph_indirect_call_info
@@ -1509,7 +1474,7 @@ enum cgraph_state
};
extern enum cgraph_state cgraph_state;
extern bool cgraph_function_flags_ready;
-extern cgraph_node_set cgraph_new_nodes;
+extern vec<cgraph_node *> cgraph_new_nodes;
extern GTY(()) struct asm_node *asm_nodes;
extern GTY(()) int symtab_order;
@@ -1615,24 +1580,7 @@ void record_references_in_initializer (tree, bool);
/* In ipa.c */
bool symtab_remove_unreachable_nodes (bool, FILE *);
-cgraph_node_set cgraph_node_set_new (void);
-cgraph_node_set_iterator cgraph_node_set_find (cgraph_node_set,
- cgraph_node *);
-void cgraph_node_set_add (cgraph_node_set, cgraph_node *);
-void cgraph_node_set_remove (cgraph_node_set, cgraph_node *);
-void dump_cgraph_node_set (FILE *, cgraph_node_set);
-void debug_cgraph_node_set (cgraph_node_set);
-void free_cgraph_node_set (cgraph_node_set);
void cgraph_build_static_cdtor (char which, tree body, int priority);
-
-varpool_node_set varpool_node_set_new (void);
-varpool_node_set_iterator varpool_node_set_find (varpool_node_set,
- varpool_node *);
-void varpool_node_set_add (varpool_node_set, varpool_node *);
-void varpool_node_set_remove (varpool_node_set, varpool_node *);
-void dump_varpool_node_set (FILE *, varpool_node_set);
-void debug_varpool_node_set (varpool_node_set);
-void free_varpool_node_set (varpool_node_set);
void ipa_discover_readonly_nonaddressable_vars (void);
/* In predict.c */
@@ -1948,93 +1896,6 @@ cgraph_next_function_with_gimple_body (cgraph_node *node)
/* Create a new static variable of type TYPE. */
tree add_new_static_var (tree type);
-/* Return true if iterator CSI points to nothing. */
-static inline bool
-csi_end_p (cgraph_node_set_iterator csi)
-{
- return csi.index >= csi.set->nodes.length ();
-}
-
-/* Advance iterator CSI. */
-static inline void
-csi_next (cgraph_node_set_iterator *csi)
-{
- csi->index++;
-}
-
-/* Return the node pointed to by CSI. */
-static inline cgraph_node *
-csi_node (cgraph_node_set_iterator csi)
-{
- return csi.set->nodes[csi.index];
-}
-
-/* Return an iterator to the first node in SET. */
-static inline cgraph_node_set_iterator
-csi_start (cgraph_node_set set)
-{
- cgraph_node_set_iterator csi;
-
- csi.set = set;
- csi.index = 0;
- return csi;
-}
-
-/* Return true if SET contains NODE. */
-static inline bool
-cgraph_node_in_set_p (cgraph_node *node, cgraph_node_set set)
-{
- cgraph_node_set_iterator csi;
- csi = cgraph_node_set_find (set, node);
- return !csi_end_p (csi);
-}
-
-/* Return number of nodes in SET. */
-static inline size_t
-cgraph_node_set_size (cgraph_node_set set)
-{
- return set->nodes.length ();
-}
-
-/* Return true if iterator VSI points to nothing. */
-static inline bool
-vsi_end_p (varpool_node_set_iterator vsi)
-{
- return vsi.index >= vsi.set->nodes.length ();
-}
-
-/* Advance iterator VSI. */
-static inline void
-vsi_next (varpool_node_set_iterator *vsi)
-{
- vsi->index++;
-}
-
-/* Return the node pointed to by VSI. */
-static inline varpool_node *
-vsi_node (varpool_node_set_iterator vsi)
-{
- return vsi.set->nodes[vsi.index];
-}
-
-/* Return an iterator to the first node in SET. */
-static inline varpool_node_set_iterator
-vsi_start (varpool_node_set set)
-{
- varpool_node_set_iterator vsi;
-
- vsi.set = set;
- vsi.index = 0;
- return vsi;
-}
-
-/* Return number of nodes in SET. */
-static inline size_t
-varpool_node_set_size (varpool_node_set set)
-{
- return set->nodes.length ();
-}
-
/* Uniquize all constants that appear in memory.
Each constant in memory thus far output is recorded
in `const_desc_table'. */
@@ -2052,20 +1913,6 @@ struct GTY(()) constant_descriptor_tree {
hashval_t hash;
};
-/* Return true if set is nonempty. */
-static inline bool
-cgraph_node_set_nonempty_p (cgraph_node_set set)
-{
- return !set->nodes.is_empty ();
-}
-
-/* Return true if set is nonempty. */
-static inline bool
-varpool_node_set_nonempty_p (varpool_node_set set)
-{
- return !set->nodes.is_empty ();
-}
-
/* Return true when function is only called directly or it has alias.
i.e. it is not externally visible, address was not taken and
it is not used in any other non-standard way. */
@@ -215,7 +215,7 @@ along with GCC; see the file COPYING3. If not see
/* Queue of cgraph nodes scheduled to be added into cgraph. This is a
secondary queue used during optimization to accommodate passes that
may generate new functions that need to be optimized and expanded. */
-cgraph_node_set cgraph_new_nodes;
+vec<cgraph_node *> cgraph_new_nodes;
static void expand_all_functions (void);
static void mark_functions_to_output (void);
@@ -300,17 +300,16 @@ void
cgraph_process_new_functions (void)
{
tree fndecl;
- struct cgraph_node *node;
- cgraph_node_set_iterator csi;
- if (!cgraph_new_nodes)
+ if (!cgraph_new_nodes.exists ())
return;
+
handle_alias_pairs ();
/* Note that this queue may grow as its being processed, as the new
functions may generate new ones. */
- for (csi = csi_start (cgraph_new_nodes); !csi_end_p (csi); csi_next (&csi))
+ for (unsigned i = 0; i < cgraph_new_nodes.length (); i++)
{
- node = csi_node (csi);
+ cgraph_node *node = cgraph_new_nodes[i];
fndecl = node->decl;
switch (cgraph_state)
{
@@ -357,8 +356,8 @@ cgraph_process_new_functions (void)
break;
}
}
- free_cgraph_node_set (cgraph_new_nodes);
- cgraph_new_nodes = NULL;
+
+ cgraph_new_nodes.release ();
}
/* As an GCC extension we allow redefinition of the function. The
@@ -501,9 +500,7 @@ cgraph_node::add_new_function (tree fndecl, bool lowered)
node = cgraph_node::get_create (fndecl);
if (lowered)
node->lowered = true;
- if (!cgraph_new_nodes)
- cgraph_new_nodes = cgraph_node_set_new ();
- cgraph_node_set_add (cgraph_new_nodes, node);
+ cgraph_new_nodes.safe_push (node);
break;
case CGRAPH_STATE_IPA:
@@ -529,9 +526,7 @@ cgraph_node::add_new_function (tree fndecl, bool lowered)
}
if (lowered)
node->lowered = true;
- if (!cgraph_new_nodes)
- cgraph_new_nodes = cgraph_node_set_new ();
- cgraph_node_set_add (cgraph_new_nodes, node);
+ cgraph_new_nodes.safe_push (node);
break;
case CGRAPH_STATE_FINISHED:
@@ -96,7 +96,7 @@ can_remove_node_now_p_1 (struct cgraph_node *node)
&& !DECL_VIRTUAL_P (node->decl)
/* During early inlining some unanalyzed cgraph nodes might be in the
callgraph and they might reffer the function in question. */
- && !cgraph_new_nodes);
+ && !cgraph_new_nodes.exists ());
}
/* We are going to eliminate last direct call to NODE (or alias of it) via edge E.
@@ -380,265 +380,6 @@ get_base_var (tree t)
return t;
}
-
-/* Create a new cgraph node set. */
-
-cgraph_node_set
-cgraph_node_set_new (void)
-{
- cgraph_node_set new_node_set;
-
- new_node_set = XCNEW (struct cgraph_node_set_def);
- new_node_set->map = pointer_map_create ();
- new_node_set->nodes.create (0);
- return new_node_set;
-}
-
-
-/* Add cgraph_node NODE to cgraph_node_set SET. */
-
-void
-cgraph_node_set_add (cgraph_node_set set, struct cgraph_node *node)
-{
- void **slot;
-
- slot = pointer_map_insert (set->map, node);
-
- if (*slot)
- {
- int index = (size_t) *slot - 1;
- gcc_checking_assert ((set->nodes[index]
- == node));
- return;
- }
-
- *slot = (void *)(size_t) (set->nodes.length () + 1);
-
- /* Insert into node vector. */
- set->nodes.safe_push (node);
-}
-
-
-/* Remove cgraph_node NODE from cgraph_node_set SET. */
-
-void
-cgraph_node_set_remove (cgraph_node_set set, struct cgraph_node *node)
-{
- void **slot, **last_slot;
- int index;
- struct cgraph_node *last_node;
-
- slot = pointer_map_contains (set->map, node);
- if (slot == NULL || !*slot)
- return;
-
- index = (size_t) *slot - 1;
- gcc_checking_assert (set->nodes[index]
- == node);
-
- /* Remove from vector. We do this by swapping node with the last element
- of the vector. */
- last_node = set->nodes.pop ();
- if (last_node != node)
- {
- last_slot = pointer_map_contains (set->map, last_node);
- gcc_checking_assert (last_slot && *last_slot);
- *last_slot = (void *)(size_t) (index + 1);
-
- /* Move the last element to the original spot of NODE. */
- set->nodes[index] = last_node;
- }
-
- /* Remove element from hash table. */
- *slot = NULL;
-}
-
-
-/* Find NODE in SET and return an iterator to it if found. A null iterator
- is returned if NODE is not in SET. */
-
-cgraph_node_set_iterator
-cgraph_node_set_find (cgraph_node_set set, struct cgraph_node *node)
-{
- void **slot;
- cgraph_node_set_iterator csi;
-
- slot = pointer_map_contains (set->map, node);
- if (slot == NULL || !*slot)
- csi.index = (unsigned) ~0;
- else
- csi.index = (size_t)*slot - 1;
- csi.set = set;
-
- return csi;
-}
-
-
-/* Dump content of SET to file F. */
-
-void
-dump_cgraph_node_set (FILE *f, cgraph_node_set set)
-{
- cgraph_node_set_iterator iter;
-
- for (iter = csi_start (set); !csi_end_p (iter); csi_next (&iter))
- {
- struct cgraph_node *node = csi_node (iter);
- fprintf (f, " %s/%i", node->name (), node->order);
- }
- fprintf (f, "\n");
-}
-
-
-/* Dump content of SET to stderr. */
-
-DEBUG_FUNCTION void
-debug_cgraph_node_set (cgraph_node_set set)
-{
- dump_cgraph_node_set (stderr, set);
-}
-
-
-/* Free varpool node set. */
-
-void
-free_cgraph_node_set (cgraph_node_set set)
-{
- set->nodes.release ();
- pointer_map_destroy (set->map);
- free (set);
-}
-
-
-/* Create a new varpool node set. */
-
-varpool_node_set
-varpool_node_set_new (void)
-{
- varpool_node_set new_node_set;
-
- new_node_set = XCNEW (struct varpool_node_set_def);
- new_node_set->map = pointer_map_create ();
- new_node_set->nodes.create (0);
- return new_node_set;
-}
-
-
-/* Add varpool_node NODE to varpool_node_set SET. */
-
-void
-varpool_node_set_add (varpool_node_set set, varpool_node *node)
-{
- void **slot;
-
- slot = pointer_map_insert (set->map, node);
-
- if (*slot)
- {
- int index = (size_t) *slot - 1;
- gcc_checking_assert ((set->nodes[index]
- == node));
- return;
- }
-
- *slot = (void *)(size_t) (set->nodes.length () + 1);
-
- /* Insert into node vector. */
- set->nodes.safe_push (node);
-}
-
-
-/* Remove varpool_node NODE from varpool_node_set SET. */
-
-void
-varpool_node_set_remove (varpool_node_set set, varpool_node *node)
-{
- void **slot, **last_slot;
- int index;
- varpool_node *last_node;
-
- slot = pointer_map_contains (set->map, node);
- if (slot == NULL || !*slot)
- return;
-
- index = (size_t) *slot - 1;
- gcc_checking_assert (set->nodes[index]
- == node);
-
- /* Remove from vector. We do this by swapping node with the last element
- of the vector. */
- last_node = set->nodes.pop ();
- if (last_node != node)
- {
- last_slot = pointer_map_contains (set->map, last_node);
- gcc_checking_assert (last_slot && *last_slot);
- *last_slot = (void *)(size_t) (index + 1);
-
- /* Move the last element to the original spot of NODE. */
- set->nodes[index] = last_node;
- }
-
- /* Remove element from hash table. */
- *slot = NULL;
-}
-
-
-/* Find NODE in SET and return an iterator to it if found. A null iterator
- is returned if NODE is not in SET. */
-
-varpool_node_set_iterator
-varpool_node_set_find (varpool_node_set set, varpool_node *node)
-{
- void **slot;
- varpool_node_set_iterator vsi;
-
- slot = pointer_map_contains (set->map, node);
- if (slot == NULL || !*slot)
- vsi.index = (unsigned) ~0;
- else
- vsi.index = (size_t)*slot - 1;
- vsi.set = set;
-
- return vsi;
-}
-
-
-/* Dump content of SET to file F. */
-
-void
-dump_varpool_node_set (FILE *f, varpool_node_set set)
-{
- varpool_node_set_iterator iter;
-
- for (iter = vsi_start (set); !vsi_end_p (iter); vsi_next (&iter))
- {
- varpool_node *node = vsi_node (iter);
- fprintf (f, " %s", node->name ());
- }
- fprintf (f, "\n");
-}
-
-
-/* Free varpool node set. */
-
-void
-free_varpool_node_set (varpool_node_set set)
-{
- set->nodes.release ();
- pointer_map_destroy (set->map);
- free (set);
-}
-
-
-/* Dump content of SET to stderr. */
-
-DEBUG_FUNCTION void
-debug_varpool_node_set (varpool_node_set set)
-{
- dump_varpool_node_set (stderr, set);
-}
-
-
/* SRC and DST are going to be merged. Take SRC's profile and merge it into
DST so it is not going to be lost. Destroy SRC's body on the way. */
@@ -42,7 +42,7 @@ along with GCC; see the file COPYING3. If not see
#include "target.h"
#include "targhooks.h"
#include "tree-iterator.h"
-
+#include "hash-map.h"
/* Whenever a target does not support thread-local storage (TLS) natively,
we can emulate it with some run-time support in libgcc. This will in
@@ -67,15 +67,17 @@ along with GCC; see the file COPYING3. If not see
to the symbol table early in the GIMPLE optimization path, before we
write things out to LTO intermediate files. */
-/* These two vectors, once fully populated, are kept in lock-step so that
- the index of a TLS variable equals the index of its control variable in
- the other vector. */
-static varpool_node_set tls_vars;
-static vec<varpool_node *> control_vars;
+/* Value for TLS varpool node where a pointer to control variable and
+ access variable are stored. */
+struct tls_var_data
+{
+ varpool_node *control_var;
+ tree access;
+};
-/* For the current basic block, an SSA_NAME that has computed the address
- of the TLS variable at the corresponding index. */
-static vec<tree> access_vars;
+/* TLS map accesses mapping between a TLS varpool node and a pair
+ made by control variable and access variable. */
+static hash_map<varpool_node *, tls_var_data> *tls_map = NULL;
/* The type of the control structure, shared with the emutls.c runtime. */
static tree emutls_object_type;
@@ -350,33 +352,6 @@ new_emutls_decl (tree decl, tree alias_of)
return to;
}
-/* Look up the index of the TLS variable DECL. This index can then be
- used in both the control_vars and access_vars arrays. */
-
-static unsigned int
-emutls_index (tree decl)
-{
- varpool_node_set_iterator i;
-
- i = varpool_node_set_find (tls_vars, varpool_node::get (decl));
- gcc_assert (i.index != ~0u);
-
- return i.index;
-}
-
-/* Look up the control variable for the TLS variable DECL. */
-
-static tree
-emutls_decl (tree decl)
-{
- varpool_node *var;
- unsigned int i;
-
- i = emutls_index (decl);
- var = control_vars[i];
- return var->decl;
-}
-
/* Generate a call statement to initialize CONTROL_DECL for TLS_DECL.
This only needs to happen for TLS COMMON variables; non-COMMON
variables can be initialized statically. Insert the generated
@@ -423,19 +398,17 @@ struct lower_emutls_data
static tree
gen_emutls_addr (tree decl, struct lower_emutls_data *d)
{
- unsigned int index;
- tree addr;
-
/* Compute the address of the TLS variable with help from runtime. */
- index = emutls_index (decl);
- addr = access_vars[index];
+ tls_var_data *data = tls_map->get (varpool_node::get (decl));
+ tree addr = data->access;
+
if (addr == NULL)
{
varpool_node *cvar;
tree cdecl;
gimple x;
- cvar = control_vars[index];
+ cvar = data->control_var;
cdecl = cvar->decl;
TREE_ADDRESSABLE (cdecl) = 1;
@@ -455,7 +428,7 @@ gen_emutls_addr (tree decl, struct lower_emutls_data *d)
d->cfun_node->add_reference (cvar, IPA_REF_ADDR, x);
/* Record this ssa_name for possible use later in the basic block. */
- access_vars[index] = addr;
+ data->access = addr;
}
return addr;
@@ -608,13 +581,20 @@ lower_emutls_phi_arg (gimple phi, unsigned int i, struct lower_emutls_data *d)
}
}
+bool
+reset_access (varpool_node * const &, tls_var_data *data, void *)
+{
+ data->access = NULL;
+
+ return true;
+}
+
/* Clear the ACCESS_VARS array, in order to begin a new block. */
static inline void
clear_access_vars (void)
{
- memset (access_vars.address (), 0,
- access_vars.length () * sizeof (tree));
+ tls_map->traverse<void *, reset_access> (NULL);
}
/* Lower the entire function NODE. */
@@ -705,14 +685,13 @@ static bool
create_emultls_var (varpool_node *var, void *data)
{
tree cdecl;
- varpool_node *cvar;
+ tls_var_data value;
cdecl = new_emutls_decl (var->decl,
var->alias && var->analyzed
? var->get_alias_target ()->decl : NULL);
- cvar = varpool_node::get (cdecl);
- control_vars.quick_push (cvar);
+ varpool_node *cvar = varpool_node::get (cdecl);
if (!var->alias)
{
@@ -730,6 +709,10 @@ create_emultls_var (varpool_node *var, void *data)
which is special-cased inside the DWARF2 output routines. */
SET_DECL_VALUE_EXPR (var->decl, cdecl);
DECL_HAS_VALUE_EXPR_P (var->decl) = 1;
+
+ value.control_var = cvar;
+ tls_map->put (var, value);
+
return false;
}
@@ -739,12 +722,11 @@ static unsigned int
ipa_lower_emutls (void)
{
varpool_node *var;
- struct cgraph_node *func;
+ cgraph_node *func;
bool any_aliases = false;
tree ctor_body = NULL;
- unsigned int i, n_tls;
- tls_vars = varpool_node_set_new ();
+ auto_vec <varpool_node *> tls_vars;
/* Examine all global variables for TLS variables. */
FOR_EACH_VARIABLE (var)
@@ -752,30 +734,25 @@ ipa_lower_emutls (void)
{
gcc_checking_assert (TREE_STATIC (var->decl)
|| DECL_EXTERNAL (var->decl));
- varpool_node_set_add (tls_vars, var);
+ tls_vars.safe_push (var);
if (var->alias && var->definition)
- varpool_node_set_add (tls_vars, var->ultimate_alias_target ());
+ tls_vars.safe_push (var->ultimate_alias_target ());
}
/* If we found no TLS variables, then there is no further work to do. */
- if (!tls_vars->nodes.exists ())
+ if (tls_vars.is_empty ())
{
- tls_vars = NULL;
if (dump_file)
fprintf (dump_file, "No TLS variables found.\n");
return 0;
}
- /* Allocate the on-the-side arrays that share indicies with the TLS vars. */
- n_tls = tls_vars->nodes.length ();
- control_vars.create (n_tls);
- access_vars.create (n_tls);
- access_vars.safe_grow_cleared (n_tls);
+ tls_map = new hash_map <varpool_node *, tls_var_data> ();
/* Create the control variables for each TLS variable. */
- FOR_EACH_VEC_ELT (tls_vars->nodes, i, var)
+ for (unsigned i = 0; i < tls_vars.length (); i++)
{
- var = tls_vars->nodes[i];
+ var = tls_vars[i];
if (var->alias && !var->analyzed)
any_aliases = true;
@@ -787,10 +764,12 @@ ipa_lower_emutls (void)
if (any_aliases)
{
alias_pair *p;
+ unsigned int i;
FOR_EACH_VEC_SAFE_ELT (alias_pairs, i, p)
if (DECL_THREAD_LOCAL_P (p->decl))
{
- p->decl = emutls_decl (p->decl);
+ p->decl = tls_map->get
+ (varpool_node::get (p->decl))->control_var->decl;
p->target = get_emutls_object_name (p->target);
}
}
@@ -804,9 +783,7 @@ ipa_lower_emutls (void)
if (ctor_body)
cgraph_build_static_cdtor ('I', ctor_body, DEFAULT_INIT_PRIORITY);
- control_vars.release ();
- access_vars.release ();
- free_varpool_node_set (tls_vars);
+ delete tls_map;
return 0;
}