X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Ftree-dfa.c;h=90ff710a44b84daf8fdaae0c9e5f7f215ff0bc61;hb=4fec1d6c59baf0070f3ae1b62e5564a588603f7d;hp=cda68487efb41a419e4e47e73e0490c5581e6f72;hpb=4ee9c6840ad3fc92a9034343278a1e476ad6872a;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c index cda68487efb..90ff710a44b 100644 --- a/gcc/tree-dfa.c +++ b/gcc/tree-dfa.c @@ -24,6 +24,7 @@ Boston, MA 02111-1307, USA. */ #include "coretypes.h" #include "tm.h" #include "hashtab.h" +#include "pointer-set.h" #include "tree.h" #include "rtl.h" #include "tm_p.h" @@ -39,13 +40,13 @@ Boston, MA 02111-1307, USA. */ #include "function.h" #include "diagnostic.h" #include "tree-dump.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "tree-flow.h" #include "tree-inline.h" -#include "tree-alias-common.h" #include "tree-pass.h" #include "convert.h" #include "params.h" +#include "cgraph.h" /* Build and maintain data flow information for trees. */ @@ -59,8 +60,9 @@ struct dfa_stats_d long num_phis; long num_phi_args; int max_num_phi_args; - long num_vdefs; + long num_v_may_defs; long num_vuses; + long num_v_must_defs; }; @@ -80,8 +82,6 @@ static tree find_vars_r (tree *, int *, void *); static void add_referenced_var (tree, struct walk_state *); static void compute_immediate_uses_for_phi (tree, bool (*)(tree)); static void compute_immediate_uses_for_stmt (tree, int, bool (*)(tree)); -static void find_hidden_use_vars (tree); -static tree find_hidden_use_vars_r (tree *, int *, void *); /* Global declarations. */ @@ -108,25 +108,6 @@ find_referenced_vars (void) basic_block bb; block_stmt_iterator si; struct walk_state walk_state; - tree block; - - /* This is the very first pass in preparation for building the SSA - form of the function, so initialize internal data structures now. */ - init_tree_ssa (); - - /* Walk the lexical blocks in the function looking for variables that may - have been used to declare VLAs and for nested functions. Both - constructs create hidden uses of variables. - - Note that at this point we may have multiple blocks hung off - DECL_INITIAL chained through the BLOCK_CHAIN field due to - how inlining works. Egad. */ - block = DECL_INITIAL (current_function_decl); - while (block) - { - find_hidden_use_vars (block); - block = BLOCK_CHAIN (block); - } vars_found = htab_create (50, htab_hash_pointer, htab_eq_pointer, NULL); memset (&walk_state, 0, sizeof (walk_state)); @@ -150,17 +131,18 @@ struct tree_opt_pass pass_referenced_vars = NULL, /* sub */ NULL, /* next */ 0, /* static_pass_number */ - 0, /* tv_id */ + TV_FIND_REFERENCED_VARS, /* tv_id */ PROP_gimple_leh | PROP_cfg, /* properties_required */ PROP_referenced_vars, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - 0, /* todo_flags_finish */ + 0, /* todo_flags_finish */ + 0 /* letter */ }; -/* Compute immediate uses. - +/* Compute immediate uses. + CALC_FOR is an optional function pointer which indicates whether immediate uses information should be calculated for a given SSA variable. If NULL, then information is computed for all @@ -180,8 +162,21 @@ compute_immediate_uses (int flags, bool (*calc_for)(tree)) { tree phi; - for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) - compute_immediate_uses_for_phi (phi, calc_for); + for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi)) + { + if (is_gimple_reg (PHI_RESULT (phi))) + { + if (!(flags & TDFA_USE_OPS)) + continue; + } + else + { + if (!(flags & TDFA_USE_VOPS)) + continue; + } + + compute_immediate_uses_for_phi (phi, calc_for); + } for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si)) { @@ -195,26 +190,44 @@ compute_immediate_uses (int flags, bool (*calc_for)(tree)) /* Invalidates dataflow information for a statement STMT. */ -static void +void free_df_for_stmt (tree stmt) { - stmt_ann_t ann = stmt_ann (stmt); + dataflow_t *df; - if (ann && ann->df) + if (TREE_CODE (stmt) == PHI_NODE) + df = &PHI_DF (stmt); + else { - /* If we have a varray of immediate uses, then go ahead and release - it for re-use. */ - if (ann->df->immediate_uses) - ggc_free (ann->df->immediate_uses); - - /* Similarly for the main dataflow structure. */ - ggc_free (ann->df); - ann->df = NULL; + stmt_ann_t ann = stmt_ann (stmt); + + if (!ann) + return; + + df = &ann->df; } + + if (!*df) + return; + + /* If we have a varray of immediate uses, then go ahead and release + it for re-use. */ + if ((*df)->immediate_uses) + ggc_free ((*df)->immediate_uses); + + /* Similarly for the main dataflow structure. */ + ggc_free (*df); + *df = NULL; } -/* Invalidate dataflow information for the whole function. */ +/* Invalidate dataflow information for the whole function. + + Note this only invalidates dataflow information on statements and + PHI nodes which are reachable. + + A deleted statement may still have attached dataflow information + on it. */ void free_df (void) @@ -226,7 +239,7 @@ free_df (void) { tree phi; - for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi)) free_df_for_stmt (phi); for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si)) @@ -250,17 +263,14 @@ compute_immediate_uses_for_phi (tree phi, bool (*calc_for)(tree)) { int i; -#ifdef ENABLE_CHECKING - if (TREE_CODE (phi) != PHI_NODE) - abort (); -#endif + gcc_assert (TREE_CODE (phi) == PHI_NODE); for (i = 0; i < PHI_NUM_ARGS (phi); i++) { tree arg = PHI_ARG_DEF (phi, i); if (TREE_CODE (arg) == SSA_NAME && (!calc_for || calc_for (arg))) - { + { tree imm_rdef_stmt = SSA_NAME_DEF_STMT (PHI_ARG_DEF (phi, i)); if (!IS_EMPTY_STMT (imm_rdef_stmt)) add_immediate_use (imm_rdef_stmt, phi); @@ -277,26 +287,17 @@ compute_immediate_uses_for_phi (tree phi, bool (*calc_for)(tree)) static void compute_immediate_uses_for_stmt (tree stmt, int flags, bool (*calc_for)(tree)) { - size_t i; - use_optype uses; - vuse_optype vuses; - vdef_optype vdefs; - stmt_ann_t ann; + tree use; + ssa_op_iter iter; -#ifdef ENABLE_CHECKING /* PHI nodes are handled elsewhere. */ - if (TREE_CODE (stmt) == PHI_NODE) - abort (); -#endif + gcc_assert (TREE_CODE (stmt) != PHI_NODE); /* Look at USE_OPS or VUSE_OPS according to FLAGS. */ - ann = stmt_ann (stmt); if (flags & TDFA_USE_OPS) { - uses = USE_OPS (ann); - for (i = 0; i < NUM_USES (uses); i++) + FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE) { - tree use = USE_OP (uses, i); tree imm_stmt = SSA_NAME_DEF_STMT (use); if (!IS_EMPTY_STMT (imm_stmt) && (!calc_for || calc_for (use))) add_immediate_use (imm_stmt, stmt); @@ -305,24 +306,20 @@ compute_immediate_uses_for_stmt (tree stmt, int flags, bool (*calc_for)(tree)) if (flags & TDFA_USE_VOPS) { - vuses = VUSE_OPS (ann); - for (i = 0; i < NUM_VUSES (vuses); i++) + FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_VIRTUAL_USES) { - tree vuse = VUSE_OP (vuses, i); - tree imm_rdef_stmt = SSA_NAME_DEF_STMT (vuse); - if (!IS_EMPTY_STMT (imm_rdef_stmt) && (!calc_for || calc_for (vuse))) + tree imm_rdef_stmt = SSA_NAME_DEF_STMT (use); + if (!IS_EMPTY_STMT (imm_rdef_stmt) && (!calc_for || calc_for (use))) add_immediate_use (imm_rdef_stmt, stmt); } - - vdefs = VDEF_OPS (ann); - for (i = 0; i < NUM_VDEFS (vdefs); i++) + + FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_ALL_KILLS) { - tree vuse = VDEF_OP (vdefs, i); - tree imm_rdef_stmt = SSA_NAME_DEF_STMT (vuse); - if (!IS_EMPTY_STMT (imm_rdef_stmt) && (!calc_for || calc_for (vuse))) + tree imm_rdef_stmt = SSA_NAME_DEF_STMT (use); + if (!IS_EMPTY_STMT (imm_rdef_stmt) && (!calc_for || calc_for (use))) add_immediate_use (imm_rdef_stmt, stmt); } - } + } } @@ -332,38 +329,44 @@ compute_immediate_uses_for_stmt (tree stmt, int flags, bool (*calc_for)(tree)) static void add_immediate_use (tree stmt, tree use_stmt) { - stmt_ann_t ann = get_stmt_ann (stmt); - struct dataflow_d *df; + struct dataflow_d **df; - df = ann->df; - if (df == NULL) + if (TREE_CODE (stmt) == PHI_NODE) + df = &PHI_DF (stmt); + else + { + stmt_ann_t ann = get_stmt_ann (stmt); + df = &ann->df; + } + + if (*df == NULL) { - df = ann->df = ggc_alloc (sizeof (struct dataflow_d)); - memset ((void *) df, 0, sizeof (struct dataflow_d)); - df->uses[0] = use_stmt; + *df = ggc_alloc (sizeof (struct dataflow_d)); + memset ((void *) *df, 0, sizeof (struct dataflow_d)); + (*df)->uses[0] = use_stmt; return; } - if (!df->uses[1]) + if (!(*df)->uses[1]) { - df->uses[1] = use_stmt; + (*df)->uses[1] = use_stmt; return; } - if (ann->df->immediate_uses == NULL) - VARRAY_TREE_INIT (ann->df->immediate_uses, 4, "immediate_uses"); + if ((*df)->immediate_uses == NULL) + VARRAY_TREE_INIT ((*df)->immediate_uses, 4, "immediate_uses"); - VARRAY_PUSH_TREE (ann->df->immediate_uses, use_stmt); + VARRAY_PUSH_TREE ((*df)->immediate_uses, use_stmt); } /* If the immediate use of USE points to OLD, then redirect it to NEW. */ - + static void redirect_immediate_use (tree use, tree old, tree new) { tree imm_stmt = SSA_NAME_DEF_STMT (use); - struct dataflow_d *df = get_stmt_ann (imm_stmt)->df; + struct dataflow_d *df = get_immediate_uses (imm_stmt); unsigned int num_uses = num_immediate_uses (df); unsigned int i; @@ -387,21 +390,11 @@ redirect_immediate_use (tree use, tree old, tree new) void redirect_immediate_uses (tree old, tree new) { - stmt_ann_t ann = get_stmt_ann (old); - use_optype uses = USE_OPS (ann); - vuse_optype vuses = VUSE_OPS (ann); - vdef_optype vdefs = VDEF_OPS (ann); - unsigned int i; + ssa_op_iter iter; + tree val; - /* Look at USE_OPS or VUSE_OPS according to FLAGS. */ - for (i = 0; i < NUM_USES (uses); i++) - redirect_immediate_use (USE_OP (uses, i), old, new); - - for (i = 0; i < NUM_VUSES (vuses); i++) - redirect_immediate_use (VUSE_OP (vuses, i), old, new); - - for (i = 0; i < NUM_VDEFS (vdefs); i++) - redirect_immediate_use (VDEF_OP (vdefs, i), old, new); + FOR_EACH_SSA_TREE_OPERAND (val, old, iter, SSA_OP_ALL_USES) + redirect_immediate_use (val, old, new); } @@ -415,20 +408,16 @@ create_var_ann (tree t) { var_ann_t ann; -#if defined ENABLE_CHECKING - if (t == NULL_TREE - || !DECL_P (t) - || (t->common.ann - && t->common.ann->common.type != VAR_ANN)) - abort (); -#endif + gcc_assert (t); + gcc_assert (DECL_P (t)); + gcc_assert (!t->common.ann || t->common.ann->common.type == VAR_ANN); ann = ggc_alloc (sizeof (*ann)); memset ((void *) ann, 0, sizeof (*ann)); ann->common.type = VAR_ANN; - t->common.ann = (tree_ann) ann; + t->common.ann = (tree_ann_t) ann; return ann; } @@ -441,12 +430,8 @@ create_stmt_ann (tree t) { stmt_ann_t ann; -#if defined ENABLE_CHECKING - if ((!is_gimple_stmt (t) && !is_essa_node (t)) - || (t->common.ann - && t->common.ann->common.type != STMT_ANN)) - abort (); -#endif + gcc_assert (is_gimple_stmt (t)); + gcc_assert (!t->common.ann || t->common.ann->common.type == STMT_ANN); ann = ggc_alloc (sizeof (*ann)); memset ((void *) ann, 0, sizeof (*ann)); @@ -456,35 +441,45 @@ create_stmt_ann (tree t) /* Since we just created the annotation, mark the statement modified. */ ann->modified = true; - t->common.ann = (tree_ann) ann; + t->common.ann = (tree_ann_t) ann; return ann; } -/* Create a new annotation for an SSA name T. */ +/* Create a new annotation for a tree T. */ -ssa_name_ann_t -create_ssa_name_ann (tree t) +tree_ann_t +create_tree_ann (tree t) { - ssa_name_ann_t ann; + tree_ann_t ann; -#if defined ENABLE_CHECKING - if (t == NULL_TREE - || (t->common.ann - && t->common.ann->common.type != SSA_NAME_ANN)) - abort (); -#endif + gcc_assert (t); + gcc_assert (!t->common.ann || t->common.ann->common.type == TREE_ANN_COMMON); ann = ggc_alloc (sizeof (*ann)); memset ((void *) ann, 0, sizeof (*ann)); - ann->common.type = SSA_NAME_ANN; - t->common.ann = (tree_ann) ann; + ann->common.type = TREE_ANN_COMMON; + t->common.ann = ann; return ann; } +/* Build a temporary. Make sure and register it to be renamed. */ + +tree +make_rename_temp (tree type, const char *prefix) +{ + tree t = create_tmp_var (type, prefix); + if (referenced_vars) + { + add_referenced_tmp_var (t); + bitmap_set_bit (vars_to_rename, var_ann (t)->uid); + } + return t; +} + /*--------------------------------------------------------------------------- @@ -498,7 +493,7 @@ dump_referenced_vars (FILE *file) { size_t i; - fprintf (file, "\nReferenced variables in %s: %u\n\n", + fprintf (file, "\nReferenced variables in %s: %u\n\n", get_name (current_function_decl), (unsigned) num_referenced_vars); for (i = 0; i < num_referenced_vars; i++) @@ -527,6 +522,13 @@ dump_variable (FILE *file, tree var) { var_ann_t ann; + if (TREE_CODE (var) == SSA_NAME) + { + if (POINTER_TYPE_P (TREE_TYPE (var))) + dump_points_to_info_for (file, var); + var = SSA_NAME_VAR (var); + } + if (var == NULL_TREE) { fprintf (file, ""); @@ -534,16 +536,13 @@ dump_variable (FILE *file, tree var) } print_generic_expr (file, var, dump_flags); - - if (TREE_CODE (var) == SSA_NAME) - var = SSA_NAME_VAR (var); ann = var_ann (var); fprintf (file, ", UID %u", (unsigned) ann->uid); - if (ann->has_hidden_use) - fprintf (file, ", has hidden uses"); + fprintf (file, ", "); + print_generic_expr (file, TREE_TYPE (var), dump_flags); if (ann->type_mem_tag) { @@ -554,8 +553,14 @@ dump_variable (FILE *file, tree var) if (ann->is_alias_tag) fprintf (file, ", is an alias tag"); - if (needs_to_live_in_memory (var)) - fprintf (file, ", is %s", TREE_STATIC (var) ? "static" : "global"); + if (TREE_ADDRESSABLE (var)) + fprintf (file, ", is addressable"); + + if (is_global_var (var)) + fprintf (file, ", is global"); + + if (TREE_THIS_VOLATILE (var)) + fprintf (file, ", is volatile"); if (is_call_clobbered (var)) fprintf (file, ", call clobbered"); @@ -593,7 +598,7 @@ dump_immediate_uses (FILE *file) basic_block bb; block_stmt_iterator si; const char *funcname - = (*lang_hooks.decl_printable_name) (current_function_decl, 2); + = lang_hooks.decl_printable_name (current_function_decl, 2); fprintf (file, "\nDef-use edges for function %s\n", funcname); @@ -601,7 +606,7 @@ dump_immediate_uses (FILE *file) { tree phi; - for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi)) dump_immediate_uses_for (file, phi); for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si)) @@ -670,7 +675,7 @@ dump_dfa_stats (FILE *file) const char * const fmt_str_1 = "%-30s%13lu%11lu%c\n"; const char * const fmt_str_3 = "%-43s%11lu%c\n"; const char *funcname - = (*lang_hooks.decl_printable_name) (current_function_decl, 2); + = lang_hooks.decl_printable_name (current_function_decl, 2); collect_dfa_stats (&dfa_stats); @@ -683,7 +688,7 @@ dump_dfa_stats (FILE *file) size = num_referenced_vars * sizeof (tree); total += size; - fprintf (file, fmt_str_1, "Referenced variables", num_referenced_vars, + fprintf (file, fmt_str_1, "Referenced variables", (unsigned long)num_referenced_vars, SCALE (size), LABEL (size)); size = dfa_stats.num_stmt_anns * sizeof (struct stmt_ann_d); @@ -711,9 +716,14 @@ dump_dfa_stats (FILE *file) fprintf (file, fmt_str_1, "VUSE operands", dfa_stats.num_vuses, SCALE (size), LABEL (size)); - size = dfa_stats.num_vdefs * sizeof (tree *); + size = dfa_stats.num_v_may_defs * sizeof (tree *); + total += size; + fprintf (file, fmt_str_1, "V_MAY_DEF operands", dfa_stats.num_v_may_defs, + SCALE (size), LABEL (size)); + + size = dfa_stats.num_v_must_defs * sizeof (tree *); total += size; - fprintf (file, fmt_str_1, "VDEF operands", dfa_stats.num_vdefs, + fprintf (file, fmt_str_1, "V_MUST_DEF operands", dfa_stats.num_v_must_defs, SCALE (size), LABEL (size)); size = dfa_stats.num_phis * sizeof (struct tree_phi_node); @@ -756,29 +766,28 @@ debug_dfa_stats (void) static void collect_dfa_stats (struct dfa_stats_d *dfa_stats_p) { - htab_t htab; + struct pointer_set_t *pset; basic_block bb; block_stmt_iterator i; - if (dfa_stats_p == NULL) - abort (); + gcc_assert (dfa_stats_p); memset ((void *)dfa_stats_p, 0, sizeof (struct dfa_stats_d)); /* Walk all the trees in the function counting references. Start at basic block 0, but don't stop at block boundaries. */ - htab = htab_create (30, htab_hash_pointer, htab_eq_pointer, NULL); + pset = pointer_set_create (); for (i = bsi_start (BASIC_BLOCK (0)); !bsi_end_p (i); bsi_next (&i)) walk_tree (bsi_stmt_ptr (i), collect_dfa_stats_r, (void *) dfa_stats_p, - (void *) htab); + pset); - htab_delete (htab); + pointer_set_destroy (pset); FOR_EACH_BB (bb) { tree phi; - for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi)) { dfa_stats_p->num_phis++; dfa_stats_p->num_phi_args += PHI_NUM_ARGS (phi); @@ -809,8 +818,11 @@ collect_dfa_stats_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, dfa_stats_p->num_stmt_anns++; dfa_stats_p->num_defs += NUM_DEFS (DEF_OPS (ann)); dfa_stats_p->num_uses += NUM_USES (USE_OPS (ann)); - dfa_stats_p->num_vdefs += NUM_VDEFS (VDEF_OPS (ann)); + dfa_stats_p->num_v_may_defs += + NUM_V_MAY_DEFS (V_MAY_DEF_OPS (ann)); dfa_stats_p->num_vuses += NUM_VUSES (VUSE_OPS (ann)); + dfa_stats_p->num_v_must_defs += + NUM_V_MUST_DEFS (V_MUST_DEF_OPS (ann)); break; } @@ -836,24 +848,17 @@ collect_dfa_stats_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, static tree find_vars_r (tree *tp, int *walk_subtrees, void *data) { - tree t = *tp; - struct walk_state *walk_state = (struct walk_state *)data; + struct walk_state *walk_state = (struct walk_state *) data; - if (SSA_VAR_P (t)) - { - /* If T is a regular variable that the optimizers are interested - in, add it to the list of variables. */ - add_referenced_var (t, walk_state); - } - else if (DECL_P (t) - || TYPE_P (t) - || TREE_CODE_CLASS (TREE_CODE (t)) == 'c') - { - /* Type, _DECL and constant nodes have no interesting children. - Ignore them. */ - *walk_subtrees = 0; - } + /* If T is a regular variable that the optimizers are interested + in, add it to the list of variables. */ + if (SSA_VAR_P (*tp)) + add_referenced_var (*tp, walk_state); + /* Type, _DECL and constant nodes have no interesting children. + Ignore them. */ + else if (IS_TYPE_OR_DECL_P (*tp) || CONSTANT_CLASS_P (*tp)) + *walk_subtrees = 0; return NULL_TREE; } @@ -889,14 +894,16 @@ add_referenced_var (tree var, struct walk_state *walk_state) v_ann->uid = num_referenced_vars; VARRAY_PUSH_TREE (referenced_vars, var); - /* Global and static variables are call-clobbered, always. */ - if (needs_to_live_in_memory (var)) + /* Global variables are always call-clobbered. */ + if (is_global_var (var)) mark_call_clobbered (var); - /* DECL_NONLOCAL variables should not be removed, as they are needed - to emit nested functions. */ - if (DECL_NONLOCAL (var)) - v_ann->used = 1; + /* Scan DECL_INITIAL for pointer variables as they may contain + address arithmetic referencing the address of other + variables. */ + if (DECL_INITIAL (var) + && POINTER_TYPE_P (TREE_TYPE (var))) + walk_tree (&DECL_INITIAL (var), find_vars_r, walk_state, 0); } } @@ -906,112 +913,24 @@ add_referenced_var (tree var, struct walk_state *walk_state) tree get_virtual_var (tree var) { - enum tree_code code; - STRIP_NOPS (var); if (TREE_CODE (var) == SSA_NAME) var = SSA_NAME_VAR (var); - code = TREE_CODE (var); - - while (code == ARRAY_REF - || code == COMPONENT_REF - || code == REALPART_EXPR - || code == IMAGPART_EXPR) - { - var = TREE_OPERAND (var, 0); - code = TREE_CODE (var); - } + while (TREE_CODE (var) == REALPART_EXPR || TREE_CODE (var) == IMAGPART_EXPR + || handled_component_p (var)) + var = TREE_OPERAND (var, 0); -#ifdef ENABLE_CHECKING /* Treating GIMPLE registers as virtual variables makes no sense. Also complain if we couldn't extract a _DECL out of the original expression. */ - if (!SSA_VAR_P (var) - || is_gimple_reg (var)) - abort (); -#endif + gcc_assert (SSA_VAR_P (var)); + gcc_assert (!is_gimple_reg (var)); return var; } - -/* Mark variables in BLOCK that have hidden uses. A hidden use can - occur due to VLA declarations or nested functions. */ - -static void -find_hidden_use_vars (tree block) -{ - tree sub, decl, tem; - - /* Check all the arrays declared in the block for VLAs. - While scanning the block's variables, also see if there is - a nested function at this scope. */ - for (decl = BLOCK_VARS (block); decl; decl = TREE_CHAIN (decl)) - { - int inside_vla = 0; - walk_tree (&decl, find_hidden_use_vars_r, &inside_vla, NULL); - } - - /* Now repeat the search in any sub-blocks. */ - for (sub = BLOCK_SUBBLOCKS (block); sub; sub = TREE_CHAIN (sub)) - find_hidden_use_vars (sub); - - /* A VLA parameter may use a variable which as set from another - parameter to declare the size of the VLA. We need to mark the - variable as having a hidden use since it is used to declare the - VLA parameter and that declaration is not seen by the SSA code. - - Note get_pending_sizes clears the PENDING_SIZES chain, so we - must restore it. */ - tem = get_pending_sizes (); - put_pending_sizes (tem); - for (; tem; tem = TREE_CHAIN (tem)) - { - int inside_vla = 1; - walk_tree (&TREE_VALUE (tem), find_hidden_use_vars_r, &inside_vla, NULL); - } -} - - -/* Callback for walk_tree used by find_hidden_use_vars to analyze each - variable in a lexical block. If the variable's size has a variable - size, then mark all objects needed to compute the variable's size - as having hidden uses. */ - -static tree -find_hidden_use_vars_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED) -{ - int *inside_vla = (int *) data; - - /* We need to look for hidden uses due to VLAs in variable - definitions. We originally used to look for these hidden - uses in the variable's type, but that's unreliable if the - type's size contains a SAVE_EXPR for a different function - context than the variable is used within. */ - if (SSA_VAR_P (*tp) - && ((DECL_SIZE (*tp) - && ! really_constant_p (DECL_SIZE (*tp))) - || (DECL_SIZE_UNIT (*tp) - && ! really_constant_p (DECL_SIZE_UNIT (*tp))))) - { - int save = *inside_vla; - - *inside_vla = 1; - walk_tree (&DECL_SIZE (*tp), find_hidden_use_vars_r, inside_vla, NULL); - walk_tree (&DECL_SIZE_UNIT (*tp), find_hidden_use_vars_r, - inside_vla, NULL); - *inside_vla = save; - } - else if (*inside_vla && SSA_VAR_P (*tp)) - set_has_hidden_use (*tp); - - return NULL_TREE; -} - - /* Add a temporary variable to REFERENCED_VARS. This is similar to add_referenced_var, but is used by passes that need to add new temps to the REFERENCED_VARS array after the program has been scanned for @@ -1025,41 +944,18 @@ add_referenced_tmp_var (tree var) } -/* Return true if VDEFS_AFTER contains fewer entries than VDEFS_BEFORE. - Note that this assumes that both varrays are VDEF operands for the same - statement. */ - -static inline bool -vdefs_disappeared_p (vdef_optype vdefs_before, vdef_optype vdefs_after) -{ - /* If there was nothing before, nothing could've disappeared. */ - if (vdefs_before == NULL) - return false; - - /* All/some of them gone. */ - if (vdefs_after == NULL - || NUM_VDEFS (vdefs_before) > NUM_VDEFS (vdefs_after)) - return true; - - return false; -} - - /* Add all the non-SSA variables found in STMT's operands to the bitmap VARS_TO_RENAME. */ void mark_new_vars_to_rename (tree stmt, bitmap vars_to_rename) { - def_optype defs; - use_optype uses; - vdef_optype vdefs; - vuse_optype vuses; - size_t i; + ssa_op_iter iter; + tree val; bitmap vars_in_vops_to_rename; bool found_exposed_symbol = false; - vdef_optype vdefs_before, vdefs_after; - stmt_ann_t ann; + int v_may_defs_before, v_may_defs_after; + int v_must_defs_before, v_must_defs_after; vars_in_vops_to_rename = BITMAP_XMALLOC (); @@ -1072,23 +968,15 @@ mark_new_vars_to_rename (tree stmt, bitmap vars_to_rename) We flag them in a separate bitmap because we don't really want to rename them if there are not any newly exposed symbols in the statement operands. */ - ann = stmt_ann (stmt); - vdefs_before = vdefs = VDEF_OPS (ann); - for (i = 0; i < NUM_VDEFS (vdefs); i++) - { - tree var = VDEF_RESULT (vdefs, i); - if (!DECL_P (var)) - var = SSA_NAME_VAR (var); - bitmap_set_bit (vars_in_vops_to_rename, var_ann (var)->uid); - } + v_may_defs_before = NUM_V_MAY_DEFS (STMT_V_MAY_DEF_OPS (stmt)); + v_must_defs_before = NUM_V_MUST_DEFS (STMT_V_MUST_DEF_OPS (stmt)); - vuses = VUSE_OPS (ann); - for (i = 0; i < NUM_VUSES (vuses); i++) + FOR_EACH_SSA_TREE_OPERAND (val, stmt, iter, + SSA_OP_VMAYDEF | SSA_OP_VUSE | SSA_OP_VMUSTDEF) { - tree var = VUSE_OP (vuses, i); - if (!DECL_P (var)) - var = SSA_NAME_VAR (var); - bitmap_set_bit (vars_in_vops_to_rename, var_ann (var)->uid); + if (!DECL_P (val)) + val = SSA_NAME_VAR (val); + bitmap_set_bit (vars_in_vops_to_rename, var_ann (val)->uid); } /* Now force an operand re-scan on the statement and mark any newly @@ -1096,47 +984,15 @@ mark_new_vars_to_rename (tree stmt, bitmap vars_to_rename) modify_stmt (stmt); get_stmt_operands (stmt); - defs = DEF_OPS (ann); - for (i = 0; i < NUM_DEFS (defs); i++) - { - tree var = DEF_OP (defs, i); - if (DECL_P (var)) - { - found_exposed_symbol = true; - bitmap_set_bit (vars_to_rename, var_ann (var)->uid); - } - } - - uses = USE_OPS (ann); - for (i = 0; i < NUM_USES (uses); i++) - { - tree var = USE_OP (uses, i); - if (DECL_P (var)) - { - found_exposed_symbol = true; - bitmap_set_bit (vars_to_rename, var_ann (var)->uid); - } - } - - vdefs_after = vdefs = VDEF_OPS (ann); - for (i = 0; i < NUM_VDEFS (vdefs); i++) - { - tree var = VDEF_RESULT (vdefs, i); - if (DECL_P (var)) - { - found_exposed_symbol = true; - bitmap_set_bit (vars_to_rename, var_ann (var)->uid); - } - } + v_may_defs_after = NUM_V_MAY_DEFS (STMT_V_MAY_DEF_OPS (stmt)); + v_must_defs_after = NUM_V_MUST_DEFS (STMT_V_MUST_DEF_OPS (stmt)); - vuses = VUSE_OPS (ann); - for (i = 0; i < NUM_VUSES (vuses); i++) + FOR_EACH_SSA_TREE_OPERAND (val, stmt, iter, SSA_OP_ALL_OPERANDS) { - tree var = VUSE_OP (vuses, i); - if (DECL_P (var)) + if (DECL_P (val)) { found_exposed_symbol = true; - bitmap_set_bit (vars_to_rename, var_ann (var)->uid); + bitmap_set_bit (vars_to_rename, var_ann (val)->uid); } } @@ -1146,8 +1002,33 @@ mark_new_vars_to_rename (tree stmt, bitmap vars_to_rename) vanishing VDEFs because in those cases, the names that were formerly generated by this statement are not going to be available anymore. */ if (found_exposed_symbol - || vdefs_disappeared_p (vdefs_before, vdefs_after)) - bitmap_a_or_b (vars_to_rename, vars_to_rename, vars_in_vops_to_rename); + || v_may_defs_before > v_may_defs_after + || v_must_defs_before > v_must_defs_after) + bitmap_ior_into (vars_to_rename, vars_in_vops_to_rename); BITMAP_XFREE (vars_in_vops_to_rename); } + +/* Find all variables within the gimplified statement that were not previously + visible to the function and add them to the referenced variables list. */ + +static tree +find_new_referenced_vars_1 (tree *tp, int *walk_subtrees, + void *data ATTRIBUTE_UNUSED) +{ + tree t = *tp; + + if (TREE_CODE (t) == VAR_DECL && !var_ann (t)) + add_referenced_tmp_var (t); + + if (IS_TYPE_OR_DECL_P (t)) + *walk_subtrees = 0; + + return NULL; +} + +void +find_new_referenced_vars (tree *stmt_p) +{ + walk_tree (stmt_p, find_new_referenced_vars_1, NULL, NULL); +}