X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;ds=sidebyside;f=gcc%2Fipa-pure-const.c;h=a2c920601ac76a97640193c341a1979526f80ab0;hb=f69b7efb46e48bce7beb22bf8f1e26f487998aac;hp=1402607aa8b0945efa1c3a79f600aa2c2070242e;hpb=f7d118a953d1e3d86a4ef955c4e0e4627d145ca6;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c index 1402607aa8b..a2c920601ac 100644 --- a/gcc/ipa-pure-const.c +++ b/gcc/ipa-pure-const.c @@ -1,12 +1,12 @@ /* Callgraph based analysis of static variables. - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc. Contributed by Kenneth Zadeck This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later +Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY @@ -15,12 +15,12 @@ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +along with GCC; see the file COPYING3. If not see +. */ /* This file mark functions as being either const (TREE_READONLY) or - pure (DECL_IS_PURE). + pure (DECL_PURE_P). It can also set the a variant of these that + are allowed to infinite loop (DECL_LOOPING_CONST_PURE_P). This must be run after inlining decisions have been made since otherwise, the local sets will not contain information that is @@ -51,6 +51,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "timevar.h" #include "diagnostic.h" #include "langhooks.h" +#include "target.h" static struct pointer_set_t *visited_nodes; @@ -69,6 +70,7 @@ enum pure_const_state_e struct funct_state_d { enum pure_const_state_e pure_const_state; + bool looping; bool state_set_in_source; }; @@ -79,8 +81,8 @@ typedef struct funct_state_d * funct_state; static inline funct_state get_function_state (struct cgraph_node *node) { - struct ipa_dfs_info * info = node->aux; - return info->aux; + struct ipa_dfs_info * info = (struct ipa_dfs_info *) node->aux; + return (funct_state) info->aux; } /* Check to see if the use (or definition when CHECHING_WRITE is true) @@ -95,6 +97,7 @@ check_decl (funct_state local, if (lookup_attribute ("used", DECL_ATTRIBUTES (t))) { local->pure_const_state = IPA_NEITHER; + local->looping = false; return; } @@ -103,6 +106,7 @@ check_decl (funct_state local, if (TREE_THIS_VOLATILE (t)) { local->pure_const_state = IPA_NEITHER; + local->looping = false; return; } @@ -114,7 +118,11 @@ check_decl (funct_state local, are CHECKING_WRITE, this cannot be a pure or constant function. */ if (checking_write) - local->pure_const_state = IPA_NEITHER; + { + local->pure_const_state = IPA_NEITHER; + local->looping = false; + return; + } if (DECL_EXTERNAL (t) || TREE_PUBLIC (t)) { @@ -162,9 +170,19 @@ check_operand (funct_state local, static void check_tree (funct_state local, tree t, bool checking_write) { - if ((TREE_CODE (t) == EXC_PTR_EXPR) || (TREE_CODE (t) == FILTER_EXPR)) + if ((TREE_CODE (t) == EXC_PTR_EXPR) || (TREE_CODE (t) == FILTER_EXPR) + || TREE_CODE (t) == SSA_NAME) return; + /* Any tree which is volatile disqualifies thie function from being + const or pure. */ + if (TREE_THIS_VOLATILE (t)) + { + local->pure_const_state = IPA_NEITHER; + local->looping = false; + return; + } + while (TREE_CODE (t) == REALPART_EXPR || TREE_CODE (t) == IMAGPART_EXPR || handled_component_p (t)) @@ -182,13 +200,16 @@ check_tree (funct_state local, tree t, bool checking_write) /* Any indirect reference that occurs on the lhs disqualifies the function from being pure or const. Any - indirect reference that occurs on the rhs disqualifies - the function from being const. */ + indirect reference that occurs on the rhs disqualifies the + function from being const. */ if (checking_write) - local->pure_const_state = IPA_NEITHER; - else - if (local->pure_const_state == IPA_CONST) - local->pure_const_state = IPA_PURE; + { + local->pure_const_state = IPA_NEITHER; + local->looping = false; + return; + } + else if (local->pure_const_state == IPA_CONST) + local->pure_const_state = IPA_PURE; } if (SSA_VAR_P (t)) @@ -304,20 +325,15 @@ get_asm_expr_operands (funct_state local, tree stmt) static void check_call (funct_state local, tree call_expr) { - int flags = call_expr_flags(call_expr); - tree operand_list = TREE_OPERAND (call_expr, 1); + int flags = call_expr_flags (call_expr); tree operand; + call_expr_arg_iterator iter; tree callee_t = get_callee_fndecl (call_expr); struct cgraph_node* callee; enum availability avail = AVAIL_NOT_AVAILABLE; - for (operand = operand_list; - operand != NULL_TREE; - operand = TREE_CHAIN (operand)) - { - tree argument = TREE_VALUE (operand); - check_rhs_var (local, argument); - } + FOR_EACH_CALL_EXPR_ARG (operand, iter, call_expr) + check_rhs_var (local, operand); /* The const and pure flags are set by a variety of places in the compiler (including here). If someone has already set the flags @@ -337,7 +353,10 @@ check_call (funct_state local, tree call_expr) /* When bad things happen to bad functions, they cannot be const or pure. */ if (setjmp_call_p (callee_t)) - local->pure_const_state = IPA_NEITHER; + { + local->pure_const_state = IPA_NEITHER; + local->looping = false; + } if (DECL_BUILT_IN_CLASS (callee_t) == BUILT_IN_NORMAL) switch (DECL_FUNCTION_CODE (callee_t)) @@ -345,6 +364,7 @@ check_call (funct_state local, tree call_expr) case BUILT_IN_LONGJMP: case BUILT_IN_NONLOCAL_GOTO: local->pure_const_state = IPA_NEITHER; + local->looping = false; break; default: break; @@ -389,7 +409,7 @@ scan_function (tree *tp, int *walk_subtrees, void *data) { - struct cgraph_node *fn = data; + struct cgraph_node *fn = (struct cgraph_node *) data; tree t = *tp; funct_state local = get_function_state (fn); @@ -401,11 +421,11 @@ scan_function (tree *tp, *walk_subtrees = 0; break; - case MODIFY_EXPR: + case GIMPLE_MODIFY_STMT: { /* First look on the lhs and see what variable is stored to */ - tree lhs = TREE_OPERAND (t, 0); - tree rhs = TREE_OPERAND (t, 1); + tree lhs = GIMPLE_STMT_OPERAND (t, 0); + tree rhs = GIMPLE_STMT_OPERAND (t, 1); check_lhs_var (local, lhs); /* For the purposes of figuring out what the cast affects */ @@ -440,7 +460,14 @@ scan_function (tree *tp, case ADDR_EXPR: check_rhs_var (local, rhs); break; - case CALL_EXPR: + default: + break; + } + break; + case tcc_vl_exp: + switch (TREE_CODE (rhs)) + { + case CALL_EXPR: check_call (local, rhs); break; default: @@ -464,7 +491,10 @@ scan_function (tree *tp, case LABEL_EXPR: if (DECL_NONLOCAL (TREE_OPERAND (t, 0))) /* Target of long jump. */ - local->pure_const_state = IPA_NEITHER; + { + local->pure_const_state = IPA_NEITHER; + local->looping = false; + } break; case CALL_EXPR: @@ -489,18 +519,24 @@ scan_function (tree *tp, static void analyze_function (struct cgraph_node *fn) { - funct_state l = xcalloc (1, sizeof (struct funct_state_d)); + funct_state l = XCNEW (struct funct_state_d); tree decl = fn->decl; - struct ipa_dfs_info * w_info = fn->aux; + struct ipa_dfs_info * w_info = (struct ipa_dfs_info *) fn->aux; w_info->aux = l; l->pure_const_state = IPA_CONST; l->state_set_in_source = false; + if (DECL_LOOPING_CONST_OR_PURE_P (decl)) + l->looping = true; + else + l->looping = false; - /* If this is a volatile function, do not touch this unless it has - been marked as const or pure by the front end. */ - if (TREE_THIS_VOLATILE (decl)) + /* If this function does not return normally or does not bind local, + do not touch this unless it has been marked as const or pure by the + front end. */ + if (TREE_THIS_VOLATILE (decl) + || !targetm.binds_local_p (decl)) { l->pure_const_state = IPA_NEITHER; return; @@ -511,7 +547,7 @@ analyze_function (struct cgraph_node *fn) l->pure_const_state = IPA_CONST; l->state_set_in_source = true; } - if (DECL_IS_PURE (decl)) + if (DECL_PURE_P (decl)) { l->pure_const_state = IPA_PURE; l->state_set_in_source = true; @@ -537,7 +573,7 @@ analyze_function (struct cgraph_node *fn) walk_tree (bsi_stmt_ptr (bsi), scan_function, fn, visited_nodes); if (l->pure_const_state == IPA_NEITHER) - return; + goto end; } } @@ -564,6 +600,14 @@ analyze_function (struct cgraph_node *fn) pop_cfun (); } } + +end: + if (dump_file) + { + fprintf (dump_file, "after local analysis of %s with initial value = %d\n ", + cgraph_node_name (fn), + l->pure_const_state); + } } @@ -571,14 +615,14 @@ analyze_function (struct cgraph_node *fn) on the local information that was produced by ipa_analyze_function and ipa_analyze_variable. */ -static void +static unsigned int static_execute (void) { struct cgraph_node *node; struct cgraph_node *w; struct cgraph_node **order = - xcalloc (cgraph_n_nodes, sizeof (struct cgraph_node *)); - int order_pos = order_pos = ipa_utils_reduced_inorder (order, true, false); + XCNEWVEC (struct cgraph_node *, cgraph_n_nodes); + int order_pos = ipa_utils_reduced_inorder (order, true, false); int i; struct ipa_dfs_info * w_info; @@ -618,6 +662,8 @@ static_execute (void) for (i = 0; i < order_pos; i++ ) { enum pure_const_state_e pure_const_state = IPA_CONST; + bool looping = false; + int count = 0; node = order[i]; /* Find the worst state for any node in the cycle. */ @@ -628,17 +674,28 @@ static_execute (void) if (pure_const_state < w_l->pure_const_state) pure_const_state = w_l->pure_const_state; + if (w_l->looping) + looping = true; + if (pure_const_state == IPA_NEITHER) break; if (!w_l->state_set_in_source) { struct cgraph_edge *e; + count++; + + if (count > 1) + looping = true; + for (e = w->callees; e; e = e->next_callee) { struct cgraph_node *y = e->callee; /* Only look at the master nodes and skip external nodes. */ y = cgraph_master_clone (y); + + if (w == y) + looping = true; if (y) { funct_state y_l = get_function_state (y); @@ -646,10 +703,12 @@ static_execute (void) pure_const_state = y_l->pure_const_state; if (pure_const_state == IPA_NEITHER) break; + if (y_l->looping) + looping = true; } } } - w_info = w->aux; + w_info = (struct ipa_dfs_info *) w->aux; w = w_info->next_cycle; } @@ -668,15 +727,19 @@ static_execute (void) { case IPA_CONST: TREE_READONLY (w->decl) = 1; + DECL_LOOPING_CONST_OR_PURE_P (w->decl) = looping; if (dump_file) - fprintf (dump_file, "Function found to be const: %s\n", + fprintf (dump_file, "Function found to be %sconst: %s\n", + looping ? "looping " : "", lang_hooks.decl_printable_name(w->decl, 2)); break; case IPA_PURE: - DECL_IS_PURE (w->decl) = 1; + DECL_PURE_P (w->decl) = 1; + DECL_LOOPING_CONST_OR_PURE_P (w->decl) = looping; if (dump_file) - fprintf (dump_file, "Function found to be pure: %s\n", + fprintf (dump_file, "Function found to be %spure: %s\n", + looping ? "looping " : "", lang_hooks.decl_printable_name(w->decl, 2)); break; @@ -684,7 +747,7 @@ static_execute (void) break; } } - w_info = w->aux; + w_info = (struct ipa_dfs_info *) w->aux; w = w_info->next_cycle; } } @@ -694,11 +757,15 @@ static_execute (void) /* Get rid of the aux information. */ if (node->aux) { + w_info = (struct ipa_dfs_info *) node->aux; + if (w_info->aux) + free (w_info->aux); free (node->aux); node->aux = NULL; } free (order); + return 0; } static bool @@ -709,9 +776,11 @@ gate_pure_const (void) && !(errorcount || sorrycount)); } -struct tree_opt_pass pass_ipa_pure_const = +struct simple_ipa_opt_pass pass_ipa_pure_const = { - "ipa-pure-const", /* name */ + { + SIMPLE_IPA_PASS, + "pure-const", /* name */ gate_pure_const, /* gate */ static_execute, /* execute */ NULL, /* sub */ @@ -722,8 +791,8 @@ struct tree_opt_pass pass_ipa_pure_const = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - 0, /* todo_flags_finish */ - 0 /* letter */ + 0 /* todo_flags_finish */ + } };