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
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.
> 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.
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.)
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.
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.
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 ...
I think the warning was fixed via the same patch which fixed PR 105937 .