diff mbox

Add -funknown-commons to work around PR/69368 (and others) in SPEC2006

Message ID 1456423200-16337-1-git-send-email-alan.lawrence@arm.com
State New
Headers show

Commit Message

Alan Lawrence Feb. 25, 2016, 6 p.m. UTC
On 22/02/16 12:03, Jakub Jelinek wrote:
> (f) A global command-line option, which we check alongside DECL_COMMON and
> further tests (basically, we want only DECL_COMMON decls that either have
> ARRAY_TYPE, or some other aggregate type with flexible array member or some
> other trailing array in the struct), and use the resulting predicate in
> places where we optimize based on DECL_SIZE{,_UNIT} of the decl - if that
> predicate returns true, we assume the DECL_SIZE is
> "variable"/"unlimited"/whatever.
> The two spots known to me that would need to use this new predicate would
> be:
> tree.c (array_at_struct_end_p):
[...]
> tree-dfa.c (get_ref_base_and_extent):
[...]

Close enough to what I meant by (a)/(b), but never mind that, and I hadn't
looked at where the change for aggressive loop opts needed to be. However...
Well you are essentially writing the patch for me at this point (so, thanks!),
 but here's a patch that puts that under a global -funknown-commons flag.
Testcase as before.

Bootstrapped (with flag overridden to true) on x86_64 and aarch64, check-gcc,
check-fortran, and tested 416.gamess on AArch64, where this patch enables
running *without* the -fno-aggressive-loop-opts previously required.

In the gcc testsuite, these fail with the option turned on:
gcc.dg/pr53265.c  (test for warnings, line 137)
gcc.dg/pr53265.c  (test for warnings, line 138)
gcc.dg/pr64277.c scan-tree-dump cunroll ... (*2)
gcc.dg/tree-ssa/cunroll-{1,2,3,4,9,10,11}.c scan-tree-dump cunroll/cunrolli/ivcanon (various)
gcc.dg/tree-ssa/loop-38.c scan-tree-dump cunrolli "Loop 1 iterates at most 11 times"
...which all appear harmless.

Thomas Koenig suggests (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69368#c80)
that this be combined with some flag fiddling and warnings in the Fortran
front-end; this patch doesn't do that, as I'm not very familiar with the
frontends, but that can follow in a separate patch. (Thomas?)

OK for trunk?

Cheers, Alan

gcc/ChangeLog:

DATE  Alan Lawrence  <alan.lawrence@arm.com>
      Jakub Jelinek  <jakub@redhat.com>

	* common.opt (funknown-commons, flag_unknown_commons): New.
	* tree.c (array_at_struct_end_p): Do not limit to size of decl for
	DECL_COMMONS if flag_unknown_commons is set.
	* tree-dfa.c (get_ref_base_and_extent): Likewise.

gcc/testsuite/ChangeLog:

	* gfortran.dg/unknown_commons.f: New.
---
 gcc/common.opt                              |  4 ++++
 gcc/testsuite/gfortran.dg/unknown_commons.f | 20 ++++++++++++++++++++
 gcc/tree-dfa.c                              | 15 ++++++++++++++-
 gcc/tree.c                                  |  6 ++++--
 4 files changed, 42 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/unknown_commons.f

Comments

Alan Lawrence March 3, 2016, 10:20 a.m. UTC | #1
On 25/02/16 18:00, Alan Lawrence wrote:
> On 22/02/16 12:03, Jakub Jelinek wrote:
>> (f) A global command-line option, which we check alongside DECL_COMMON and
>> further tests (basically, we want only DECL_COMMON decls that either have
>> ARRAY_TYPE, or some other aggregate type with flexible array member or some
>> other trailing array in the struct), and use the resulting predicate in
>> places where we optimize based on DECL_SIZE{,_UNIT} of the decl - if that
>> predicate returns true, we assume the DECL_SIZE is
>> "variable"/"unlimited"/whatever.
>> The two spots known to me that would need to use this new predicate would
>> be:
>> tree.c (array_at_struct_end_p):
> [...]
>> tree-dfa.c (get_ref_base_and_extent):
> [...]
>
> Close enough to what I meant by (a)/(b), but never mind that, and I hadn't
> looked at where the change for aggressive loop opts needed to be. However...
> Well you are essentially writing the patch for me at this point (so, thanks!),
>   but here's a patch that puts that under a global -funknown-commons flag.
> Testcase as before.
>
> Bootstrapped (with flag overridden to true) on x86_64 and aarch64, check-gcc,
> check-fortran, and tested 416.gamess on AArch64, where this patch enables
> running *without* the -fno-aggressive-loop-opts previously required.
>
> In the gcc testsuite, these fail with the option turned on:
> gcc.dg/pr53265.c  (test for warnings, line 137)
> gcc.dg/pr53265.c  (test for warnings, line 138)
> gcc.dg/pr64277.c scan-tree-dump cunroll ... (*2)
> gcc.dg/tree-ssa/cunroll-{1,2,3,4,9,10,11}.c scan-tree-dump cunroll/cunrolli/ivcanon (various)
> gcc.dg/tree-ssa/loop-38.c scan-tree-dump cunrolli "Loop 1 iterates at most 11 times"
> ...which all appear harmless.
>
> Thomas Koenig suggests (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69368#c80)
> that this be combined with some flag fiddling and warnings in the Fortran
> front-end; this patch doesn't do that, as I'm not very familiar with the
> frontends, but that can follow in a separate patch. (Thomas?)
>
> OK for trunk?
>
> Cheers, Alan
>
> gcc/ChangeLog:
>
> DATE  Alan Lawrence  <alan.lawrence@arm.com>
>        Jakub Jelinek  <jakub@redhat.com>
>
> 	* common.opt (funknown-commons, flag_unknown_commons): New.
> 	* tree.c (array_at_struct_end_p): Do not limit to size of decl for
> 	DECL_COMMONS if flag_unknown_commons is set.
> 	* tree-dfa.c (get_ref_base_and_extent): Likewise.
>
> gcc/testsuite/ChangeLog:
>
> 	* gfortran.dg/unknown_commons.f: New.

Ping.

(Besides my original patch 
https://gcc.gnu.org/ml/gcc-patches/2016-02/msg01356.html which we decided was 
too fragile, I believe this is the only patch proposed that actually fixes the 
miscompare in 416.gamess.)

Thanks, Alan
Richard Biener March 4, 2016, 1:27 p.m. UTC | #2
On Thu, Feb 25, 2016 at 7:00 PM, Alan Lawrence <alan.lawrence@arm.com> wrote:
> On 22/02/16 12:03, Jakub Jelinek wrote:
>> (f) A global command-line option, which we check alongside DECL_COMMON and
>> further tests (basically, we want only DECL_COMMON decls that either have
>> ARRAY_TYPE, or some other aggregate type with flexible array member or some
>> other trailing array in the struct), and use the resulting predicate in
>> places where we optimize based on DECL_SIZE{,_UNIT} of the decl - if that
>> predicate returns true, we assume the DECL_SIZE is
>> "variable"/"unlimited"/whatever.
>> The two spots known to me that would need to use this new predicate would
>> be:
>> tree.c (array_at_struct_end_p):
> [...]
>> tree-dfa.c (get_ref_base_and_extent):
> [...]
>
> Close enough to what I meant by (a)/(b), but never mind that, and I hadn't
> looked at where the change for aggressive loop opts needed to be. However...
> Well you are essentially writing the patch for me at this point (so, thanks!),
>  but here's a patch that puts that under a global -funknown-commons flag.
> Testcase as before.
>
> Bootstrapped (with flag overridden to true) on x86_64 and aarch64, check-gcc,
> check-fortran, and tested 416.gamess on AArch64, where this patch enables
> running *without* the -fno-aggressive-loop-opts previously required.
>
> In the gcc testsuite, these fail with the option turned on:
> gcc.dg/pr53265.c  (test for warnings, line 137)
> gcc.dg/pr53265.c  (test for warnings, line 138)
> gcc.dg/pr64277.c scan-tree-dump cunroll ... (*2)
> gcc.dg/tree-ssa/cunroll-{1,2,3,4,9,10,11}.c scan-tree-dump cunroll/cunrolli/ivcanon (various)
> gcc.dg/tree-ssa/loop-38.c scan-tree-dump cunrolli "Loop 1 iterates at most 11 times"
> ...which all appear harmless.
>
> Thomas Koenig suggests (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69368#c80)
> that this be combined with some flag fiddling and warnings in the Fortran
> front-end; this patch doesn't do that, as I'm not very familiar with the
> frontends, but that can follow in a separate patch. (Thomas?)
>
> OK for trunk?

Comments below.

> Cheers, Alan
>
> gcc/ChangeLog:
>
> DATE  Alan Lawrence  <alan.lawrence@arm.com>
>       Jakub Jelinek  <jakub@redhat.com>
>
>         * common.opt (funknown-commons, flag_unknown_commons): New.
>         * tree.c (array_at_struct_end_p): Do not limit to size of decl for
>         DECL_COMMONS if flag_unknown_commons is set.
>         * tree-dfa.c (get_ref_base_and_extent): Likewise.
>
> gcc/testsuite/ChangeLog:
>
>         * gfortran.dg/unknown_commons.f: New.
> ---
>  gcc/common.opt                              |  4 ++++
>  gcc/testsuite/gfortran.dg/unknown_commons.f | 20 ++++++++++++++++++++
>  gcc/tree-dfa.c                              | 15 ++++++++++++++-
>  gcc/tree.c                                  |  6 ++++--
>  4 files changed, 42 insertions(+), 3 deletions(-)
>  create mode 100644 gcc/testsuite/gfortran.dg/unknown_commons.f
>
> diff --git a/gcc/common.opt b/gcc/common.opt
> index 520fa9c..b5b1282 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -2455,6 +2455,10 @@ funit-at-a-time
>  Common Report Var(flag_unit_at_a_time) Init(1)
>  Compile whole compilation unit at a time.
>
> +funknown-commons
> +Common Var(flag_unknown_commons)
> +Assume common declarations may be overridden with unknown larger sizes

I think to make it work with LTO you need to mark it 'Optimization'.
Also it's about
arrays so maybe

'Assume common declarations may be overridden with ones with a larger
trailing array'

also if we document it here we should eventually document it in invoke.texi.

Not sure if "unknown commons" is a good term, maybe "unconstrained
commons" instead?

Otherwise looks ok to me.

Richard.

> +
>  funroll-loops
>  Common Report Var(flag_unroll_loops) Optimization
>  Perform loop unrolling when iteration count is known.
> diff --git a/gcc/testsuite/gfortran.dg/unknown_commons.f b/gcc/testsuite/gfortran.dg/unknown_commons.f
> new file mode 100644
> index 0000000..97e3ce3
> --- /dev/null
> +++ b/gcc/testsuite/gfortran.dg/unknown_commons.f
> @@ -0,0 +1,20 @@
> +! { dg-do compile }
> +! { dg-options "-O3 -funknown-commons -fdump-tree-dom2-details" }
> +
> +! Test for PR69368: a single-element array in a common block, which will be
> +! overridden with a larger size at link time (contrary to language spec).
> +! Dominator opts considers accesses to differently-computed elements of X as
> +! equivalent, unless -funknown-commons is passed in.
> +      SUBROUTINE FOO
> +      IMPLICIT DOUBLE PRECISION (X)
> +      INTEGER J
> +      COMMON /MYCOMMON / X(1)
> +      DO 10 J=1,1024
> +         X(J+1)=X(J+7)
> +  10  CONTINUE
> +      RETURN
> +      END
> +! { dg-final { scan-tree-dump-not "FIND" "dom2" } }
> +! We should retain both a read and write of mycommon.x.
> +! { dg-final { scan-tree-dump-times "  _\[0-9\]+ = mycommon\\.x\\\[_\[0-9\]+\\\];" 1 "dom2" } }
> +! { dg-final { scan-tree-dump-times "  mycommon\\.x\\\[_\[0-9\]+\\\] = _\[0-9\]+;" 1 "dom2" } }
> diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c
> index 0e98056..017e98e 100644
> --- a/gcc/tree-dfa.c
> +++ b/gcc/tree-dfa.c
> @@ -612,9 +612,22 @@ get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset,
>
>    if (DECL_P (exp))
>      {
> +      if (flag_unknown_commons
> +         && TREE_CODE (exp) == VAR_DECL && DECL_COMMON (exp))
> +       {
> +         tree sz_tree = TYPE_SIZE (TREE_TYPE (exp));
> +         /* If size is unknown, or we have read to the end, assume there
> +            may be more to the structure than we are told.  */
> +         if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE
> +             || (seen_variable_array_ref
> +                 && (sz_tree == NULL_TREE
> +                     || TREE_CODE (sz_tree) != INTEGER_CST
> +                     || (bit_offset + maxsize == wi::to_offset (sz_tree)))))
>        /* If maxsize is unknown adjust it according to the size of the
>           base decl.  */
> -      if (maxsize == -1
> +      else if (maxsize == -1
>           && DECL_SIZE (exp)
>           && TREE_CODE (DECL_SIZE (exp)) == INTEGER_CST)
>         maxsize = wi::to_offset (DECL_SIZE (exp)) - bit_offset;
> diff --git a/gcc/tree.c b/gcc/tree.c
> index 07cb9d9..eb6b642 100644
> --- a/gcc/tree.c
> +++ b/gcc/tree.c
> @@ -12957,8 +12957,10 @@ array_at_struct_end_p (tree ref)
>      }
>
>    /* If the reference is based on a declared entity, the size of the array
> -     is constrained by its given domain.  */
> -  if (DECL_P (ref))
> +     is constrained by its given domain.  (Do not trust commons PR/69368).  */
> +  if (DECL_P (ref)
> +      && !(flag_unknown_commons
> +          && TREE_CODE (ref) == VAR_DECL && DECL_COMMON (ref)))
>      return false;
>
>    return true;
> --
> 1.9.1
>
Jakub Jelinek March 4, 2016, 1:33 p.m. UTC | #3
On Fri, Mar 04, 2016 at 02:27:46PM +0100, Richard Biener wrote:
> > +funknown-commons
> > +Common Var(flag_unknown_commons)
> > +Assume common declarations may be overridden with unknown larger sizes
> 
> I think to make it work with LTO you need to mark it 'Optimization'.
> Also it's about
> arrays so maybe
> 
> 'Assume common declarations may be overridden with ones with a larger
> trailing array'
> 
> also if we document it here we should eventually document it in invoke.texi.

Also, isn't the *.opt description line supposed to end with a full stop?

	Jakub
diff mbox

Patch

diff --git a/gcc/common.opt b/gcc/common.opt
index 520fa9c..b5b1282 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2455,6 +2455,10 @@  funit-at-a-time
 Common Report Var(flag_unit_at_a_time) Init(1)
 Compile whole compilation unit at a time.
 
+funknown-commons
+Common Var(flag_unknown_commons)
+Assume common declarations may be overridden with unknown larger sizes
+
 funroll-loops
 Common Report Var(flag_unroll_loops) Optimization
 Perform loop unrolling when iteration count is known.
diff --git a/gcc/testsuite/gfortran.dg/unknown_commons.f b/gcc/testsuite/gfortran.dg/unknown_commons.f
new file mode 100644
index 0000000..97e3ce3
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/unknown_commons.f
@@ -0,0 +1,20 @@ 
+! { dg-do compile }
+! { dg-options "-O3 -funknown-commons -fdump-tree-dom2-details" }
+
+! Test for PR69368: a single-element array in a common block, which will be
+! overridden with a larger size at link time (contrary to language spec).
+! Dominator opts considers accesses to differently-computed elements of X as
+! equivalent, unless -funknown-commons is passed in.
+      SUBROUTINE FOO
+      IMPLICIT DOUBLE PRECISION (X)
+      INTEGER J
+      COMMON /MYCOMMON / X(1)
+      DO 10 J=1,1024
+         X(J+1)=X(J+7)
+  10  CONTINUE
+      RETURN
+      END
+! { dg-final { scan-tree-dump-not "FIND" "dom2" } }
+! We should retain both a read and write of mycommon.x.
+! { dg-final { scan-tree-dump-times "  _\[0-9\]+ = mycommon\\.x\\\[_\[0-9\]+\\\];" 1 "dom2" } }
+! { dg-final { scan-tree-dump-times "  mycommon\\.x\\\[_\[0-9\]+\\\] = _\[0-9\]+;" 1 "dom2" } }
diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c
index 0e98056..017e98e 100644
--- a/gcc/tree-dfa.c
+++ b/gcc/tree-dfa.c
@@ -612,9 +612,22 @@  get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset,
 
   if (DECL_P (exp))
     {
+      if (flag_unknown_commons
+	  && TREE_CODE (exp) == VAR_DECL && DECL_COMMON (exp))
+	{
+	  tree sz_tree = TYPE_SIZE (TREE_TYPE (exp));
+	  /* If size is unknown, or we have read to the end, assume there
+	     may be more to the structure than we are told.  */
+	  if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE
+	      || (seen_variable_array_ref
+		  && (sz_tree == NULL_TREE
+		      || TREE_CODE (sz_tree) != INTEGER_CST
+		      || (bit_offset + maxsize == wi::to_offset (sz_tree)))))
+	    maxsize = -1;
+	}
       /* If maxsize is unknown adjust it according to the size of the
          base decl.  */
-      if (maxsize == -1
+      else if (maxsize == -1
 	  && DECL_SIZE (exp)
 	  && TREE_CODE (DECL_SIZE (exp)) == INTEGER_CST)
 	maxsize = wi::to_offset (DECL_SIZE (exp)) - bit_offset;
diff --git a/gcc/tree.c b/gcc/tree.c
index 07cb9d9..eb6b642 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -12957,8 +12957,10 @@  array_at_struct_end_p (tree ref)
     }
 
   /* If the reference is based on a declared entity, the size of the array
-     is constrained by its given domain.  */
-  if (DECL_P (ref))
+     is constrained by its given domain.  (Do not trust commons PR/69368).  */
+  if (DECL_P (ref)
+      && !(flag_unknown_commons
+	   && TREE_CODE (ref) == VAR_DECL && DECL_COMMON (ref)))
     return false;
 
   return true;