Bug 66459 - bogus warning 'w.offset' may be used uninitialized in this function [-Wmaybe-uninitialized] caused by loop invariant motion (LIM)
Summary: bogus warning 'w.offset' may be used uninitialized in this function [-Wmaybe-...
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 5.1.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on:
Blocks: Wuninitialized
  Show dependency treegraph
 
Reported: 2015-06-08 11:02 UTC by Mario Baumann
Modified: 2022-09-04 09:01 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2022-08-30 00:00:00


Attachments
Fortran Fixed Form File (186 bytes, text/plain)
2015-06-08 11:02 UTC, Mario Baumann
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Mario Baumann 2015-06-08 11:02:27 UTC
Created attachment 35716 [details]
Fortran Fixed Form File

Hi All,

The attached file generates bogus warnings if compiled with -Wall AND -O1(or higher optimizations).


> gfortran -c -Wall -O1 foo.F
foo.F:14:0:

                W(J,I) = 0
 ^
Warning: 'w.offset' may be used uninitialized in this function [-Wmaybe-uninitialized]
foo.F:14:0: Warning: 'w.dim[1].stride' may be used uninitialized in this function [-Wmaybe-uninitialized]
 

> gfortran -v
Using built-in specs.
COLLECT_GCC=./gfortran
COLLECT_LTO_WRAPPER=/Build/gcc/5.1.0/install/libexec/gcc/x86_64-apple-darwin13/5.1.0/lto-wrapper
Target: x86_64-apple-darwin13
Configured with: /Source/gcc/5.1.0/configure --prefix=/Build/gcc/5.1.0/install --build=x86_64-apple-darwin13 --enable-languages=c,c++,fortran,lto --enable-cloog-backend=isl --enable-stage1-checking --enable-lto --enable-libstdcxx-time --with-system-zlib --disable-cloog-version-check --disable-nls --disable-libquadmath-support
Thread model: posix
gcc version 5.1.0 (GCC)


NOTEs:
- -O0 works fine
- same behaviour with gcc-4.9.2
Comment 1 Mikael Morin 2015-06-08 14:46:36 UTC
Confirmed.
Possibly related bug: PR60500

(In reply to Mario Baumann from comment #0)
> - -O0 works fine

This is expected, uninitializedness may only become apparent to the compiler after some optimization passes have simplified/reorganized the code.
Comment 2 Dominique d'Humieres 2015-11-04 17:49:54 UTC
> Possibly related bug: PR60500

Likely, but I get the warning for this PR for 4.5.4, but not 4.4.7, while the warnings for PR60500 appear only for 4.7.3.
Comment 3 Manuel López-Ibáñez 2016-09-07 20:23:25 UTC
If you do

gfortran -Wuninitialized test.f90 -fdump-tree-all-all-lineno -O1

and look at test.f90.162t.uninit1, we see:

  # .MEM_24 = PHI <.MEM_15(D)(28), .MEM_68(37)>
  # w$dim$1$stride_46 = PHI <w$dim$1$stride_85(D)(28), [test.f90:9:0] w$dim$1$stride_22(37)>
  # w$offset_26 = PHI <w$offset_16(D)(28), [test.f90:9:0] w$offset_56(37)>

but this code is transformed by optimization. The unoptimized SSA contains:

  [test.f90:9:0] # VUSE <.MEM_18>
  _22 = [test.f90:9:0] *m_21(D);
  [test.f90:9:0] _23 = MAX_EXPR <_22, 0>;
  [test.f90:9:0] _24 = (integer(kind=8)D.9) _23;
...
  [test.f90:9:0] _39 = _24;
...
  [test.f90:9:0] _68 = ~_39;
...
  [test.f90:9:0] wD.3400.offsetD.3387 = _68;

and the gimple generated by Fortran contains something similar:

            [test.f90:9:0] D.3429 = [test.f90:9:0] *mD.3381;
            [test.f90:9:0] D.3430 = MAX_EXPR <D.3429, 0>;
            [test.f90:9:0] D.3402 = (integer(kind=8)D.9) D.3430;

It seems that *mD.3381 is not initialized.

(It is very strange that gfortran converts user-defined variables to lowercase. It makes reading the dumps more difficult. It also does many unnecessary copies, making the code harder to analyze.)
Comment 4 Thomas Koenig 2019-02-03 10:21:57 UTC
The code that gfortran generates is correct, it is just that
the middle-end does not quite understand it and generates a
warning for it.

The -fdump-tree-original dump shows

      if (*l)
        {
          {
[...]
            w.dtype = {.elem_len=4, .rank=2, .type=1};
            D.3881 = (integer(kind=8)) MAX_EXPR <*m, 0>;
            D.3882 = NON_LVALUE_EXPR <__builtin_expect ((integer(kind=8)) (D.3881 == 0), 0, 46) ? 0 : __builtin_expect ((integer(kind=8)) (9223372036854775807 / D.3881 <= 0), 0, 41) ? 1 : 0>;
            D.3883 = NON_LVALUE_EXPR <D.3881>;
            D.3884 = (integer(kind=8)) MAX_EXPR <*n, 0>;
            D.3885 = (__builtin_expect ((integer(kind=8)) (D.3884 == 0), 0, 46) ? 0 : __builtin_expect ((integer(kind=8)) (9223372036854775807 / D.3884 < D.3883), 0, 41) ? 1 : 0) + D.3882;
            D.3886 = D.3883 * D.3884;
            D.3887 = D.3886;
            D.3888 = (__builtin_expect ((integer(kind=8)) ((unsigned long) D.3886 > 4611686018427387903), 0, 41) ? 1 : 0) + D.3885;
            D.3889 = ~NON_LVALUE_EXPR <D.3883>;
  
            if (D.3891)
              {
                size.0 = 0;
              }
            else
              {
                size.0 = (unsigned long) D.3886 * 4;
              }
            overflow.1 = D.3888;
            if (__builtin_expect ((integer(kind=8)) (overflow.1 != 0), 0, 41))
              {
                _gfortran_runtime_error (&"Ganzzahl\xc3\xbcberlauf bei der Berechnung des zu reservierenden Speichers"[1]{lb: 1 sz: 1});
              }
            else
              {
                if (__builtin_expect ((integer(kind=8)) (w.data != 0B), 0, 43))
                  {
                    _gfortran_runtime_error_at (&"At line 9 of file b.f"[1]{lb: 1 sz: 1}, &"Versuch, bereits reservierte Variable \xc2\xbb%s\xc2\xab zu reservieren"[1]{lb: 1 sz: 1}, &"w"[1]{lb: 1 sz: 1});
                  }
                else
                  {
                    w.data = (void * restrict) __builtin_malloc (MAX_EXPR <size.0, 1>);
                    if (__builtin_expect ((integer(kind=8)) (w.data == 0B), 0, 42))
                      {
                        _gfortran_os_error (&"Reservierung w\xc3\xbcrde Speichergrenze \xc3\xbcberschreiten"[1]{lb: 1 sz: 1});
                      }
                  }
              }
            w.dim[0].lbound = 1;
            w.dim[0].ubound = (integer(kind=8)) *m;
            w.dim[0].stride = 1;
            w.dim[1].lbound = 1;
            w.dim[1].ubound = (integer(kind=8)) *n;
            w.dim[1].stride = D.3883;
            w.offset = D.3889;
          }
        }

and then

                      if ((integer(kind=4)[0:] * restrict) w.data != 0B)
                        {
                          (*(integer(kind=4)[0:] * restrict) w.data)[(w.offset + (integer(kind=8)) i * w.dim[1].stride) + (integer(kind=8)) j] = 0;

Now, the thing is that, on leaving the if (*l) block, data has to be non-zero,
otherwise _gfortran_os_error would have been called (which is marked
with TREE_THIS_VOLATILE, hence noreturn). So, the variables 

Is there something the Fortran front end can do better? If not, I think
this is better classified as a middle-end bug.
Comment 5 Marc Glisse 2019-02-03 12:00:30 UTC
ESRA creates
  w$offset_132 = PHI <w$offset_95(D)(2), w$offset_103(21)>
before we read n. LIM later pulls some computations using w$offset_132 before the test on w.data, but that's not really relevant. I don't think there is anything the front-end can do about that, it seems to be purely middle-end, SRA creating exactly what uninit likes to warn about.
Comment 6 Richard Biener 2022-08-30 08:54:37 UTC
what we warn about in the end is the path when l == 0 && n > 0.  that's also
visible in the initial gfortran IL:

  try
    {
      w.data = 0B;
      w.dtype = {.elem_len=4, .rank=2, .type=1};
      if (*l)
        {
...
        }
      L.1:;
      {
        integer(kind=4) D.4258;

        D.4258 = *n;
        i = 1;
        while (1)
          {
            {
              logical(kind=4) D.4261;

              D.4261 = i > D.4258;
              if (D.4261) goto L.3;
              {
                integer(kind=4) D.4262;

                D.4262 = *m;
                j = 1;
                while (1)
                  {
                    {
                      logical(kind=4) D.4265;

                      D.4265 = j > D.4262;
                      if (D.4265) goto L.5;
                      if ((integer(kind=4)[0:] * restrict) w.data != 0B)
                        {
                          (*(integer(kind=4)[0:] * restrict) w.data)[(w.offset + (integer(kind=8)) i * w.dim[1].stride) + (integer(kind=8)) j] = 0;
                        }
                      L.6:;
                      L.4:;
                      j = j + 1;
                    }
                  }
                L.5:;
              }
              L.2:;
              i = i + 1;
            }
          }
        L.3:;

the n > 0 check is simplified from D.4258 = *n; i = 1; D.4261 = i > D.4258;
There's some extra guard, m > j, but that's not related so what uninit
analysis would need to see is the w.data != 0 guard but as Manu said, the
LIM pass hoists the loop invariant uses out of this conditional.

IIRC there's a related bug somewhere for LIM exposing uninitialized uses
to code paths that are not known to execute but here it's not trivial to
see the uninitializedness.

The bogus diagnostic goes away with -fno-tree-loop-im (but you usually do
not want to do that for performance reasons).  At -O3 we unswitch on
w.data != 0 but LIM already moved the access then.  One old idea is to
make sure to disable diagnostics on stmts we move for the sake of
introducing false negatives ...