/* Static IDs for the special variables. Variable ID zero is unused
and used as terminator for the sub-variable chain. */
enum { nothing_id = 1, anything_id = 2, string_id = 3,
- escaped_id = 4, nonlocal_id = 5,
- storedanything_id = 6, integer_id = 7 };
+ escaped_id = 4, nonlocal_id = 5, escaped_return_id = 6,
+ storedanything_id = 7, integer_id = 8 };
/* Return a new variable info structure consisting for a variable
named NAME, and using constraint graph node NODE. Append it
&& gimple_return_retval (as_a <greturn *> (t)) != NULL_TREE)
{
greturn *return_stmt = as_a <greturn *> (t);
- fi = NULL;
- if (!in_ipa_mode
- && 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)
+ tree retval = gimple_return_retval (return_stmt);
+ if (!in_ipa_mode)
+ make_constraint_to (escaped_return_id, retval);
+ else
{
struct constraint_expr lhs ;
struct constraint_expr *rhsp;
unsigned i;
+ fi = lookup_vi_for_tree (fn->decl);
lhs = get_function_part_constraint (fi, fi_result);
- get_constraint_for_rhs (gimple_return_retval (return_stmt), &rhsc);
+ get_constraint_for_rhs (retval, &rhsc);
FOR_EACH_VEC_ELT (rhsc, i, rhsp)
process_constraint (new_constraint (lhs, *rhsp));
}
unsigned int i;
bitmap_iterator bi;
varinfo_t escaped_vi = get_varinfo (find (escaped_id));
+ varinfo_t escaped_return_vi = get_varinfo (find (escaped_return_id));
bool everything_escaped
= escaped_vi->solution && bitmap_bit_p (escaped_vi->solution, anything_id);
pt->vars_contains_escaped = true;
pt->vars_contains_escaped_heap |= vi->is_heap_var;
}
+ if (escaped_return_vi->solution
+ && bitmap_bit_p (escaped_return_vi->solution, i))
+ pt->vars_contains_escaped_heap |= vi->is_heap_var;
if (vi->is_restrict_var)
pt->vars_contains_restrict = true;
varinfo_t var_string;
varinfo_t var_escaped;
varinfo_t var_nonlocal;
+ varinfo_t var_escaped_return;
varinfo_t var_storedanything;
varinfo_t var_integer;
var_nonlocal->fullsize = ~0;
var_nonlocal->is_special_var = 1;
+ /* Create the ESCAPED_RETURN variable, used to represent the set of escaped
+ memory via a regular return stmt. */
+ var_escaped_return = new_var_info (NULL_TREE, "ESCAPED_RETURN", false);
+ gcc_assert (var_escaped_return->id == escaped_return_id);
+ var_escaped_return->is_artificial_var = 1;
+ var_escaped_return->offset = 0;
+ var_escaped_return->size = ~0;
+ var_escaped_return->fullsize = ~0;
+ var_escaped_return->is_special_var = 0;
+
/* ESCAPED = *ESCAPED, because escaped is may-deref'd at calls, etc. */
lhs.type = SCALAR;
lhs.var = escaped_id;
rhs.offset = 0;
process_constraint (new_constraint (lhs, rhs));
+ /* Transitively close ESCAPED_RETURN.
+ ESCAPED_RETURN = ESCAPED_RETURN + UNKNOWN_OFFSET
+ ESCAPED_RETURN = *ESCAPED_RETURN. */
+ lhs.type = SCALAR;
+ lhs.var = escaped_return_id;
+ lhs.offset = 0;
+ rhs.type = SCALAR;
+ rhs.var = escaped_return_id;
+ rhs.offset = UNKNOWN_OFFSET;
+ process_constraint (new_constraint (lhs, rhs));
+ lhs.type = SCALAR;
+ lhs.var = escaped_return_id;
+ lhs.offset = 0;
+ rhs.type = DEREF;
+ rhs.var = escaped_return_id;
+ rhs.offset = 0;
+ process_constraint (new_constraint (lhs, rhs));
+
/* Create the STOREDANYTHING variable, used to represent the set of
variables stored to *ANYTHING. */
var_storedanything = new_var_info (NULL_TREE, "STOREDANYTHING", false);
/* 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 *> (*gsi_last_bb (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_flags & TDF_STATS))
dump_sa_stats (dump_file);
points-to solution queries. */
cfun->gimple_df->escaped.escaped = 0;
+ /* The ESCAPED_RETURN solution is what contains all memory that needs
+ to be considered global. */
+ cfun->gimple_df->escaped_return
+ = find_what_var_points_to (cfun->decl, get_varinfo (escaped_return_id));
+ cfun->gimple_df->escaped_return.escaped = 1;
+
/* Compute the points-to sets for pointer SSA_NAMEs. */
unsigned i;
tree ptr;