+ /* Compute the global points-to sets for ESCAPED.
+ ??? Note that the computed escape set is not correct
+ for the whole unit as we fail to consider graph edges to
+ externally visible functions. */
+ find_what_var_points_to (get_varinfo (escaped_id), &ipa_escaped_pt);
+
+ /* Make sure the ESCAPED solution (which is used as placeholder in
+ other solutions) does not reference itself. This simplifies
+ points-to solution queries. */
+ ipa_escaped_pt.ipa_escaped = 0;
+
+ /* Assign the points-to sets to the SSA names in the unit. */
+ for (node = cgraph_nodes; node; node = node->next)
+ {
+ tree ptr;
+ struct function *fn;
+ unsigned i;
+ varinfo_t fi;
+ basic_block bb;
+ struct pt_solution uses, clobbers;
+ struct cgraph_edge *e;
+
+ /* Nodes without a body are not interesting. */
+ if (!gimple_has_body_p (node->decl)
+ || node->clone_of)
+ continue;
+
+ fn = DECL_STRUCT_FUNCTION (node->decl);
+
+ /* Compute the points-to sets for pointer SSA_NAMEs. */
+ for (i = 0; VEC_iterate (tree, fn->gimple_df->ssa_names, i, ptr); ++i)
+ {
+ if (ptr
+ && POINTER_TYPE_P (TREE_TYPE (ptr)))
+ find_what_p_points_to (ptr);
+ }
+
+ /* Compute the call-use and call-clobber sets for all direct calls. */
+ fi = lookup_vi_for_tree (node->decl);
+ gcc_assert (fi->is_fn_info);
+ find_what_var_points_to (first_vi_for_offset (fi, fi_clobbers),
+ &clobbers);
+ find_what_var_points_to (first_vi_for_offset (fi, fi_uses), &uses);
+ for (e = node->callers; e; e = e->next_caller)
+ {
+ if (!e->call_stmt)
+ continue;
+
+ *gimple_call_clobber_set (e->call_stmt) = clobbers;
+ *gimple_call_use_set (e->call_stmt) = uses;
+ }
+
+ /* Compute the call-use and call-clobber sets for indirect calls
+ and calls to external functions. */
+ FOR_EACH_BB_FN (bb, fn)
+ {
+ gimple_stmt_iterator gsi;
+
+ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple stmt = gsi_stmt (gsi);
+ struct pt_solution *pt;
+ varinfo_t vi;
+ tree decl;
+
+ if (!is_gimple_call (stmt))
+ continue;
+
+ /* Handle direct calls to external functions. */
+ decl = gimple_call_fndecl (stmt);
+ if (decl
+ && (!(fi = lookup_vi_for_tree (decl))
+ || !fi->is_fn_info))
+ {
+ pt = gimple_call_use_set (stmt);
+ if (gimple_call_flags (stmt) & ECF_CONST)
+ memset (pt, 0, sizeof (struct pt_solution));
+ else if ((vi = lookup_call_use_vi (stmt)) != NULL)
+ {
+ find_what_var_points_to (vi, pt);
+ /* Escaped (and thus nonlocal) variables are always
+ implicitly used by calls. */
+ /* ??? ESCAPED can be empty even though NONLOCAL
+ always escaped. */
+ pt->nonlocal = 1;
+ pt->ipa_escaped = 1;
+ }
+ else
+ {
+ /* If there is nothing special about this call then
+ we have made everything that is used also escape. */
+ *pt = ipa_escaped_pt;
+ pt->nonlocal = 1;
+ }
+
+ pt = gimple_call_clobber_set (stmt);
+ if (gimple_call_flags (stmt) & (ECF_CONST|ECF_PURE|ECF_NOVOPS))
+ memset (pt, 0, sizeof (struct pt_solution));
+ else if ((vi = lookup_call_clobber_vi (stmt)) != NULL)
+ {
+ find_what_var_points_to (vi, pt);
+ /* Escaped (and thus nonlocal) variables are always
+ implicitly clobbered by calls. */
+ /* ??? ESCAPED can be empty even though NONLOCAL
+ always escaped. */
+ pt->nonlocal = 1;
+ pt->ipa_escaped = 1;
+ }
+ else
+ {
+ /* If there is nothing special about this call then
+ we have made everything that is used also escape. */
+ *pt = ipa_escaped_pt;
+ pt->nonlocal = 1;
+ }
+ }
+
+ /* Handle indirect calls. */
+ if (!decl
+ && (fi = get_fi_for_callee (stmt)))
+ {
+ /* We need to accumulate all clobbers/uses of all possible
+ callees. */
+ fi = get_varinfo (find (fi->id));
+ /* If we cannot constrain the set of functions we'll end up
+ calling we end up using/clobbering everything. */
+ if (bitmap_bit_p (fi->solution, anything_id)
+ || bitmap_bit_p (fi->solution, nonlocal_id)
+ || bitmap_bit_p (fi->solution, escaped_id))
+ {
+ pt_solution_reset (gimple_call_clobber_set (stmt));
+ pt_solution_reset (gimple_call_use_set (stmt));
+ }
+ else
+ {
+ bitmap_iterator bi;
+ unsigned i;
+ struct pt_solution *uses, *clobbers;
+
+ uses = gimple_call_use_set (stmt);
+ clobbers = gimple_call_clobber_set (stmt);
+ memset (uses, 0, sizeof (struct pt_solution));
+ memset (clobbers, 0, sizeof (struct pt_solution));
+ EXECUTE_IF_SET_IN_BITMAP (fi->solution, 0, i, bi)
+ {
+ struct pt_solution sol;
+
+ vi = get_varinfo (i);
+ if (!vi->is_fn_info)
+ {
+ /* ??? We could be more precise here? */
+ uses->nonlocal = 1;
+ uses->ipa_escaped = 1;
+ clobbers->nonlocal = 1;
+ clobbers->ipa_escaped = 1;
+ continue;
+ }
+
+ if (!uses->anything)
+ {
+ find_what_var_points_to
+ (first_vi_for_offset (vi, fi_uses), &sol);
+ pt_solution_ior_into (uses, &sol);
+ }
+ if (!clobbers->anything)
+ {
+ find_what_var_points_to
+ (first_vi_for_offset (vi, fi_clobbers), &sol);
+ pt_solution_ior_into (clobbers, &sol);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ fn->gimple_df->ipa_pta = true;
+ }
+