public inbox for gcc@gcc.gnu.org
 help / color / mirror / Atom feed
From: Richard Biener <rguenther@suse.de>
To: Jan Hubicka <hubicka@ucw.cz>
Cc: gcc@gcc.gnu.org, gcc-patches@gcc.gnu.org
Subject: Re: Detect EAF flags in ipa-modref
Date: Tue, 10 Nov 2020 12:04:31 +0100 (CET)	[thread overview]
Message-ID: <nycvar.YFH.7.76.2011101136010.10073@p653.nepu.fhfr.qr> (raw)
In-Reply-To: <20201109231418.GF65107@kam.mff.cuni.cz>

On Tue, 10 Nov 2020, Jan Hubicka wrote:

> Hi,
> this is updated patch for autodetection of EAF flags.  Still the goal is
> to avoid fancy stuff and get besic logic in place (so no dataflow, no IPA
> propagation, no attempts to handle trickier cases).  There is one new failure
> 
> ./gcc/testsuite/gcc/gcc.sum:FAIL: gcc.dg/sso/t2.c   -Wno-scalar-storage-order -O1 -fno-inline  output pattern test
> ./gcc/testsuite/gcc/gcc.sum:FAIL: gcc.dg/sso/t2.c   -Wno-scalar-storage-order -O2  output pattern test
> ./gcc/testsuite/gcc/gcc.sum:FAIL: gcc.dg/sso/t2.c   -Wno-scalar-storage-order -Os  output pattern test
> 
> Which I blieve is bug exposed by detecting dump function to be EAF_DIRECT and
> NOESCAPE (which it is) and packing/updacking the bitfields leads in one bit
> difference. Still no idea why.
> 
> Patch seems to be quite effective on cc1plus turning:
> 
> Alias oracle query stats:
>   refs_may_alias_p: 65808750 disambiguations, 75664890 queries
>   ref_maybe_used_by_call_p: 153485 disambiguations, 66711204 queries
>   call_may_clobber_ref_p: 22816 disambiguations, 28889 queries
>   nonoverlapping_component_refs_p: 0 disambiguations, 36846 queries
>   nonoverlapping_refs_since_match_p: 27271 disambiguations, 58917 must overlaps, 86958 queries
>   aliasing_component_refs_p: 65808 disambiguations, 2067256 queries
>   TBAA oracle: 25929211 disambiguations 60395141 queries
>                12391384 are in alias set 0
>                10783783 queries asked about the same object
>                126 queries asked about the same alias set
>                0 access volatile
>                9598698 are dependent in the DAG
>                1691939 are aritificially in conflict with void *
> 
> Modref stats:
>   modref use: 14284 disambiguations, 53336 queries
>   modref clobber: 1660281 disambiguations, 2130440 queries
>   4311165 tbaa queries (2.023603 per modref query)
>   685304 base compares (0.321673 per modref query)
> 
> PTA query stats:
>   pt_solution_includes: 959190 disambiguations, 13169678 queries
>   pt_solutions_intersect: 1050969 disambiguations, 13246686 queries
> 
> Alias oracle query stats:
>   refs_may_alias_p: 66914578 disambiguations, 76692648 queries
>   ref_maybe_used_by_call_p: 244077 disambiguations, 67732086 queries
>   call_may_clobber_ref_p: 111475 disambiguations, 116613 queries
>   nonoverlapping_component_refs_p: 0 disambiguations, 37091 queries
>   nonoverlapping_refs_since_match_p: 27267 disambiguations, 59019 must overlaps, 87056 queries
>   aliasing_component_refs_p: 65870 disambiguations, 2063394 queries
>   TBAA oracle: 26024415 disambiguations 60579490 queries
>                12450910 are in alias set 0
>                10806673 queries asked about the same object
>                125 queries asked about the same alias set
>                0 access volatile
>                9605837 are dependent in the DAG
>                1691530 are aritificially in conflict with void *
> 
> Modref stats:
>   modref use: 14272 disambiguations, 277680 queries
>   modref clobber: 1669753 disambiguations, 7849135 queries
>   4330162 tbaa queries (0.551674 per modref query)
>   699241 base compares (0.089085 per modref query)
> 
> PTA query stats:
>   pt_solution_includes: 1833920 disambiguations, 13846032 queries
>   pt_solutions_intersect: 1093785 disambiguations, 13309954 queries
> 
> So almost twice as many pt_solution_includes disambiguations.
> I will re-run the stats overnight to be sure that it is not independent
> change (but both build was from almost same checkout).
> 
> Bootstrapped/regtested x86_64-linux, OK?
> (I will analyze more the t2.c failure)
> 
> Honza
> 
> gcc/ChangeLog:
> 
> 2020-11-10  Jan Hubicka  <hubicka@ucw.cz>
> 
> 	* gimple.c: Include ipa-modref-tree.h and ipa-modref.h.
> 	(gimple_call_arg_flags): Use modref to determine flags.
> 	* ipa-modref.c: Include gimple-ssa.h, tree-phinodes.h,
> 	tree-ssa-operands.h, stringpool.h and tree-ssanames.h.
> 	(analyze_ssa_name_flags): Declare.
> 	(modref_summary::useful_p): Summary is also useful if arg flags are
> 	known.
> 	(dump_eaf_flags): New function.
> 	(modref_summary::dump): Use it.
> 	(get_modref_function_summary): Be read for current_function_decl
> 	being NULL.
> 	(memory_access_to): New function.
> 	(deref_flags): New function.
> 	(call_lhs_flags): New function.
> 	(analyze_parms): New function.
> 	(analyze_function): Use it.
> 	* ipa-modref.h (struct modref_summary): Add arg_flags.
> 
> gcc/testsuite/ChangeLog:
> 
> 2020-11-10  Jan Hubicka  <hubicka@ucw.cz>
> 
> 	* gcc.dg/torture/pta-ptrarith-1.c: Escape parametrs.
> 
> diff --git a/gcc/gimple.c b/gcc/gimple.c
> index 1afed88e1f1..da90716aa23 100644
> --- a/gcc/gimple.c
> +++ b/gcc/gimple.c
> @@ -46,6 +46,8 @@ along with GCC; see the file COPYING3.  If not see
>  #include "asan.h"
>  #include "langhooks.h"
>  #include "attr-fnspec.h"
> +#include "ipa-modref-tree.h"
> +#include "ipa-modref.h"
>  
>  
>  /* All the tuples have their operand vector (if present) at the very bottom
> @@ -1532,24 +1534,45 @@ int
>  gimple_call_arg_flags (const gcall *stmt, unsigned arg)
>  {
>    attr_fnspec fnspec = gimple_call_fnspec (stmt);
> -
> -  if (!fnspec.known_p ())
> -    return 0;
> -
>    int flags = 0;
>  
> -  if (!fnspec.arg_specified_p (arg))
> -    ;
> -  else if (!fnspec.arg_used_p (arg))
> -    flags = EAF_UNUSED;
> -  else
> +  if (fnspec.known_p ())
>      {
> -      if (fnspec.arg_direct_p (arg))
> -	flags |= EAF_DIRECT;
> -      if (fnspec.arg_noescape_p (arg))
> -	flags |= EAF_NOESCAPE;
> -      if (fnspec.arg_readonly_p (arg))
> -	flags |= EAF_NOCLOBBER;
> +      if (!fnspec.arg_specified_p (arg))
> +	;
> +      else if (!fnspec.arg_used_p (arg))
> +	flags = EAF_UNUSED;
> +      else
> +	{
> +	  if (fnspec.arg_direct_p (arg))
> +	    flags |= EAF_DIRECT;
> +	  if (fnspec.arg_noescape_p (arg))
> +	    flags |= EAF_NOESCAPE;
> +	  if (fnspec.arg_readonly_p (arg))
> +	    flags |= EAF_NOCLOBBER;
> +	}
> +    }
> +  tree callee = gimple_call_fndecl (stmt);
> +  if (callee)
> +    {
> +      cgraph_node *node = cgraph_node::get (callee);
> +      modref_summary *summary = node ? get_modref_function_summary (node)
> +				: NULL;
> +
> +      if (summary && summary->arg_flags.length () > arg)

So could we make modref "transform" push this as fnspec attribute or
would that not really be an optimization?

> +	{
> +	  int modref_flags = summary->arg_flags[arg];
> +
> +	  /* We have possibly optimized out load.  Be conservative here.  */
> +	  if (!node->binds_to_current_def_p ())
> +	    {
> +	      if ((modref_flags & EAF_UNUSED) && !(flags & EAF_UNUSED))
> +		modref_flags &= ~EAF_UNUSED;
> +	      if ((modref_flags & EAF_DIRECT) && !(flags & EAF_DIRECT))
> +		modref_flags &= ~EAF_DIRECT;
> +	    }
> +	  flags |= modref_flags;
> +	}
>      }
>    return flags;
>  }
> diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c
> index 3f46bebed3c..bde626115ff 100644
> --- a/gcc/ipa-modref.c
> +++ b/gcc/ipa-modref.c
> @@ -61,6 +61,14 @@ along with GCC; see the file COPYING3.  If not see
>  #include "ipa-fnsummary.h"
>  #include "attr-fnspec.h"
>  #include "symtab-clones.h"
> +#include "gimple-ssa.h"
> +#include "tree-phinodes.h"
> +#include "tree-ssa-operands.h"
> +#include "ssa-iterators.h"
> +#include "stringpool.h"
> +#include "tree-ssanames.h"
> +
> +static int analyze_ssa_name_flags (tree name, vec<int> *known_flags, int depth);
>  
>  /* We record fnspec specifiers for call edges since they depends on actual
>     gimple statements.  */
> @@ -186,6 +194,8 @@ modref_summary::useful_p (int ecf_flags)
>  {
>    if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
>      return false;
> +  if (arg_flags.length ())
> +    return true;
>    if (loads && !loads->every_base)
>      return true;
>    if (ecf_flags & ECF_PURE)
> @@ -355,6 +365,22 @@ dump_lto_records (modref_records_lto *tt, FILE *out)
>      }
>  }
>  
> +/* Dump EAF flags.  */
> +
> +static void
> +dump_eaf_flags (FILE *out, int flags)
> +{
> +  if (flags & EAF_DIRECT)
> +    fprintf (out, " direct");
> +  if (flags & EAF_NOCLOBBER)
> +    fprintf (out, " noclobber");
> +  if (flags & EAF_NOESCAPE)
> +    fprintf (out, " noescape");
> +  if (flags & EAF_UNUSED)
> +    fprintf (out, " unused");
> +  fprintf (out, "\n");
> +}
> +
>  /* Dump summary.  */
>  
>  void
> @@ -372,6 +398,15 @@ modref_summary::dump (FILE *out)
>      }
>    if (writes_errno)
>      fprintf (out, "  Writes errno\n");
> +  if (arg_flags.length ())
> +    {
> +      for (unsigned int i = 0; i < arg_flags.length (); i++)
> +	if (arg_flags[i])
> +	  {
> +	    fprintf (out, "  parm %i flags:", i);
> +	    dump_eaf_flags (out, arg_flags[i]);
> +	  }
> +    }
>  }
>  
>  /* Dump summary.  */
> @@ -402,7 +437,8 @@ get_modref_function_summary (cgraph_node *func)
>       function.  */
>    enum availability avail;
>    func = func->function_or_virtual_thunk_symbol
> -	     (&avail, cgraph_node::get (current_function_decl));
> +		 (&avail, current_function_decl ?
> +			  cgraph_node::get (current_function_decl) : NULL);
>    if (avail <= AVAIL_INTERPOSABLE)
>      return NULL;
>  
> @@ -1067,6 +1103,315 @@ remove_summary (bool lto, bool nolto, bool ipa)
>  	     " - modref done with result: not tracked.\n");
>  }
>  
> +/* Return true if OP accesses memory pointed to by SSA_NAME.  */
> +
> +bool
> +memory_access_to (tree op, tree ssa_name)
> +{
> +  tree base = get_base_address (op);
> +  if (!base)
> +    return false;
> +  if (TREE_CODE (base) != MEM_REF && TREE_CODE (base) != TARGET_MEM_REF)
> +    return false;
> +  return TREE_OPERAND (base, 0) == ssa_name;
> +}
> +
> +/* Consider statement val = *arg.
> +   return EAF flags of ARG that can be determined from EAF flags of VAL
> +   (which are known to be FLAGS).  If IGNORE_STORES is true we can ignore
> +   all stores to VAL, i.e. when handling noreturn function.  */
> +
> +static int
> +deref_flags (int flags, bool ignore_stores)
> +{
> +  int ret = 0;
> +  if (flags & EAF_UNUSED)
> +    ret |= EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE;
> +  else
> +    {
> +      if ((flags & EAF_NOCLOBBER) || ignore_stores)
> +	ret |= EAF_NOCLOBBER;
> +      if ((flags & EAF_NOESCAPE) || ignore_stores)
> +	ret |= EAF_NOESCAPE;
> +    }
> +  return ret;
> +}
> +
> +/* Call statements may return their parameters.  Consider argument number
> +   ARG of USE_STMT and determine flags that can needs to be cleared
> +   in case pointer possibly indirectly references from ARG I is returned.
> +   KNOWN_FLAGS and DEPTH are same as in analyze_ssa_name_flags.  */
> +
> +static int
> +call_lhs_flags (gimple *use_stmt, int arg, vec<int> *known_flags, int depth)
> +{
> +  /* If there is no return value, no flags are affected.  */
> +  if (!gimple_call_lhs (use_stmt))
> +    return EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED;
> +
> +  /* If we know that function returns given argument and it is not ARG
> +     we can still be happy.  */
> +  int flags = gimple_call_return_flags (as_a <gcall *> (use_stmt));
> +  if ((flags & ERF_RETURNS_ARG)
> +      && (flags & ERF_RETURN_ARG_MASK) != arg)
> +    return EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED;
> +
> +  /* If return value is SSA name determine its flags.  */
> +  if (TREE_CODE (gimple_call_lhs (use_stmt)) == SSA_NAME)
> +    return analyze_ssa_name_flags
> +		       (gimple_call_lhs (use_stmt), known_flags,
> +			depth + 1);
> +  /* In the case of memory store we can do nothing.  */
> +  else
> +    return 0;
> +}
> +
> +/* Analyze EAF flags for SSA name NAME.
> +   KNOWN_FLAGS is a cache for flags we already determined.
> +   DEPTH is a recursion depth used to make debug output prettier.  */
> +
> +static int
> +analyze_ssa_name_flags (tree name, vec<int> *known_flags, int depth)

C++ has references which makes the access to known_flags nicer ;)

> +{
> +  imm_use_iterator ui;
> +  gimple *use_stmt;
> +  int flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED;
> +
> +  /* See if value is already computed.  */
> +  if ((*known_flags)[SSA_NAME_VERSION (name)])
> +    {
> +      /* Punt on cycles for now, so we do not need dataflow.  */
> +      if ((*known_flags)[SSA_NAME_VERSION (name)] == 1)
> +	{
> +	  if (dump_file)
> +	    fprintf (dump_file,
> +		     "%*sGiving up on a cycle in SSA graph\n", depth * 4, "");
> +	  return 0;
> +	}
> +      return (*known_flags)[SSA_NAME_VERSION (name)] - 2;
> +    }
> +  /* Recursion guard.  */
> +  (*known_flags)[SSA_NAME_VERSION (name)] = 1;

This also guards against multiple evaluations of the same stmts
but only in some cases?  Consider

  _1 = ..;
  _2 = _1 + _3;
  _4 = _1 + _5;
  _6 = _2 + _4;

where we visit _2 = and _4 = from _1 but from both are going
to visit _6.

Maybe I'm blind but you're not limiting depth?  Guess that asks
for problems, esp. as you are recursing rather than using a
worklist or so?

I see you try to "optimize" the walk by only visiting def->use
links from parameters but then a RPO walk over all stmts would
be simpler iteration-wise ...

> +  if (dump_file)
> +    {
> +      fprintf (dump_file,
> +	       "%*sAnalyzing flags of ssa name: ", depth * 4, "");
> +      print_generic_expr (dump_file, name);
> +      fprintf (dump_file, "\n");
> +    }
> +
> +  FOR_EACH_IMM_USE_STMT (use_stmt, ui, name)
> +    {
> +      if (flags == 0)
> +	{
> +	  BREAK_FROM_IMM_USE_STMT (ui);
> +	}
> +      if (is_gimple_debug (use_stmt))
> +	continue;
> +      if (dump_file)
> +	{
> +	  fprintf (dump_file, "%*s  Analyzing stmt:", depth * 4, "");
> +	  print_gimple_stmt (dump_file, use_stmt, 0);
> +	}
> +
> +      /* Gimple return may load the return value.  */
> +      if (gimple_code (use_stmt) == GIMPLE_RETURN)

 if (greturn *ret = dyn_cast <greturn *> (use_stmt))

makes the as_a below not needed, similar for the other cases (it
also makes accesses cheaper, avoiding some checking code).

> +	{
> +	  if (memory_access_to (gimple_return_retval
> +				   (as_a <greturn *> (use_stmt)), name))
> +	    flags &= ~EAF_UNUSED;
> +	}
> +      /* Account for LHS store, arg loads and flags from callee function.  */
> +      else if (is_gimple_call (use_stmt))
> +	{
> +	  tree callee = gimple_call_fndecl (use_stmt);
> +
> +	  /* Recursion would require bit of propagation; give up for now.  */
> +	  if (callee && recursive_call_p (current_function_decl, callee))
> +	    flags = 0;
> +	  else
> +	    {
> +	      int ecf_flags = gimple_call_flags (use_stmt);
> +	      bool ignore_stores = ignore_stores_p (current_function_decl,
> +						    ecf_flags);
> +
> +	      /* Handle *name = func (...).  */
> +	      if (gimple_call_lhs (use_stmt)
> +		  && memory_access_to (gimple_call_lhs (use_stmt), name))
> +		flags &= ~(EAF_UNUSED | EAF_NOCLOBBER);
> +
> +	      /* Handle all function parameters.  */
> +	      for (unsigned i = 0; i < gimple_call_num_args (use_stmt); i++)
> +		/* Name is directly passed to the callee.  */
> +		if (gimple_call_arg (use_stmt, i) == name)
> +		  {
> +		    if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
> +		      flags &= ignore_stores
> +			       ? 0
> +			       : call_lhs_flags (use_stmt, i,
> +						 known_flags, depth);
> +		    else
> +		      {
> +			int call_flags = gimple_call_arg_flags (as_a <gcall *>
> +								 (use_stmt), i);
> +			if (ignore_stores)
> +			  call_flags |= EAF_NOCLOBBER | EAF_NOESCAPE;
> +			else
> +			  call_flags &= call_lhs_flags (use_stmt, i,
> +							known_flags, depth);
> +
> +			flags &= call_flags;
> +		      }
> +		  }
> +		/* Name is dereferenced and passed to a callee.  */
> +		else if (memory_access_to (gimple_call_arg (use_stmt, i), name))
> +		  {
> +		    if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
> +		      flags &= ~EAF_UNUSED;
> +		    else
> +		      flags &= deref_flags (gimple_call_arg_flags
> +						(as_a <gcall *> (use_stmt), i),
> +					    ignore_stores);
> +		    if (!ignore_stores)
> +		      flags &= call_lhs_flags (use_stmt, i, known_flags,
> +					       depth);
> +		  }

Hmm, you forget gimple_call_chain at least which is at least
argument passing?  Possibly the chain argument is never a function
parameter but how do you know... (partial inlining?)

Then there's gimple_call_fn for indirect function calls to a
function parameter?

I guess it would be nice to amend the gimple_walk_ stuff to have
a SSA name callback where the tree and the SSA use is passed.
Well, for another time.

> +	    }
> +	  /* Only NOCLOBBER or DIRECT flags alone are not useful (see comments
> +	     in tree-ssa-alias.c).  Give up earlier.  */
> +	  if ((flags & ~(EAF_DIRECT | EAF_NOCLOBBER)) == 0)
> +	    flags = 0;
> +	}
> +      else if (gimple_assign_load_p (use_stmt))
> +	{
> +	  /* Memory to memory copy.  */
> +	  if (gimple_store_p (use_stmt))
> +	    {
> +	      /* Handle *name = *exp.  */
> +	      if (memory_access_to (gimple_assign_lhs (use_stmt), name))
> +		flags &= ~(EAF_UNUSED | EAF_NOCLOBBER);
> +
> +	      /* Handle *lhs = *name.
> +
> +		 We do not track memory locations, so assume that value
> +		 is used arbitrarily.  */
> +	      if (memory_access_to (gimple_assign_rhs1 (use_stmt), name))
> +		flags = 0;
> +	    }
> +	  /* Handle lhs = *name.  */
> +	  else if (memory_access_to (gimple_assign_rhs1 (use_stmt), name))
> +	    flags &= deref_flags (analyze_ssa_name_flags
> +				      (gimple_assign_lhs (use_stmt),
> +				       known_flags, depth + 1), false);
> +	}
> +      else if (gimple_store_p (use_stmt))
> +	{
> +	  /* Handle *lhs = name.  */
> +	  if (is_gimple_assign (use_stmt)
> +	      && gimple_assign_rhs1 (use_stmt) == name)
> +	    {
> +	      if (dump_file)
> +		fprintf (dump_file, "%*s  ssa name saved to memory\n",
> +			 depth * 4, "");
> +	      flags = 0;
> +	    }
> +	  /* Handle *name = exp.  */
> +	  else if (is_gimple_assign (use_stmt)
> +		   && memory_access_to (gimple_assign_lhs (use_stmt), name))
> +	    flags &= ~(EAF_UNUSED | EAF_NOCLOBBER);
> +	  /* ASM statements etc.  */
> +	  else if (!is_gimple_assign (use_stmt))
> +	    {
> +	      if (dump_file)
> +		fprintf (dump_file, "%*s  Unhandled store\n",
> +			 depth * 4, "");
> +	      flags = 0;
> +	    }
> +	}
> +      else if (is_gimple_assign (use_stmt))
> +	{
> +	  enum tree_code code = gimple_assign_rhs_code (use_stmt);
> +
> +	  /* See if operation is a merge as considered by
> +	     tree-ssa-structalias.c:find_func_aliases.  */
> +	  if (!truth_value_p (code)
> +	      && code != POINTER_DIFF_EXPR
> +	      && (code != POINTER_PLUS_EXPR
> +		  || gimple_assign_rhs1 (use_stmt) == name))
> +	    flags &= analyze_ssa_name_flags
> +			       (gimple_assign_lhs (use_stmt), known_flags,
> +				depth + 1);
> +	}
> +      else if (gimple_code (use_stmt) == GIMPLE_PHI)
> +	{
> +	  flags &= analyze_ssa_name_flags
> +			     (gimple_phi_result (use_stmt), known_flags,
> +			      depth + 1);
> +	}
> +      /* Conditions are not considered escape points
> +	 by tree-ssa-structalias.  */
> +      else if (gimple_code (use_stmt) == GIMPLE_COND)
> +	;
> +      else
> +	{
> +	  if (dump_file)
> +	    fprintf (dump_file, "%*s  Unhandled stmt\n", depth * 4, "");
> +	  flags = 0;
> +	}
> +
> +      if (dump_file)
> +	{
> +	  fprintf (dump_file, "%*s  current flags of ", depth * 4, "");
> +	  print_generic_expr (dump_file, name);
> +	  dump_eaf_flags (dump_file, flags);
> +	}
> +    }
> +  if (dump_file)
> +    {
> +      fprintf (dump_file, "%*sflags of ssa name ", depth * 4, "");
> +      print_generic_expr (dump_file, name);
> +      dump_eaf_flags (dump_file, flags);
> +    }
> +  (*known_flags)[SSA_NAME_VERSION (name)] = flags + 2;
> +  return flags;
> +}
> +
> +/* Determine EAF flags for function parameters.  */
> +
> +static void
> +analyze_parms (modref_summary *summary)
> +{
> +  unsigned int parm_index = 0;
> +  unsigned int count = 0;
> +
> +  for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
> +       parm = TREE_CHAIN (parm))
> +    count++;
> +
> +  if (!count)
> +    return;
> +
> +  auto_vec<int> known_flags;
> +  known_flags.safe_grow_cleared (num_ssa_names);

, true for exact reserve.  Could be space optimized by not using
auto_vec<int> but auto_vec<usigned char>?

> +
> +  for (tree parm = DECL_ARGUMENTS (current_function_decl); parm; parm_index++,
> +       parm = TREE_CHAIN (parm))
> +    {
> +      tree name = ssa_default_def (cfun, parm);
> +      if (!name)
> +	continue;

looks like the vec might be quite sparse ...

> +      int flags = analyze_ssa_name_flags (name, &known_flags, 0);
> +
> +      if (flags)
> +	{
> +	  if (parm_index >= summary->arg_flags.length ())
> +	    summary->arg_flags.safe_grow_cleared (count);

you want , true for exact reserve.

> +	  summary->arg_flags[parm_index] = flags;

maybe this as well - does it make sense to skip !is_gimple_reg_type
params in the counting?  Guess it makes lookup too complicated.
But we do have testcases with >30000 parameters ...

> +	}
> +    }
> +}
> +
>  /* Analyze function F.  IPA indicates whether we're running in local mode
>     (false) or the IPA mode (true).  */
>  
> @@ -1174,6 +1519,10 @@ analyze_function (function *f, bool ipa)
>  				  param_modref_max_accesses);
>        summary_lto->writes_errno = false;
>      }
> +
> +  if (!ipa)
> +    analyze_parms (summary);
> +
>    int ecf_flags = flags_from_decl_or_type (current_function_decl);
>    auto_vec <gimple *, 32> recursive_calls;
>  
> @@ -1191,8 +1540,9 @@ analyze_function (function *f, bool ipa)
>  	      || ((!summary || !summary->useful_p (ecf_flags))
>  		  && (!summary_lto || !summary_lto->useful_p (ecf_flags))))
>  	    {
> -	      remove_summary (lto, nolto, ipa);
> -	      return;
> +	      collapse_loads (summary, summary_lto);
> +	      collapse_stores (summary, summary_lto);
> +	      break;
>  	    }
>  	}
>      }
> diff --git a/gcc/ipa-modref.h b/gcc/ipa-modref.h
> index 31ceffa8d34..8fa05aaf7fb 100644
> --- a/gcc/ipa-modref.h
> +++ b/gcc/ipa-modref.h
> @@ -29,6 +29,7 @@ struct GTY(()) modref_summary
>    /* Load and stores in function (transitively closed to all callees)  */
>    modref_records *loads;
>    modref_records *stores;
> +  auto_vec<int> GTY((skip)) arg_flags;
>  
>    modref_summary ();
>    ~modref_summary ();
> diff --git a/gcc/testsuite/gcc.dg/torture/pta-ptrarith-1.c b/gcc/testsuite/gcc.dg/torture/pta-ptrarith-1.c
> index 99a548840df..85b68068b12 100644
> --- a/gcc/testsuite/gcc.dg/torture/pta-ptrarith-1.c
> +++ b/gcc/testsuite/gcc.dg/torture/pta-ptrarith-1.c
> @@ -6,11 +6,14 @@ struct Foo {
>    int *p;
>  };
>  
> +struct Foo *ff;
> +
>  void __attribute__((noinline))
>  foo (void *p)
>  {
>    struct Foo *f = (struct Foo *)p - 1;
>    *f->p = 0;
> +  ff = f;
>  }
>  
>  int bar (void)
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Felix Imend

  parent reply	other threads:[~2020-11-10 11:04 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-11-08 12:47 Definition of EAF_NOESCAPE and fnspec strings Jan Hubicka
2020-11-09  7:31 ` Richard Biener
2020-11-09 10:29   ` Jan Hubicka
2020-11-09 12:38     ` Richard Biener
2020-11-09 13:16       ` Detect EAF flags in ipa-modref Jan Hubicka
2020-11-09 23:14         ` Jan Hubicka
2020-11-10  9:17           ` Jan Hubicka
2020-11-10 10:25           ` Jan Hubicka
2020-11-10 10:55             ` Jan Hubicka
2020-11-10 11:04           ` Richard Biener [this message]
2020-11-10 12:54             ` Jan Hubicka
2020-11-10 14:31               ` Jan Hubicka
2020-11-13  8:06                 ` Richard Biener
2020-11-15 13:25                   ` H.J. Lu
2020-11-15 14:13                     ` Jan Hubicka
2020-11-15 10:41                 ` Andreas Schwab
2020-11-15 11:12                   ` Jan Hubicka
2020-11-15 11:25                     ` Rainer Orth
2020-11-15 12:33                       ` Jan Hubicka
2020-11-15 12:43                         ` Rainer Orth
2020-11-15 13:03                           ` Jan Hubicka
2020-11-15 16:03                             ` Rainer Orth
2020-11-15 16:15                             ` Andreas Schwab
2020-11-15 18:07                               ` Jan Hubicka
2020-11-16  7:48                                 ` Richard Biener
2020-11-16  9:26                                 ` Andreas Schwab
2020-11-16 10:59                                   ` Jan Hubicka
2020-11-16 12:36                                     ` Richard Biener
2020-11-16 12:44                                       ` Jan Hubicka
2020-11-16 19:33                                         ` Martin Liška
2020-11-16 19:46                                           ` Jan Hubicka
2020-11-11 10:09               ` Richard Biener

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=nycvar.YFH.7.76.2011101136010.10073@p653.nepu.fhfr.qr \
    --to=rguenther@suse.de \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=gcc@gcc.gnu.org \
    --cc=hubicka@ucw.cz \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).