+/* Return true when function NODE can be removed from callgraph
+ if all direct calls are eliminated. */
+
+bool
+cgraph_can_remove_if_no_direct_calls_and_refs_p (struct cgraph_node *node)
+{
+ gcc_assert (!node->global.inlined_to);
+ /* Extern inlines can always go, we will use the external definition. */
+ if (DECL_EXTERNAL (node->decl))
+ return true;
+ /* When function is needed, we can not remove it. */
+ if (node->needed || node->reachable_from_other_partition)
+ return false;
+ if (DECL_STATIC_CONSTRUCTOR (node->decl)
+ || DECL_STATIC_DESTRUCTOR (node->decl))
+ return false;
+ /* Only COMDAT functions can be removed if externally visible. */
+ if (node->local.externally_visible
+ && (!DECL_COMDAT (node->decl)
+ || cgraph_used_from_object_file_p (node)))
+ return false;
+ return true;
+}
+
+/* Worker for cgraph_can_remove_if_no_direct_calls_p. */
+
+static bool
+nonremovable_p (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
+{
+ return !cgraph_can_remove_if_no_direct_calls_and_refs_p (node);
+}
+
+/* Return true when function NODE and its aliases can be removed from callgraph
+ if all direct calls are eliminated. */
+
+bool
+cgraph_can_remove_if_no_direct_calls_p (struct cgraph_node *node)
+{
+ /* Extern inlines can always go, we will use the external definition. */
+ if (DECL_EXTERNAL (node->decl))
+ return true;
+ if (node->address_taken)
+ return false;
+ return !cgraph_for_node_and_aliases (node, nonremovable_p, NULL, true);
+}
+
+/* Worker for cgraph_can_remove_if_no_direct_calls_p. */
+
+static bool
+used_from_object_file_p (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
+{
+ return cgraph_used_from_object_file_p (node);
+}
+
+/* Return true when function NODE can be expected to be removed
+ from program when direct calls in this compilation unit are removed.
+
+ As a special case COMDAT functions are
+ cgraph_can_remove_if_no_direct_calls_p while the are not
+ cgraph_only_called_directly_p (it is possible they are called from other
+ unit)
+
+ This function behaves as cgraph_only_called_directly_p because eliminating
+ all uses of COMDAT function does not make it necessarily disappear from
+ the program unless we are compiling whole program or we do LTO. In this
+ case we know we win since dynamic linking will not really discard the
+ linkonce section. */
+
+bool
+cgraph_will_be_removed_from_program_if_no_direct_calls (struct cgraph_node *node)
+{
+ gcc_assert (!node->global.inlined_to);
+ if (cgraph_for_node_and_aliases (node, used_from_object_file_p, NULL, true))
+ return false;
+ if (!in_lto_p && !flag_whole_program)
+ return cgraph_only_called_directly_p (node);
+ else
+ {
+ if (DECL_EXTERNAL (node->decl))
+ return true;
+ return cgraph_can_remove_if_no_direct_calls_p (node);
+ }
+}
+
+/* Return true when RESOLUTION indicate that linker will use
+ the symbol from non-LTO object files. */
+
+bool
+resolution_used_from_other_file_p (enum ld_plugin_symbol_resolution resolution)
+{
+ return (resolution == LDPR_PREVAILING_DEF
+ || resolution == LDPR_PREEMPTED_REG
+ || resolution == LDPR_RESOLVED_EXEC
+ || resolution == LDPR_RESOLVED_DYN);
+}
+
+
+/* Return true when NODE is known to be used from other (non-LTO) object file.
+ Known only when doing LTO via linker plugin. */
+
+bool
+cgraph_used_from_object_file_p (struct cgraph_node *node)
+{
+ gcc_assert (!node->global.inlined_to);
+ if (!TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl))
+ return false;
+ if (resolution_used_from_other_file_p (node->resolution))
+ return true;
+ return false;
+}
+
+/* Worker for cgraph_only_called_directly_p. */
+
+static bool
+cgraph_not_only_called_directly_p_1 (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
+{
+ return !cgraph_only_called_directly_or_aliased_p (node);
+}
+
+/* Return true when function NODE and all its aliases are only called
+ directly.
+ i.e. it is not externally visible, address was not taken and
+ it is not used in any other non-standard way. */
+
+bool
+cgraph_only_called_directly_p (struct cgraph_node *node)
+{
+ gcc_assert (cgraph_function_or_thunk_node (node, NULL) == node);
+ return !cgraph_for_node_and_aliases (node, cgraph_not_only_called_directly_p_1,
+ NULL, true);
+}
+
+
+/* Collect all callers of NODE. Worker for collect_callers_of_node. */
+
+static bool
+collect_callers_of_node_1 (struct cgraph_node *node, void *data)
+{
+ VEC (cgraph_edge_p, heap) ** redirect_callers = (VEC (cgraph_edge_p, heap) **)data;
+ struct cgraph_edge *cs;
+ enum availability avail;
+ cgraph_function_or_thunk_node (node, &avail);
+
+ if (avail > AVAIL_OVERWRITABLE)
+ for (cs = node->callers; cs != NULL; cs = cs->next_caller)
+ if (!cs->indirect_inlining_edge)
+ VEC_safe_push (cgraph_edge_p, heap, *redirect_callers, cs);
+ return false;
+}
+
+/* Collect all callers of NODE and its aliases that are known to lead to NODE
+ (i.e. are not overwritable). */
+
+VEC (cgraph_edge_p, heap) *
+collect_callers_of_node (struct cgraph_node *node)
+{
+ VEC (cgraph_edge_p, heap) * redirect_callers = NULL;
+ cgraph_for_node_and_aliases (node, collect_callers_of_node_1,
+ &redirect_callers, false);
+ return redirect_callers;
+}
+