Index: tree-ssa-alias.c =================================================================== --- tree-ssa-alias.c (revision 117243) +++ tree-ssa-alias.c (working copy) @@ -2103,24 +2103,17 @@ 3- STMT is an assignment to a non-local variable, or 4- STMT is a return statement. - AI points to the alias information collected so far. - Return the type of escape site found, if we found one, or NO_ESCAPE if none. */ enum escape_type -is_escape_site (tree stmt, struct alias_info *ai) +is_escape_site (tree stmt) { tree call = get_call_expr_in (stmt); if (call != NULL_TREE) { - ai->num_calls_found++; - if (!TREE_SIDE_EFFECTS (call)) - { - ai->num_pure_const_calls_found++; - return ESCAPE_TO_PURE_CONST; - } + return ESCAPE_TO_PURE_CONST; return ESCAPE_TO_CALL; } Index: tree-flow.h =================================================================== --- tree-flow.h (revision 117243) +++ tree-flow.h (working copy) @@ -434,6 +434,10 @@ #define num_ssa_names (VEC_length (tree, ssa_names)) #define ssa_name(i) (VEC_index (tree, ssa_names, (i))) +/* Artificial variable used to model the existence of non-local + variables. */ +extern tree nonlocal_var; + /* Artificial variable used to model the effects of function calls. */ extern GTY(()) tree global_var; Index: tree-ssa-structalias.c =================================================================== --- tree-ssa-structalias.c (revision 117243) +++ tree-ssa-structalias.c (working copy) @@ -163,6 +163,9 @@ static GTY ((if_marked ("tree_map_marked_p"), param_is (struct tree_map))) htab_t heapvar_for_stmt; + +/* Variable to represent nonlocals. */ +tree nonlocal_var; static bool use_field_sensitive = true; static int in_ipa_mode = 0; static bitmap_obstack predbitmap_obstack; @@ -312,6 +315,11 @@ static tree integer_tree; static unsigned int integer_id; +/* Variable that represents escaped variables. This is used to give + incoming pointer variables a better set than ANYTHING. */ +static varinfo_t var_escaped_vars; +static tree escaped_vars_tree; +static unsigned int escaped_vars_id; /* Lookup a heap var for FROM, and return it if we find one. */ @@ -342,7 +350,7 @@ h->to = to; loc = htab_find_slot_with_hash (heapvar_for_stmt, h, h->hash, INSERT); *(struct tree_map **) loc = h; -} +} /* Return a new variable info structure consisting for a variable named NAME, and using constraint graph node NODE. */ @@ -2027,54 +2035,70 @@ bitmap_iterator bi; VEC(constraint_t,heap) *complex = get_varinfo (i)->complex; VEC(constraint_edge_t,heap) *succs; + bool solution_empty; RESET_BIT (changed, i); changed_count--; + solution = get_varinfo (i)->solution; + solution_empty = bitmap_empty_p (solution); + /* Process the complex constraints */ - solution = get_varinfo (i)->solution; for (j = 0; VEC_iterate (constraint_t, complex, j, c); j++) - do_complex_constraint (graph, c, solution); + { + /* The only complex constraint that can change our + solution to non-empty, given an empty solution, + is a constraint where the lhs side is receiving + some set from elsewhere. */ + if (!solution_empty || c->lhs.type != DEREF) + do_complex_constraint (graph, c, solution); + } - /* Propagate solution to all successors. */ - succs = graph->succs[i]; - - EXECUTE_IF_IN_NONNULL_BITMAP (graph->zero_weight_succs[i], 0, j, bi) + solution_empty = bitmap_empty_p (solution); + + if (!solution_empty) { - bitmap tmp = get_varinfo (j)->solution; - bool flag = false; + /* Propagate solution to all successors. */ + succs = graph->succs[i]; - flag = set_union_with_increment (tmp, solution, 0); + EXECUTE_IF_IN_NONNULL_BITMAP (graph->zero_weight_succs[i], + 0, j, bi) + { + bitmap tmp = get_varinfo (j)->solution; + bool flag = false; - if (flag) - { - get_varinfo (j)->solution = tmp; - if (!TEST_BIT (changed, j)) + flag = set_union_with_increment (tmp, solution, 0); + + if (flag) { - SET_BIT (changed, j); - changed_count++; + get_varinfo (j)->solution = tmp; + if (!TEST_BIT (changed, j)) + { + SET_BIT (changed, j); + changed_count++; + } } } - } - for (j = 0; VEC_iterate (constraint_edge_t, succs, j, e); j++) - { - bitmap tmp = get_varinfo (e->dest)->solution; - bool flag = false; - unsigned int k; - bitmap weights = e->weights; - bitmap_iterator bi; + for (j = 0; VEC_iterate (constraint_edge_t, succs, j, e); j++) + { + bitmap tmp = get_varinfo (e->dest)->solution; + bool flag = false; + unsigned int k; + bitmap weights = e->weights; + bitmap_iterator bi; - gcc_assert (weights && !bitmap_empty_p (weights)); - EXECUTE_IF_SET_IN_BITMAP (weights, 0, k, bi) - flag |= set_union_with_increment (tmp, solution, k); + gcc_assert (weights && !bitmap_empty_p (weights)); + EXECUTE_IF_SET_IN_BITMAP (weights, 0, k, bi) + flag |= set_union_with_increment (tmp, solution, k); - if (flag) - { - get_varinfo (e->dest)->solution = tmp; - if (!TEST_BIT (changed, e->dest)) + if (flag) { - SET_BIT (changed, e->dest); - changed_count++; + get_varinfo (e->dest)->solution = tmp; + if (!TEST_BIT (changed, e->dest)) + { + SET_BIT (changed, e->dest); + changed_count++; + } } } } @@ -2297,7 +2321,20 @@ } } +/* Return true if T is a variable of a type that could contain + pointers. */ +static bool +could_have_pointers (tree t) +{ + tree type = TREE_TYPE (t); + + if (POINTER_TYPE_P (type) || AGGREGATE_TYPE_P (type) + || TREE_CODE (type) == COMPLEX_TYPE) + return true; + return false; +} + /* Return the position, in bits, of FIELD_DECL from the beginning of its structure. */ @@ -2364,6 +2401,8 @@ } t = get_ref_base_and_extent (t, &bitpos, &bitsize, &bitmaxsize); + if (TREE_CODE (t) == STRING_CST) + return; get_constraint_for (t, results); result = VEC_last (ce_s, *results); result->offset = bitpos; @@ -2482,7 +2521,7 @@ VEC_safe_push (ce_s, heap, *results, &temp); return; } - + switch (TREE_CODE_CLASS (TREE_CODE (t))) { case tcc_expression: @@ -2507,6 +2546,9 @@ varinfo_t origvar; struct constraint_expr tmp; + if (VEC_length (ce_s, *results) == 0) + return; + gcc_assert (VEC_length (ce_s, *results) == 1); origrhs = VEC_last (ce_s, *results); tmp = *origrhs; @@ -2549,7 +2591,6 @@ } break; case CALL_EXPR: - /* XXX: In interprocedural mode, if we didn't have the body, we would need to do *each pointer argument = &ANYTHING added. */ @@ -2578,7 +2619,16 @@ VEC_safe_push (ce_s, heap, *results, &temp); return; } - /* FALLTHRU */ + else + { + temp.var = escaped_vars_id; + temp.type = SCALAR; + temp.offset = 0; + VEC_safe_push (ce_s, heap, *results, &temp); + return; + } + break; + default: { temp.type = ADDRESSOF; @@ -2974,9 +3024,17 @@ bitmap addr_taken; use_operand_p use_p; ssa_op_iter iter; - enum escape_type stmt_escape_type = is_escape_site (stmt, ai); + enum escape_type stmt_escape_type = is_escape_site (stmt); tree op; + if (stmt_escape_type == ESCAPE_TO_CALL + || stmt_escape_type == ESCAPE_TO_PURE_CONST) + { + ai->num_calls_found++; + if (stmt_escape_type == ESCAPE_TO_PURE_CONST) + ai->num_pure_const_calls_found++; + } + /* Mark all the variables whose address are taken by the statement. */ addr_taken = addresses_taken (stmt); if (addr_taken) @@ -3257,8 +3315,7 @@ /* Only care about pointers and structures containing pointers. */ - if (POINTER_TYPE_P (TREE_TYPE (PHI_RESULT (t))) - || TREE_CODE (TREE_TYPE (PHI_RESULT (t))) == COMPLEX_TYPE) + if (could_have_pointers (PHI_RESULT (t))) { int i; unsigned int j; @@ -3407,9 +3464,7 @@ { /* Only care about operations with pointers, structures containing pointers, dereferences, and call expressions. */ - if (POINTER_TYPE_P (TREE_TYPE (lhsop)) - || AGGREGATE_TYPE_P (TREE_TYPE (lhsop)) - || TREE_CODE (TREE_TYPE (lhsop)) == COMPLEX_TYPE + if (could_have_pointers (lhsop) || TREE_CODE (rhsop) == CALL_EXPR) { get_constraint_for (lhsop, &lhsc); @@ -3712,8 +3767,9 @@ return count; } +/* Create a constraint from ESCAPED_VARS variable to VI. */ static void -make_constraint_to_anything (varinfo_t vi) +make_constraint_from_escaped (varinfo_t vi) { struct constraint_expr lhs, rhs; @@ -3721,12 +3777,27 @@ lhs.offset = 0; lhs.type = SCALAR; - rhs.var = anything_id; - rhs.offset =0 ; - rhs.type = ADDRESSOF; + rhs.var = escaped_vars_id; + rhs.offset = 0; + rhs.type = SCALAR; process_constraint (new_constraint (lhs, rhs)); } +/* Create a constraint to the ESCAPED_VARS variable from constraint + expression RHS. */ + +static void +make_constraint_to_escaped (struct constraint_expr rhs) +{ + struct constraint_expr lhs; + + lhs.var = escaped_vars_id; + lhs.offset = 0; + lhs.type = SCALAR; + + process_constraint (new_constraint (lhs, rhs)); +} + /* Count the number of arguments DECL has, and set IS_VARARGS to true if it is a varargs function. */ @@ -3876,6 +3947,45 @@ } return false; } + +static tree +find_global_initializers (tree *tp, int *walk_subtrees, void *viv) +{ + varinfo_t vi = (varinfo_t)viv; + tree t = *tp; + + switch (TREE_CODE (t)) + { + case INDIRECT_REF: + case ADDR_EXPR: + { + struct constraint_expr *c; + size_t i; + + VEC(ce_s, heap) *rhsc = NULL; + get_constraint_for (t, &rhsc); + for (i = 0; VEC_iterate (ce_s, rhsc, i, c); i++) + { + struct constraint_expr lhs; + + lhs.var = vi->id; + lhs.type = SCALAR; + lhs.offset = 0; + process_constraint (new_constraint (lhs, *c)); + } + + VEC_free (ce_s, heap, rhsc); + *walk_subtrees = 0; + return NULL_TREE; + } + break; + default: + break; + } + return NULL_TREE; +} + + /* Create a varinfo structure for NAME and DECL, and add it to VARMAP. This will also create any varinfo structures necessary for fields of DECL. */ @@ -3933,7 +4043,19 @@ insert_id_for_tree (vi->decl, index); VEC_safe_push (varinfo_t, heap, varmap, vi); if (is_global && (!flag_whole_program || !in_ipa_mode)) - make_constraint_to_anything (vi); + { + struct constraint_expr rhs; + + make_constraint_from_escaped (vi); + rhs.var = index; + rhs.type = ADDRESSOF; + rhs.offset = 0; + make_constraint_to_escaped (rhs); + if (DECL_INITIAL (decl)) + walk_tree_without_duplicates (&DECL_INITIAL (decl), + find_global_initializers, + (void *)vi); + } stats.total_vars++; if (use_field_sensitive @@ -4013,8 +4135,16 @@ insert_into_field_list (vi, newvi); VEC_safe_push (varinfo_t, heap, varmap, newvi); if (is_global && (!flag_whole_program || !in_ipa_mode)) - make_constraint_to_anything (newvi); - + { + struct constraint_expr rhs; + + rhs.var = newindex; + rhs.type = ADDRESSOF; + rhs.offset = 0; + make_constraint_to_escaped (rhs); + make_constraint_from_escaped (newvi); + } + stats.total_vars++; } VEC_free (fieldoff_s, heap, fieldstack); @@ -4047,7 +4177,6 @@ dump_solution_for_var (stdout, var); } - /* Create varinfo structures for all of the variables in the function for intraprocedural mode. */ @@ -4056,16 +4185,18 @@ { tree t; - /* For each incoming argument arg, ARG = &ANYTHING or a dummy variable if - flag_argument_noalias > 2. */ + /* For each incoming pointer argument arg, ARG = ESCAPED_VARS or a + dummy variable if flag_argument_noalias > 2. */ for (t = DECL_ARGUMENTS (current_function_decl); t; t = TREE_CHAIN (t)) { - struct constraint_expr lhs; + struct constraint_expr lhs, rhs; varinfo_t p; + unsigned int arg_id; - lhs.offset = 0; - lhs.type = SCALAR; - lhs.var = create_variable_info_for (t, alias_get_name (t)); + if (!could_have_pointers (t)) + continue; + + arg_id = create_variable_info_for (t, alias_get_name (t)); /* With flag_argument_noalias greater than two means that the incoming argument cannot alias anything except for itself so create a HEAP @@ -4074,9 +4205,13 @@ && flag_argument_noalias > 2) { varinfo_t vi; - struct constraint_expr rhs; tree heapvar = heapvar_lookup (t); unsigned int id; + + lhs.offset = 0; + lhs.type = SCALAR; + lhs.var = create_variable_info_for (t, alias_get_name (t)); + if (heapvar == NULL_TREE) { heapvar = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (t)), @@ -4102,8 +4237,10 @@ } } else - for (p = get_varinfo (lhs.var); p; p = p->next) - make_constraint_to_anything (p); + { + for (p = get_varinfo (arg_id); p; p = p->next) + make_constraint_from_escaped (p); + } } } @@ -4290,6 +4427,8 @@ init_base_vars (void) { struct constraint_expr lhs, rhs; + unsigned int nonlocal_id; + varinfo_t nonlocal; /* Create the NULL variable, used to represent that a variable points to NULL. */ @@ -4375,8 +4514,8 @@ integer_id = 3; VEC_safe_push (varinfo_t, heap, varmap, var_integer); - /* *INTEGER = ANYTHING, because we don't know where a dereference of a random - integer will point to. */ + /* INTEGER = ANYTHING, because we don't know where a dereference of + a random integer will point to. */ lhs.type = SCALAR; lhs.var = integer_id; lhs.offset = 0; @@ -4384,6 +4523,47 @@ rhs.var = anything_id; rhs.offset = 0; process_constraint (new_constraint (lhs, rhs)); + + /* Create the ESCAPED_VARS variable used to represent variables that + escape this function. */ + escaped_vars_tree = create_tmp_var_raw (void_type_node, "ESCAPED_VARS"); + var_escaped_vars = new_var_info (escaped_vars_tree, 4, "ESCAPED_VARS", 4); + insert_id_for_tree (escaped_vars_tree, 4); + var_escaped_vars->is_artificial_var = 1; + var_escaped_vars->size = ~0; + var_escaped_vars->fullsize = ~0; + var_escaped_vars->offset = 0; + var_escaped_vars->next = NULL; + escaped_vars_id = 4; + VEC_safe_push (varinfo_t, heap, varmap, var_escaped_vars); + + /* ESCAPED_VARS = *ESCAPED_VARS */ + lhs.type = SCALAR; + lhs.var = escaped_vars_id; + lhs.offset = 0; + rhs.type = DEREF; + rhs.var = escaped_vars_id; + rhs.offset = 0; + process_constraint (new_constraint (lhs, rhs)); + + /* Create variable info for the nonlocal var if it does not + exist. */ + nonlocal_id = create_variable_info_for (nonlocal_var, + get_name (nonlocal_var)); + nonlocal = get_varinfo (nonlocal_id); + nonlocal->is_artificial_var = 1; + nonlocal->is_heap_var = 1; + nonlocal->is_unknown_size_var = 1; + + rhs.var = nonlocal_id; + rhs.type = ADDRESSOF; + rhs.offset = 0; + + lhs.var = escaped_vars_id; + lhs.type = SCALAR; + lhs.offset = 0; + + process_constraint (new_constraint (lhs, rhs)); } /* Return true if we actually need to solve the constraint graph in order to @@ -4447,7 +4627,106 @@ init_base_vars (); } +/* Given a statement stmt, generate necessary constraints to + escaped_vars for the escaping variables. */ +static void +find_escape_constraints (tree stmt) +{ + enum escape_type stmt_escape_type = is_escape_site (stmt); + tree rhs; + VEC(ce_s, heap) *rhsc = NULL; + struct constraint_expr *c; + size_t i; + + if (stmt_escape_type == NO_ESCAPE) + return; + + if (TREE_CODE (stmt) == RETURN_EXPR) + { + /* Returns are either bare, with an embedded MODIFY_EXPR, or + just a plain old expression. */ + if (!TREE_OPERAND (stmt, 0)) + return; + if (TREE_CODE (TREE_OPERAND (stmt, 0)) == MODIFY_EXPR) + rhs = TREE_OPERAND (TREE_OPERAND (stmt, 0), 1); + else + rhs = TREE_OPERAND (stmt, 0); + + get_constraint_for (rhs, &rhsc); + for (i = 0; VEC_iterate (ce_s, rhsc, i, c); i++) + make_constraint_to_escaped (*c); + VEC_free (ce_s, heap, rhsc); + return; + } + else if (TREE_CODE (stmt) == ASM_EXPR) + { + /* Whatever the inputs of the ASM are, escape. */ + tree arg; + + for (arg = ASM_INPUTS (stmt); arg; arg = TREE_CHAIN (arg)) + { + rhsc = NULL; + get_constraint_for (TREE_VALUE (arg), &rhsc); + for (i = 0; VEC_iterate (ce_s, rhsc, i, c); i++) + make_constraint_to_escaped (*c); + VEC_free (ce_s, heap, rhsc); + } + return; + } + else if (TREE_CODE (stmt) == CALL_EXPR + || (TREE_CODE (stmt) == MODIFY_EXPR + && TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR)) + { + /* Calls cause all of the arguments passed in to escape. */ + tree arg; + + if (TREE_CODE (stmt) == MODIFY_EXPR) + stmt = TREE_OPERAND (stmt, 1); + for (arg = TREE_OPERAND (stmt, 1); arg; arg = TREE_CHAIN (arg)) + { + if (POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arg)))) + { + rhsc = NULL; + get_constraint_for (TREE_VALUE (arg), &rhsc); + for (i = 0; VEC_iterate (ce_s, rhsc, i, c); i++) + make_constraint_to_escaped (*c); + VEC_free (ce_s, heap, rhsc); + } + } + return; + } + else + { + gcc_assert (TREE_CODE (stmt) == MODIFY_EXPR); + } + + gcc_assert (stmt_escape_type == ESCAPE_BAD_CAST + || stmt_escape_type == ESCAPE_STORED_IN_GLOBAL + || stmt_escape_type == ESCAPE_UNKNOWN); + rhs = TREE_OPERAND (stmt, 1); + + /* Look through casts for the real escaping variable. + Constants don't really escape, so ignore them. + Otherwise, whatever escapes must be on our RHS. */ + if (TREE_CODE (rhs) == NOP_EXPR + || TREE_CODE (rhs) == CONVERT_EXPR + || TREE_CODE (rhs) == NON_LVALUE_EXPR) + { + get_constraint_for (TREE_OPERAND (rhs, 0), &rhsc); + } + else if (CONSTANT_CLASS_P (rhs)) + return; + else + { + get_constraint_for (rhs, &rhsc); + } + + for (i = 0; VEC_iterate (ce_s, rhsc, i, c); i++) + make_constraint_to_escaped (*c); + VEC_free (ce_s, heap, rhsc); +} + /* Create points-to sets for the current function. See the comments at the start of the file for an algorithmic overview. */ @@ -4484,11 +4763,13 @@ for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) { tree stmt = bsi_stmt (bsi); + find_func_aliases (stmt); - /* Update various related attributes like escaped - addresses, pointer dereferences for loads and stores. - This is used when creating name tags and alias - sets. */ + find_escape_constraints (stmt); + /* Update various related attributes like escaped + addresses, pointer dereferences for loads and stores. + This is used when creating name tags and alias + sets. */ update_alias_info (stmt, ai); } } @@ -4590,7 +4871,7 @@ { varinfo_t fi = get_varinfo (varid); for (; fi; fi = fi->next) - make_constraint_to_anything (fi); + make_constraint_from_escaped (fi); } } } @@ -4690,12 +4971,16 @@ init_alias_heapvars (void) { heapvar_for_stmt = htab_create_ggc (11, tree_map_hash, tree_map_eq, NULL); + nonlocal_var = create_tmp_var_raw (void_type_node, "NONLOCAL"); + if (referenced_vars) + add_referenced_var (nonlocal_var); + DECL_EXTERNAL (nonlocal_var) = 1; } void delete_alias_heapvars (void) { - htab_delete (heapvar_for_stmt); + htab_delete (heapvar_for_stmt); } Index: tree-ssa-structalias.h =================================================================== --- tree-ssa-structalias.h (revision 117243) +++ tree-ssa-structalias.h (working copy) @@ -81,7 +81,7 @@ #define NUM_REFERENCES_SET(ANN, VAL) (ANN)->common.aux = (void*) ((void *)(VAL)) /* In tree-ssa-alias.c. */ -enum escape_type is_escape_site (tree, struct alias_info *); +enum escape_type is_escape_site (tree); /* In tree-ssa-structalias.c. */ extern void compute_points_to_sets (struct alias_info *); Index: tree-ssa-operands.c =================================================================== --- tree-ssa-operands.c (revision 117243) +++ tree-ssa-operands.c (working copy) @@ -1047,6 +1047,12 @@ unsigned HOST_WIDE_INT uoffset = (unsigned HOST_WIDE_INT) offset; tree base = ref ? get_base_address (ref) : NULL; + /* We can't prune out any accesses to the non-local variable, + because it is just a proxy representing possible non-local + variables. */ + if (alias == nonlocal_var) + return true; + /* If ALIAS is .GLOBAL_VAR then the memory reference REF must be using a call-clobbered memory tag. By definition, call-clobbered memory tags can always touch .GLOBAL_VAR. */