#include "stringpool.h"
#include "tree-ssanames.h"
#include "attribs.h"
+#include "tree-cfg.h"
namespace {
struct escape_entry
{
/* Parameter that escapes at a given call. */
- unsigned int parm_index;
+ int parm_index;
/* Argument it escapes to. */
unsigned int arg;
/* Minimal flags known about the argument. */
/* Summary for a single function which this pass produces. */
modref_summary::modref_summary ()
- : loads (NULL), stores (NULL), writes_errno (NULL)
+ : loads (NULL), stores (NULL), retslot_flags (0), writes_errno (false)
{
}
if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
return true;
arg_flags.release ();
+ if (check_flags && remove_useless_eaf_flags (retslot_flags, ecf_flags, false))
+ return true;
if (ecf_flags & ECF_CONST)
return false;
if (loads && !loads->every_base)
modref_records_lto *loads;
modref_records_lto *stores;
auto_vec<eaf_flags_t> GTY((skip)) arg_flags;
+ eaf_flags_t retslot_flags;
bool writes_errno;
modref_summary_lto ();
/* Summary for a single function which this pass produces. */
modref_summary_lto::modref_summary_lto ()
- : loads (NULL), stores (NULL), writes_errno (NULL)
+ : loads (NULL), stores (NULL), retslot_flags (0), writes_errno (false)
{
}
if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
return true;
arg_flags.release ();
+ if (check_flags && remove_useless_eaf_flags (retslot_flags, ecf_flags, false))
+ return true;
if (ecf_flags & ECF_CONST)
return false;
if (loads && !loads->every_base)
dump_eaf_flags (out, arg_flags[i]);
}
}
+ if (retslot_flags)
+ {
+ fprintf (out, " Retslot flags:");
+ dump_eaf_flags (out, retslot_flags);
+ }
}
/* Dump summary. */
dump_eaf_flags (out, arg_flags[i]);
}
}
+ if (retslot_flags)
+ {
+ fprintf (out, " Retslot flags:");
+ dump_eaf_flags (out, retslot_flags);
+ }
}
/* Get function summary for FUNC if it exists, return NULL otherwise. */
struct escape_point
{
+ /* Extra hidden args we keep track of. */
+ enum hidden_args
+ {
+ retslot_arg = -1
+ };
/* Value escapes to this call. */
gcall *call;
/* Argument it escapes to. */
Returning name counts as an use by tree-ssa-structalias.c */
if (greturn *ret = dyn_cast <greturn *> (use_stmt))
{
- if (gimple_return_retval (ret) == name)
+ /* Returning through return slot is seen as memory write earlier. */
+ if (DECL_RESULT (current_function_decl)
+ && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
+ ;
+ else if (gimple_return_retval (ret) == name)
lattice[index].merge (~(EAF_UNUSED | EAF_NOT_RETURNED));
else if (memory_access_to (gimple_return_retval (ret), name))
{
may make LHS to escape. See PR 98499. */
if (gimple_call_return_slot_opt_p (call)
&& TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (call))))
- lattice[index].merge (EAF_NOREAD | EAF_DIRECT);
+ lattice[index].merge (gimple_call_retslot_flags (call));
}
/* We do not track accesses to the static chain (we could)
lattice[index].merge (call_flags);
else
lattice[index].add_escape_point (call, i,
- call_flags, true);
+ call_flags, true);
}
if (!ignore_retval)
merge_call_lhs_flags (call, i, index, false,
lattice[index].known = true;
}
+/* Record escape points of PARM_INDEX according to LATTICE. */
+
+static void
+record_escape_points (modref_lattice &lattice, int parm_index, int flags)
+{
+ if (lattice.escape_points.length ())
+ {
+ escape_point *ep;
+ unsigned int ip;
+ cgraph_node *node = cgraph_node::get (current_function_decl);
+
+ FOR_EACH_VEC_ELT (lattice.escape_points, ip, ep)
+ if ((ep->min_flags & flags) != flags)
+ {
+ cgraph_edge *e = node->get_edge (ep->call);
+ struct escape_entry ee = {parm_index, ep->arg,
+ ep->min_flags, ep->direct};
+
+ escape_summaries->get_create (e)->esc.safe_push (ee);
+ }
+ }
+}
+
/* Determine EAF flags for function parameters. */
static void
unsigned int parm_index = 0;
unsigned int count = 0;
int ecf_flags = flags_from_decl_or_type (current_function_decl);
+ tree retslot = NULL;
/* For novops functions we have nothing to gain by EAF flags. */
if (ecf_flags & ECF_NOVOPS)
return;
+ /* If there is return slot, look up its SSA name. */
+ if (DECL_RESULT (current_function_decl)
+ && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
+ retslot = ssa_default_def (cfun, DECL_RESULT (current_function_decl));
+
for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
parm = TREE_CHAIN (parm))
count++;
- if (!count)
+ if (!count && !retslot)
return;
auto_vec<modref_lattice> lattice;
summary_lto->arg_flags.safe_grow_cleared (count, true);
summary_lto->arg_flags[parm_index] = flags;
}
- if (lattice[SSA_NAME_VERSION (name)].escape_points.length ())
- {
- escape_point *ep;
- unsigned int ip;
- cgraph_node *node = cgraph_node::get (current_function_decl);
-
- gcc_checking_assert (ipa);
- FOR_EACH_VEC_ELT
- (lattice[SSA_NAME_VERSION (name)].escape_points, ip, ep)
- if ((ep->min_flags & flags) != flags)
- {
- cgraph_edge *e = node->get_edge (ep->call);
- struct escape_entry ee = {parm_index, ep->arg,
- ep->min_flags, ep->direct};
+ record_escape_points (lattice[SSA_NAME_VERSION (name)],
+ parm_index, flags);
+ }
+ }
+ if (retslot)
+ {
+ analyze_ssa_name_flags (retslot, lattice, 0, ipa);
+ int flags = lattice[SSA_NAME_VERSION (retslot)].flags;
- escape_summaries->get_create (e)->esc.safe_push (ee);
- }
- }
+ flags = remove_useless_eaf_flags (flags, ecf_flags, false);
+ if (flags)
+ {
+ if (summary)
+ summary->retslot_flags = flags;
+ if (summary_lto)
+ summary_lto->retslot_flags = flags;
+ record_escape_points (lattice[SSA_NAME_VERSION (retslot)],
+ escape_point::retslot_arg, flags);
}
}
if (ipa)
dst_data->writes_errno = src_data->writes_errno;
if (src_data->arg_flags.length ())
dst_data->arg_flags = src_data->arg_flags.copy ();
+ dst_data->retslot_flags = src_data->retslot_flags;
}
/* Called when new clone is inserted to callgraph late. */
dst_data->writes_errno = src_data->writes_errno;
if (src_data->arg_flags.length ())
dst_data->arg_flags = src_data->arg_flags.copy ();
+ dst_data->retslot_flags = src_data->retslot_flags;
}
namespace
escape_entry *ee;
FOR_EACH_VEC_ELT (esum->esc, i, ee)
{
- bp_pack_var_len_unsigned (bp, ee->parm_index);
+ bp_pack_var_len_int (bp, ee->parm_index);
bp_pack_var_len_unsigned (bp, ee->arg);
bp_pack_var_len_unsigned (bp, ee->min_flags);
bp_pack_value (bp, ee->direct, 1);
for (unsigned int i = 0; i < n; i++)
{
escape_entry ee;
- ee.parm_index = bp_unpack_var_len_unsigned (bp);
+ ee.parm_index = bp_unpack_var_len_int (bp);
ee.arg = bp_unpack_var_len_unsigned (bp);
ee.min_flags = bp_unpack_var_len_unsigned (bp);
ee.direct = bp_unpack_value (bp, 1);
streamer_write_uhwi (ob, r->arg_flags.length ());
for (unsigned int i = 0; i < r->arg_flags.length (); i++)
streamer_write_uhwi (ob, r->arg_flags[i]);
+ streamer_write_uhwi (ob, r->retslot_flags);
write_modref_records (r->loads, ob);
write_modref_records (r->stores, ob);
if (modref_sum_lto)
modref_sum_lto->arg_flags.quick_push (flags);
}
+ eaf_flags_t flags = streamer_read_uhwi (&ib);
+ if (modref_sum)
+ modref_sum->retslot_flags = flags;
+ if (modref_sum_lto)
+ modref_sum_lto->retslot_flags = flags;
read_modref_records (&ib, data_in,
modref_sum ? &modref_sum->loads : NULL,
modref_sum_lto ? &modref_sum_lto->loads : NULL);
bool direct;
};
-/* Update escape map fo E. */
+/* Update escape map for E. */
static void
update_escape_summary_1 (cgraph_edge *e,
{
unsigned int j;
struct escape_map *em;
- if (ee->parm_index >= map.length ())
+ /* TODO: We do not have jump functions for return slots, so we
+ never propagate them to outer function. */
+ if (ee->parm_index >= (int)map.length ()
+ || ee->parm_index < 0)
continue;
FOR_EACH_VEC_ELT (map[ee->parm_index], j, em)
{
if (ee->direct && !em->direct)
min_flags = deref_flags (min_flags, ignore_stores);
struct escape_entry entry = {em->parm_index, ee->arg,
- ee->min_flags,
+ ee->min_flags,
ee->direct & em->direct};
sum->esc.safe_push (entry);
}
FOR_EACH_VEC_ELT (sum->esc, i, ee)
{
bool needed = false;
- if (to_info && to_info->arg_flags.length () > ee->parm_index)
+ /* TODO: We do not have jump functions for return slots, so we
+ never propagate them to outer function. */
+ if (ee->parm_index < 0)
+ continue;
+ if (to_info && (int)to_info->arg_flags.length () > ee->parm_index)
{
int flags = callee_info
&& callee_info->arg_flags.length () > ee->arg
if (to_info->arg_flags[ee->parm_index])
needed = true;
}
- if (to_info_lto && to_info_lto->arg_flags.length () > ee->parm_index)
+ if (to_info_lto && (int)to_info_lto->arg_flags.length () > ee->parm_index)
{
int flags = callee_info_lto
&& callee_info_lto->arg_flags.length () > ee->arg
if (flags_lto & EAF_NOESCAPE)
flags_lto |= EAF_NODIRECTESCAPE;
if (!(flags & EAF_UNUSED)
- && cur_summary && ee->parm_index < cur_summary->arg_flags.length ())
+ && cur_summary && ee->parm_index < (int)cur_summary->arg_flags.length ())
{
- int f = cur_summary->arg_flags[ee->parm_index];
+ eaf_flags_t &f = ee->parm_index == escape_point::retslot_arg
+ ? cur_summary->retslot_flags
+ : cur_summary->arg_flags[ee->parm_index];
if ((f & flags) != f)
{
f = remove_useless_eaf_flags
(f & flags, ecf_flags,
VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
- cur_summary->arg_flags[ee->parm_index] = f;
changed = true;
}
}
if (!(flags_lto & EAF_UNUSED)
&& cur_summary_lto
- && ee->parm_index < cur_summary_lto->arg_flags.length ())
+ && ee->parm_index < (int)cur_summary_lto->arg_flags.length ())
{
- int f = cur_summary_lto->arg_flags[ee->parm_index];
+ eaf_flags_t &f = ee->parm_index == escape_point::retslot_arg
+ ? cur_summary_lto->retslot_flags
+ : cur_summary_lto->arg_flags[ee->parm_index];
if ((f & flags_lto) != f)
{
f = remove_useless_eaf_flags
(f & flags_lto, ecf_flags,
VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
- cur_summary_lto->arg_flags[ee->parm_index] = f;
changed = true;
}
}