X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fipa-pure-const.c;h=04d4e112ed350974a57576203822af190cdb68ba;hb=a1e880328b19d607aeef6885338b2d5df8fe86bb;hp=1aef09f5221ebd250241f0073cf37ed7f8f28a2c;hpb=17b28e52019eff5c40389d7c25d6da967bb6f8c9;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c index 1aef09f5221..04d4e112ed3 100644 --- a/gcc/ipa-pure-const.c +++ b/gcc/ipa-pure-const.c @@ -1,5 +1,5 @@ /* Callgraph based analysis of static variables. - Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc. Contributed by Kenneth Zadeck This file is part of GCC. @@ -43,7 +43,6 @@ along with GCC; see the file COPYING3. If not see #include "pointer-set.h" #include "ggc.h" #include "ipa-utils.h" -#include "c-common.h" #include "gimple.h" #include "cgraph.h" #include "output.h" @@ -52,6 +51,8 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic.h" #include "langhooks.h" #include "target.h" +#include "cfgloop.h" +#include "tree-scalar-evolution.h" static struct pointer_set_t *visited_nodes; @@ -72,7 +73,8 @@ struct funct_state_d /* See above. */ 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; + enum pure_const_state_e state_previously_known; + bool looping_previously_known; /* True if the function could possibly infinite loop. There are a lot of ways that this could be determined. We are pretty @@ -211,13 +213,23 @@ check_decl (funct_state local, static inline void check_op (funct_state local, tree t, bool checking_write) { - if (TREE_THIS_VOLATILE (t)) + t = get_base_address (t); + if (t && TREE_THIS_VOLATILE (t)) { local->pure_const_state = IPA_NEITHER; if (dump_file) fprintf (dump_file, " Volatile indirect ref is not const/pure\n"); return; } + else if (t + && INDIRECT_REF_P (t) + && TREE_CODE (TREE_OPERAND (t, 0)) == SSA_NAME + && !ptr_deref_may_alias_global_p (TREE_OPERAND (t, 0))) + { + if (dump_file) + fprintf (dump_file, " Indirect ref to local memory is OK\n"); + return; + } else if (checking_write) { local->pure_const_state = IPA_NEITHER; @@ -334,8 +346,8 @@ check_call (funct_state local, gimple call, bool ipa) { if (dump_file) { - fprintf (dump_file, " can throw externally in region %i\n", - lookup_stmt_eh_region (call)); + fprintf (dump_file, " can throw externally to lp %i\n", + lookup_stmt_eh_lp (call)); if (callee_t) fprintf (dump_file, " callee:%s\n", IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (callee_t))); @@ -399,6 +411,9 @@ check_stmt (gimple_stmt_iterator *gsip, funct_state local, bool ipa) gimple stmt = gsi_stmt (*gsip); unsigned int i = 0; + if (is_gimple_debug (stmt)) + return; + if (dump_file) { fprintf (dump_file, " scanning: "); @@ -485,7 +500,8 @@ analyze_function (struct cgraph_node *fn, bool ipa) l = XCNEW (struct funct_state_d); l->pure_const_state = IPA_CONST; - l->state_set_in_source = IPA_NEITHER; + l->state_previously_known = IPA_NEITHER; + l->looping_previously_known = true; l->looping = false; l->can_throw = false; @@ -521,24 +537,53 @@ end: indication of possible infinite loop side effect. */ if (mark_dfs_back_edges ()) - l->looping = true; - + { + /* Preheaders are needed for SCEV to work. + Simple lateches and recorded exits improve chances that loop will + proved to be finite in testcases such as in loop-15.c and loop-24.c */ + loop_optimizer_init (LOOPS_NORMAL + | LOOPS_HAVE_RECORDED_EXITS); + 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)) { l->pure_const_state = IPA_CONST; - l->state_set_in_source = IPA_CONST; + l->state_previously_known = IPA_CONST; if (!DECL_LOOPING_CONST_OR_PURE_P (decl)) - l->looping = false; + l->looping = false, l->looping_previously_known = false; } if (DECL_PURE_P (decl)) { if (l->pure_const_state != IPA_CONST) l->pure_const_state = IPA_PURE; - l->state_set_in_source = IPA_PURE; + l->state_previously_known = IPA_PURE; if (!DECL_LOOPING_CONST_OR_PURE_P (decl)) - l->looping = false; + l->looping = false, l->looping_previously_known = false; } if (TREE_NOTHROW (decl)) l->can_throw = false; @@ -643,6 +688,18 @@ ignore_edge (struct cgraph_edge *e) return (!e->can_throw_external); } +/* Return true if NODE is self recursive function. */ + +static bool +self_recursive_p (struct cgraph_node *node) +{ + struct cgraph_edge *e; + for (e = node->callees; e; e = e->next_callee) + if (e->callee == node) + return true; + return false; +} + /* Produce the global information by preforming a transitive closure on the local information that was produced by generate_summary. Note that there is no function_transform pass since this only @@ -728,12 +785,13 @@ 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_previously_known != IPA_NEITHER + && this_state > w_l->state_previously_known) + this_state = w_l->state_previously_known; + if (!this_looping && self_recursive_p (w)) + this_looping = true; + if (!w_l->looping_previously_known) + this_looping = false; /* All nodes within a cycle share the same info. */ w_l->pure_const_state = this_state; @@ -830,6 +888,7 @@ propagate (void) w = node; while (w) { + funct_state w_l = get_function_state (w); if (!can_throw && !TREE_NOTHROW (w->decl)) { struct cgraph_edge *e; @@ -840,6 +899,8 @@ propagate (void) fprintf (dump_file, "Function found to be nothrow: %s\n", cgraph_node_name (w)); } + else if (can_throw && !TREE_NOTHROW (w->decl)) + w_l->can_throw = true; w_info = (struct ipa_dfs_info *) w->aux; w = w_info->next_cycle; } @@ -873,7 +934,7 @@ gate_pure_const (void) && !(errorcount || sorrycount)); } -struct ipa_opt_pass pass_ipa_pure_const = +struct ipa_opt_pass_d pass_ipa_pure_const = { { IPA_PASS,