[PATCH] ipa: Teach IPA-CP transformation about IPA-SRA modifications (PR 103227)

2021-11-24 Thread Martin Jambor
Hi,

PR 103227 exposed an issue with ordering of transformations of IPA
passes.  IPA-CP can create clones for constants passed by reference
and at the same time IPA-SRA can also decide that the parameter does
not need to be a pointer (or an aggregate) and plan to convert it
into (a) simple scalar(s).  Because no intermediate clone is created
just for the purpose of ordering the transformations and because
IPA-SRA transformation is implemented as part of clone
materialization, the IPA-CP transformation happens only afterwards,
reversing the order of the transformations compared to the ordering of
analyses.

IPA-CP transformation looks at planned substitutions for values passed
by reference or in aggregates but finds that all the relevant
parameters no longer exist.  Currently it subsequently simply gives
up, leading to clones created for no good purpose (and huge regression
of 548.exchange_r.  This patch teaches it recognize the situation,
look up the new scalarized parameter and perform value substitution on
it.  On my desktop this has recovered the lost exchange2 run-time (and
some more).

I have disabled IPA-SRA in a Fortran testcase so that the dumping from
the transformation phase can still be matched in order to verify that
IPA-CP understands the IL after verifying that it does the right thing
also with IPA-SRA.

Bootstrapped, LTO-bootstrapped and tested on x86_64.
Profiled-LTO-bootstrap on the same platform and normal bootstrap and
testing is underway on i686-linux and aarch64-linux.  OK all of that
passes as well?

Thanks,

Martin


gcc/ChangeLog:

2021-11-23  Martin Jambor  

PR ipa/103227
* ipa-prop.h (ipa_get_param): New overload.  Move bits of the existing
one to the new one.
* ipa-param-manipulation.h (ipa_param_adjustments): New member
function get_updated_index_or_split.
* ipa-param-manipulation.c
(ipa_param_adjustments::get_updated_index_or_split): New function.
* ipa-prop.c (adjust_agg_replacement_values): Reimplement, add
capability to identify scalarized parameters and perform substitution
on them.
(ipcp_transform_function): Create descriptors earlier, handle new
return values of adjust_agg_replacement_values.

gcc/testsuite/ChangeLog:

2021-11-23  Martin Jambor  

PR ipa/103227
* gcc.dg/ipa/pr103227-1.c: New test.
* gcc.dg/ipa/pr103227-3.c: Likewise.
* gcc.dg/ipa/pr103227-2.c: Likewise.
* gfortran.dg/pr53787.f90: Disable IPA-SRA.
---
 gcc/ipa-param-manipulation.c  | 33 
 gcc/ipa-param-manipulation.h  |  7 +++
 gcc/ipa-prop.c| 73 +++
 gcc/ipa-prop.h| 15 --
 gcc/testsuite/gcc.dg/ipa/pr103227-1.c | 29 +++
 gcc/testsuite/gcc.dg/ipa/pr103227-2.c | 29 +++
 gcc/testsuite/gcc.dg/ipa/pr103227-3.c | 52 +++
 gcc/testsuite/gfortran.dg/pr53787.f90 |  2 +-
 8 files changed, 216 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/ipa/pr103227-1.c
 create mode 100644 gcc/testsuite/gcc.dg/ipa/pr103227-2.c
 create mode 100644 gcc/testsuite/gcc.dg/ipa/pr103227-3.c

diff --git a/gcc/ipa-param-manipulation.c b/gcc/ipa-param-manipulation.c
index cec1dba701f..479c20b3871 100644
--- a/gcc/ipa-param-manipulation.c
+++ b/gcc/ipa-param-manipulation.c
@@ -449,6 +449,39 @@ ipa_param_adjustments::get_updated_indices (vec 
*new_indices)
 }
 }
 
+/* If a parameter with original INDEX has survived intact, return its new
+   index.  Otherwise return -1.  In that case, if it has been split and there
+   is a new parameter representing a portion at unit OFFSET for which a value
+   of a TYPE can be substituted, store its new index into SPLIT_INDEX,
+   otherwise store -1 there.  */
+int
+ipa_param_adjustments::get_updated_index_or_split (int index,
+  unsigned unit_offset,
+  tree type, int *split_index)
+{
+  unsigned adj_len = vec_safe_length (m_adj_params);
+  for (unsigned i = 0; i < adj_len ; i++)
+{
+  ipa_adjusted_param *apm = &(*m_adj_params)[i];
+  if (apm->base_index != index)
+   continue;
+  if (apm->op == IPA_PARAM_OP_COPY)
+   return i;
+  if (apm->op == IPA_PARAM_OP_SPLIT
+ && apm->unit_offset == unit_offset)
+   {
+ if (useless_type_conversion_p (apm->type, type))
+   *split_index = i;
+ else
+   *split_index = -1;
+ return -1;
+   }
+}
+
+  *split_index = -1;
+  return -1;
+}
+
 /* Return the original index for the given new parameter index.  Return a
negative number if not available.  */
 
diff --git a/gcc/ipa-param-manipulation.h b/gcc/ipa-param-manipulation.h
index 5adf8a22356..d1dad9fac73 100644
--- a/gcc/ipa-param-manipulation.h
+++ b/gcc/ipa-param-manipulation.h
@@ -236,6 +236,13 @@ public:
   void get_surviving_params (vec *

Re: [PATCH] ipa: Teach IPA-CP transformation about IPA-SRA modifications (PR 103227)

2021-11-25 Thread Jan Hubicka via Gcc-patches
> 
> gcc/ChangeLog:
> 
> 2021-11-23  Martin Jambor  
> 
>   PR ipa/103227
>   * ipa-prop.h (ipa_get_param): New overload.  Move bits of the existing
>   one to the new one.
>   * ipa-param-manipulation.h (ipa_param_adjustments): New member
>   function get_updated_index_or_split.
>   * ipa-param-manipulation.c
>   (ipa_param_adjustments::get_updated_index_or_split): New function.
>   * ipa-prop.c (adjust_agg_replacement_values): Reimplement, add
>   capability to identify scalarized parameters and perform substitution
>   on them.
>   (ipcp_transform_function): Create descriptors earlier, handle new
>   return values of adjust_agg_replacement_values.
> 
> gcc/testsuite/ChangeLog:
> 
> 2021-11-23  Martin Jambor  
> 
>   PR ipa/103227
>   * gcc.dg/ipa/pr103227-1.c: New test.
>   * gcc.dg/ipa/pr103227-3.c: Likewise.
>   * gcc.dg/ipa/pr103227-2.c: Likewise.
>   * gfortran.dg/pr53787.f90: Disable IPA-SRA.
> ---
>  gcc/ipa-param-manipulation.c  | 33 
>  gcc/ipa-param-manipulation.h  |  7 +++
>  gcc/ipa-prop.c| 73 +++
>  gcc/ipa-prop.h| 15 --
>  gcc/testsuite/gcc.dg/ipa/pr103227-1.c | 29 +++
>  gcc/testsuite/gcc.dg/ipa/pr103227-2.c | 29 +++
>  gcc/testsuite/gcc.dg/ipa/pr103227-3.c | 52 +++
>  gcc/testsuite/gfortran.dg/pr53787.f90 |  2 +-
>  8 files changed, 216 insertions(+), 24 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/ipa/pr103227-1.c
>  create mode 100644 gcc/testsuite/gcc.dg/ipa/pr103227-2.c
>  create mode 100644 gcc/testsuite/gcc.dg/ipa/pr103227-3.c
> 
> diff --git a/gcc/ipa-param-manipulation.c b/gcc/ipa-param-manipulation.c
> index cec1dba701f..479c20b3871 100644
> --- a/gcc/ipa-param-manipulation.c
> +++ b/gcc/ipa-param-manipulation.c
> @@ -449,6 +449,39 @@ ipa_param_adjustments::get_updated_indices (vec 
> *new_indices)
>  }
>  }
>  
> +/* If a parameter with original INDEX has survived intact, return its new
> +   index.  Otherwise return -1.  In that case, if it has been split and there
> +   is a new parameter representing a portion at unit OFFSET for which a value
> +   of a TYPE can be substituted, store its new index into SPLIT_INDEX,
> +   otherwise store -1 there.  */
> +int
> +ipa_param_adjustments::get_updated_index_or_split (int index,
> +unsigned unit_offset,
> +tree type, int *split_index)
> +{
> +  unsigned adj_len = vec_safe_length (m_adj_params);
> +  for (unsigned i = 0; i < adj_len ; i++)

In ipa-modref I precompute this to map so we do not need to walk all
params, but the loop is probably not bad since functions do not have
tens of thousdands parameters :)

Can I use it in ipa-modref to discover what parameters was turned from
by-reference to scalar, too?
> +{
> +  ipa_adjusted_param *apm = &(*m_adj_params)[i];
> +  if (apm->base_index != index)
> + continue;
> +  if (apm->op == IPA_PARAM_OP_COPY)
> + return i;
> +  if (apm->op == IPA_PARAM_OP_SPLIT
> +   && apm->unit_offset == unit_offset)
> + {
> +   if (useless_type_conversion_p (apm->type, type))
> + *split_index = i;
> +   else
> + *split_index = -1;
> +   return -1;
> + }
> +}
> +
> +  *split_index = -1;
> +  return -1;
> +}
> +
>  /* Return the original index for the given new parameter index.  Return a
> negative number if not available.  */
>  
> diff --git a/gcc/ipa-param-manipulation.h b/gcc/ipa-param-manipulation.h
> index 5adf8a22356..d1dad9fac73 100644
> --- a/gcc/ipa-param-manipulation.h
> +++ b/gcc/ipa-param-manipulation.h
> @@ -236,6 +236,13 @@ public:
>void get_surviving_params (vec *surviving_params);
>/* Fill a vector with new indices of surviving original parameters.  */
>void get_updated_indices (vec *new_indices);
> +  /* If a parameter with original INDEX has survived intact, return its new
> + index.  Otherwise return -1.  In that case, if it has been split and 
> there
> + is a new parameter representing a portion at UNIT_OFFSET for which a 
> value
> + of a TYPE can be substituted, store its new index into SPLIT_INDEX,
> + otherwise store -1 there.  */
> +  int get_updated_index_or_split (int index, unsigned unit_offset, tree type,
> +   int *split_index);
>/* Return the original index for the given new parameter index.  Return a
>   negative number if not available.  */
>int get_original_index (int newidx);
> diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
> index e85df0971fc..a297f50e945 100644
> --- a/gcc/ipa-prop.c
> +++ b/gcc/ipa-prop.c
> @@ -5578,32 +5578,55 @@ ipcp_read_transformation_summaries (void)
>  }
>  
>  /* Adjust the aggregate replacements in AGGVAL to reflect parameters skipped 
> in
> -   NODE.  */
> +   NODE but also if any parameter was I

Re: [PATCH] ipa: Teach IPA-CP transformation about IPA-SRA modifications (PR 103227)

2021-11-25 Thread Martin Jambor
Hi,

On Thu, Nov 25 2021, Jan Hubicka wrote:
>> 
>> gcc/ChangeLog:
>> 
>> 2021-11-23  Martin Jambor  
>> 
>>  PR ipa/103227
>>  * ipa-prop.h (ipa_get_param): New overload.  Move bits of the existing
>>  one to the new one.
>>  * ipa-param-manipulation.h (ipa_param_adjustments): New member
>>  function get_updated_index_or_split.
>>  * ipa-param-manipulation.c
>>  (ipa_param_adjustments::get_updated_index_or_split): New function.
>>  * ipa-prop.c (adjust_agg_replacement_values): Reimplement, add
>>  capability to identify scalarized parameters and perform substitution
>>  on them.
>>  (ipcp_transform_function): Create descriptors earlier, handle new
>>  return values of adjust_agg_replacement_values.
>> 
>> gcc/testsuite/ChangeLog:
>> 
>> 2021-11-23  Martin Jambor  
>> 
>>  PR ipa/103227
>>  * gcc.dg/ipa/pr103227-1.c: New test.
>>  * gcc.dg/ipa/pr103227-3.c: Likewise.
>>  * gcc.dg/ipa/pr103227-2.c: Likewise.
>>  * gfortran.dg/pr53787.f90: Disable IPA-SRA.
>> ---
>>  gcc/ipa-param-manipulation.c  | 33 
>>  gcc/ipa-param-manipulation.h  |  7 +++
>>  gcc/ipa-prop.c| 73 +++
>>  gcc/ipa-prop.h| 15 --
>>  gcc/testsuite/gcc.dg/ipa/pr103227-1.c | 29 +++
>>  gcc/testsuite/gcc.dg/ipa/pr103227-2.c | 29 +++
>>  gcc/testsuite/gcc.dg/ipa/pr103227-3.c | 52 +++
>>  gcc/testsuite/gfortran.dg/pr53787.f90 |  2 +-
>>  8 files changed, 216 insertions(+), 24 deletions(-)
>>  create mode 100644 gcc/testsuite/gcc.dg/ipa/pr103227-1.c
>>  create mode 100644 gcc/testsuite/gcc.dg/ipa/pr103227-2.c
>>  create mode 100644 gcc/testsuite/gcc.dg/ipa/pr103227-3.c
>> 
>> diff --git a/gcc/ipa-param-manipulation.c b/gcc/ipa-param-manipulation.c
>> index cec1dba701f..479c20b3871 100644
>> --- a/gcc/ipa-param-manipulation.c
>> +++ b/gcc/ipa-param-manipulation.c
>> @@ -449,6 +449,39 @@ ipa_param_adjustments::get_updated_indices (vec 
>> *new_indices)
>>  }
>>  }
>>  
>> +/* If a parameter with original INDEX has survived intact, return its new
>> +   index.  Otherwise return -1.  In that case, if it has been split and 
>> there
>> +   is a new parameter representing a portion at unit OFFSET for which a 
>> value
>> +   of a TYPE can be substituted, store its new index into SPLIT_INDEX,
>> +   otherwise store -1 there.  */
>> +int
>> +ipa_param_adjustments::get_updated_index_or_split (int index,
>> +   unsigned unit_offset,
>> +   tree type, int *split_index)
>> +{
>> +  unsigned adj_len = vec_safe_length (m_adj_params);
>> +  for (unsigned i = 0; i < adj_len ; i++)
>
> In ipa-modref I precompute this to map so we do not need to walk all
> params, but the loop is probably not bad since functions do not have
> tens of thousdands parameters :)

The most I have seen is about 70 and those were big outliers.

I was thinking of precomputing it somehow but for one parameter there
can be up to param ipa-sra-max-replacements replacements (default 8 -
and there is another, by default stricter, limit for pointers).  So it
would have to be a hash table or something like it.

>
> Can I use it in ipa-modref to discover what parameters was turned from
> by-reference to scalar, too?

IIUC, I don't think you directly can, also because for one parameter you
can have more scalar replacements and the interface needs an offset for
which to look.  OTOH, if you only care about simple scalars passed by
reference, then passing zero as offset - and probably adding a flag to
check there are no replacements at other offsets - would work.  (But
that information could also be easily pre-computed.)

>> +{
>> +  ipa_adjusted_param *apm = &(*m_adj_params)[i];
>> +  if (apm->base_index != index)
>> +continue;
>> +  if (apm->op == IPA_PARAM_OP_COPY)
>> +return i;
>> +  if (apm->op == IPA_PARAM_OP_SPLIT
>> +  && apm->unit_offset == unit_offset)
>> +{
>> +  if (useless_type_conversion_p (apm->type, type))
>> +*split_index = i;
>> +  else
>> +*split_index = -1;
>> +  return -1;
>> +}
>> +}
>> +
>> +  *split_index = -1;
>> +  return -1;
>> +}
>> +
>>  /* Return the original index for the given new parameter index.  Return a
>> negative number if not available.  */
>>  
>> diff --git a/gcc/ipa-param-manipulation.h b/gcc/ipa-param-manipulation.h
>> index 5adf8a22356..d1dad9fac73 100644
>> --- a/gcc/ipa-param-manipulation.h
>> +++ b/gcc/ipa-param-manipulation.h
>> @@ -236,6 +236,13 @@ public:
>>void get_surviving_params (vec *surviving_params);
>>/* Fill a vector with new indices of surviving original parameters.  */
>>void get_updated_indices (vec *new_indices);
>> +  /* If a parameter with original INDEX has survived intact, return its new
>> + index.  Otherwise return -1.  In that case, if it has been spli

Re: [PATCH] ipa: Teach IPA-CP transformation about IPA-SRA modifications (PR 103227)

2021-11-25 Thread Jan Hubicka via Gcc-patches
> >
> > In ipa-modref I precompute this to map so we do not need to walk all
> > params, but the loop is probably not bad since functions do not have
> > tens of thousdands parameters :)
> 
> The most I have seen is about 70 and those were big outliers.
> 
> I was thinking of precomputing it somehow but for one parameter there
> can be up to param ipa-sra-max-replacements replacements (default 8 -
> and there is another, by default stricter, limit for pointers).  So it
> would have to be a hash table or something like it.

Yep, I think given that we have API, we can play with this later.
> 
> >
> > Can I use it in ipa-modref to discover what parameters was turned from
> > by-reference to scalar, too?
> 
> IIUC, I don't think you directly can, also because for one parameter you
> can have more scalar replacements and the interface needs an offset for
> which to look.  OTOH, if you only care about simple scalars passed by
> reference, then passing zero as offset - and probably adding a flag to
> check there are no replacements at other offsets - would work.  (But
> that information could also be easily pre-computed.)

If parameter is broken up into multipe pieces, I can just duplicate its
ECF flags (if I know that pointers from whole structure does not escape,
neither does pointers from its part). However presently modref compute
noting useful for aggregate parameters (have patch for that but it was
too late in this stage1 to push out everything, so it will come next
stage1).

If parameter is turned from by-reference and possibly offsetted, I can
use the original ECF flag after applying deref_flags translation.
Again it is not problem to multily it if the parameter is stplit into
multiple subparameters.

Honza