Add static_chain support to ipa-modref

Message ID 20211101081027.GA74431@kam.mff.cuni.cz
State Committed
Commit a70c05120ae6f15f204a04a7df7d19941ab33ef1
Headers
Series Add static_chain support to ipa-modref |

Commit Message

Jan Hubicka Nov. 1, 2021, 8:10 a.m. UTC
  Hi,
this is patchs teaches ipa-modref about the static chain that is, like
retslot, a hiden argument.  The patch is pretty much symemtric to what
was done for retslot handling and I verified it does the intended job
for Ada LTO bootstrap.

Bootstrapped/regtested x86_64-linux, OK?

Honza

gcc/ChangeLog:

	* gimple.c (gimple_call_static_chain_flags): New function.
	* gimple.h (gimple_call_static_chain_flags): Declare
	* ipa-modref.c (modref_summary::modref_summary): Initialize
	static_chain_flags.
	(modref_summary_lto::modref_summary_lto): Likewise.
	(modref_summary::useful_p): Test static_chain_flags.
	(modref_summary_lto::useful_p): Likewise.
	(struct modref_summary_lto): Add static_chain_flags.
	(modref_summary::dump): Dump static_chain_flags.
	(modref_summary_lto::dump): Likewise.
	(struct escape_point): Add static_cahin_arg.
	(analyze_ssa_name_flags): Use gimple_call_static_chain_flags.
	(analyze_parms): Handle static chains.
	(modref_summaries::duplicate): Duplicate static_chain_flags.
	(modref_summaries_lto::duplicate): Likewise.
	(modref_write): Stream static_chain_flags.
	(read_section): Likewise.
	(modref_merge_call_site_flags): Handle static_chain_flags.
	* ipa-modref.h (struct modref_summary): Add static_chain_flags.
	* tree-ssa-structalias.c (handle_rhs_call): Use
	* gimple_static_chain_flags.

gcc/testsuite/ChangeLog:

	* gcc.dg/ipa/modref-3.c: New test.
  

Comments

Richard Biener Nov. 2, 2021, 1:21 p.m. UTC | #1
On Mon, 1 Nov 2021, Jan Hubicka wrote:

> Hi,
> this is patchs teaches ipa-modref about the static chain that is, like
> retslot, a hiden argument.  The patch is pretty much symemtric to what
> was done for retslot handling and I verified it does the intended job
> for Ada LTO bootstrap.
> 
> Bootstrapped/regtested x86_64-linux, OK?

OK.

Thanks,
Richard.

> Honza
> 
> gcc/ChangeLog:
> 
> 	* gimple.c (gimple_call_static_chain_flags): New function.
> 	* gimple.h (gimple_call_static_chain_flags): Declare
> 	* ipa-modref.c (modref_summary::modref_summary): Initialize
> 	static_chain_flags.
> 	(modref_summary_lto::modref_summary_lto): Likewise.
> 	(modref_summary::useful_p): Test static_chain_flags.
> 	(modref_summary_lto::useful_p): Likewise.
> 	(struct modref_summary_lto): Add static_chain_flags.
> 	(modref_summary::dump): Dump static_chain_flags.
> 	(modref_summary_lto::dump): Likewise.
> 	(struct escape_point): Add static_cahin_arg.
> 	(analyze_ssa_name_flags): Use gimple_call_static_chain_flags.
> 	(analyze_parms): Handle static chains.
> 	(modref_summaries::duplicate): Duplicate static_chain_flags.
> 	(modref_summaries_lto::duplicate): Likewise.
> 	(modref_write): Stream static_chain_flags.
> 	(read_section): Likewise.
> 	(modref_merge_call_site_flags): Handle static_chain_flags.
> 	* ipa-modref.h (struct modref_summary): Add static_chain_flags.
> 	* tree-ssa-structalias.c (handle_rhs_call): Use
> 	* gimple_static_chain_flags.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.dg/ipa/modref-3.c: New test.
> 
> diff --git a/gcc/gimple.c b/gcc/gimple.c
> index 22dd6417d19..ef07d9385c5 100644
> --- a/gcc/gimple.c
> +++ b/gcc/gimple.c
> @@ -1647,6 +1647,33 @@ gimple_call_retslot_flags (const gcall *stmt)
>    return flags;
>  }
>  
> +/* Detects argument flags for static chain on call STMT.  */
> +
> +int
> +gimple_call_static_chain_flags (const gcall *stmt)
> +{
> +  int flags = 0;
> +
> +  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)
> +	{
> +	  int modref_flags = summary->static_chain_flags;
> +
> +	  /* We have possibly optimized out load.  Be conservative here.  */
> +	  gcc_checking_assert (node->binds_to_current_def_p ());
> +	  if (dbg_cnt (ipa_mod_ref_pta))
> +	    flags |= modref_flags;
> +	}
> +    }
> +  return flags;
> +}
> +
>  /* Detects return flags for the call STMT.  */
>  
>  int
> diff --git a/gcc/gimple.h b/gcc/gimple.h
> index 23a124ec769..3cde3cde7fe 100644
> --- a/gcc/gimple.h
> +++ b/gcc/gimple.h
> @@ -1590,6 +1590,7 @@ bool gimple_call_same_target_p (const gimple *, const gimple *);
>  int gimple_call_flags (const gimple *);
>  int gimple_call_arg_flags (const gcall *, unsigned);
>  int gimple_call_retslot_flags (const gcall *);
> +int gimple_call_static_chain_flags (const gcall *);
>  int gimple_call_return_flags (const gcall *);
>  bool gimple_call_nonnull_result_p (gcall *);
>  tree gimple_call_nonnull_arg (gcall *);
> diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c
> index d866d9ed6b3..ae8ed53b396 100644
> --- a/gcc/ipa-modref.c
> +++ b/gcc/ipa-modref.c
> @@ -270,7 +270,8 @@ static GTY(()) fast_function_summary <modref_summary_lto *, va_gc>
>  /* Summary for a single function which this pass produces.  */
>  
>  modref_summary::modref_summary ()
> -  : loads (NULL), stores (NULL), retslot_flags (0), writes_errno (false)
> +  : loads (NULL), stores (NULL), retslot_flags (0), static_chain_flags (0),
> +    writes_errno (false)
>  {
>  }
>  
> @@ -325,6 +326,9 @@ modref_summary::useful_p (int ecf_flags, bool check_flags)
>    arg_flags.release ();
>    if (check_flags && remove_useless_eaf_flags (retslot_flags, ecf_flags, false))
>      return true;
> +  if (check_flags
> +      && remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
> +    return true;
>    if (ecf_flags & ECF_CONST)
>      return false;
>    if (loads && !loads->every_base)
> @@ -367,6 +371,7 @@ struct GTY(()) modref_summary_lto
>    modref_records_lto *stores;
>    auto_vec<eaf_flags_t> GTY((skip)) arg_flags;
>    eaf_flags_t retslot_flags;
> +  eaf_flags_t static_chain_flags;
>    bool writes_errno;
>  
>    modref_summary_lto ();
> @@ -378,7 +383,8 @@ struct GTY(()) modref_summary_lto
>  /* Summary for a single function which this pass produces.  */
>  
>  modref_summary_lto::modref_summary_lto ()
> -  : loads (NULL), stores (NULL), retslot_flags (0), writes_errno (false)
> +  : loads (NULL), stores (NULL), retslot_flags (0), static_chain_flags (0),
> +    writes_errno (false)
>  {
>  }
>  
> @@ -406,6 +412,9 @@ modref_summary_lto::useful_p (int ecf_flags, bool check_flags)
>    arg_flags.release ();
>    if (check_flags && remove_useless_eaf_flags (retslot_flags, ecf_flags, false))
>      return true;
> +  if (check_flags
> +      && remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
> +    return true;
>    if (ecf_flags & ECF_CONST)
>      return false;
>    if (loads && !loads->every_base)
> @@ -619,6 +628,11 @@ modref_summary::dump (FILE *out)
>        fprintf (out, "  Retslot flags:");
>        dump_eaf_flags (out, retslot_flags);
>      }
> +  if (static_chain_flags)
> +    {
> +      fprintf (out, "  Static chain flags:");
> +      dump_eaf_flags (out, static_chain_flags);
> +    }
>  }
>  
>  /* Dump summary.  */
> @@ -646,6 +660,11 @@ modref_summary_lto::dump (FILE *out)
>        fprintf (out, "  Retslot flags:");
>        dump_eaf_flags (out, retslot_flags);
>      }
> +  if (static_chain_flags)
> +    {
> +      fprintf (out, "  Static chain flags:");
> +      dump_eaf_flags (out, static_chain_flags);
> +    }
>  }
>  
>  /* Get function summary for FUNC if it exists, return NULL otherwise.  */
> @@ -1415,7 +1434,8 @@ struct escape_point
>    /* Extra hidden args we keep track of.  */
>    enum hidden_args
>    {
> -    retslot_arg = -1
> +    retslot_arg = -1,
> +    static_chain_arg = -2
>    };
>    /* Value escapes to this call.  */
>    gcall *call;
> @@ -1776,11 +1796,9 @@ analyze_ssa_name_flags (tree name, vec<modref_lattice> &lattice, int depth,
>  		    lattice[index].merge (gimple_call_retslot_flags (call));
>  		}
>  
> -	      /* We do not track accesses to the static chain (we could)
> -		 so give up.  */
>  	      if (gimple_call_chain (call)
>  		  && (gimple_call_chain (call) == name))
> -		lattice[index].merge (0);
> +		lattice[index].merge (gimple_call_static_chain_flags (call));
>  
>  	      /* Process internal functions and right away.  */
>  	      bool record_ipa = ipa && !gimple_call_internal_p (call);
> @@ -1970,6 +1988,7 @@ analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
>    unsigned int count = 0;
>    int ecf_flags = flags_from_decl_or_type (current_function_decl);
>    tree retslot = NULL;
> +  tree static_chain = NULL;
>  
>    /* For novops functions we have nothing to gain by EAF flags.  */
>    if (ecf_flags & ECF_NOVOPS)
> @@ -1979,12 +1998,14 @@ analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
>    if (DECL_RESULT (current_function_decl)
>        && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
>      retslot = ssa_default_def (cfun, DECL_RESULT (current_function_decl));
> +  if (cfun->static_chain_decl)
> +    static_chain = ssa_default_def (cfun, cfun->static_chain_decl);
>  
>    for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
>         parm = TREE_CHAIN (parm))
>      count++;
>  
> -  if (!count && !retslot)
> +  if (!count && !retslot && !static_chain)
>      return;
>  
>    auto_vec<modref_lattice> lattice;
> @@ -2058,6 +2079,22 @@ analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
>  				escape_point::retslot_arg, flags);
>  	}
>      }
> +  if (static_chain)
> +    {
> +      analyze_ssa_name_flags (static_chain, lattice, 0, ipa);
> +      int flags = lattice[SSA_NAME_VERSION (static_chain)].flags;
> +
> +      flags = remove_useless_eaf_flags (flags, ecf_flags, false);
> +      if (flags)
> +	{
> +	  if (summary)
> +	    summary->static_chain_flags = flags;
> +	  if (summary_lto)
> +	    summary_lto->static_chain_flags = flags;
> +	  record_escape_points (lattice[SSA_NAME_VERSION (static_chain)],
> +				escape_point::static_chain_arg, flags);
> +	}
> +    }
>    if (ipa)
>      for (unsigned int i = 0; i < num_ssa_names; i++)
>        lattice[i].release ();
> @@ -2342,6 +2379,7 @@ modref_summaries::duplicate (cgraph_node *, cgraph_node *dst,
>    if (src_data->arg_flags.length ())
>      dst_data->arg_flags = src_data->arg_flags.copy ();
>    dst_data->retslot_flags = src_data->retslot_flags;
> +  dst_data->static_chain_flags = src_data->static_chain_flags;
>  }
>  
>  /* Called when new clone is inserted to callgraph late.  */
> @@ -2368,6 +2406,7 @@ modref_summaries_lto::duplicate (cgraph_node *, cgraph_node *,
>    if (src_data->arg_flags.length ())
>      dst_data->arg_flags = src_data->arg_flags.copy ();
>    dst_data->retslot_flags = src_data->retslot_flags;
> +  dst_data->static_chain_flags = src_data->static_chain_flags;
>  }
>  
>  namespace
> @@ -2685,6 +2724,7 @@ modref_write ()
>  	  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);
> +	  streamer_write_uhwi (ob, r->static_chain_flags);
>  
>  	  write_modref_records (r->loads, ob);
>  	  write_modref_records (r->stores, ob);
> @@ -2786,6 +2826,13 @@ read_section (struct lto_file_decl_data *file_data, const char *data,
>  	modref_sum->retslot_flags = flags;
>        if (modref_sum_lto)
>  	modref_sum_lto->retslot_flags = flags;
> +
> +      flags = streamer_read_uhwi (&ib);
> +      if (modref_sum)
> +	modref_sum->static_chain_flags = flags;
> +      if (modref_sum_lto)
> +	modref_sum_lto->static_chain_flags = flags;
> +
>        read_modref_records (&ib, data_in,
>  			   modref_sum ? &modref_sum->loads : NULL,
>  			   modref_sum_lto ? &modref_sum_lto->loads : NULL);
> @@ -3871,6 +3918,8 @@ modref_merge_call_site_flags (escape_summary *sum,
>  	{
>  	  eaf_flags_t &f = ee->parm_index == escape_point::retslot_arg
>  			   ? cur_summary->retslot_flags
> +			   : ee->parm_index == escape_point::static_chain_arg
> +			   ? cur_summary->static_chain_flags
>  			   : cur_summary->arg_flags[ee->parm_index];
>  	  if ((f & flags) != f)
>  	    {
> @@ -3886,6 +3935,8 @@ modref_merge_call_site_flags (escape_summary *sum,
>  	{
>  	  eaf_flags_t &f = ee->parm_index == escape_point::retslot_arg
>  			   ? cur_summary_lto->retslot_flags
> +			   : ee->parm_index == escape_point::static_chain_arg
> +			   ? cur_summary_lto->static_chain_flags
>  			   : cur_summary_lto->arg_flags[ee->parm_index];
>  	  if ((f & flags_lto) != f)
>  	    {
> diff --git a/gcc/ipa-modref.h b/gcc/ipa-modref.h
> index a4db27471eb..ddc86869069 100644
> --- a/gcc/ipa-modref.h
> +++ b/gcc/ipa-modref.h
> @@ -32,6 +32,7 @@ struct GTY(()) modref_summary
>    modref_records *stores;
>    auto_vec<eaf_flags_t> GTY((skip)) arg_flags;
>    eaf_flags_t retslot_flags;
> +  eaf_flags_t static_chain_flags;
>    bool writes_errno;
>  
>    modref_summary ();
> diff --git a/gcc/testsuite/gcc.dg/ipa/modref-3.c b/gcc/testsuite/gcc.dg/ipa/modref-3.c
> new file mode 100644
> index 00000000000..84013541ce8
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/ipa/modref-3.c
> @@ -0,0 +1,20 @@
> +/* { dg-options "-O2 -fdump-ipa-modref"  } */
> +/* { dg-do link } */
> +int *ptr;
> +void linker_error ();
> +int
> +main ()
> +{
> +  int a;
> +  __attribute__((noinline)) int test2 ()
> +  {
> +    ptr = 0;
> +    return a;
> +  }
> +  a = 1;
> +  test2 ();
> +  if (a != 1)
> +    linker_error ();
> +  return 0;
> +}
> +/* { dg-final { scan-ipa-dump "Static chain flags: noclobber noescape nodirectescape" "modref" } } */
> diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
> index 99072df0768..d2a955dafeb 100644
> --- a/gcc/tree-ssa-structalias.c
> +++ b/gcc/tree-ssa-structalias.c
> @@ -4246,7 +4246,8 @@ handle_rhs_call (gcall *stmt, vec<ce_s> *results,
>    /* The static chain escapes as well.  */
>    if (gimple_call_chain (stmt))
>      handle_call_arg (stmt, gimple_call_chain (stmt), results,
> -		     implicit_eaf_flags,
> +		     implicit_eaf_flags
> +		     | gimple_call_static_chain_flags (stmt),
>  		     callescape->id, writes_global_memory);
>  
>    /* And if we applied NRV the address of the return slot escapes as well.  */
>
  

Patch

diff --git a/gcc/gimple.c b/gcc/gimple.c
index 22dd6417d19..ef07d9385c5 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -1647,6 +1647,33 @@  gimple_call_retslot_flags (const gcall *stmt)
   return flags;
 }
 
+/* Detects argument flags for static chain on call STMT.  */
+
+int
+gimple_call_static_chain_flags (const gcall *stmt)
+{
+  int flags = 0;
+
+  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)
+	{
+	  int modref_flags = summary->static_chain_flags;
+
+	  /* We have possibly optimized out load.  Be conservative here.  */
+	  gcc_checking_assert (node->binds_to_current_def_p ());
+	  if (dbg_cnt (ipa_mod_ref_pta))
+	    flags |= modref_flags;
+	}
+    }
+  return flags;
+}
+
 /* Detects return flags for the call STMT.  */
 
 int
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 23a124ec769..3cde3cde7fe 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1590,6 +1590,7 @@  bool gimple_call_same_target_p (const gimple *, const gimple *);
 int gimple_call_flags (const gimple *);
 int gimple_call_arg_flags (const gcall *, unsigned);
 int gimple_call_retslot_flags (const gcall *);
+int gimple_call_static_chain_flags (const gcall *);
 int gimple_call_return_flags (const gcall *);
 bool gimple_call_nonnull_result_p (gcall *);
 tree gimple_call_nonnull_arg (gcall *);
diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c
index d866d9ed6b3..ae8ed53b396 100644
--- a/gcc/ipa-modref.c
+++ b/gcc/ipa-modref.c
@@ -270,7 +270,8 @@  static GTY(()) fast_function_summary <modref_summary_lto *, va_gc>
 /* Summary for a single function which this pass produces.  */
 
 modref_summary::modref_summary ()
-  : loads (NULL), stores (NULL), retslot_flags (0), writes_errno (false)
+  : loads (NULL), stores (NULL), retslot_flags (0), static_chain_flags (0),
+    writes_errno (false)
 {
 }
 
@@ -325,6 +326,9 @@  modref_summary::useful_p (int ecf_flags, bool check_flags)
   arg_flags.release ();
   if (check_flags && remove_useless_eaf_flags (retslot_flags, ecf_flags, false))
     return true;
+  if (check_flags
+      && remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
+    return true;
   if (ecf_flags & ECF_CONST)
     return false;
   if (loads && !loads->every_base)
@@ -367,6 +371,7 @@  struct GTY(()) modref_summary_lto
   modref_records_lto *stores;
   auto_vec<eaf_flags_t> GTY((skip)) arg_flags;
   eaf_flags_t retslot_flags;
+  eaf_flags_t static_chain_flags;
   bool writes_errno;
 
   modref_summary_lto ();
@@ -378,7 +383,8 @@  struct GTY(()) modref_summary_lto
 /* Summary for a single function which this pass produces.  */
 
 modref_summary_lto::modref_summary_lto ()
-  : loads (NULL), stores (NULL), retslot_flags (0), writes_errno (false)
+  : loads (NULL), stores (NULL), retslot_flags (0), static_chain_flags (0),
+    writes_errno (false)
 {
 }
 
@@ -406,6 +412,9 @@  modref_summary_lto::useful_p (int ecf_flags, bool check_flags)
   arg_flags.release ();
   if (check_flags && remove_useless_eaf_flags (retslot_flags, ecf_flags, false))
     return true;
+  if (check_flags
+      && remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
+    return true;
   if (ecf_flags & ECF_CONST)
     return false;
   if (loads && !loads->every_base)
@@ -619,6 +628,11 @@  modref_summary::dump (FILE *out)
       fprintf (out, "  Retslot flags:");
       dump_eaf_flags (out, retslot_flags);
     }
+  if (static_chain_flags)
+    {
+      fprintf (out, "  Static chain flags:");
+      dump_eaf_flags (out, static_chain_flags);
+    }
 }
 
 /* Dump summary.  */
@@ -646,6 +660,11 @@  modref_summary_lto::dump (FILE *out)
       fprintf (out, "  Retslot flags:");
       dump_eaf_flags (out, retslot_flags);
     }
+  if (static_chain_flags)
+    {
+      fprintf (out, "  Static chain flags:");
+      dump_eaf_flags (out, static_chain_flags);
+    }
 }
 
 /* Get function summary for FUNC if it exists, return NULL otherwise.  */
@@ -1415,7 +1434,8 @@  struct escape_point
   /* Extra hidden args we keep track of.  */
   enum hidden_args
   {
-    retslot_arg = -1
+    retslot_arg = -1,
+    static_chain_arg = -2
   };
   /* Value escapes to this call.  */
   gcall *call;
@@ -1776,11 +1796,9 @@  analyze_ssa_name_flags (tree name, vec<modref_lattice> &lattice, int depth,
 		    lattice[index].merge (gimple_call_retslot_flags (call));
 		}
 
-	      /* We do not track accesses to the static chain (we could)
-		 so give up.  */
 	      if (gimple_call_chain (call)
 		  && (gimple_call_chain (call) == name))
-		lattice[index].merge (0);
+		lattice[index].merge (gimple_call_static_chain_flags (call));
 
 	      /* Process internal functions and right away.  */
 	      bool record_ipa = ipa && !gimple_call_internal_p (call);
@@ -1970,6 +1988,7 @@  analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
   unsigned int count = 0;
   int ecf_flags = flags_from_decl_or_type (current_function_decl);
   tree retslot = NULL;
+  tree static_chain = NULL;
 
   /* For novops functions we have nothing to gain by EAF flags.  */
   if (ecf_flags & ECF_NOVOPS)
@@ -1979,12 +1998,14 @@  analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
   if (DECL_RESULT (current_function_decl)
       && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
     retslot = ssa_default_def (cfun, DECL_RESULT (current_function_decl));
+  if (cfun->static_chain_decl)
+    static_chain = ssa_default_def (cfun, cfun->static_chain_decl);
 
   for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
        parm = TREE_CHAIN (parm))
     count++;
 
-  if (!count && !retslot)
+  if (!count && !retslot && !static_chain)
     return;
 
   auto_vec<modref_lattice> lattice;
@@ -2058,6 +2079,22 @@  analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
 				escape_point::retslot_arg, flags);
 	}
     }
+  if (static_chain)
+    {
+      analyze_ssa_name_flags (static_chain, lattice, 0, ipa);
+      int flags = lattice[SSA_NAME_VERSION (static_chain)].flags;
+
+      flags = remove_useless_eaf_flags (flags, ecf_flags, false);
+      if (flags)
+	{
+	  if (summary)
+	    summary->static_chain_flags = flags;
+	  if (summary_lto)
+	    summary_lto->static_chain_flags = flags;
+	  record_escape_points (lattice[SSA_NAME_VERSION (static_chain)],
+				escape_point::static_chain_arg, flags);
+	}
+    }
   if (ipa)
     for (unsigned int i = 0; i < num_ssa_names; i++)
       lattice[i].release ();
@@ -2342,6 +2379,7 @@  modref_summaries::duplicate (cgraph_node *, cgraph_node *dst,
   if (src_data->arg_flags.length ())
     dst_data->arg_flags = src_data->arg_flags.copy ();
   dst_data->retslot_flags = src_data->retslot_flags;
+  dst_data->static_chain_flags = src_data->static_chain_flags;
 }
 
 /* Called when new clone is inserted to callgraph late.  */
@@ -2368,6 +2406,7 @@  modref_summaries_lto::duplicate (cgraph_node *, cgraph_node *,
   if (src_data->arg_flags.length ())
     dst_data->arg_flags = src_data->arg_flags.copy ();
   dst_data->retslot_flags = src_data->retslot_flags;
+  dst_data->static_chain_flags = src_data->static_chain_flags;
 }
 
 namespace
@@ -2685,6 +2724,7 @@  modref_write ()
 	  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);
+	  streamer_write_uhwi (ob, r->static_chain_flags);
 
 	  write_modref_records (r->loads, ob);
 	  write_modref_records (r->stores, ob);
@@ -2786,6 +2826,13 @@  read_section (struct lto_file_decl_data *file_data, const char *data,
 	modref_sum->retslot_flags = flags;
       if (modref_sum_lto)
 	modref_sum_lto->retslot_flags = flags;
+
+      flags = streamer_read_uhwi (&ib);
+      if (modref_sum)
+	modref_sum->static_chain_flags = flags;
+      if (modref_sum_lto)
+	modref_sum_lto->static_chain_flags = flags;
+
       read_modref_records (&ib, data_in,
 			   modref_sum ? &modref_sum->loads : NULL,
 			   modref_sum_lto ? &modref_sum_lto->loads : NULL);
@@ -3871,6 +3918,8 @@  modref_merge_call_site_flags (escape_summary *sum,
 	{
 	  eaf_flags_t &f = ee->parm_index == escape_point::retslot_arg
 			   ? cur_summary->retslot_flags
+			   : ee->parm_index == escape_point::static_chain_arg
+			   ? cur_summary->static_chain_flags
 			   : cur_summary->arg_flags[ee->parm_index];
 	  if ((f & flags) != f)
 	    {
@@ -3886,6 +3935,8 @@  modref_merge_call_site_flags (escape_summary *sum,
 	{
 	  eaf_flags_t &f = ee->parm_index == escape_point::retslot_arg
 			   ? cur_summary_lto->retslot_flags
+			   : ee->parm_index == escape_point::static_chain_arg
+			   ? cur_summary_lto->static_chain_flags
 			   : cur_summary_lto->arg_flags[ee->parm_index];
 	  if ((f & flags_lto) != f)
 	    {
diff --git a/gcc/ipa-modref.h b/gcc/ipa-modref.h
index a4db27471eb..ddc86869069 100644
--- a/gcc/ipa-modref.h
+++ b/gcc/ipa-modref.h
@@ -32,6 +32,7 @@  struct GTY(()) modref_summary
   modref_records *stores;
   auto_vec<eaf_flags_t> GTY((skip)) arg_flags;
   eaf_flags_t retslot_flags;
+  eaf_flags_t static_chain_flags;
   bool writes_errno;
 
   modref_summary ();
diff --git a/gcc/testsuite/gcc.dg/ipa/modref-3.c b/gcc/testsuite/gcc.dg/ipa/modref-3.c
new file mode 100644
index 00000000000..84013541ce8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/modref-3.c
@@ -0,0 +1,20 @@ 
+/* { dg-options "-O2 -fdump-ipa-modref"  } */
+/* { dg-do link } */
+int *ptr;
+void linker_error ();
+int
+main ()
+{
+  int a;
+  __attribute__((noinline)) int test2 ()
+  {
+    ptr = 0;
+    return a;
+  }
+  a = 1;
+  test2 ();
+  if (a != 1)
+    linker_error ();
+  return 0;
+}
+/* { dg-final { scan-ipa-dump "Static chain flags: noclobber noescape nodirectescape" "modref" } } */
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index 99072df0768..d2a955dafeb 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -4246,7 +4246,8 @@  handle_rhs_call (gcall *stmt, vec<ce_s> *results,
   /* The static chain escapes as well.  */
   if (gimple_call_chain (stmt))
     handle_call_arg (stmt, gimple_call_chain (stmt), results,
-		     implicit_eaf_flags,
+		     implicit_eaf_flags
+		     | gimple_call_static_chain_flags (stmt),
 		     callescape->id, writes_global_memory);
 
   /* And if we applied NRV the address of the return slot escapes as well.  */