From b7091901cd984928b3599dc62507045dee1754d6 Mon Sep 17 00:00:00 2001 From: Richard Guenther Date: Fri, 27 Jun 2008 18:53:43 +0000 Subject: [PATCH] re PR tree-optimization/36400 (points-to results wrong) 2008-06-27 Richard Guenther PR tree-optimization/36400 PR tree-optimization/36373 PR tree-optimization/36344 * tree-ssa-structalias.c (var_escaped, escaped_tree, escaped_id, var_nonlocal, nonlocal_tree, nonlocal_id): New globals (update_alias_info): Remove call clobbering code. (make_constraint_to): New helper function. (make_escape_constraint): Likewise. (handle_rhs_call): Use it on all pointer containing arguments. Also mark the static chain escaped. (handle_lhs_call): Make constraints from NONLOCAL and ESCAPED instead of ANYTHING. (make_constraint_from): New helper split out from ... (make_constraint_from_anything): ... here. (find_func_aliases): Add constraints for escape sites. (intra_create_variable_infos): Make constraints from NONLOCAL for parameters. (find_what_p_points_to): Interpret NONLOCAL and ESCAPED the same as ANYTHING. (clobber_what_p_points_to): Remove. (clobber_what_escaped): New function. (init_base_vars): Init NONLOCAL and ESCAPED. (do_sd_constraint): Do not propagate the solution from ESCAPED but use ESCAPED as a placeholder. (solve_graph): Likewise. * tree-flow.h (clobber_what_p_points_to): Remove. (clobber_what_escaped): Declare. * tree-ssa-alias.c (set_initial_properties): Call it. Remove code clobbering escaped pointers. * gcc.dg/torture/pr36373-1.c: New testcase. * gcc.dg/torture/pr36373-2.c: Likewise. * gcc.dg/torture/pr36373-3.c: Likewise. * gcc.dg/torture/pr36373-4.c: Likewise. * gcc.dg/torture/pr36373-5.c: Likewise. * gcc.dg/torture/pr36373-6.c: Likewise. * gcc.dg/torture/pr36373-7.c: Likewise. * gcc.dg/torture/pr36373-8.c: Likewise. * gcc.dg/torture/pr36373-9.c: Likewise. * gcc.dg/torture/pr36373-10.c: Likewise. * gcc.dg/torture/pr36400.c: Likewise. * gcc.c-torture/execute/pta-field-1.c: Likewise. * gcc.c-torture/execute/pta-field-2.c: Likewise. * gcc.dg/tree-ssa/loadpre8.c: Remove XFAIL. * gcc.dg/tree-ssa/pr24287.c: XFAIL. From-SVN: r137197 --- gcc/ChangeLog | 32 ++ gcc/testsuite/ChangeLog | 21 ++ gcc/testsuite/gcc.dg/tree-ssa/loadpre8.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/pr24287.c | 2 +- gcc/tree-flow.h | 2 +- gcc/tree-ssa-alias.c | 24 +- gcc/tree-ssa-structalias.c | 383 +++++++++++++++++------ 7 files changed, 353 insertions(+), 113 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c8ddda0b721..f1279f8b7af 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,35 @@ +2008-06-27 Richard Guenther + + PR tree-optimization/36400 + PR tree-optimization/36373 + PR tree-optimization/36344 + * tree-ssa-structalias.c (var_escaped, escaped_tree, escaped_id, + var_nonlocal, nonlocal_tree, nonlocal_id): New globals + (update_alias_info): Remove call clobbering code. + (make_constraint_to): New helper function. + (make_escape_constraint): Likewise. + (handle_rhs_call): Use it on all pointer containing arguments. + Also mark the static chain escaped. + (handle_lhs_call): Make constraints from NONLOCAL and ESCAPED + instead of ANYTHING. + (make_constraint_from): New helper split out from ... + (make_constraint_from_anything): ... here. + (find_func_aliases): Add constraints for escape sites. + (intra_create_variable_infos): Make constraints from NONLOCAL + for parameters. + (find_what_p_points_to): Interpret NONLOCAL and ESCAPED the same + as ANYTHING. + (clobber_what_p_points_to): Remove. + (clobber_what_escaped): New function. + (init_base_vars): Init NONLOCAL and ESCAPED. + (do_sd_constraint): Do not propagate the solution from ESCAPED + but use ESCAPED as a placeholder. + (solve_graph): Likewise. + * tree-flow.h (clobber_what_p_points_to): Remove. + (clobber_what_escaped): Declare. + * tree-ssa-alias.c (set_initial_properties): Call it. + Remove code clobbering escaped pointers. + 2008-06-27 Richard Sandiford * function.c (allocate_struct_function): Only allocate a unique diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 64384d5621a..086345b87ca 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,24 @@ +2008-06-27 Richard Guenther + + PR tree-optimization/36400 + PR tree-optimization/36373 + PR tree-optimization/36344 + * gcc.dg/torture/pr36373-1.c: New testcase. + * gcc.dg/torture/pr36373-2.c: Likewise. + * gcc.dg/torture/pr36373-3.c: Likewise. + * gcc.dg/torture/pr36373-4.c: Likewise. + * gcc.dg/torture/pr36373-5.c: Likewise. + * gcc.dg/torture/pr36373-6.c: Likewise. + * gcc.dg/torture/pr36373-7.c: Likewise. + * gcc.dg/torture/pr36373-8.c: Likewise. + * gcc.dg/torture/pr36373-9.c: Likewise. + * gcc.dg/torture/pr36373-10.c: Likewise. + * gcc.dg/torture/pr36400.c: Likewise. + * gcc.c-torture/execute/pta-field-1.c: Likewise. + * gcc.c-torture/execute/pta-field-2.c: Likewise. + * gcc.dg/tree-ssa/loadpre8.c: Remove XFAIL. + * gcc.dg/tree-ssa/pr24287.c: XFAIL. + 2008-06-27 Eric Botcazou * gnat.dg/aggr9.ad[sb]: New test. diff --git a/gcc/testsuite/gcc.dg/tree-ssa/loadpre8.c b/gcc/testsuite/gcc.dg/tree-ssa/loadpre8.c index 6be2b3ec7fd..056c3fd6354 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/loadpre8.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/loadpre8.c @@ -93,5 +93,5 @@ rewrite_add_phi_arguments (basic_block bb) get_reaching_def ((get_def_from_ptr (get_phi_result_ptr (phi)))->ssa_name.var); } } -/* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre" { xfail *-*-* } } } */ +/* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre" } } */ /* { dg-final { cleanup-tree-dump "pre" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr24287.c b/gcc/testsuite/gcc.dg/tree-ssa/pr24287.c index 8e7f18691dc..c4b172295b4 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr24287.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr24287.c @@ -21,5 +21,5 @@ int g(void) link_error (); return t2 == 2; } -/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized"} } */ +/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" { xfail *-*-* } } } */ /* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h index 855f0807951..15329ac002e 100644 --- a/gcc/tree-flow.h +++ b/gcc/tree-flow.h @@ -1173,7 +1173,7 @@ tree gimple_fold_indirect_ref (tree); /* In tree-ssa-structalias.c */ bool find_what_p_points_to (tree); -bool clobber_what_p_points_to (tree); +bool clobber_what_escaped (void); /* In tree-ssa-live.c */ extern void remove_unused_locals (void); diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index 748ff31684e..7c24739e407 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -537,6 +537,12 @@ set_initial_properties (struct alias_info *ai) } } + if (!clobber_what_escaped ()) + { + any_pt_anything = true; + pt_anything_mask |= ESCAPE_TO_CALL; + } + for (i = 0; VEC_iterate (tree, ai->processed_ptrs, i, ptr); i++) { struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr); @@ -557,18 +563,6 @@ set_initial_properties (struct alias_info *ai) if (tag) mark_call_clobbered (tag, pi->escape_mask); - - /* Defer to points-to analysis if possible, otherwise - clobber all addressable variables. Parameters cannot - point to local memory though. - ??? Properly tracking which pointers point to non-local - memory only would make a big difference here. */ - if (!clobber_what_p_points_to (ptr) - && !(pi->escape_mask & ESCAPE_IS_PARM)) - { - any_pt_anything = true; - pt_anything_mask |= pi->escape_mask; - } } /* If the name tag is call clobbered, so is the symbol tag @@ -2906,6 +2900,12 @@ is_escape_site (tree stmt) if (TREE_CODE (lhs) == SSA_NAME) return NO_ESCAPE; + /* If the LHS is a non-global decl, it isn't a non-local memory store. + If the LHS escapes, the RHS escape is dealt with in the PTA solver. */ + if (DECL_P (lhs) + && !is_global_var (lhs)) + return NO_ESCAPE; + /* FIXME: LHS is not an SSA_NAME. Even if it's an assignment to a local variables we cannot be sure if it will escape, because we don't have information about objects not in SSA form. Need to diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index a9eaa97c52c..2b6c56fa1a7 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -294,26 +294,34 @@ get_varinfo_fc (unsigned int n) return v; } +/* Static IDs for the special variables. */ +enum { nothing_id = 0, anything_id = 1, readonly_id = 2, + escaped_id = 3, nonlocal_id = 4, integer_id = 5 }; + /* Variable that represents the unknown pointer. */ static varinfo_t var_anything; static tree anything_tree; -static unsigned int anything_id; /* Variable that represents the NULL pointer. */ static varinfo_t var_nothing; static tree nothing_tree; -static unsigned int nothing_id; /* Variable that represents read only memory. */ static varinfo_t var_readonly; static tree readonly_tree; -static unsigned int readonly_id; + +/* Variable that represents escaped memory. */ +static varinfo_t var_escaped; +static tree escaped_tree; + +/* Variable that represents nonlocal memory. */ +static varinfo_t var_nonlocal; +static tree nonlocal_tree; /* Variable that represents integers. This is used for when people do things like &0->a.b. */ static varinfo_t var_integer; static tree integer_tree; -static unsigned int integer_id; /* Lookup a heap var for FROM, and return it if we find one. */ @@ -1399,6 +1407,7 @@ do_sd_constraint (constraint_graph_t graph, constraint_t c, bitmap_set_bit (sol, anything_id); goto done; } + /* For each variable j in delta (Sol(y)), add an edge in the graph from j to x, and union Sol(j) into Sol(x). */ EXECUTE_IF_SET_IN_BITMAP (delta, 0, j, bi) @@ -1417,8 +1426,16 @@ do_sd_constraint (constraint_graph_t graph, constraint_t c, /* Adding edges from the special vars is pointless. They don't have sets that can change. */ - if (get_varinfo (t) ->is_special_var) + if (get_varinfo (t)->is_special_var) flag |= bitmap_ior_into (sol, get_varinfo (t)->solution); + /* Merging the solution from ESCAPED needlessly increases + the set. Use ESCAPED as representative instead. */ + else if (get_varinfo (t)->id == escaped_id + && !bitmap_bit_p (sol, get_varinfo (t)->id)) + { + bitmap_set_bit (sol, escaped_id); + flag = true; + } else if (add_graph_edge (graph, lhs, t)) flag |= bitmap_ior_into (sol, get_varinfo (t)->solution); } @@ -2351,7 +2368,9 @@ solve_graph (constraint_graph_t graph) solution_empty = bitmap_empty_p (solution); - if (!solution_empty) + if (!solution_empty + /* Do not propagate the ESCAPED solution. */ + && i != escaped_id) { bitmap_iterator bi; @@ -3271,24 +3290,7 @@ update_alias_info (tree stmt, struct alias_info *ai) /* Mark all the variables whose address are taken by the statement. */ addr_taken = addresses_taken (stmt); if (addr_taken) - { - bitmap_ior_into (gimple_addressable_vars (cfun), addr_taken); - - /* If STMT is an escape point, all the addresses taken by it are - call-clobbered. */ - if (stmt_escape_type != NO_ESCAPE) - { - bitmap_iterator bi; - unsigned i; - - EXECUTE_IF_SET_IN_BITMAP (addr_taken, 0, i, bi) - { - tree rvar = referenced_var (i); - if (!unmodifiable_var_p (rvar)) - mark_call_clobbered (rvar, stmt_escape_type); - } - } - } + bitmap_ior_into (gimple_addressable_vars (cfun), addr_taken); /* Process each operand use. For pointers, determine whether they are dereferenced by the statement, or whether their value @@ -3573,6 +3575,34 @@ handle_ptr_arith (VEC (ce_s, heap) *lhsc, tree expr) return true; } +/* Create a constraint ID = OP. */ + +static void +make_constraint_to (unsigned id, tree op) +{ + VEC(ce_s, heap) *rhsc = NULL; + struct constraint_expr *c; + struct constraint_expr includes; + unsigned int j; + + includes.var = id; + includes.offset = 0; + includes.type = SCALAR; + + get_constraint_for (op, &rhsc); + for (j = 0; VEC_iterate (ce_s, rhsc, j, c); j++) + process_constraint_1 (new_constraint (includes, *c), true); + VEC_free (ce_s, heap, rhsc); +} + +/* Make constraints necessary to make OP escape. */ + +static void +make_escape_constraint (tree op) +{ + make_constraint_to (escaped_id, op); +} + /* For non-IPA mode, generate constraints necessary for a call on the RHS. */ @@ -3581,35 +3611,21 @@ handle_rhs_call (tree rhs) { tree arg; call_expr_arg_iterator iter; - struct constraint_expr rhsc; - - rhsc.var = anything_id; - rhsc.offset = 0; - rhsc.type = ADDRESSOF; FOR_EACH_CALL_EXPR_ARG (arg, iter, rhs) - { - VEC(ce_s, heap) *lhsc = NULL; - - /* Find those pointers being passed, and make sure they end up - pointing to anything. */ - if (POINTER_TYPE_P (TREE_TYPE (arg))) - { - unsigned int j; - struct constraint_expr *lhsp; - - get_constraint_for (arg, &lhsc); - do_deref (&lhsc); - for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++) - process_constraint_1 (new_constraint (*lhsp, rhsc), true); - VEC_free (ce_s, heap, lhsc); - } - } + /* Find those pointers being passed, and make sure they end up + pointing to anything. */ + if (could_have_pointers (arg)) + make_escape_constraint (arg); + + /* The static chain escapes as well. */ + if (CALL_EXPR_STATIC_CHAIN (rhs)) + make_escape_constraint (CALL_EXPR_STATIC_CHAIN (rhs)); } /* For non-IPA mode, generate constraints necessary for a call that returns a pointer and assigns it to LHS. This simply makes - the LHS point to anything. */ + the LHS point to global and escaped variables. */ static void handle_lhs_call (tree lhs) @@ -3619,12 +3635,70 @@ handle_lhs_call (tree lhs) unsigned int j; struct constraint_expr *lhsp; - rhsc.var = anything_id; + get_constraint_for (lhs, &lhsc); + rhsc.var = nonlocal_id; + rhsc.offset = 0; + rhsc.type = ADDRESSOF; + for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++) + process_constraint_1 (new_constraint (*lhsp, rhsc), true); + rhsc.var = escaped_id; rhsc.offset = 0; rhsc.type = ADDRESSOF; + for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++) + process_constraint_1 (new_constraint (*lhsp, rhsc), true); + VEC_free (ce_s, heap, lhsc); +} + +/* For non-IPA mode, generate constraints necessary for a call of a + const function that returns a pointer in the statement STMT. */ + +static void +handle_const_call (tree stmt) +{ + tree lhs = GIMPLE_STMT_OPERAND (stmt, 0); + tree call = get_call_expr_in (stmt); + VEC(ce_s, heap) *lhsc = NULL; + struct constraint_expr rhsc; + unsigned int j; + struct constraint_expr *lhsp; + tree arg; + call_expr_arg_iterator iter; + get_constraint_for (lhs, &lhsc); + + /* If this is a nested function then it can return anything. */ + if (CALL_EXPR_STATIC_CHAIN (call)) + { + rhsc.var = anything_id; + rhsc.offset = 0; + rhsc.type = ADDRESSOF; + for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++) + process_constraint_1 (new_constraint (*lhsp, rhsc), true); + VEC_free (ce_s, heap, lhsc); + return; + } + + /* May return addresses of globals. */ + rhsc.var = nonlocal_id; + rhsc.offset = 0; + rhsc.type = ADDRESSOF; for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++) process_constraint_1 (new_constraint (*lhsp, rhsc), true); + + /* May return arguments. */ + FOR_EACH_CALL_EXPR_ARG (arg, iter, call) + if (could_have_pointers (arg)) + { + VEC(ce_s, heap) *argc = NULL; + struct constraint_expr *argp; + int i; + get_constraint_for (arg, &argc); + for (i = 0; VEC_iterate (ce_s, argc, i, argp); i++) + for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++) + process_constraint_1 (new_constraint (*lhsp, *argp), true); + VEC_free (ce_s, heap, argc); + } + VEC_free (ce_s, heap, lhsc); } @@ -3636,10 +3710,12 @@ handle_lhs_call (tree lhs) static void find_func_aliases (tree origt) { - tree t = origt; + tree call, t = origt; VEC(ce_s, heap) *lhsc = NULL; VEC(ce_s, heap) *rhsc = NULL; struct constraint_expr *c; + enum escape_type stmt_escape_type; + int flags; if (TREE_CODE (t) == RETURN_EXPR && TREE_OPERAND (t, 0)) t = TREE_OPERAND (t, 0); @@ -3688,17 +3764,26 @@ find_func_aliases (tree origt) In non-ipa mode, we need to generate constraints for each pointer passed by address. */ - else if (((TREE_CODE (t) == GIMPLE_MODIFY_STMT - && TREE_CODE (GIMPLE_STMT_OPERAND (t, 1)) == CALL_EXPR - && !(call_expr_flags (GIMPLE_STMT_OPERAND (t, 1)) - & (ECF_MALLOC | ECF_MAY_BE_ALLOCA))) - || (TREE_CODE (t) == CALL_EXPR - && !(call_expr_flags (t) - & (ECF_MALLOC | ECF_MAY_BE_ALLOCA))))) + else if ((call = get_call_expr_in (t)) != NULL_TREE + && !((flags = call_expr_flags (call)) + & (ECF_MALLOC | ECF_MAY_BE_ALLOCA))) { if (!in_ipa_mode) { - if (TREE_CODE (t) == GIMPLE_MODIFY_STMT) + /* Const functions can return their arguments and addresses + of global memory but not of escaped memory. */ + if (flags & ECF_CONST) + { + if (TREE_CODE (t) == GIMPLE_MODIFY_STMT + && could_have_pointers (GIMPLE_STMT_OPERAND (t, 1))) + handle_const_call (t); + } + /* Pure functions can return addresses in and of memory + reachable from their arguments, but they are not an escape + point for reachable memory of their arguments. But as we + do not compute call-used memory separately we cannot do + something special here. */ + else if (TREE_CODE (t) == GIMPLE_MODIFY_STMT) { handle_rhs_call (GIMPLE_STMT_OPERAND (t, 1)); if (could_have_pointers (GIMPLE_STMT_OPERAND (t, 1))) @@ -3893,6 +3978,57 @@ find_func_aliases (tree origt) get_varinfo (c->var)->no_tbaa_pruning = true; } + stmt_escape_type = is_escape_site (t); + if (stmt_escape_type == ESCAPE_STORED_IN_GLOBAL) + { + tree rhs; + gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT); + rhs = GIMPLE_STMT_OPERAND (t, 1); + if (TREE_CODE (rhs) == ADDR_EXPR) + { + tree base = get_base_address (TREE_OPERAND (rhs, 0)); + if (base + && (!DECL_P (base) + || !is_global_var (base))) + make_escape_constraint (rhs); + } + else if (TREE_CODE (rhs) == SSA_NAME + && POINTER_TYPE_P (TREE_TYPE (rhs))) + make_escape_constraint (rhs); + else if (could_have_pointers (rhs)) + make_escape_constraint (rhs); + } + else if (stmt_escape_type == ESCAPE_BAD_CAST) + { + tree rhs; + gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT); + rhs = GIMPLE_STMT_OPERAND (t, 1); + gcc_assert (CONVERT_EXPR_P (rhs) + || TREE_CODE (rhs) == VIEW_CONVERT_EXPR); + rhs = TREE_OPERAND (rhs, 0); + make_escape_constraint (rhs); + } + else if (stmt_escape_type == ESCAPE_TO_ASM) + { + tree link; + int i; + for (i = 0, link = ASM_OUTPUTS (t); link; i++, link = TREE_CHAIN (link)) + { + tree op = TREE_VALUE (link); + if (op && could_have_pointers (op)) + /* Strictly we'd only need the constraints from ESCAPED and + NONLOCAL. */ + make_escape_constraint (op); + } + for (i = 0, link = ASM_INPUTS (t); link; i++, link = TREE_CHAIN (link)) + { + tree op = TREE_VALUE (link); + if (op && could_have_pointers (op)) + /* Strictly we'd only need the constraint to ESCAPED. */ + make_escape_constraint (op); + } + } + /* After promoting variables and computing aliasing we will need to re-scan most statements. FIXME: Try to minimize the number of statements re-scanned. It's not really necessary to @@ -4118,9 +4254,10 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack, return count; } -/* Create a constraint from ANYTHING variable to VI. */ +/* Create a constraint ID = &FROM. */ + static void -make_constraint_from_anything (varinfo_t vi) +make_constraint_from (varinfo_t vi, int from) { struct constraint_expr lhs, rhs; @@ -4128,12 +4265,19 @@ make_constraint_from_anything (varinfo_t vi) lhs.offset = 0; lhs.type = SCALAR; - rhs.var = anything_id; + rhs.var = from; rhs.offset = 0; rhs.type = ADDRESSOF; process_constraint (new_constraint (lhs, rhs)); } +/* Create a constraint from ANYTHING variable to VI. */ +static void +make_constraint_from_anything (varinfo_t vi) +{ + make_constraint_from (vi, anything_id); +} + /* Count the number of arguments DECL has, and set IS_VARARGS to true if it is a varargs function. */ @@ -4478,7 +4622,7 @@ intra_create_variable_infos (void) struct constraint_expr lhs, rhs; /* For each incoming pointer argument arg, create the constraint ARG - = ANYTHING or a dummy variable if flag_argument_noalias is set. */ + = NONLOCAL or a dummy variable if flag_argument_noalias is set. */ for (t = DECL_ARGUMENTS (current_function_decl); t; t = TREE_CHAIN (t)) { varinfo_t p; @@ -4539,7 +4683,7 @@ intra_create_variable_infos (void) varinfo_t arg_vi = get_vi_for_tree (t); for (p = arg_vi; p; p = p->next) - make_constraint_from_anything (p); + make_constraint_from (p, nonlocal_id); } } } @@ -4794,7 +4938,9 @@ find_what_p_points_to (tree p) aliases. */ if (vi->id == nothing_id) pi->pt_null = 1; - else if (vi->id == anything_id) + else if (vi->id == anything_id + || vi->id == nonlocal_id + || vi->id == escaped_id) was_pt_anything = 1; else if (vi->id == readonly_id) was_pt_anything = 1; @@ -4843,42 +4989,23 @@ find_what_p_points_to (tree p) return false; } -/* Mark everything that p points to as call clobbered. Returns true - if everything is done and false if all addressable variables need to - be clobbered because p points to anything. */ +/* Mark the ESCAPED solution as call clobbered. Returns false if + pt_anything escaped which needs all locals that have their address + taken marked call clobbered as well. */ bool -clobber_what_p_points_to (tree p) +clobber_what_escaped (void) { - tree lookup_p = p; varinfo_t vi; - struct ptr_info_def *pi; unsigned int i; bitmap_iterator bi; if (!have_alias_info) return false; - /* For parameters, get at the points-to set for the actual parm - decl. */ - if (TREE_CODE (p) == SSA_NAME - && TREE_CODE (SSA_NAME_VAR (p)) == PARM_DECL - && SSA_NAME_IS_DEFAULT_DEF (p)) - lookup_p = SSA_NAME_VAR (p); - - vi = lookup_vi_for_tree (lookup_p); - if (!vi) - return false; - - /* We are asking for the points-to solution of pointers. */ - gcc_assert (!vi->is_artificial_var - && vi->size == vi->fullsize); - - pi = get_ptr_info (p); - /* This variable may have been collapsed, let's get the real - variable. */ - vi = get_varinfo (find (vi->id)); + variable for escaped_id. */ + vi = get_varinfo (find (escaped_id)); /* Mark variables in the solution call-clobbered. */ EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi) @@ -4903,12 +5030,13 @@ clobber_what_p_points_to (tree p) || TREE_CODE (vi->decl) == PARM_DECL || TREE_CODE (vi->decl) == RESULT_DECL) && !unmodifiable_var_p (vi->decl)) - mark_call_clobbered (vi->decl, pi->escape_mask); + mark_call_clobbered (vi->decl, ESCAPE_TO_CALL); } return true; } + /* Dump points-to information to OUTFILE. */ void @@ -4959,20 +5087,19 @@ init_base_vars (void) /* Create the NULL variable, used to represent that a variable points to NULL. */ nothing_tree = create_tmp_var_raw (void_type_node, "NULL"); - var_nothing = new_var_info (nothing_tree, 0, "NULL"); + var_nothing = new_var_info (nothing_tree, nothing_id, "NULL"); insert_vi_for_tree (nothing_tree, var_nothing); var_nothing->is_artificial_var = 1; var_nothing->offset = 0; var_nothing->size = ~0; var_nothing->fullsize = ~0; var_nothing->is_special_var = 1; - nothing_id = 0; VEC_safe_push (varinfo_t, heap, varmap, var_nothing); /* Create the ANYTHING variable, used to represent that a variable points to some unknown piece of memory. */ anything_tree = create_tmp_var_raw (void_type_node, "ANYTHING"); - var_anything = new_var_info (anything_tree, 1, "ANYTHING"); + var_anything = new_var_info (anything_tree, anything_id, "ANYTHING"); insert_vi_for_tree (anything_tree, var_anything); var_anything->is_artificial_var = 1; var_anything->size = ~0; @@ -4980,7 +5107,6 @@ init_base_vars (void) var_anything->next = NULL; var_anything->fullsize = ~0; var_anything->is_special_var = 1; - anything_id = 1; /* Anything points to anything. This makes deref constraints just work in the presence of linked list and other p = *p type loops, @@ -5001,7 +5127,7 @@ init_base_vars (void) /* Create the READONLY variable, used to represent that a variable points to readonly memory. */ readonly_tree = create_tmp_var_raw (void_type_node, "READONLY"); - var_readonly = new_var_info (readonly_tree, 2, "READONLY"); + var_readonly = new_var_info (readonly_tree, readonly_id, "READONLY"); var_readonly->is_artificial_var = 1; var_readonly->offset = 0; var_readonly->size = ~0; @@ -5009,7 +5135,6 @@ init_base_vars (void) var_readonly->next = NULL; var_readonly->is_special_var = 1; insert_vi_for_tree (readonly_tree, var_readonly); - readonly_id = 2; VEC_safe_push (varinfo_t, heap, varmap, var_readonly); /* readonly memory points to anything, in order to make deref @@ -5020,15 +5145,58 @@ init_base_vars (void) lhs.var = readonly_id; lhs.offset = 0; rhs.type = ADDRESSOF; - rhs.var = anything_id; + rhs.var = readonly_id; /* FIXME */ rhs.offset = 0; + process_constraint (new_constraint (lhs, rhs)); + /* Create the ESCAPED variable, used to represent the set of escaped + memory. */ + escaped_tree = create_tmp_var_raw (void_type_node, "ESCAPED"); + var_escaped = new_var_info (escaped_tree, escaped_id, "ESCAPED"); + insert_vi_for_tree (escaped_tree, var_escaped); + var_escaped->is_artificial_var = 1; + var_escaped->offset = 0; + var_escaped->size = ~0; + var_escaped->fullsize = ~0; + var_escaped->is_special_var = 0; + VEC_safe_push (varinfo_t, heap, varmap, var_escaped); + gcc_assert (VEC_index (varinfo_t, varmap, 3) == var_escaped); + + /* ESCAPED = *ESCAPED, because escaped is may-deref'd at calls, etc. */ + lhs.type = SCALAR; + lhs.var = escaped_id; + lhs.offset = 0; + rhs.type = DEREF; + rhs.var = escaped_id; + rhs.offset = 0; + process_constraint_1 (new_constraint (lhs, rhs), true); + + /* Create the NONLOCAL variable, used to represent the set of nonlocal + memory. */ + nonlocal_tree = create_tmp_var_raw (void_type_node, "NONLOCAL"); + var_nonlocal = new_var_info (nonlocal_tree, nonlocal_id, "NONLOCAL"); + insert_vi_for_tree (nonlocal_tree, var_nonlocal); + var_nonlocal->is_artificial_var = 1; + var_nonlocal->offset = 0; + var_nonlocal->size = ~0; + var_nonlocal->fullsize = ~0; + var_nonlocal->is_special_var = 1; + VEC_safe_push (varinfo_t, heap, varmap, var_nonlocal); + + /* Nonlocal memory points to escaped (which includes nonlocal), + in order to make deref easier. */ + lhs.type = SCALAR; + lhs.var = nonlocal_id; + lhs.offset = 0; + rhs.type = ADDRESSOF; + rhs.var = escaped_id; + rhs.offset = 0; process_constraint (new_constraint (lhs, rhs)); /* Create the INTEGER variable, used to represent that a variable points to an INTEGER. */ integer_tree = create_tmp_var_raw (void_type_node, "INTEGER"); - var_integer = new_var_info (integer_tree, 3, "INTEGER"); + var_integer = new_var_info (integer_tree, integer_id, "INTEGER"); insert_vi_for_tree (integer_tree, var_integer); var_integer->is_artificial_var = 1; var_integer->size = ~0; @@ -5036,7 +5204,6 @@ init_base_vars (void) var_integer->offset = 0; var_integer->next = NULL; var_integer->is_special_var = 1; - integer_id = 3; VEC_safe_push (varinfo_t, heap, varmap, var_integer); /* INTEGER = ANYTHING, because we don't know where a dereference of @@ -5048,6 +5215,26 @@ init_base_vars (void) rhs.var = anything_id; rhs.offset = 0; process_constraint (new_constraint (lhs, rhs)); + + /* *ESCAPED = &ESCAPED. This is true because we have to assume + everything pointed to by escaped can also point to escaped. */ + lhs.type = DEREF; + lhs.var = escaped_id; + lhs.offset = 0; + rhs.type = ADDRESSOF; + rhs.var = escaped_id; + rhs.offset = 0; + process_constraint_1 (new_constraint (lhs, rhs), true); + + /* *ESCAPED = &NONLOCAL. This is true because we have to assume + everything pointed to by escaped can also point to nonlocal. */ + lhs.type = DEREF; + lhs.var = escaped_id; + lhs.offset = 0; + rhs.type = ADDRESSOF; + rhs.var = nonlocal_id; + rhs.offset = 0; + process_constraint_1 (new_constraint (lhs, rhs), true); } /* Initialize things necessary to perform PTA */ -- 2.30.2