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

            Bug ID: 86763
           Summary: Wrong code comparing member of copy of a 237 byte
                    object with nontrivial default constructor on x86-64
                    arch
           Product: gcc
           Version: 8.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: curlypaul924 at gmail dot com
  Target Milestone: ---

Created attachment 44475
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=44475&action=edit
.ii file generated from t4.cpp

The following program produces an incorrect result on GCC 8.1 and 8.2.  It
succeeds on 7.2.

AFAICT, the problem is that the comparison happens before the object has been
copied.  The compiler could compare using the temporary stored in rdx, but it
instead compares using the value at [rsp+8], which isn't yet written to.

This happens when using -march=x86-64, but does not happen on -march=core2 or
newer.  In these cases, memcpy is used to do the copy, and the comparison
happens after the call to memcpy.

Moreover, GCC misses an opportunity to optimize away the copy altogether. 
Clang 6.0.0 does optimize away the copy.

The misplaced comparison happens at -O2 or higher; at -O1, the comparison is
done after the copy.

#include <cstdint>
#include <cassert>
#include <time.h>
struct ID {
  uint64_t value;
};
uint64_t value(ID id) { return id.value; }
uint64_t gen { 1000 };
struct Msg {
  uint64_t time;
  ID id;
};
struct V {
  V() { }
  V(Msg const & msg) : msg(msg) { }
  Msg & get() { return msg; }
  Msg msg;
  char pad[237 - sizeof(Msg)];
};
struct T : V { using V::V; };
Msg init_msg() {
  Msg msg;
  timespec t;
  clock_gettime(CLOCK_REALTIME, &t);
  msg.time = t.tv_sec + t.tv_nsec;
  msg.id.value = ++gen;
  return msg;
}
int main() {
  T t;
  t = init_msg();
  assert(value(t.get().id) == 1001);
}

$ g++-8.1 -std=c++14 -O2 -Wall -Werror -march=x86-64 -save-temps -v t4.cpp
Using built-in specs.                                                           
COLLECT_GCC=/usr/local/bin/g++-8.1                                              
COLLECT_LTO_WRAPPER=/opt/gcc/8.1/libexec/gcc/x86_64-linux-gnu/8.1.0/lto-wrapper 
Target: x86_64-linux-gnu                                                        
Configured with: /home/pbrannan/git/theme_infra/packaging/gcc-8.1.0/configure
--prefix=/opt/gcc/8.1 --enable-languages=c,c++ --with-pkgversion='Thesys GCC
8.1.0 for Ubuntu 16.04' --enable-shared --enable-gnu-unique-object
--enable-threads=posix --enable-checking=release --disable-vtable-verify
--enable-lto --with-ab
i=m64 --enable-multiarch --disable-multilib --with-build-config=bootstrap-lto
--build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu      
Thread model: posix                                                             
gcc version 8.1.0 (Thesys GCC 8.1.0 for Ubuntu 16.04)                           
COLLECT_GCC_OPTIONS='-std=c++14' '-O2' '-Wall' '-Werror' '-march=x86-64'
'-save-temps' '-v' '-shared-libgcc'                                             
 /opt/gcc/8.1/libexec/gcc/x86_64-linux-gnu/8.1.0/cc1plus -E -quiet -v
-imultiarch x86_64-linux-gnu -D_GNU_SOURCE t4.cpp -march=x86-64 -std=c++14
-Wall -Werror -O2 -fpch-preprocess -o t4.ii
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory
"/opt/gcc/8.1/lib/gcc/x86_64-linux-gnu/8.1.0/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /opt/gcc/8.1/lib/gcc/x86_64-linux-gnu/8.1.0/../../../../include/c++/8.1.0

/opt/gcc/8.1/lib/gcc/x86_64-linux-gnu/8.1.0/../../../../include/c++/8.1.0/x86_64-linux-gnu

/opt/gcc/8.1/lib/gcc/x86_64-linux-gnu/8.1.0/../../../../include/c++/8.1.0/backward
 /opt/gcc/8.1/lib/gcc/x86_64-linux-gnu/8.1.0/include
 /usr/local/include
 /opt/gcc/8.1/include
 /opt/gcc/8.1/lib/gcc/x86_64-linux-gnu/8.1.0/include-fixed
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.
COLLECT_GCC_OPTIONS='-std=c++14' '-O2' '-Wall' '-Werror' '-march=x86-64'
'-save-temps' '-v' '-shared-libgcc'
 /opt/gcc/8.1/libexec/gcc/x86_64-linux-gnu/8.1.0/cc1plus -fpreprocessed t4.ii
-quiet -dumpbase t4.cpp -march=x86-64 -auxbase t4 -O2 -Wall -Werror -std=c++14
-version -o t4.s
GNU C++14 (Thesys GCC 8.1.0 for Ubuntu 16.04) version 8.1.0 (x86_64-linux-gnu)
        compiled by GNU C version 8.1.0, GMP version 6.1.0, MPFR version 3.1.4,
MPC version 1.0.3, isl version isl-0.16.1-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
GNU C++14 (Thesys GCC 8.1.0 for Ubuntu 16.04) version 8.1.0 (x86_64-linux-gnu)
        compiled by GNU C version 8.1.0, GMP version 6.1.0, MPFR version 3.1.4,
MPC version 1.0.3, isl version isl-0.16.1-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 6724e7d270573c4346dc08c31ad9ce91
COLLECT_GCC_OPTIONS='-std=c++14' '-O2' '-Wall' '-Werror' '-march=x86-64'
'-save-temps' '-v' '-shared-libgcc'
 as -v --64 -o t4.o t4.s
GNU assembler version 2.26.1 (x86_64-linux-gnu) using BFD version (GNU Binutils
for Ubuntu) 2.26.1
COMPILER_PATH=/opt/gcc/8.1/libexec/gcc/x86_64-linux-gnu/8.1.0/:/opt/gcc/8.1/libexec/gcc/x86_64-linux-gnu/8.1.0/:/opt/gcc/8.1/libexec/gcc/x86_64-linux-gnu/:/opt/gcc/8.1/lib/gcc/x86_64-linux-gnu/8.1.0/:/opt/gcc/8.1/lib/gcc/x86_64-linux-gnu/
LIBRARY_PATH=/opt/gcc/8.1/lib/gcc/x86_64-linux-gnu/8.1.0/:/opt/gcc/8.1/lib/gcc/x86_64-linux-gnu/8.1.0/../../../../lib64/:/lib/x86_64-linux-gnu/:/lib/../lib64/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib64/:/opt/gcc/8.1/lib/gcc/x86_64-linux-gnu/8.1.0/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-std=c++14' '-O2' '-Wall' '-Werror' '-march=x86-64'
'-save-temps' '-v' '-shared-libgcc'
 /opt/gcc/8.1/libexec/gcc/x86_64-linux-gnu/8.1.0/collect2 -plugin
/opt/gcc/8.1/libexec/gcc/x86_64-linux-gnu/8.1.0/liblto_plugin.so
-plugin-opt=/opt/gcc/8.1/libexec/gcc/x86_64-linux-gnu/8.1.0/lto-wrapper
-plugin-opt=-fresolution=t4.res -plugin-opt=-pass-through=-lgcc_s
-plugin-opt=-pass-through=-lgcc -plugin-opt=-pas
s-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc
--eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2
/usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o
/opt/gcc/8.1/lib/gcc/x86_64-linux-gnu/8.1.0/crtbegin.o
-L/opt/gcc/8.1/lib/gcc/x86_64-linux-gnu/8.1
.0 -L/opt/gcc/8.1/lib/gcc/x86_64-linux-gnu/8.1.0/../../../../lib64
-L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu
-L/usr/lib/../lib64 -L/opt/gcc/8.1/lib/gcc/x86_64-linux-gnu/8.1.0/../../.. t4.o
-lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc
/opt/gcc/8.1/lib/gcc/x86_64-linux-gnu/8.1.0/crtend.o /usr
/lib/x86_64-linux-gnu/crtn.o
COLLECT_GCC_OPTIONS='-std=c++14' '-O2' '-Wall' '-Werror' '-march=x86-64'
'-save-temps' '-v' '-shared-libgcc'

Reply via email to