https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128278

            Bug ID: 128278
           Summary: [x86_64-w64-mingw32] wrong code at -O2 with IPA-SRA:
                    LOGICAL(8) parameter stored with 4-byte movl, callee
                    tests 8 bytes
           Product: gcc
           Version: 16.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: ipa
          Assignee: unassigned at gcc dot gnu.org
          Reporter: KnowlesPJ at Cardiff dot ac.uk
  Target Milestone: ---

Created attachment 66032
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=66032&action=edit
reproducing example

The attached Fortran program (pr.f90, a single self-contained source: no
INCLUDE files, no preprocessing) gives wrong results at -O2 with gfortran
16.2.0 for x86_64-w64-mingw32. It is correct at -O0, -O1 and -O3 (at -O3 the
procedure is inlined), and with -O2 -fno-ipa-sra. The result is the same on
every run.

Command lines and complete output. There are no compiler diagnostics, even
with -Wall -Wextra:


    $ gfortran -O2 -Wall -Wextra pr.f90 -o pr.exe
    $ ./pr.exe
      24.0  24.0  24.0
      24.0  24.0  24.0
      24.0  24.0  24.0
     WRONG

    $ gfortran -O2 -fno-ipa-sra -Wall -Wextra pr.f90 -o pr.exe
    $ ./pr.exe
     OK

    $ gfortran -O0 -Wall -Wextra pr.f90 -o pr.exe
    $ ./pr.exe
     OK

    $ gfortran -O1 -Wall -Wextra pr.f90 -o pr.exe
    $ ./pr.exe
     OK

    $ gfortran -O3 -Wall -Wextra pr.f90 -o pr.exe
    $ ./pr.exe
     OK

-O2 -fcheck=all reports no runtime errors and still prints WRONG.

Analysis
--------
IPA-SRA turns the LOGICAL(8), intent(in) dummy TRANS of the internal procedure
ADD into a by-value parameter of the clone add.0.constprop.0.isra.0. In
-fdump-ipa-sra-details the new parameter has type
<boolean_type logical(kind=8)>. Under the Windows x64 calling convention it is
passed in a stack slot.

The caller (OUTER, from gfortran -O2 -S pr.f90) writes only the low 4 bytes
of that 8-byte slot:

        xorl    %r12d, %r12d
        cmpq    %r14, %rsi
        setne   %r12b
        ...
        movl    %r12d, 72(%rsp)
        ...
        call    add.0.constprop.0.isra.0

The clone reads and tests all 8 bytes of the same slot. Its frame is 8 pushes
plus subq $24,%rsp plus the return address, 96 bytes, so 72 + 96 = 168:

    add.0.constprop.0.isra.0:
        ...
        subq    $24, %rsp
        ...
        movq    168(%rsp), %rsi
        ...
        testq   %rsi, %rsi

The upper 4 bytes keep whatever an earlier call left in the slot. In the test
case that is the earlier call to SINK, which passes the addresses of module
variables. These lie in the executable image, whose addresses have non-zero
upper bytes. So TRANS is read as .true. when I == J, and every element gets
24 instead of 18.

It seems that one side treats the parameter as a promoted 32-bit value while
the other treats it as DImode.

Context and what was not tried
------------------------------
- Found in Molpro, a large Fortran application built with
  -fdefault-integer-8, so that default LOGICAL is 8 bytes.
  The same source is reported to work with gfortran 16 at -O2 on
  x86_64-linux-gnu. I did not run this test case on a Linux target.
- The compiler is the MSYS2 UCRT64 package. The GCC project does not
  distribute Windows binaries. I checked the patches MSYS2 applies
  (https://github.com/msys2/MINGW-packages/tree/master/mingw-w64-gcc). The
  only ones outside Ada, libgfortran locale handling, driver/build cosmetics
  and Rust/CodeView are these:
  - 0002 enables SEH for Win64 sysv_abi functions (cygming.h TARGET_SEH).
  - 0014 keeps an "@N" stdcall suffix on clone names (cgraphclones.cc).
  - 0200 adds -m(no-)align-vector-insn.
  None of them touch argument passing, promotion or IPA-SRA.
- I have not tried GCC trunk or another release on this target.

gfortran -v
-----------
Using built-in specs.
COLLECT_GCC=C:\msys64\ucrt64\bin\gfortran.ex
COLLECT_LTO_WRAPPER=C:/msys64/ucrt64/bin/../lib/gcc/x86_64-w64-mingw32/16.2.0/lto-wrapper.exe
Target: x86_64-w64-mingw32
Configured with: ../gcc-16.2.0/configure --prefix=/ucrt64
--with-sysroot=/ucrt64
--with-build-sysroot=D:/M/msys64/ucrt64
--wi-native-system-header-dir=/include--libexecdir=/ucrt64/lib
--enable-bootstrap --enable-checking=release --with-arch=nocona
--with-tune=generic
--enable-mingw-wildcard --enable-languages=c-c++,jit --enable-shared
--enable-static--enable-libatomic --enable-threads=posix --enable-tls
--enable-graphite --enable-fully-dynamic-string
--enable-libstdcxx-backtrace=yes --enable-lie-libstdcxx-time
--disable-libstdcxx-pch--enable-libgomp --disable-libssp --disable-multilib
--disable-rpath --disable-win32-registry --disable-nls
--disable-werror --disable-symvers --with-liith-gmp=/ucrt64
--with-mpfr=/ucrt64--with-mpc=/ucrt64 --with-isl=/ucrt64
--with-pkgversion='Rev6, Built by MSYS2 project'
--with-bugurl=https://github.com/msys2/MINGWs --with-gnu-ld
--with-libstdcxx-zoneinfo=yes --disable-libstdcxx-debug --enable-lto
--enable-plugin --with-boot-ldflags=-static-libstdc++
--with-stage1-ldflags=-static-libstdc++
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 16.2.0 (Rev6, Built by MSYS2 project)

Host: Windows 11 (the x86_64 compiler and program run under x64 emulation on
an arm64 machine; the generated code shown above is wrong regardless of where
it runs).

This report was prepared by Claude Code (an AI coding agent) on behalf of
Peter Knowles (GitHub pjknowles). The test case and analysis were produced
with it and run on the machine described above.

Reply via email to