#include "stringpool.h"
#include "attribs.h"
#include "tree-ssa.h"
+#include "tree-cfg.h"
/* The idea behind this analyzer is to generate set constraints from the
program, then solve the resulting constraints in order to generate the
DECL_EXTERNAL (heapvar) = 1;
vi = new_var_info (heapvar, name, add_id);
- vi->is_artificial_var = true;
vi->is_heap_var = true;
vi->is_unknown_size_var = true;
vi->offset = 0;
process_constraint (new_constraint (*lhsp, ac));
return true;
}
+ case BUILT_IN_STACK_SAVE:
+ case BUILT_IN_STACK_RESTORE:
+ /* Nothing interesting happens. */
+ return true;
+ case BUILT_IN_ALLOCA:
+ case BUILT_IN_ALLOCA_WITH_ALIGN:
+ case BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX:
+ {
+ tree ptr = gimple_call_lhs (t);
+ if (ptr == NULL_TREE)
+ return true;
+ get_constraint_for (ptr, &lhsc);
+ varinfo_t vi = make_heapvar ("HEAP", true);
+ /* Alloca storage is never global. To exempt it from escaped
+ handling make it a non-heap var. */
+ DECL_EXTERNAL (vi->decl) = 0;
+ vi->is_global_var = 0;
+ vi->is_heap_var = 0;
+ struct constraint_expr tmpc;
+ tmpc.var = vi->id;
+ tmpc.offset = 0;
+ tmpc.type = ADDRESSOF;
+ rhsc.safe_push (tmpc);
+ process_all_all_constraints (lhsc, rhsc);
+ return true;
+ }
case BUILT_IN_POSIX_MEMALIGN:
{
tree ptrptr = gimple_call_arg (t, 0);
greturn *return_stmt = as_a <greturn *> (t);
fi = NULL;
if (!in_ipa_mode
- || !(fi = get_vi_for_tree (fn->decl)))
+ && SSA_VAR_P (gimple_return_retval (return_stmt)))
+ {
+ /* We handle simple returns by post-processing the solutions. */
+ ;
+ }
+ if (!(fi = get_vi_for_tree (fn->decl)))
make_escape_constraint (gimple_return_retval (return_stmt));
else if (in_ipa_mode)
{
{
varinfo_t vi = get_varinfo (i);
- /* The only artificial variables that are allowed in a may-alias
- set are heap variables. */
- if (vi->is_artificial_var && !vi->is_heap_var)
+ if (vi->is_artificial_var)
continue;
if (everything_escaped
}
else if (vi->id == nonlocal_id)
pt->nonlocal = 1;
- else if (vi->is_heap_var)
- /* We represent heapvars in the points-to set properly. */
- ;
else if (vi->id == string_id)
/* Nobody cares - STRING_CSTs are read-only entities. */
;
dump_constraint_graph (dump_file);
fprintf (dump_file, "\n\n");
}
-
- if (dump_file)
- dump_sa_points_to_info (dump_file);
}
/* Create points-to sets for the current function. See the comments
/* From the constraints compute the points-to sets. */
solve_constraints ();
+ /* Post-process solutions for escapes through returns. */
+ edge_iterator ei;
+ edge e;
+ FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
+ if (greturn *ret = safe_dyn_cast <greturn *> (last_stmt (e->src)))
+ {
+ tree val = gimple_return_retval (ret);
+ /* ??? Easy to handle simple indirections with some work.
+ Arbitrary references like foo.bar.baz are more difficult
+ (but conservatively easy enough with just looking at the base).
+ Mind to fixup find_func_aliases as well. */
+ if (!val || !SSA_VAR_P (val))
+ continue;
+ /* returns happen last in non-IPA so they only influence
+ the ESCAPED solution and we can filter local variables. */
+ varinfo_t escaped_vi = get_varinfo (find (escaped_id));
+ varinfo_t vi = lookup_vi_for_tree (val);
+ bitmap delta = BITMAP_ALLOC (&pta_obstack);
+ bitmap_iterator bi;
+ unsigned i;
+ for (; vi; vi = vi_next (vi))
+ {
+ varinfo_t part_vi = get_varinfo (find (vi->id));
+ EXECUTE_IF_AND_COMPL_IN_BITMAP (part_vi->solution,
+ escaped_vi->solution, 0, i, bi)
+ {
+ varinfo_t pointed_to_vi = get_varinfo (i);
+ if (pointed_to_vi->is_global_var
+ /* We delay marking of heap memory as global. */
+ || pointed_to_vi->is_heap_var)
+ bitmap_set_bit (delta, i);
+ }
+ }
+
+ /* Now compute the transitive closure. */
+ bitmap_ior_into (escaped_vi->solution, delta);
+ bitmap new_delta = BITMAP_ALLOC (&pta_obstack);
+ while (!bitmap_empty_p (delta))
+ {
+ EXECUTE_IF_SET_IN_BITMAP (delta, 0, i, bi)
+ {
+ varinfo_t pointed_to_vi = get_varinfo (i);
+ pointed_to_vi = get_varinfo (find (pointed_to_vi->id));
+ unsigned j;
+ bitmap_iterator bi2;
+ EXECUTE_IF_AND_COMPL_IN_BITMAP (pointed_to_vi->solution,
+ escaped_vi->solution,
+ 0, j, bi2)
+ {
+ varinfo_t pointed_to_vi2 = get_varinfo (j);
+ if (pointed_to_vi2->is_global_var
+ /* We delay marking of heap memory as global. */
+ || pointed_to_vi2->is_heap_var)
+ bitmap_set_bit (new_delta, j);
+ }
+ }
+ bitmap_ior_into (escaped_vi->solution, new_delta);
+ bitmap_clear (delta);
+ std::swap (delta, new_delta);
+ }
+ BITMAP_FREE (delta);
+ BITMAP_FREE (new_delta);
+ }
+
+ if (dump_file)
+ dump_sa_points_to_info (dump_file);
+
/* Compute the points-to set for ESCAPED used for call-clobber analysis. */
cfun->gimple_df->escaped = find_what_var_points_to (cfun->decl,
get_varinfo (escaped_id));
/* From the constraints compute the points-to sets. */
solve_constraints ();
+ if (dump_file)
+ dump_sa_points_to_info (dump_file);
+
/* Now post-process solutions to handle locals from different
runtime instantiations coming in through recursive invocations. */
unsigned shadow_var_cnt = 0;