+/* Allocate and construct a symbol alias set. */
+
+static symbol_alias_set_t *
+symbol_alias_set_create (void)
+{
+ return pointer_set_create ();
+}
+
+/* Destruct and free a symbol alias set. */
+
+void
+symbol_alias_set_destroy (symbol_alias_set_t *aset)
+{
+ pointer_set_destroy (aset);
+}
+
+/* Test if a symbol alias set contains a given name. */
+
+int
+symbol_alias_set_contains (const symbol_alias_set_t *aset, tree t)
+{
+ /* We accept either a DECL or an IDENTIFIER directly. */
+ if (TREE_CODE (t) != IDENTIFIER_NODE)
+ t = DECL_ASSEMBLER_NAME (t);
+ t = targetm.asm_out.mangle_assembler_name (IDENTIFIER_POINTER (t));
+ return pointer_set_contains (aset, t);
+}
+
+/* Enter a new name into a symbol alias set. */
+
+static int
+symbol_alias_set_insert (symbol_alias_set_t *aset, tree t)
+{
+ /* We accept either a DECL or an IDENTIFIER directly. */
+ if (TREE_CODE (t) != IDENTIFIER_NODE)
+ t = DECL_ASSEMBLER_NAME (t);
+ t = targetm.asm_out.mangle_assembler_name (IDENTIFIER_POINTER (t));
+ return pointer_set_insert (aset, t);
+}
+
+/* IN_SET_P is a predicate function assuming to be taken
+ alias_pair->decl, alias_pair->target and DATA arguments.
+
+ Compute set of aliases by including everything where TRIVIALLY_VISIBLE
+ predeicate is true and propagate across aliases such that when
+ alias DECL is included, its TARGET is included too. */
+
+static symbol_alias_set_t *
+propagate_aliases_forward (bool (*in_set_p)
+ (tree decl, tree target, void *data),
+ void *data)
+{
+ symbol_alias_set_t *set;
+ unsigned i;
+ alias_pair *p;
+ bool changed;
+
+ set = symbol_alias_set_create ();
+ for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); ++i)
+ if (in_set_p (p->decl, p->target, data))
+ symbol_alias_set_insert (set, p->decl);
+ do
+ {
+ changed = false;
+ for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); ++i)
+ if (symbol_alias_set_contains (set, p->decl)
+ && !symbol_alias_set_insert (set, p->target))
+ changed = true;
+ }
+ while (changed);
+
+ return set;
+}
+
+/* Like propagate_aliases_forward but do backward propagation. */
+
+symbol_alias_set_t *
+propagate_aliases_backward (bool (*in_set_p)
+ (tree decl, tree target, void *data),
+ void *data)
+{
+ symbol_alias_set_t *set;
+ unsigned i;
+ alias_pair *p;
+ bool changed;
+
+ /* We have to compute the set of set nodes including aliases
+ themselves. */
+ set = symbol_alias_set_create ();
+ for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); ++i)
+ if (in_set_p (p->decl, p->target, data))
+ symbol_alias_set_insert (set, p->target);
+ do
+ {
+ changed = false;
+ for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); ++i)
+ if (symbol_alias_set_contains (set, p->target)
+ && !symbol_alias_set_insert (set, p->decl))
+ changed = true;
+ }
+ while (changed);
+
+ return set;
+}
+/* See if the alias is trivially visible. This means
+ 1) alias is expoerted from the unit or
+ 2) alias is used in the code.
+ We assume that unused cgraph/varpool nodes has been
+ removed.
+ Used as callback for propagate_aliases. */
+
+static bool
+trivially_visible_alias (tree decl, tree target ATTRIBUTE_UNUSED,
+ void *data ATTRIBUTE_UNUSED)
+{
+ struct cgraph_node *fnode = NULL;
+ struct varpool_node *vnode = NULL;
+
+ if (!TREE_PUBLIC (decl))
+ {
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ fnode = cgraph_get_node (decl);
+ else
+ vnode = varpool_get_node (decl);
+ return vnode || fnode;
+ }
+ else
+ return true;
+}
+
+/* See if the target of alias is defined in this unit.
+ Used as callback for propagate_aliases. */
+
+static bool
+trivially_defined_alias (tree decl ATTRIBUTE_UNUSED,
+ tree target,
+ void *data ATTRIBUTE_UNUSED)
+{
+ struct cgraph_node *fnode = NULL;
+ struct varpool_node *vnode = NULL;
+
+ fnode = cgraph_node_for_asm (target);
+ vnode = (fnode == NULL) ? varpool_node_for_asm (target) : NULL;
+ return (fnode && fnode->analyzed) || (vnode && vnode->finalized);
+}
+