+
+/* Simple local pass for pure const discovery reusing the analysis from
+ ipa_pure_const. This pass is effective when executed together with
+ other optimization passes in early optimization pass queue. */
+
+static unsigned int
+local_pure_const (void)
+{
+ bool changed = false;
+ funct_state l;
+
+ /* Because we do not schedule pass_fixup_cfg over whole program after early optimizations
+ we must not promote functions that are called by already processed functions. */
+
+ if (function_called_by_processed_nodes_p ())
+ {
+ if (dump_file)
+ fprintf (dump_file, "Function called in recursive cycle; ignoring\n");
+ return 0;
+ }
+
+ l = analyze_function (cgraph_node (current_function_decl), false);
+ if (!l)
+ {
+ if (dump_file)
+ fprintf (dump_file, "Function has wrong visibility; ignoring\n");
+ return 0;
+ }
+
+ switch (l->pure_const_state)
+ {
+ case IPA_CONST:
+ if (!TREE_READONLY (current_function_decl))
+ {
+ TREE_READONLY (current_function_decl) = 1;
+ DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) = l->looping;
+ changed = true;
+ if (dump_file)
+ fprintf (dump_file, "Function found to be %sconst: %s\n",
+ l->looping ? "looping " : "",
+ lang_hooks.decl_printable_name (current_function_decl,
+ 2));
+ }
+ else if (DECL_LOOPING_CONST_OR_PURE_P (current_function_decl)
+ && !l->looping)
+ {
+ DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) = false;
+ changed = true;
+ if (dump_file)
+ fprintf (dump_file, "Function found to be non-looping: %s\n",
+ lang_hooks.decl_printable_name (current_function_decl,
+ 2));
+ }
+ break;
+
+ case IPA_PURE:
+ if (!TREE_READONLY (current_function_decl))
+ {
+ DECL_PURE_P (current_function_decl) = 1;
+ DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) = l->looping;
+ changed = true;
+ if (dump_file)
+ fprintf (dump_file, "Function found to be %spure: %s\n",
+ l->looping ? "looping " : "",
+ lang_hooks.decl_printable_name (current_function_decl,
+ 2));
+ }
+ else if (DECL_LOOPING_CONST_OR_PURE_P (current_function_decl)
+ && !l->looping)
+ {
+ DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) = false;
+ changed = true;
+ if (dump_file)
+ fprintf (dump_file, "Function found to be non-looping: %s\n",
+ lang_hooks.decl_printable_name (current_function_decl,
+ 2));
+ }
+ break;
+
+ default:
+ break;
+ }
+ if (!l->can_throw && !TREE_NOTHROW (current_function_decl))
+ {
+ struct cgraph_edge *e;
+
+ TREE_NOTHROW (current_function_decl) = true;
+ for (e = cgraph_node (current_function_decl)->callers;
+ e; e = e->next_caller)
+ e->can_throw_external = false;
+ changed = true;
+ if (dump_file)
+ fprintf (dump_file, "Function found to be nothrow: %s\n",
+ lang_hooks.decl_printable_name (current_function_decl,
+ 2));
+ }
+ if (l)
+ free (l);
+ if (changed)
+ return execute_fixup_cfg ();
+ else
+ return 0;
+}
+
+struct gimple_opt_pass pass_local_pure_const =
+{
+ {
+ GIMPLE_PASS,
+ "local-pure-const", /* name */
+ gate_pure_const, /* gate */
+ local_pure_const, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_IPA_PURE_CONST, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0 /* todo_flags_finish */
+ }
+};