Bug 68649 - [7/8/9 Regression] note: code may be misoptimized unless -fno-strict-aliasing is used
Summary: [7/8/9 Regression] note: code may be misoptimized unless -fno-strict-aliasing...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: fortran (show other bugs)
Version: 6.0
: P4 normal
Target Milestone: 7.5
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-code
Depends on: 68560
Blocks: 77278
  Show dependency treegraph
 
Reported: 2015-12-02 06:54 UTC by Joost VandeVondele
Modified: 2019-04-02 16:24 UTC (History)
7 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2015-12-02 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Joost VandeVondele 2015-12-02 06:54:36 UTC
Today's trunk produces a lot of warnings / notes all referring to functions from libgfortran, when compiling CP2K with LTO. I'm looking at generating a reduced testcase, but the first obvious tries didn't work.

/data/vjoost/gnu/cp2k/cp2k/makefiles/../src/dbcsr_lib/dbcsr_block_access_c.F:709:0: note: ‘_gfortran_reshape_c4’ was previously declared here
              data_block%p(:,:) = RESHAPE (block, (/row_size, col_size/))


/data/vjoost/gnu/cp2k/cp2k/makefiles/../src/dbcsr_lib/dbcsr_block_access_c.F:709:0: note: code may be misoptimized unless -fno-strict-aliasing is used
/data/vjoost/gnu/cp2k/cp2k/makefiles/../src/helium_methods.F:1071:0: warning: type of ‘_gfortran_unpack1’ does not match original declaration [-Wlto-type-mismatch]
     helium%pos(:,:,:) = UNPACK(message(offset+1:offset+msglen), MASK=m, FIELD=f )


/data/vjoost/gnu/cp2k/cp2k/makefiles/../src/helium_methods.F:1699:0: warning: type of ‘_gfortran_unpack1’ does not match original declaration [-Wlto-type-mismatch]
     helium%rho_rstr(:,:,:,:) = UNPACK(message(1:msglen), MASK=m, FIELD=f)


/data/vjoost/gnu/cp2k/cp2k/makefiles/../src/helium_methods.F:1547:0: note: ‘_gfortran_unpack1’ was previously declared here
       ig(:,:) = UNPACK(message(offset+33:offset+38), MASK=m, FIELD=f )


/data/vjoost/gnu/cp2k/cp2k/makefiles/../src/helium_methods.F:1547:0: note: code may be misoptimized unless -fno-strict-aliasing is used
/data/vjoost/gnu/cp2k/cp2k/makefiles/../src/dbcsr_lib/dbcsr_block_access_s.F:709:0: warning: type of ‘_gfortran_reshape_r4’ does not match original declaration [-Wlto-type-mismatch]
              data_block%p(:,:) = RESHAPE (block, (/row_size, col_size/))


/data/vjoost/gnu/cp2k/cp2k/makefiles/../src/dbcsr_lib/dbcsr_block_access_s.F:709:0: warning: type of ‘_gfortran_reshape_r4’ does not match original declaration [-Wlto-type-mismatch]
Comment 1 Joost VandeVondele 2015-12-02 07:04:23 UTC
testcase

> cat foo.f90 
SUBROUTINE s8(a8,b8)
 REAL*8 :: a8(16),b8(4,4)
 a8=RESHAPE(b8,(/16/))
 b8=RESHAPE(a8,(/4,4/))
END SUBROUTINE
 REAL*8 :: a8(16),b8(4,4)
 CALL RANDOM_NUMBER(b8)
 CALL s8(a8,b8)
 WRITE(6,*) MAXVAL(a8),MAXVAL(b8)
END

> gfortran  -flto -O3 foo.f90 
foo.f90:3:0: warning: type of ‘_gfortran_reshape_r8’ does not match original declaration [-Wlto-type-mismatch]
  a8=RESHAPE(b8,(/16/))
 

foo.f90:4:0: note: ‘_gfortran_reshape_r8’ was previously declared here
  b8=RESHAPE(a8,(/4,4/))
 

foo.f90:4:0: note: code may be misoptimized unless -fno-strict-aliasing is used
Comment 2 Andrew Pinski 2015-12-02 07:36:37 UTC
This smells like a fortran front-end issue where _gfortran_reshape_r8's decl is created twice with two different argument types.
Comment 3 Joost VandeVondele 2015-12-02 07:42:15 UTC
Grepping the list of 'note:' in our build process, it triggers for at least these functions:

_gfortran_matmul_r8
_gfortran_reshape_4
_gfortran_reshape_c4
_gfortran_reshape_c8
_gfortran_reshape_r4
_gfortran_reshape_r8
_gfortran_unpack1

so it is somewhat general.
Comment 4 Dominique d'Humieres 2015-12-02 09:33:36 UTC
I think it is a duplicate of pr68560.

> This smells like a fortran front-end issue where _gfortran_reshape_r8's decl
> is created twice with two different argument types.

I don't think so. I think -Wlto-type-mismatch does not know part of the Fortran syntax.
Comment 5 Joost VandeVondele 2015-12-02 09:52:56 UTC
(In reply to Dominique d'Humieres from comment #4)
> I think it is a duplicate of pr68560.

seems certainly related, but PR68560 doesn't yield the worrying 'code may be misoptimized unless -fno-strict-aliasing is used'. I'll just add a dependency.

> 
> > This smells like a fortran front-end issue where _gfortran_reshape_r8's decl
> > is created twice with two different argument types.
> 
> I don't think so. I think -Wlto-type-mismatch does not know part of the
> Fortran syntax.

I'm thinking the issue is on the Fortran FE side, LTO shouldn't know the language involved. I guess some middle end person might need to have a look however.

I'm guessing it is related to the fact that _gfortran_reshape_r8 is being called with different pointer arguments (from -fdump-tree-original):

struct array1_real(kind=8) parm.0;
 _gfortran_reshape_r8 (&parm.0, D.3433, D.3437, 0B, 0B);
struct array2_real(kind=8) parm.4;
 _gfortran_reshape_r8 (&parm.4, D.3446, D.3450, 0B, 0B);

maybe for correctness there should be some casts ?
Comment 6 Dominique d'Humieres 2015-12-02 11:42:22 UTC
> seems certainly related, but PR68560 doesn't yield the worrying
> 'code may be misoptimized unless -fno-strict-aliasing is used'.
> I'll just add a dependency.

IMO these warnings are false positive (aka bogus). The minimal set of options to get the warning for the test in comment 1 is '-flto -fstrict-aliasing'.

> I'm thinking the issue is on the Fortran FE side, LTO shouldn't know
> the language involved. I guess some middle end person might need to have
> a look however.

IMO the first step is to understand why LTO is emitting these warning on valid Fortran code. Then, if this not due to a bug in LTO, it will be time to find how Fortran intrinsics have to be "decorated" to avoid the warnings.
Comment 7 Jan Hubicka 2015-12-03 06:26:35 UTC
The function is:
 <function_decl 0x7ffff6cc1380 _gfortran_reshape_r8
    type <function_type 0x7ffff6cc3930
        type <void_type 0x7ffff6af0150 void VOID
            align 8 symtab 0 alias set -1 structural equality
            pointer_to_this <pointer_type 0x7ffff6af02a0>>
        QI
        size <integer_cst 0x7ffff6ad7ca8 constant 8>
        unit size <integer_cst 0x7ffff6ad7cc0 constant 1>
        align 8 symtab 0 alias set -1 structural equality
        attributes <tree_list 0x7ffff6cc2140
            purpose <identifier_node 0x7ffff6b09a78 fn spec>
            value <tree_list 0x7ffff6cc2118
                value <string_cst 0x7ffff6cb72e0 constant ".wrrrr">>>
        arg-types <tree_list 0x7ffff6cc2258 value <reference_type 0x7ffff6cc3888>
            chain <tree_list 0x7ffff6cbcf28 value <reference_type 0x7ffff6cbfe70>
                chain <tree_list 0x7ffff6cbcf00 value <reference_type 0x7ffff6cbfd20>
                    chain <tree_list 0x7ffff6cbced8 value <pointer_type 0x7ffff6af0738>
                        chain <tree_list 0x7ffff6cbceb0 value <pointer_type 0x7ffff6cbaf18> chain <tree_list 0x7ffff6ae99b0>>>>>>
        pointer_to_this <pointer_type 0x7ffff6cc79d8>>
    addressable public external QI file a.f90 line 3 col 0 align 8 context <translation_unit_decl 0x7ffff6ae1168 D.3880>>

Second decl is:
 <function_decl 0x7ffff6cc12a0 _gfortran_reshape_r8
    type <function_type 0x7ffff6cc3498
        type <void_type 0x7ffff6af0150 void VOID
            align 8 symtab 0 alias set -1 structural equality
            pointer_to_this <pointer_type 0x7ffff6af02a0>>
        QI
        size <integer_cst 0x7ffff6ad7ca8 constant 8>
        unit size <integer_cst 0x7ffff6ad7cc0 constant 1>
        align 8 symtab 0 alias set -1 structural equality
        attributes <tree_list 0x7ffff6cc2140
            purpose <identifier_node 0x7ffff6b09a78 fn spec>
            value <tree_list 0x7ffff6cc2118
                value <string_cst 0x7ffff6cb72e0 constant ".wrrrr">>>
        arg-types <tree_list 0x7ffff6cc20f0 value <reference_type 0x7ffff6cc33f0>
            chain <tree_list 0x7ffff6cbcf28 value <reference_type 0x7ffff6cbfe70>
                chain <tree_list 0x7ffff6cbcf00 value <reference_type 0x7ffff6cbfd20>
                    chain <tree_list 0x7ffff6cbced8 value <pointer_type 0x7ffff6af0738>
                        chain <tree_list 0x7ffff6cbceb0 value <pointer_type 0x7ffff6cbaf18> chain <tree_list 0x7ffff6ae99b0>>>>>>
        pointer_to_this <pointer_type 0x7ffff6cc7d20>>
    addressable public external QI file a.f90 line 4 col 0 align 8 context <translation_unit_decl 0x7ffff6ae1168 D.3880>>


The reason is that the declaration is duplicated (that by itself is a bug violating one-decl rule) and we warn because reference type 0x7ffff6cc3888 is not compatible with reference type 0x7ffff6cc33f0. They point to different type of structure:

 <reference_type 0x7ffff6cc3888
    type <record_type 0x7ffff6cc37e0 array1_real(kind=8) BLK
        size <integer_cst 0x7ffff6cabd08 constant 384>
        unit size <integer_cst 0x7ffff6cabd98 constant 48>
        align 64 symtab 0 alias set -1 canonical type 0x7ffff6cc3690
        fields <field_decl 0x7ffff6cbebe0 data type <pointer_type 0x7ffff6cbff18>
            unsigned DI file a.f90 line 3 col 0
            size <integer_cst 0x7ffff6ad7bb8 constant 64>
            unit size <integer_cst 0x7ffff6ad7bd0 constant 8>
            align 64 offset_align 128
            offset <integer_cst 0x7ffff6ad7be8 constant 0>
            bit offset <integer_cst 0x7ffff6ad7c30 constant 0> context <record_type 0x7ffff6cc3690 array_descriptor1> chain <field_decl 0x7ffff6cbeb48 offset>>
        reference_to_this <reference_type 0x7ffff6cc3888> chain <type_decl 0x7ffff6cc4000 D.3909>>
    unsigned DI size <integer_cst 0x7ffff6ad7bb8 64> unit size <integer_cst 0x7ffff6ad7bd0 8>
    align 64 symtab 0 alias set 6 structural equality>

compared to:

 <reference_type 0x7ffff6cc33f0
    type <record_type 0x7ffff6cc3348 array2_real(kind=8) BLK
        size <integer_cst 0x7ffff6cabdb0 constant 576>
        unit size <integer_cst 0x7ffff6cabde0 constant 72>
        align 64 symtab 0 alias set -1 canonical type 0x7ffff6cc31f8
        fields <field_decl 0x7ffff6cbe558 data type <pointer_type 0x7ffff6cbff18>
            unsigned DI file a.f90 line 4 col 0
            size <integer_cst 0x7ffff6ad7bb8 constant 64>
            unit size <integer_cst 0x7ffff6ad7bd0 constant 8>
            align 64 offset_align 128
            offset <integer_cst 0x7ffff6ad7be8 constant 0>
            bit offset <integer_cst 0x7ffff6ad7c30 constant 0> context <record_type 0x7ffff6cc31f8 array_descriptor2> chain <field_decl 0x7ffff6cbe4c0 offset>>
        reference_to_this <reference_type 0x7ffff6cc33f0> chain <type_decl 0x7ffff6cbe980 D.3898>>
    unsigned DI size <integer_cst 0x7ffff6ad7bb8 64> unit size <integer_cst 0x7ffff6ad7bd0 8>
    align 64 symtab 0 alias set 7 structural equality>

Notice the difference in size of the records.
This will indeed make TBAA code to believe that those two pointers are not compatible. In libgfortran there is 
void
reshape_r8 (gfc_array_r8 * const restrict ret, 
        gfc_array_r8 * const restrict source, 
        shape_type * const restrict shape,
        gfc_array_r8 * const restrict pad, 
        shape_type * const restrict order)

ideally the fortran-fe produced declaration of reshape_r8 should be just one per unit and interoperable with the declaration above that is pointer to:
#define GFC_ARRAY_DESCRIPTOR(r, type) \
struct {\
  type *base_addr;\
  size_t offset;\
  index_type dtype;\
  descriptor_dimension dim[r];\
}
Comment 8 Dominique d'Humieres 2015-12-03 14:26:23 UTC
Further reduced test

 REAL*8 :: a8(16),b8(4,4), c8(16), d8(4,4)
 c8=RESHAPE(b8,(/16/))
 d8=RESHAPE(a8,(/4,4/))
END

> Notice the difference in size of the records.

How do they relate to the array sizes?

From https://gcc.gnu.org/onlinedocs/gfortran/RESHAPE.html#RESHAPE

Description:
Reshapes SOURCE to correspond to SHAPE. If necessary, the new array may be padded with elements from PAD or permuted as defined by ORDER. 

> In libgfortran there is 
> void
> reshape_r8 (gfc_array_r8 * const restrict ret, 
>         gfc_array_r8 * const restrict source, 
>         shape_type * const restrict shape,
>         gfc_array_r8 * const restrict pad, 
>         shape_type * const restrict order)
>
> ideally the fortran-fe produced declaration of reshape_r8 should be just one per
> unit and interoperable with the declaration above that is pointer to:
> #define GFC_ARRAY_DESCRIPTOR(r, type) \
> struct {\
>   type *base_addr;\
>   size_t offset;\
>   index_type dtype;\
>   descriptor_dimension dim[r];\
> }

Are you meaning that fortran-fe should produce one reshape_r8xx per shape of source?
Comment 9 Dominique d'Humieres 2015-12-10 12:26:09 UTC
See also pr68717 for more warnings after r231239.
Comment 10 Jerry DeLisle 2015-12-11 02:00:56 UTC
This PR is tagged as a regression.  Has anyone determined when it last worked or is it longstanding bug uncovered by recent non-fortran fe changes?
Comment 11 Joost VandeVondele 2015-12-11 09:28:54 UTC
(In reply to Jerry DeLisle from comment #10)
> This PR is tagged as a regression.  Has anyone determined when it last
> worked or is it longstanding bug uncovered by recent non-fortran fe changes?

For users it is a regression in the sense that packages that compiled with -flto -Werror with 5.3 will now stop building.

The underlying FE issue is much older, I guess.
Comment 12 Jakub Jelinek 2015-12-18 11:30:59 UTC
This is of course Fortran FE bug.

What is the Fortran FE emitting right now is kind like invalid C (and invalid middle-end) below.  It wouldn't be invalid C++, but for C++ that would be different baz functions and name mangling would differentiate those; that is not what is going on in C or in what libgfortran expects:

typedef __SIZE_TYPE__ size_t;
struct D { long stride, lower_bound, ubound; };
struct A { float *base_addr; size_t offset; long dtype; struct D dim[7]; };
struct A1 { float *base_addr; size_t offset; long dtype; struct D dim[1]; };
struct A2 { float *base_addr; size_t offset; long dtype; struct D dim[2]; };

void
foo (void)
{
  extern void baz (struct A1 *);
  struct A1 a1 = { 0, 0, 0, { { 0, 0, 0 } } };
  baz (&a1);
}

void
bar (void)
{
  extern void baz (struct A2 *);
  struct A2 a2 = { 0, 0, 0, { { 0, 0, 0 }, { 0, 0, 0 } } };
  baz (&a2);
}

Above, A stands for generic real(8) array descriptor type that supports up to maximum number of dimensions, A1 for rank 1 and A2 for rank 2 real(8) array descriptor.  IMHO you want instead:

typedef __SIZE_TYPE__ size_t;
struct D { long stride, lower_bound, ubound; };
struct A { float *base_addr; size_t offset; long dtype; struct D dim[7]; };
struct A1 { float *base_addr; size_t offset; long dtype; struct D dim[1]; };
struct A2 { float *base_addr; size_t offset; long dtype; struct D dim[2]; };

void
foo (void)
{
  extern void baz (struct A *);
  struct A1 a1 = { 0, 0, 0, { { 0, 0, 0 } } };
  baz ((struct A *) &a1);
}

void
bar (void)
{
  extern void baz (struct A *);
  struct A2 a2 = { 0, 0, 0, { { 0, 0, 0 }, { 0, 0, 0 } } };
  baz ((struct A *) &a2);
}

and ensure that A/A1/A2 etc. (the various types created by gfc_get_array_type_bounds) have the same TYPE_ALIAS to make the alias oracle happy.
I hope only the libgfortran intrinsics that handle various ranks by the same function are a problem, therefore I'd say you should be marking the symbols for those intrinsics with some flag that you want to treat their arguments like assumed rank arrays, and then just cast the addresses of the descriptors you want to pass to them to some reference type to assumed rank descriptor type
(dunno if just array7_real(kind=8) (i.e. maximum rank), or something else).
Now, the question is if this affects just the intrinsic routines from libgfortran, or user written functions/subroutines too.  I hope the latter only should be called with the right rank except for assumed
Comment 13 Richard Biener 2016-01-13 11:55:03 UTC
Note that the cast doesn't help in itself (but for the warning) as Jakub notices.
The deeper issue is type-based aliasing here.  IMHO libgfortran would need to
use

struct A { float *base_addr; size_t offset; long dtype; struct D dim[1]; } *desc;

aka a pointer to a descriptor with flexible array member.  Which I hope ends
up aliasing with one with a different size.  Well, we treat 'dim' as flexible
array member in any case but I'm not aware of any code in alias.c that makes
this work.

struct Xflex { int n; int a[1]; };
struct Xspecific { int n; int a[7]; } x;

int foo (struct Xflex *f)
{
  f->a[6] = 2;
  x.a[6] = 1;
  return f->a[6];
}

returns 2 with -fstrict-aliasing :(

Thus even the proposed fix won't end up working.
Comment 14 Jakub Jelinek 2016-04-27 10:59:15 UTC
GCC 6.1 has been released.
Comment 15 Richard Biener 2016-08-22 08:43:20 UTC
GCC 6.2 is being released, adjusting target milestone.
Comment 16 Richard Biener 2016-08-22 09:02:19 UTC
GCC 6.2 is being released, adjusting target milestone.
Comment 17 Richard Biener 2016-08-22 09:03:44 UTC
GCC 6.2 is being released, adjusting target milestone.
Comment 18 Joost VandeVondele 2016-10-18 08:02:42 UTC
since this PR, and the related PR77278 can presumably only be fixed by changing libgfortran abi (at least if I understand Richard's suggestion for fixing this). The announced major version bump of libgfortran (https://gcc.gnu.org/ml/gcc-patches/2016-10/msg01376.html) could be a good opportunity for this change. It is the major thing holding back the use of LTO with Fortran projects, I think.
Comment 19 Jakub Jelinek 2016-12-21 11:00:08 UTC
GCC 6.3 is being released, adjusting target milestone.
Comment 20 Richard Biener 2017-07-04 08:51:02 UTC
GCC 6.4 is being released, adjusting target milestone.
Comment 21 Eric Gallager 2017-07-05 18:32:29 UTC
Bug 80379 is related
Comment 22 Thomas Koenig 2018-02-04 10:49:11 UTC
What we _could_ do with our array descriptors is to cast them to
a pointer containing a flexible array member, i.e.

struct type_descr {
  type *base_addr;
  size_t offset;
  dtype_type dtype;
  index_type span;
  descriptor_dimension dim[];
}

which would make all our function calls equal.

I have lightly tested the concept with a C program, i.e.

foo.c:

struct Xflex { int n; int a[]; };

int foo (struct Xflex *f)
{
  int i;
  int s;
  s = 0;
  for (i=0; i<f->n; i++)
    s += f->a[i];

  return s;
}

bar.c:

#include <stdio.h>

struct Xflex { int n; int a[]; };
struct X2 { int n; int a[2]; };

struct X2 x;

int foo (struct Xflex *f);

int main(void)
{
  x.n = 2;
  x.a[0] = 1;
  x.a[1] = 3;
  printf("%d\n", foo((struct Xflex *) &x));
}

which seems to work.
Comment 23 Jakub Jelinek 2018-10-26 10:24:27 UTC
GCC 6 branch is being closed
Comment 24 Dominique d'Humieres 2018-11-12 17:57:13 UTC
The warnings are gone between revisions r265814 and r265942.
Comment 25 Thomas Koenig 2019-02-17 22:26:26 UTC
(In reply to Dominique d'Humieres from comment #24)
> The warnings are gone between revisions r265814 and r265942.

I can confirm that.

So, are there objections to just committing a test case and
closing this bug?
Comment 26 Dominique d'Humieres 2019-02-18 00:05:16 UTC
> > The warnings are gone between revisions r265814 and r265942.
>
> I can confirm that.

> So, are there objections to just committing a test case and
> closing this bug?

My (shallow) understanding of the above thread was that the warning made sense.
If this is still true, then the missing warning is a regression.
If not, why?
Comment 27 Dominique d'Humieres 2019-04-02 16:24:43 UTC
See pr68717 comment 11, closing.