This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [pretty-ipa] pure-const improvements, finite loop removal in CD-DCE and pure/const warning


On Wed, Apr 22, 2009 at 8:05 PM, Jan Hubicka <hubicka@ucw.cz> wrote:
>
> Hi,
> this patch imrpves pure-const discovery so it attempts to prove finiteness of
> loop. ?I added finite_loop_p prepdicate for this reason and updated empty loop
> removal to use it. ?It is based on iteration code, just bit simpler than the
> code trying to bound number of iterations. ?It is now bit smarter and it also
> makes assumption that loops in pure/const functions are finite. ?Doing this
> helps analysis on tramp3d quite a bit.
>
> I also made cd-dce to remove probably finite loops and added the warning on
> missing nothrow/const/pure markers. ?It seems that we can prove finitarity of
> most of loops in libstdc++ with exception of stuff like RB tree walking that is
> not obviously finite in any way.
>
> Bootstrapped/regtested x86_64-linux, comitting to pretty-ipa so we can see how
> much effect the extra calls to SCEV have on compile time.

Comments inline

> ? ? ? ?* tree-ssa-loop-niter.c (finite_loop_p): New function.
> ? ? ? ?* cfgloopanal.c (irred_loop_found): New static var.
> ? ? ? ?(check_irred): set it.
> ? ? ? ?(mark_irreducible_loops): Return true if found.
> ? ? ? ?* toplev.h (warn_function_nothrow): New function.
> ? ? ? ?* cp/decl.c (finish_function): Use it.
> ? ? ? ?* ipa-pure.const.c: Include toplev.h, flags.h, pointer-set.h, cfgloop.h
> ? ? ? ?and tree-scalar-evolution.h
> ? ? ? ?(struct funct_state_d): Add looping_in_source.
> ? ? ? ?(function_always_visible_to_compiler_p): New predicate.
> ? ? ? ?(warn_function_nothrow, warn_function_pure, warn_function_const): New
> ? ? ? ?functions.
> ? ? ? ?(check_call): More verbose debug output.
> ? ? ? ?(analyze_function): Do not bail out for overwrittable functions; try
> ? ? ? ?to prove finiteness of the loops; handle looping_in_source.
> ? ? ? ?(propagate): Hande looping in source; output warnings.
> ? ? ? ?(skip_function_for_local_pure_const): New function.
> ? ? ? ?(local_pure_const): Analyze overwrittable function body when asked for warnings;
> ? ? ? ?handle looping_in_source.
> ? ? ? ?* tree-ssa-loop-ivcanon.c (empty_loop_p): Use finite_loop_p predicate.
> ? ? ? ?* except.c (set_nothrow_function_flags): Warn.
> ? ? ? ?* common.opt (Wmissing-const, Wmissing-nothrow, Wmissing-pure): New.
> ? ? ? ?* tree-ssa-dce.c (find_obviously_necessary_stmts): Try to prove finiteness
> ? ? ? ?of loop.
> ? ? ? ?(perform_tree_ssa_dce): Initialize loop optimizer if needed.
> ? ? ? ?* cfgloop.h (mark_irreducible_loops): Declare.
> ? ? ? ?(finite_loop_p): Declare.
> Index: tree-ssa-loop-niter.c
> ===================================================================
> --- tree-ssa-loop-niter.c ? ? ? (revision 146576)
> +++ tree-ssa-loop-niter.c ? ? ? (working copy)
> @@ -1953,6 +1953,50 @@ find_loop_niter (struct loop *loop, edge
> ? return niter ? niter : chrec_dont_know;
> ?}
>
> +/* Return true if loop is known to be finite. ?*/
> +bool
> +finite_loop_p (struct loop *loop)
> +{
> + ?unsigned i;
> + ?VEC (edge, heap) *exits = get_loop_exit_edges (loop);
> + ?edge ex;
> + ?struct tree_niter_desc desc;
> + ?bool finite = false;
> +
> + ?if (flag_unsafe_loop_optimizations)
> + ? ?return true;
> + ?if ((TREE_READONLY (current_function_decl)
> + ? ? ? || DECL_PURE_P (current_function_decl))
> + ? ? ?&& !DECL_LOOPING_CONST_OR_PURE_P (current_function_decl))
> + ? ?{
> + ? ? ?if (dump_file && (dump_flags & TDF_DETAILS))
> + ? ? ? fprintf (dump_file, "Found loop %i to be finite: it is within pure or const function.\n",
> + ? ? ? ? ? ? ? ?loop->num);
> + ? ? ?return true;
> + ? ?}
> +
> + ?exits = get_loop_exit_edges (loop);
> + ?for (i = 0; VEC_iterate (edge, exits, i, ex); i++)
> + ? ?{
> + ? ? ?if (!just_once_each_iteration_p (loop, ex->src))
> + ? ? ? continue;
> +
> + ? ? ?if (number_of_iterations_exit (loop, ex, &desc, false))
> + ? ? ? ?{
> + ? ? ? ? if (dump_file && (dump_flags & TDF_DETAILS))
> + ? ? ? ? ? {
> + ? ? ? ? ? ? fprintf (dump_file, "Found loop %i to be finite: iterating ", loop->num);
> + ? ? ? ? ? ? print_generic_expr (dump_file, desc.niter, TDF_SLIM);
> + ? ? ? ? ? ? fprintf (dump_file, " times\n");
> + ? ? ? ? ? }
> + ? ? ? ? finite = true;
> + ? ? ? ? break;
> + ? ? ? }
> + ? ?}
> + ?VEC_free (edge, heap, exits);
> + ?return finite;
> +}

The logic in this function could need some comments.

> ?/*
>
> ? ?Analysis of a number of iterations of a loop by a brute-force evaluation.
> Index: cfgloopanal.c
> ===================================================================
> --- cfgloopanal.c ? ? ? (revision 146576)
> +++ cfgloopanal.c ? ? ? (working copy)
> @@ -52,6 +52,8 @@ just_once_each_iteration_p (const struct
> ? return true;
> ?}
>
> +static bool irred_loop_found;

Ugh.  Better make check_irred return that?

> ?/* Marks the edge E in graph G irreducible if it connects two vertices in the
> ? ?same scc. ?*/
>
> @@ -68,6 +70,7 @@ check_irred (struct graph *g, struct gra
> ? ? return;
>
> ? real->flags |= EDGE_IRREDUCIBLE_LOOP;
> + ?irred_loop_found = true;
> ? if (flow_bb_inside_loop_p (real->src->loop_father, real->dest))
> ? ? real->src->flags |= BB_IRREDUCIBLE_LOOP;
> ?}
> @@ -84,7 +87,7 @@ check_irred (struct graph *g, struct gra
> ?#define LOOP_REPR(LOOP) ((LOOP)->num + last_basic_block)
> ?#define BB_REPR(BB) ((BB)->index + 1)
>
> -void
> +bool
> ?mark_irreducible_loops (void)

Comment for this function is missing.

> ?{
> ? basic_block act;
> @@ -153,12 +156,14 @@ mark_irreducible_loops (void)
> ? /* Find the strongly connected components. ?*/
> ? graphds_scc (g, NULL);
>
> + ?irred_loop_found = false;
> ? /* Mark the irreducible loops. ?*/
> ? for_each_edge (g, check_irred);
>
> ? free_graph (g);
>
> ? loops_state_set (LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS);
> + ?return irred_loop_found;
> ?}
>
> ?/* Counts number of insns inside LOOP. ?*/
> Index: toplev.h
> ===================================================================
> --- toplev.h ? ?(revision 146576)
> +++ toplev.h ? ?(working copy)
> @@ -210,4 +210,6 @@ extern bool set_src_pwd ? ? ? ? ? ? ? ? ? ?(const c
> ?extern const char *get_random_seed (bool);
> ?extern const char *set_random_seed (const char *);
>
> +extern void warn_function_nothrow (tree);
> +
> ?#endif /* ! GCC_TOPLEV_H */
> Index: cp/decl.c
> ===================================================================
> --- cp/decl.c ? (revision 146576)
> +++ cp/decl.c ? (working copy)
> @@ -12254,7 +12254,10 @@ finish_function (int flags)
> ? ? ? && !cp_function_chain->can_throw
> ? ? ? && !flag_non_call_exceptions
> ? ? ? && !DECL_REPLACEABLE_P (fndecl))
> - ? ?TREE_NOTHROW (fndecl) = 1;
> + ? ?{
> + ? ? ?TREE_NOTHROW (fndecl) = 1;
> + ? ? ?warn_function_nothrow (fndecl);
> + ? ?}
>
> ? /* This must come after expand_function_end because cleanups might
> ? ? ?have declarations (from inline functions) that need to go into
> Index: ipa-pure-const.c
> ===================================================================
> --- ipa-pure-const.c ? ?(revision 146576)
> +++ ipa-pure-const.c ? ?(working copy)
> @@ -52,6 +52,11 @@ along with GCC; see the file COPYING3.
> ?#include "diagnostic.h"
> ?#include "langhooks.h"
> ?#include "target.h"
> +#include "toplev.h"
> +#include "flags.h"
> +#include "pointer-set.h"
> +#include "cfgloop.h"
> +#include "tree-scalar-evolution.h"
>
> ?static struct pointer_set_t *visited_nodes;
>
> @@ -73,6 +78,7 @@ struct funct_state_d
> ? enum pure_const_state_e pure_const_state;
> ? /* What user set here; we can be always sure about this. ?*/
> ? enum pure_const_state_e state_set_in_source;
> + ?bool looping_in_source;
>
> ? /* True if the function could possibly infinite loop. ?There are a
> ? ? ?lot of ways that this could be determined. ?We are pretty
> @@ -102,6 +108,76 @@ static struct cgraph_node_hook_list *fun
> ?static struct cgraph_2node_hook_list *node_duplication_hook_holder;
> ?static struct cgraph_node_hook_list *node_removal_hook_holder;
>
> +/* Try to guess if function body will always be visible to compiler
> + ? when compiling the call and whether compiler will be able
> + ? to propagate the information by itself. ?*/
> +
> +static bool
> +function_always_visible_to_compiler_p (tree decl)
> +{
> + ?if (!TREE_PUBLIC (decl)
> + ? ? ?|| DECL_DECLARED_INLINE_P (decl))
> + ? ?return true;
> + ?return false;
> +}
> +
> +void
> +warn_function_nothrow (tree decl)

Missing docs.

> +{
> + ?static struct pointer_set_t *warned_about;
> +
> + ?if (!warn_missing_nothrow || TREE_THIS_VOLATILE (decl))
> + ? ?return;
> + ?if (function_always_visible_to_compiler_p (decl))
> + ? ?return;
> +
> + ?if (!warned_about)
> + ? ?warned_about = pointer_set_create ();
> + ?if (pointer_set_contains (warned_about, decl))
> + ? ?return;
> + ?pointer_set_insert (warned_about, decl);
> + ?warning (OPT_Wmissing_noreturn, "%Jfunction might be possible candidate "

OPT_Wmissing_nothrow

> + ? ? ? ? ? "for attribute %<nothrow%> or %<throw ()%> marker in C++ code.",
> + ? ? ? ? ?decl);
> +}
> +
> +static void
> +warn_function_pure (tree decl, bool known_finite)
> +{

Likewise.

> + ?if (!warn_missing_pure || TREE_THIS_VOLATILE (decl))
> + ? ?return;
> + ?if (!known_finite)
> + ? ?{
> + ? ? ?warning (OPT_Wmissing_noreturn, "%Jfunction might be possible candidate "

OPT_Wmissing_pure

> + ? ? ? ? ? ? ? "for attribute %<pure%> if it is known to be finite.",
> + ? ? ? ? ? ? ?decl);
> + ? ? ?return;
> + ? ?}
> + ?if (function_always_visible_to_compiler_p (decl))
> + ? ?return;
> + ?warning (OPT_Wmissing_noreturn, "%Jfunction might be possible candidate "
> + ? ? ? ? ? "for attribute %<pure%>.",
> + ? ? ? ? ?decl);
> +}
> +
> +static void
> +warn_function_const (tree decl, bool known_finite)
> +{

Likewise.

> + ?if (!warn_missing_const || TREE_THIS_VOLATILE (decl))
> + ? ?return;
> + ?if (!known_finite)
> + ? ?{
> + ? ? ?warning (OPT_Wmissing_noreturn, "%Jfunction might be possible candidate "

OPT_Wmising_const

> + ? ? ? ? ? ? ? "for attribute %<const%> if it is known to be finite.",
> + ? ? ? ? ? ? ?decl);
> + ? ? ?return;
> + ? ?}
> + ?if (function_always_visible_to_compiler_p (decl))
> + ? ?return;
> + ?warning (OPT_Wmissing_noreturn, "%Jfunction might be possible candidate "
> + ? ? ? ? ? "for attribute %<const%>.",
> + ? ? ? ? ?decl);
> +}
> ?/* Init the function state. ?*/
>
> ?static void
> @@ -316,7 +392,11 @@ check_call (funct_state local, gimple ca
>
> ? /* When not in IPA mode, we can still handle self recursion. ?*/
> ? if (!ipa && callee_t == current_function_decl)
> - ? ?local->looping = true;
> + ? ?{
> + ? ? ?if (dump_file)
> + ? ? ? ?fprintf (dump_file, " ? ?Recursive call can loop.\n");
> + ? ? ?local->looping = true;
> + ? ?}
> ? /* The callee is either unknown (indirect call) or there is just no
> ? ? ?scannable code for it (external call) . ?We look to see if there
> ? ? ?are any bits available for the callee (such as by declaration or
> @@ -345,12 +425,20 @@ check_call (funct_state local, gimple ca
> ? ? ? if (flags & ECF_CONST)
> ? ? ? ?{
> ? ? ? ? ? if (callee_t && DECL_LOOPING_CONST_OR_PURE_P (callee_t))
> - ? ? ? ? ? ?local->looping = true;
> + ? ? ? ? ? {
> + ? ? ? ? ? ? if (dump_file)
> + ? ? ? ? ? ? ? fprintf (dump_file, " ? ?calls looping pure.\n");
> + ? ? ? ? ? ? ?local->looping = true;
> + ? ? ? ? ? }
> ? ? ? ? }
> ? ? ? else if (flags & ECF_PURE)
> ? ? ? ?{
> ? ? ? ? ? if (callee_t && DECL_LOOPING_CONST_OR_PURE_P (callee_t))
> - ? ? ? ? ? ?local->looping = true;
> + ? ? ? ? ? {
> + ? ? ? ? ? ? if (dump_file)
> + ? ? ? ? ? ? ? fprintf (dump_file, " ? ?calls looping const.\n");
> + ? ? ? ? ? ? ?local->looping = true;
> + ? ? ? ? ? }
> ? ? ? ? ?if (dump_file)
> ? ? ? ? ? ?fprintf (dump_file, " ? ?pure function call in not const\n");
> ? ? ? ? ?if (local->pure_const_state == IPA_CONST)
> @@ -476,16 +564,10 @@ analyze_function (struct cgraph_node *fn
> ? funct_state l;
> ? basic_block this_block;
>
> - ?if (cgraph_function_body_availability (fn) <= AVAIL_OVERWRITABLE)
> - ? ?{
> - ? ? ?if (dump_file)
> - ? ? ? ?fprintf (dump_file, "Function is not available or overwrittable; not analyzing.\n");
> - ? ? ?return NULL;
> - ? ?}
> -
> ? l = XCNEW (struct funct_state_d);
> ? l->pure_const_state = IPA_CONST;
> ? l->state_set_in_source = IPA_NEITHER;
> + ?l->looping_in_source = true;
> ? l->looping = false;
> ? l->can_throw = false;
>
> @@ -521,8 +603,33 @@ end:
> ? ? ? ? indication of possible infinite loop side
> ? ? ? ? effect. ?*/
> ? ? ? if (mark_dfs_back_edges ())
> - ? ? ? l->looping = true;
> -
> + ? ? ? ?{
> + ? ? ? ? loop_optimizer_init (LOOPS_HAVE_PREHEADERS);
> + ? ? ? ? if (dump_file && (dump_flags & TDF_DETAILS))
> + ? ? ? ? ? flow_loops_dump (dump_file, NULL, 0);
> + ? ? ? ? if (mark_irreducible_loops ())
> + ? ? ? ? ? {
> + ? ? ? ? ? ? if (dump_file)
> + ? ? ? ? ? ? ? fprintf (dump_file, " ? ?has irreducible loops\n");
> + ? ? ? ? ? ? l->looping = true;
> + ? ? ? ? ? }
> + ? ? ? ? else
> + ? ? ? ? ? {
> + ? ? ? ? ? ? loop_iterator li;
> + ? ? ? ? ? ? struct loop *loop;
> + ? ? ? ? ? ? scev_initialize ();
> + ? ? ? ? ? ? FOR_EACH_LOOP (li, loop, 0)
> + ? ? ? ? ? ? ? if (!finite_loop_p (loop))
> + ? ? ? ? ? ? ? ? {
> + ? ? ? ? ? ? ? ? ? if (dump_file)
> + ? ? ? ? ? ? ? ? ? ? fprintf (dump_file, " ? ?can not prove finiteness of loop %i\n", loop->num);
> + ? ? ? ? ? ? ? ? ? l->looping =true;
> + ? ? ? ? ? ? ? ? ? break;
> + ? ? ? ? ? ? ? ? }
> + ? ? ? ? ? ? scev_finalize ();
> + ? ? ? ? ? }
> + ? ? ? ? ?loop_optimizer_finalize ();
> + ? ? ? }
> ? ? }
>
> ? if (TREE_READONLY (decl))
> @@ -530,7 +637,7 @@ end:
> ? ? ? l->pure_const_state = IPA_CONST;
> ? ? ? l->state_set_in_source = IPA_CONST;
> ? ? ? if (!DECL_LOOPING_CONST_OR_PURE_P (decl))
> - ? ? ? ?l->looping = false;
> + ? ? ? ?l->looping = false, l->looping_in_source = false;
> ? ? }
> ? if (DECL_PURE_P (decl))
> ? ? {
> @@ -538,7 +645,7 @@ end:
> ? ? ? ? l->pure_const_state = IPA_PURE;
> ? ? ? l->state_set_in_source = IPA_PURE;
> ? ? ? if (!DECL_LOOPING_CONST_OR_PURE_P (decl))
> - ? ? ? ?l->looping = false;
> + ? ? ? ?l->looping = false, l->looping_in_source = false;
> ? ? }
> ? if (TREE_NOTHROW (decl))
> ? ? l->can_throw = false;
> @@ -570,7 +677,8 @@ add_new_function (struct cgraph_node *no
> ? ? ?since all we would be interested in are the addressof
> ? ? ?operations. ?*/
> ? visited_nodes = pointer_set_create ();
> - ?set_function_state (node, analyze_function (node, true));
> + ?if (cgraph_function_body_availability (node) > AVAIL_OVERWRITABLE)
> + ? ?set_function_state (node, analyze_function (node, true));
> ? pointer_set_destroy (visited_nodes);
> ? visited_nodes = NULL;
> ?}
> @@ -728,12 +836,11 @@ propagate (void)
> ? ? ? ? ?enum pure_const_state_e this_state = pure_const_state;
> ? ? ? ? ?bool this_looping = looping;
>
> - ? ? ? ? if (w_l->state_set_in_source != IPA_NEITHER)
> - ? ? ? ? ? {
> - ? ? ? ? ? ? if (this_state > w_l->state_set_in_source)
> - ? ? ? ? ? ? ? this_state = w_l->state_set_in_source;
> - ? ? ? ? ? ? this_looping = false;
> - ? ? ? ? ? }
> + ? ? ? ? if (w_l->state_set_in_source != IPA_NEITHER
> + ? ? ? ? ? ? && this_state > w_l->state_set_in_source)
> + ? ? ? ? ? ?this_state = w_l->state_set_in_source;
> + ? ? ? ? if (!w_l->looping_in_source)
> + ? ? ? ? ? this_looping = false;
>
> ? ? ? ? ?/* All nodes within a cycle share the same info. ?*/
> ? ? ? ? ?w_l->pure_const_state = this_state;
> @@ -742,19 +849,27 @@ propagate (void)
> ? ? ? ? ?switch (this_state)
> ? ? ? ? ? ?{
> ? ? ? ? ? ?case IPA_CONST:
> - ? ? ? ? ? ? if (!TREE_READONLY (w->decl) && dump_file)
> - ? ? ? ? ? ? ? fprintf (dump_file, "Function found to be %sconst: %s\n",
> - ? ? ? ? ? ? ? ? ? ? ? ?this_looping ? "looping " : "",
> - ? ? ? ? ? ? ? ? ? ? ? ?cgraph_node_name (w));
> + ? ? ? ? ? ? if (!TREE_READONLY (w->decl))
> + ? ? ? ? ? ? ? {
> + ? ? ? ? ? ? ? ? warn_function_const (w->decl, !this_looping);
> + ? ? ? ? ? ? ? ? if (dump_file)
> + ? ? ? ? ? ? ? ? ? fprintf (dump_file, "Function found to be %sconst: %s\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?this_looping ? "looping " : "",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?cgraph_node_name (w));
> + ? ? ? ? ? ? ? }
> ? ? ? ? ? ? ?TREE_READONLY (w->decl) = 1;
> ? ? ? ? ? ? ?DECL_LOOPING_CONST_OR_PURE_P (w->decl) = this_looping;
> ? ? ? ? ? ? ?break;
>
> ? ? ? ? ? ?case IPA_PURE:
> - ? ? ? ? ? ? if (!DECL_PURE_P (w->decl) && dump_file)
> - ? ? ? ? ? ? ? fprintf (dump_file, "Function found to be %spure: %s\n",
> - ? ? ? ? ? ? ? ? ? ? ? ?this_looping ? "looping " : "",
> - ? ? ? ? ? ? ? ? ? ? ? ?cgraph_node_name (w));
> + ? ? ? ? ? ? if (!DECL_PURE_P (w->decl))
> + ? ? ? ? ? ? ? {
> + ? ? ? ? ? ? ? ? warn_function_pure (w->decl, !this_looping);
> + ? ? ? ? ? ? ? ? if (dump_file)
> + ? ? ? ? ? ? ? ? ? fprintf (dump_file, "Function found to be %spure: %s\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?this_looping ? "looping " : "",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?cgraph_node_name (w));
> + ? ? ? ? ? ? ? }
> ? ? ? ? ? ? ?DECL_PURE_P (w->decl) = 1;
> ? ? ? ? ? ? ?DECL_LOOPING_CONST_OR_PURE_P (w->decl) = this_looping;
> ? ? ? ? ? ? ?break;
> @@ -835,6 +950,7 @@ propagate (void)
> ? ? ? ? ? ?{
> ? ? ? ? ? ? ?struct cgraph_edge *e;
> ? ? ? ? ? ? ?TREE_NOTHROW (w->decl) = true;
> + ? ? ? ? ? ? warn_function_nothrow (w->decl);
> ? ? ? ? ? ? ?for (e = w->callers; e; e = e->next_caller)
> ? ? ? ? ? ? ? ?e->can_throw_external = false;
> ? ? ? ? ? ? ?if (dump_file)
> @@ -902,16 +1018,11 @@ struct ipa_opt_pass pass_ipa_pure_const
> ?NULL ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/* variable_transform */
> ?};
>
> -/* 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. ?*/
> +/* Return true if function should be skipped for local pure const analysis. ?*/
>
> -static unsigned int
> -local_pure_const (void)
> +static bool
> +skip_function_for_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. ?*/
>
> @@ -919,25 +1030,47 @@ local_pure_const (void)
> ? ? {
> ? ? ? if (dump_file)
> ? ? ? ? fprintf (dump_file, "Function called in recursive cycle; ignoring\n");
> - ? ? ?return 0;
> + ? ? ?return true;
> ? ? }
> -
> - ?l = analyze_function (cgraph_node (current_function_decl), false);
> - ?if (!l)
> + ?if (cgraph_function_body_availability (cgraph_node (current_function_decl))
> + ? ? ?<= AVAIL_OVERWRITABLE)
> ? ? {
> ? ? ? if (dump_file)
> - ? ? ? ?fprintf (dump_file, "Function has wrong visibility; ignoring\n");
> - ? ? ?return 0;
> + ? ? ? ?fprintf (dump_file, "Function is not available or overwrittable; not analyzing.\n");
> + ? ? ?return true;
> ? ? }
> + ?return false;
> +}
> +
> +/* 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;
> + ?bool skip;
> +
> + ?skip = skip_function_for_local_pure_const ();
> + ?if (!warn_missing_const && !warn_missing_nothrow && !warn_missing_pure
> + ? ? ?&& skip)
> + ? ?return 0;
> + ?l = analyze_function (cgraph_node (current_function_decl), false);
>
> ? 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;
> + ? ? ? ? warn_function_const (current_function_decl, !l->looping);
> + ? ? ? ? if (!skip)
> + ? ? ? ? ? {
> + ? ? ? ? ? ? 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 " : "",
> @@ -947,8 +1080,11 @@ local_pure_const (void)
> ? ? ? 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 (!skip)
> + ? ? ? ? ? {
> + ? ? ? ? ? ? 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,
> @@ -959,9 +1095,13 @@ local_pure_const (void)
> ? ? 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 (!skip)
> + ? ? ? ? ? {
> + ? ? ? ? ? ? DECL_PURE_P (current_function_decl) = 1;
> + ? ? ? ? ? ? DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) = l->looping;
> + ? ? ? ? ? ? changed = true;
> + ? ? ? ? ? }
> + ? ? ? ? warn_function_pure (current_function_decl, !l->looping);
> ? ? ? ? ?if (dump_file)
> ? ? ? ? ? ?fprintf (dump_file, "Function found to be %spure: %s\n",
> ? ? ? ? ? ? ? ? ? ? l->looping ? "looping " : "",
> @@ -971,8 +1111,11 @@ local_pure_const (void)
> ? ? ? 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 (!skip)
> + ? ? ? ? ? {
> + ? ? ? ? ? ? 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,
> @@ -985,13 +1128,16 @@ local_pure_const (void)
> ? ? }
> ? 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;
> + ? ? ?warn_function_nothrow (current_function_decl);
> + ? ? ?if (!skip)
> + ? ? ? {
> + ? ? ? ? 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,
> Index: tree-ssa-loop-ivcanon.c
> ===================================================================
> --- tree-ssa-loop-ivcanon.c ? ? (revision 146576)
> +++ tree-ssa-loop-ivcanon.c ? ? (working copy)
> @@ -395,7 +395,6 @@ static bool
> ?empty_loop_p (struct loop *loop)
> ?{
> ? edge exit;
> - ?struct tree_niter_desc niter;
> ? basic_block *body;
> ? gimple_stmt_iterator gsi;
> ? unsigned i;
> @@ -408,7 +407,7 @@ empty_loop_p (struct loop *loop)
> ? ? return false;
>
> ? /* The loop must be finite. ?*/
> - ?if (!number_of_iterations_exit (loop, exit, &niter, false))
> + ?if (!finite_loop_p (loop))
> ? ? return false;
>
> ? /* Values of all loop exit phi nodes must be invariants. ?*/
> Index: except.c
> ===================================================================
> --- except.c ? ?(revision 146576)
> +++ except.c ? ?(working copy)
> @@ -2823,6 +2823,8 @@ set_nothrow_function_flags (void)
> ? ? ? ? ? ?return 0;
> ? ? ? ? ?}
> ? ? ? }
> + ?if (crtl->nothrow)
> + ? ?warn_function_nothrow (current_function_decl);
> ? if (crtl->nothrow
> ? ? ? && (cgraph_function_body_availability (cgraph_node
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (current_function_decl))
> Index: common.opt
> ===================================================================
> --- common.opt ?(revision 146576)
> +++ common.opt ?(working copy)
> @@ -132,10 +132,22 @@ Wunsafe-loop-optimizations
> ?Common Var(warn_unsafe_loop_optimizations) Warning
> ?Warn if the loop cannot be optimized due to nontrivial assumptions.
>
> +Wmissing-const
> +Common Var(warn_missing_const) Warning
> +Warn about functions which might be candidates for __attribute__((const))
> +
> +Wmissing-nothrow
> +Common Var(warn_missing_nothrow) Warning
> +Warn about functions which might be candidates for __attribute__((nothrow))
> +
> ?Wmissing-noreturn
> ?Common Var(warn_missing_noreturn) Warning
> ?Warn about functions which might be candidates for __attribute__((noreturn))
>
> +Wmissing-pure
> +Common Var(warn_missing_pure) Warning
> +Warn about functions which might be candidates for __attribute__((pure))
> +

These all need documenting in doc/invoke.texi.  There should be some basic
testcases excercising them as well.

> ?Wmudflap
> ?Common Var(warn_mudflap) Init(1) Warning
> ?Warn about constructs not instrumented by -fmudflap
> Index: tree-ssa-dce.c
> ===================================================================
> --- tree-ssa-dce.c ? ? ?(revision 146576)
> +++ tree-ssa-dce.c ? ? ?(working copy)
> @@ -427,17 +427,42 @@ find_obviously_necessary_stmts (struct e
> ? ? ? ?}
> ? ? }
>
> + ?/* Pure and const functions are finite and thus have no infinite loops in
> + ? ? them. ?*/
> + ?if ((TREE_READONLY (current_function_decl)
> + ? ? ? || DECL_PURE_P (current_function_decl))
> + ? ? ?&& !DECL_LOOPING_CONST_OR_PURE_P (current_function_decl))
> + ? ?return;
> +
> + ?/* Prevent the empty possibly infinite loops from being removed. ?*/
> ? if (el)
> ? ? {
> - ? ? ?/* Prevent the loops from being removed. ?We must keep the infinite loops,
> - ? ? ? ?and we currently do not have a means to recognize the finite ones. ?*/
> - ? ? ?FOR_EACH_BB (bb)
> - ? ? ? {
> - ? ? ? ? edge_iterator ei;
> - ? ? ? ? FOR_EACH_EDGE (e, ei, bb->succs)
> - ? ? ? ? ? if (e->flags & EDGE_DFS_BACK)
> - ? ? ? ? ? ? mark_control_dependent_edges_necessary (e->dest, el);
> - ? ? ? }
> + ? ? ?loop_iterator li;
> + ? ? ?struct loop *loop;
> + ? ? ?scev_initialize ();
> + ? ? ?if (mark_irreducible_loops ())
> + ? ? ? FOR_EACH_BB (bb)
> + ? ? ? ? {
> + ? ? ? ? ? edge_iterator ei;
> + ? ? ? ? ? FOR_EACH_EDGE (e, ei, bb->succs)
> + ? ? ? ? ? ? if ((e->flags & EDGE_DFS_BACK)
> + ? ? ? ? ? ? ? ? && (e->flags & EDGE_IRREDUCIBLE_LOOP))
> + ? ? ? ? ? ? ? {
> + ? ? ? ? ? ? ? ? if (dump_file)
> + ? ? ? ? ? ? ? ? ? fprintf (dump_file, "Marking back edge of irreducible loop %i->%i\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?e->src->index, e->dest->index);
> + ? ? ? ? ? ? ? ? mark_control_dependent_edges_necessary (e->dest, el);
> + ? ? ? ? ? ? ? }
> + ? ? ? ? }
> +
> + ? ? ?FOR_EACH_LOOP (li, loop, 0)
> + ? ? ? if (!finite_loop_p (loop))
> + ? ? ? ? {
> + ? ? ? ? ? if (dump_file)
> + ? ? ? ? ? ? fprintf (dump_file, "can not prove finiteness of loop %i\n", loop->num);
> + ? ? ? ? ? mark_control_dependent_edges_necessary (loop->latch, el);
> + ? ? ? ? }
> + ? ? ?scev_finalize ();
> ? ? }
> ?}
>
> @@ -1099,6 +1124,9 @@ perform_tree_ssa_dce (bool aggressive)
> ? struct edge_list *el = NULL;
> ? bool something_changed = 0;
>
> + ?if (aggressive)
> + ? ?loop_optimizer_init (LOOPS_HAVE_PREHEADERS);
> +
> ? tree_dce_init (aggressive);
>
> ? if (aggressive)
> @@ -1118,6 +1146,9 @@ perform_tree_ssa_dce (bool aggressive)
>
> ? find_obviously_necessary_stmts (el);
>
> + ?if (aggressive)
> + ? ?loop_optimizer_finalize ();
> +
> ? longest_chain = 0;
> ? total_chain = 0;
> ? chain_ovfl = false;
> Index: cfgloop.h
> ===================================================================
> --- cfgloop.h ? (revision 146576)
> +++ cfgloop.h ? (working copy)
> @@ -210,7 +210,7 @@ struct loop *alloc_loop (void);
> ?extern void flow_loop_free (struct loop *);
> ?int flow_loop_nodes_find (basic_block, struct loop *);
> ?void fix_loop_structure (bitmap changed_bbs);
> -void mark_irreducible_loops (void);
> +bool mark_irreducible_loops (void);
> ?void release_recorded_exits (void);
> ?void record_loop_exits (void);
> ?void rescan_loop_exit (edge, bool, bool);
> @@ -645,5 +645,6 @@ enum
> ?extern void unroll_and_peel_loops (int);
> ?extern void doloop_optimize_loops (void);
> ?extern void move_loop_invariants (void);
> +extern bool finite_loop_p (struct loop *);
>
> ?#endif /* GCC_CFGLOOP_H */
>


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]