Bug 84658 - [7 Regression] -O3 -fmerge-all-constants causes incorrect for-each loop generation.
Summary: [7 Regression] -O3 -fmerge-all-constants causes incorrect for-each loop gener...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: ipa (show other bugs)
Version: 8.0.1
: P2 normal
Target Milestone: 7.4
Assignee: Martin Liška
URL:
Keywords: alias, wrong-code
Depends on:
Blocks:
 
Reported: 2018-03-02 04:46 UTC by gnubugs
Modified: 2018-04-24 15:22 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work: 6.4.1, 7.3.1, 8.0
Known to fail:
Last reconfirmed: 2018-03-02 00:00:00


Attachments
Problematic CCP2 dump file (1.98 KB, text/plain)
2018-03-02 12:35 UTC, Martin Liška
Details

Note You need to log in before you can comment on or make changes to this bug.
Description gnubugs 2018-03-02 04:46:06 UTC
The following program should print a few numbers then exit.  Due to incorrect codegen when combining -fmerge-all-constants, -O3, and duplicate arrays of sufficient length on GCC 7.2.0+, Bar generates no bounds check and will infinite loop until it reads past the end of kTestCases and eventually crashes:



#include <stdio.h>

void Foo() {
    const int kTestCases[] = { 0, 1, 2, 3, 4, 5, 8, 15, 16, 17, 512, 1020, 1021, 1022, 1023, 1024 };
    for (int count : kTestCases) {
        printf("%d\n", count);
    }
}

void Bar() {
    const int kTestCases[] = { 0, 1, 2, 3, 4, 5, 8, 15, 16, 17, 512, 1020, 1021, 1022, 1023, 1024 };
    for (int count : kTestCases) {
        printf("%d\n", count);
    }
}

int main() {
    Foo();
    Bar();
}



I originally reproduced this bug against MinGW's GCC 7.2.0, and since reproduced on Wandbox's 7.2.0 and 8.0.1 (20180228) versions of GCC, but not 7.1.0.  (Wandbox uses -O2)
Wandbox 8.0.1 (20180228) GCC permalink:  https://wandbox.org/permlink/A0dVICb3CDTIoheX

MinGW 7.2.0 repro commands:
  C:/mingw/bin/x86_64-w64-mingw32-g++ -O3 -fmerge-all-constants -o "main.o" -c "main.cpp"
  C:/mingw/bin/x86_64-w64-mingw32-g++ -o main.exe main.o

Wandbox's 8.0.1 (20180228) repro commands:
  g++ prog.cc -Wall -Wextra -O2 -march=native "-fmerge-all-constants"

Version spam from g++ -v commands follows for completeness (in the case of wandbox, with a little extra spam - I don't know how to tell it not to pass source files.)



# MinGW 7.2.0
C:\>C:/mingw/bin/x86_64-w64-mingw32-g++ -v
Using built-in specs.
COLLECT_GCC=C:/mingw/bin/x86_64-w64-mingw32-g++
COLLECT_LTO_WRAPPER=C:/mingw/bin/../libexec/gcc/x86_64-w64-mingw32/7.2.0/lto-wrapper.exe
Target: x86_64-w64-mingw32
Configured with: ../../../src/gcc-7.2.0/configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysroot=/c/mingw720/x86_64-720-win32-sjlj-rt_v5-rev0/mingw64 --enable-shared --enable-static --enable-targets=all --enable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-time=yes --enable-threads=win32 --enable-libgomp --enable-libatomic --enable-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --enable-version-specific-runtime-libs --enable-libstdcxx-filesystem-ts=yes --enable-sjlj-exceptions --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch-32=i686 --with-arch-64=nocona --with-tune-32=generic --with-tune-64=core2 --with-libiconv --with-system-zlib --with-gmp=/c/mingw720/prerequisites/x86_64-w64-mingw32-static --with-mpfr=/c/mingw720/prerequisites/x86_64-w64-mingw32-static --with-mpc=/c/mingw720/prerequisites/x86_64-w64-mingw32-static --with-isl=/c/mingw720/prerequisites/x86_64-w64-mingw32-static --with-pkgversion='x86_64-win32-sjlj-rev0, Built by MinGW-W64 project' --with-bugurl=https://sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -fno-ident -I/c/mingw720/x86_64-720-win32-sjlj-rt_v5-rev0/mingw64/opt/include -I/c/mingw720/prerequisites/x86_64-zlib-static/include -I/c/mingw720/prerequisites/x86_64-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe -fno-ident -I/c/mingw720/x86_64-720-win32-sjlj-rt_v5-rev0/mingw64/opt/include -I/c/mingw720/prerequisites/x86_64-zlib-static/include -I/c/mingw720/prerequisites/x86_64-w64-mingw32-static/include' CPPFLAGS=' -I/c/mingw720/x86_64-720-win32-sjlj-rt_v5-rev0/mingw64/opt/include -I/c/mingw720/prerequisites/x86_64-zlib-static/include -I/c/mingw720/prerequisites/x86_64-w64-mingw32-static/include' LDFLAGS='-pipe -fno-ident -L/c/mingw720/x86_64-720-win32-sjlj-rt_v5-rev0/mingw64/opt/lib -L/c/mingw720/prerequisites/x86_64-zlib-static/lib -L/c/mingw720/prerequisites/x86_64-w64-mingw32-static/lib '
Thread model: win32
gcc version 7.2.0 (x86_64-win32-sjlj-rev0, Built by MinGW-W64 project)



# Wandbox 7.2.0
$ g++ prog.cc "-v"
Using built-in specs.
COLLECT_GCC=/opt/wandbox/gcc-7.2.0/bin/g++
COLLECT_LTO_WRAPPER=/opt/wandbox/gcc-7.2.0/libexec/gcc/x86_64-pc-linux-gnu/7.2.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: ../gcc-7.2.0/configure --prefix=/opt/wandbox/gcc-7.2.0 --enable-languages=c,c++ --disable-multilib --without-ppl --without-cloog-ppl --enable-checking=release --disable-nls LDFLAGS=-Wl,-rpath,/opt/wandbox/gcc-7.2.0/lib,-rpath,/opt/wandbox/gcc-7.2.0/lib64,-rpath,/opt/wandbox/gcc-7.2.0/lib32 --enable-lto
Thread model: posix
gcc version 7.2.0 (GCC) 
COLLECT_GCC_OPTIONS='-o' 'prog.exe' '-I' '/opt/wandbox/boost-sml/include' '-I' '/opt/wandbox/boost-di/include' '-I' '/opt/wandbox/range-v3/include' '-I' '/opt/wandbox/nlohmann-json/src' '-I' '/opt/wandbox/cmcstl2/include' '-v' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
 /opt/wandbox/gcc-7.2.0/libexec/gcc/x86_64-pc-linux-gnu/7.2.0/cc1plus -quiet -v -I /opt/wandbox/boost-sml/include -I /opt/wandbox/boost-di/include -I /opt/wandbox/range-v3/include -I /opt/wandbox/nlohmann-json/src -I /opt/wandbox/cmcstl2/include -imultiarch x86_64-linux-gnu -D_GNU_SOURCE prog.cc -quiet -dumpbase prog.cc -mtune=generic -march=x86-64 -auxbase prog -version -o /tmp/ccHRA5WI.s
GNU C++14 (GCC) version 7.2.0 (x86_64-pc-linux-gnu)
	compiled by GNU C version 7.2.0, GMP version 6.1.0, MPFR version 3.1.4, MPC version 1.0.3, isl version none
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/local/include"
ignoring nonexistent directory "/opt/wandbox/gcc-7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../x86_64-pc-linux-gnu/include"
ignoring nonexistent directory "/opt/wandbox/nlohmann-json/src"
#include "..." search starts here:
#include <...> search starts here:
 /opt/wandbox/boost-sml/include
 /opt/wandbox/boost-di/include
 /opt/wandbox/range-v3/include
 /opt/wandbox/cmcstl2/include
 /opt/wandbox/gcc-7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../include/c++/7.2.0
 /opt/wandbox/gcc-7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../include/c++/7.2.0/x86_64-pc-linux-gnu
 /opt/wandbox/gcc-7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../include/c++/7.2.0/backward
 /opt/wandbox/gcc-7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/include
 /opt/wandbox/gcc-7.2.0/include
 /opt/wandbox/gcc-7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/include-fixed
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.
GNU C++14 (GCC) version 7.2.0 (x86_64-pc-linux-gnu)
	compiled by GNU C version 7.2.0, GMP version 6.1.0, MPFR version 3.1.4, MPC version 1.0.3, isl version none
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: e4573953ae983b800fb10c1669d61c0c
COLLECT_GCC_OPTIONS='-o' 'prog.exe' '-I' '/opt/wandbox/boost-sml/include' '-I' '/opt/wandbox/boost-di/include' '-I' '/opt/wandbox/range-v3/include' '-I' '/opt/wandbox/nlohmann-json/src' '-I' '/opt/wandbox/cmcstl2/include' '-v' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
 as -v -I /opt/wandbox/boost-sml/include -I /opt/wandbox/boost-di/include -I /opt/wandbox/range-v3/include -I /opt/wandbox/nlohmann-json/src -I /opt/wandbox/cmcstl2/include --64 -o /tmp/ccfqJWSe.o /tmp/ccHRA5WI.s
GNU assembler version 2.26.1 (x86_64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.26.1
COMPILER_PATH=/opt/wandbox/gcc-7.2.0/libexec/gcc/x86_64-pc-linux-gnu/7.2.0/:/opt/wandbox/gcc-7.2.0/libexec/gcc/x86_64-pc-linux-gnu/7.2.0/:/opt/wandbox/gcc-7.2.0/libexec/gcc/x86_64-pc-linux-gnu/:/opt/wandbox/gcc-7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/:/opt/wandbox/gcc-7.2.0/lib/gcc/x86_64-pc-linux-gnu/
LIBRARY_PATH=/opt/wandbox/gcc-7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/:/opt/wandbox/gcc-7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../lib64/:/lib/x86_64-linux-gnu/:/lib/../lib64/:/usr/lib/x86_64-linux-gnu/:/opt/wandbox/gcc-7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-o' 'prog.exe' '-I' '/opt/wandbox/boost-sml/include' '-I' '/opt/wandbox/boost-di/include' '-I' '/opt/wandbox/range-v3/include' '-I' '/opt/wandbox/nlohmann-json/src' '-I' '/opt/wandbox/cmcstl2/include' '-v' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
 /opt/wandbox/gcc-7.2.0/libexec/gcc/x86_64-pc-linux-gnu/7.2.0/collect2 -plugin /opt/wandbox/gcc-7.2.0/libexec/gcc/x86_64-pc-linux-gnu/7.2.0/liblto_plugin.so -plugin-opt=/opt/wandbox/gcc-7.2.0/libexec/gcc/x86_64-pc-linux-gnu/7.2.0/lto-wrapper -plugin-opt=-fresolution=/tmp/cczT5bRK.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-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 -o prog.exe /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o /opt/wandbox/gcc-7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/crtbegin.o -L/opt/wandbox/gcc-7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0 -L/opt/wandbox/gcc-7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../lib64 -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu -L/opt/wandbox/gcc-7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../.. -rpath /opt/wandbox/gcc-7.2.0/lib64 -lpthread /tmp/ccfqJWSe.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /opt/wandbox/gcc-7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/crtend.o /usr/lib/x86_64-linux-gnu/crtn.o
COLLECT_GCC_OPTIONS='-o' 'prog.exe' '-I' '/opt/wandbox/boost-sml/include' '-I' '/opt/wandbox/boost-di/include' '-I' '/opt/wandbox/range-v3/include' '-I' '/opt/wandbox/nlohmann-json/src' '-I' '/opt/wandbox/cmcstl2/include' '-v' '-shared-libgcc' '-mtune=generic' '-march=x86-64'



# Wandbox 8.0.1 (20180228)
$ g++ prog.cc "-v"
Using built-in specs.
COLLECT_GCC=/opt/wandbox/gcc-head/bin/g++
COLLECT_LTO_WRAPPER=/opt/wandbox/gcc-head/libexec/gcc/x86_64-pc-linux-gnu/8.0.1/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: ../source/configure --prefix=/opt/wandbox/gcc-head --enable-languages=c,c++ --disable-multilib --without-ppl --without-cloog-ppl --enable-checking=release --disable-nls --enable-lto LDFLAGS=-Wl,-rpath,/opt/wandbox/gcc-head/lib,-rpath,/opt/wandbox/gcc-head/lib64,-rpath,/opt/wandbox/gcc-head/lib32
Thread model: posix
gcc version 8.0.1 20180228 (experimental) (GCC) 
COLLECT_GCC_OPTIONS='-o' 'prog.exe' '-I' '/opt/wandbox/boost-sml/include' '-I' '/opt/wandbox/boost-di/include' '-I' '/opt/wandbox/range-v3/include' '-I' '/opt/wandbox/nlohmann-json/src' '-I' '/opt/wandbox/cmcstl2/include' '-v' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
 /opt/wandbox/gcc-head/libexec/gcc/x86_64-pc-linux-gnu/8.0.1/cc1plus -quiet -v -I /opt/wandbox/boost-sml/include -I /opt/wandbox/boost-di/include -I /opt/wandbox/range-v3/include -I /opt/wandbox/nlohmann-json/src -I /opt/wandbox/cmcstl2/include -imultiarch x86_64-linux-gnu -D_GNU_SOURCE prog.cc -quiet -dumpbase prog.cc -mtune=generic -march=x86-64 -auxbase prog -version -o /tmp/ccd0D4l2.s
GNU C++14 (GCC) version 8.0.1 20180228 (experimental) (x86_64-pc-linux-gnu)
	compiled by GNU C version 8.0.1 20180228 (experimental), GMP version 6.1.0, MPFR version 3.1.4, MPC version 1.0.3, isl version none
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/local/include"
ignoring nonexistent directory "/opt/wandbox/gcc-head/lib/gcc/x86_64-pc-linux-gnu/8.0.1/../../../../x86_64-pc-linux-gnu/include"
ignoring nonexistent directory "/opt/wandbox/nlohmann-json/src"
#include "..." search starts here:
#include <...> search starts here:
 /opt/wandbox/boost-sml/include
 /opt/wandbox/boost-di/include
 /opt/wandbox/range-v3/include
 /opt/wandbox/cmcstl2/include
 /opt/wandbox/gcc-head/lib/gcc/x86_64-pc-linux-gnu/8.0.1/../../../../include/c++/8.0.1
 /opt/wandbox/gcc-head/lib/gcc/x86_64-pc-linux-gnu/8.0.1/../../../../include/c++/8.0.1/x86_64-pc-linux-gnu
 /opt/wandbox/gcc-head/lib/gcc/x86_64-pc-linux-gnu/8.0.1/../../../../include/c++/8.0.1/backward
 /opt/wandbox/gcc-head/lib/gcc/x86_64-pc-linux-gnu/8.0.1/include
 /opt/wandbox/gcc-head/include
 /opt/wandbox/gcc-head/lib/gcc/x86_64-pc-linux-gnu/8.0.1/include-fixed
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.
GNU C++14 (GCC) version 8.0.1 20180228 (experimental) (x86_64-pc-linux-gnu)
	compiled by GNU C version 8.0.1 20180228 (experimental), GMP version 6.1.0, MPFR version 3.1.4, MPC version 1.0.3, isl version none
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 19cc421d9c46f395a0adf79017271593
COLLECT_GCC_OPTIONS='-o' 'prog.exe' '-I' '/opt/wandbox/boost-sml/include' '-I' '/opt/wandbox/boost-di/include' '-I' '/opt/wandbox/range-v3/include' '-I' '/opt/wandbox/nlohmann-json/src' '-I' '/opt/wandbox/cmcstl2/include' '-v' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
 as -v -I /opt/wandbox/boost-sml/include -I /opt/wandbox/boost-di/include -I /opt/wandbox/range-v3/include -I /opt/wandbox/nlohmann-json/src -I /opt/wandbox/cmcstl2/include --64 -o /tmp/ccP1GKIN.o /tmp/ccd0D4l2.s
GNU assembler version 2.26.1 (x86_64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.26.1
COMPILER_PATH=/opt/wandbox/gcc-head/libexec/gcc/x86_64-pc-linux-gnu/8.0.1/:/opt/wandbox/gcc-head/libexec/gcc/x86_64-pc-linux-gnu/8.0.1/:/opt/wandbox/gcc-head/libexec/gcc/x86_64-pc-linux-gnu/:/opt/wandbox/gcc-head/lib/gcc/x86_64-pc-linux-gnu/8.0.1/:/opt/wandbox/gcc-head/lib/gcc/x86_64-pc-linux-gnu/
LIBRARY_PATH=/opt/wandbox/gcc-head/lib/gcc/x86_64-pc-linux-gnu/8.0.1/:/opt/wandbox/gcc-head/lib/gcc/x86_64-pc-linux-gnu/8.0.1/../../../../lib64/:/lib/x86_64-linux-gnu/:/lib/../lib64/:/usr/lib/x86_64-linux-gnu/:/opt/wandbox/gcc-head/lib/gcc/x86_64-pc-linux-gnu/8.0.1/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-o' 'prog.exe' '-I' '/opt/wandbox/boost-sml/include' '-I' '/opt/wandbox/boost-di/include' '-I' '/opt/wandbox/range-v3/include' '-I' '/opt/wandbox/nlohmann-json/src' '-I' '/opt/wandbox/cmcstl2/include' '-v' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
 /opt/wandbox/gcc-head/libexec/gcc/x86_64-pc-linux-gnu/8.0.1/collect2 -plugin /opt/wandbox/gcc-head/libexec/gcc/x86_64-pc-linux-gnu/8.0.1/liblto_plugin.so -plugin-opt=/opt/wandbox/gcc-head/libexec/gcc/x86_64-pc-linux-gnu/8.0.1/lto-wrapper -plugin-opt=-fresolution=/tmp/ccngDN7y.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-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 -o prog.exe /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o /opt/wandbox/gcc-head/lib/gcc/x86_64-pc-linux-gnu/8.0.1/crtbegin.o -L/opt/wandbox/gcc-head/lib/gcc/x86_64-pc-linux-gnu/8.0.1 -L/opt/wandbox/gcc-head/lib/gcc/x86_64-pc-linux-gnu/8.0.1/../../../../lib64 -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu -L/opt/wandbox/gcc-head/lib/gcc/x86_64-pc-linux-gnu/8.0.1/../../.. -rpath /opt/wandbox/gcc-head/lib64 -lpthread /tmp/ccP1GKIN.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /opt/wandbox/gcc-head/lib/gcc/x86_64-pc-linux-gnu/8.0.1/crtend.o /usr/lib/x86_64-linux-gnu/crtn.o
COLLECT_GCC_OPTIONS='-o' 'prog.exe' '-I' '/opt/wandbox/boost-sml/include' '-I' '/opt/wandbox/boost-di/include' '-I' '/opt/wandbox/range-v3/include' '-I' '/opt/wandbox/nlohmann-json/src' '-I' '/opt/wandbox/cmcstl2/include' '-v' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
Comment 1 Richard Biener 2018-03-02 07:55:00 UTC
Confirmed.  IPA ICF breaks this somehow, already visible with -O2 -fipa-icf.

Martin?
Comment 2 Jakub Jelinek 2018-03-02 11:59:23 UTC
Adjusted testcase for the testsuite:
// PR ipa/84658
// { dg-do run }
// { dg-options "-O3 -fmerge-all-constants" }
// { dg-output "foo 0, 1, 2, 3, 4, 5, 8, 15, 16, 17, 512, 1020, 1021, 1022, 1023, 1024, end.*" }
// { dg-output "bar 0, 1, 2, 3, 4, 5, 8, 15, 16, 17, 512, 1020, 1021, 1022, 1023, 1024, end" }

extern "C" int printf (const char *, ...);

void
foo ()
{
  const int a[] = { 0, 1, 2, 3, 4, 5, 8, 15, 16, 17, 512, 1020, 1021, 1022, 1023, 1024 };
  for (int b : a)
    printf ("%d, ", b);
}

void
bar ()
{
  const int a[] = { 0, 1, 2, 3, 4, 5, 8, 15, 16, 17, 512, 1020, 1021, 1022, 1023, 1024 };
  for (int b : a)
    printf ("%d, ", b);
}

int
main ()
{
  printf ("foo ");
  foo ();
  printf ("end\nbar ");
  bar ();
  printf ("end\n");
}
Comment 3 Jakub Jelinek 2018-03-02 12:21:12 UTC
Seems the inliner immediately undoes what ICF did and both get inlined into main as well.
The aD.2373 array becomes an alias of aD.2363.
And the real bug is introduced in ccp2:
Folding predicate __for_begin_5 == &MEM[(void *)&a + 64B] to 0
on previously:
  intD.9 bD.2396;
  const intD.9 * __for_beginD.2397;
  static const intD.9 aD.2363[16] = {0, 1, 2, 3, 4, 5, 8, 15, 16, 17, 512, 1020, 1021, 1022, 1023, 1024};
  intD.9 bD.2394;
  const intD.9 * __for_beginD.2395;
  static const intD.9 aD.2373[16];

  <bb 2> [local count: 63136019]:
  printf ("foo ");

  <bb 3> [local count: 1073741820]:
  # __for_begin_8 = PHI <&aD.2363(2), __for_begin_10(4)>
  if (__for_begin_8 == &MEM[(voidD.46 *)&aD.2363 + 64B])
    goto <bb 5>; [5.88%]
  else
    goto <bb 4>; [94.12%]

  <bb 4> [local count: 1010605800]:
  b_9 = *__for_begin_8;
  printf ("%d, ", b_9);
  __for_begin_10 = __for_begin_8 + 4;
  goto <bb 3>; [100.00%]

  <bb 5> [local count: 63136019]:
  printf ("end\nbar ");

  <bb 6> [local count: 1073741825]:
  # __for_begin_5 = PHI <&aD.2373(5), __for_begin_7(7)>
  if (__for_begin_5 == &MEM[(voidD.46 *)&aD.2373 + 64B])
    goto <bb 8>; [5.88%]
  else
    goto <bb 7>; [94.12%]

  <bb 7> [local count: 1010605805]:
  b_6 = *__for_begin_5;
  printf ("%d, ", b_6);
  __for_begin_7 = __for_begin_5 + 4;
  goto <bb 6>; [100.00%]

  <bb 8> [local count: 63136019]:
  __builtin_puts (&"end"[0]);
Comment 4 Martin Liška 2018-03-02 12:30:20 UTC
Yes, it's cpp2 that removes the check, IPA inlining is not needed:

$ cat ~/Programming/testcases/pr84658.cpp
#include <stdio.h>

const int kTestCasesFoo[] = { 0, 1, 2, 3, 4, 5, 8, 15, 16, 17, 512, 1020, 1021, 1022, 1023, 1024 };
const int kTestCasesBar[] = { 0, 1, 2, 3, 4, 5, 8, 15, 16, 17, 512, 1020, 1021, 1022, 1023, 1024 };

void Foo() {
    for (int count : kTestCasesFoo) {
        printf("foo: %d\n", count);
    }
}

void Bar() {
    for (int count : kTestCasesBar) {
        printf("bar: %d\n", count);
    }
}

int main() {
    Foo();
    Bar();
}

$ ./xg++ -B. ~/Programming/testcases/pr84658.cpp -O2 -fno-ipa-icf-functions -fmerge-all-constants -c -fno-inline
Comment 5 Martin Liška 2018-03-02 12:35:09 UTC
Created attachment 43546 [details]
Problematic CCP2 dump file

Jakub do you understand why is the folding happens? I'm not skilled in CCP.
Comment 6 Martin Liška 2018-03-02 12:40:14 UTC
(In reply to Jakub Jelinek from comment #3)
> Seems the inliner immediately undoes what ICF did and both get inlined into
> main as well.

It's not undoing the decision because the symbol (Bar) is global. So it both inlines into main and the wrapper is preserved. But it's not triggering the issue.
Comment 7 Jakub Jelinek 2018-03-02 12:44:15 UTC
Tried to look at the ccp2-uid-details dump and can't make any sense from that, so I think we need Richi on this.

A guess would be that something somewhere looks through the alais at one point and not the other point, it is referenced just in
  # __for_begin_5 = PHI <&aD.2373(5), __for_begin_7(7)>
  if (__for_begin_5 == &MEM[(voidD.46 *)&aD.2373 + 64B])
and similarly
  # __for_begin_8 = PHI <&aD.2363(2), __for_begin_10(4)>
  if (__for_begin_8 == &MEM[(voidD.46 *)&aD.2363 + 64B])
for the variable we've kept as variable, not alias, or something is upset by the const variable without initializer.

The alias has been created and its DECL_INITIAL cleared by sem_variable::merge,
2265	      DECL_INITIAL (alias->decl) = NULL;
2266	      ((symtab_node *)alias)->call_for_symbol_and_aliases (clear_decl_rtl,
2267								   NULL, true);
2268	      alias->need_bounds_init = false;
2269	      alias->remove_all_references ();
2270	      if (TREE_ADDRESSABLE (alias->decl))
2271	        original->call_for_symbol_and_aliases (set_addressable, NULL, true);
2272	
2273	      varpool_node::create_alias (alias_var->decl, decl);
2274	      alias->resolve_alias (original);
2275	
2276	      if (dump_file)
2277		fprintf (dump_file, "Unified; Variable alias has been created.\n");
Not really sure if it isn't an optimization problem if optimizers don't see the initializer (if they are smart enough to look through the alias).
Comment 8 Jakub Jelinek 2018-03-02 12:45:22 UTC
(In reply to Martin Liška from comment #6)
> (In reply to Jakub Jelinek from comment #3)
> > Seems the inliner immediately undoes what ICF did and both get inlined into
> > main as well.
> 
> It's not undoing the decision because the symbol (Bar) is global. So it both
> inlines into main and the wrapper is preserved. But it's not triggering the
> issue.

Well, it does, because it inlines Foo back into Bar, so all the ICF effort except for creating the variable alias is gone.
Comment 9 Richard Biener 2018-03-02 13:08:44 UTC
This is a points-to issue.  After inlining we have

  static const intD.9 aD.2281[16] = {0, 1, 2, 3, 4, 5, 8, 15, 16, 17, 512, 1020, 1021, 1022, 1023, 1024};
  intD.9 bD.2313;
  const intD.9 * __for_beginD.2314;
  static const intD.9 aD.2291ptD.2281[16];
...
  <bb 3> [100.00%]:
  # PT = { D.2281 } (nonlocal)
  # ALIGN = 4, MISALIGN = 0
  # __for_begin_8 = PHI <&aD.2281(2), __for_begin_10(4)>
  if (__for_begin_8 == &MEM[(voidD.43 *)&aD.2281 + 64B])
    goto <bb 5>; [5.88%]

good copy!

  <bb 6> [100.00%]:
  # PT = { D.2291 } (nonlocal)
  # ALIGN = 4, MISALIGN = 0
  # __for_begin_5 = PHI <&aD.2291ptD.2281(5), __for_begin_7(7)>
  if (__for_begin_5 == &MEM[(voidD.43 *)&aD.2291ptD.2281 + 64B])
    goto <bb 8>; [5.88%]
  else
    goto <bb 7>; [94.12%]

bad copy!  See how __for_begin_5 only points to D.2291 -- remember the
points-to sets are just bits.  But the DECL we check against has
been adjusted to the DECL_PT_UID of 2281...

I guess this is finally a case where we wondered if we get things correct... :/
I remember saying you need to adjust all existing points-to sets....

Note for the function bodies after inlining I see foo () has points-to
retained but bar () has it seemingly cleared?  But maybe this just dump
before applying the IPA ICF transform.

The ICF dump says:

Unified; Variable alias has been created.
  Setting points-to UID of [a.2291] as 2281

but then existing points-to sets containing 2291 are not adjusted.
Comment 10 Jakub Jelinek 2018-03-02 13:20:00 UTC
If ICF needs to adjust all points-to if it makes any variable aliases, perhaps it should as well adjust the code to use the variables rather than their aliases.
Comment 11 Martin Liška 2018-03-02 13:23:14 UTC
(In reply to Jakub Jelinek from comment #10)
> If ICF needs to adjust all points-to if it makes any variable aliases,
> perhaps it should as well adjust the code to use the variables rather than
> their aliases.

Similar to what we do in sanopt.c:rewrite_usage_of_param? If so, I can do that.
Comment 12 Richard Biener 2018-03-05 09:51:31 UTC
(In reply to Martin Liška from comment #11)
> (In reply to Jakub Jelinek from comment #10)
> > If ICF needs to adjust all points-to if it makes any variable aliases,
> > perhaps it should as well adjust the code to use the variables rather than
> > their aliases.
> 
> Similar to what we do in sanopt.c:rewrite_usage_of_param? If so, I can do
> that.

But that doesn't help - you'll have points-to sets mentioning both DECLs.

static decls without TREE_ADDRESSABLE set are fine to merge, those won't
ever appear in points-to sets.  For all others you really need to adjust
points-to sets.

Note the issue is "new" since we optimize address comparisons since the
idea was that for memory references aliasing doesn't really matter since
all decls we merge are readonly(?).  That's of course a bit of a fishy
view...

Given ptrs_compare_unequal is as restricted as it is now we could work
around this issue there by doing instead of

      if (VAR_P (obj1)
          && (TREE_STATIC (obj1) || DECL_EXTERNAL (obj1)))
        {
          varpool_node *node = varpool_node::get (obj1);
          /* If obj1 may bind to NULL give up (see below).  */
          if (! node
              || ! node->nonzero_address ()
              || ! decl_binds_to_current_def_p (obj1))
            return false;
        }

sth like

      if (VAR_P (obj1)
          && (TREE_STATIC (obj1) || DECL_EXTERNAL (obj1)))
        {
          varpool_node *node = varpool_node::get (obj1);
          /* If obj1 may bind to NULL give up (see below).  */
          if (! node
              || ! node->nonzero_address ()
              || ! decl_binds_to_current_def_p (obj1))
            return false;
          FOR_EACH_ALIAS (node, ...)
            {
              tree obj1_alias = ...;
              unsigned saved_pt_uid = DECL_PT_UID (obj1_alias);
              DECL_PT_UID (obj1_alias) = DECL_UID (obj1_alias);
              bool aliases = pt_solution_includes (&pi->pt, obj1_alias);
              DECL_PT_UID (obj_alias) = saved_pt_uid;
            }
         }

with the code walking over aliases adjusted accordingly.

Of course if we ever try to compare two pointers and thus have just
two points-to sets to intersect we're still lost.
Comment 13 Richard Biener 2018-03-05 09:58:10 UTC
So you can loses the TREE_ADDRESSABLE restriction somewhat in requiring at most one decl to be TREE_ADDRESSABLE - that's the one you need to keep, the others may become aliases.  Given TREE_ADDRESSABLE isn't reliable for !TREE_STATIC vars
we can't merge any exported decls that way.  Consider

const int foo1;
const int foo2;

int *bar();  // in other TU, returns address of foo1

int main ()
{
  if (bar() != &foo2)
    ...;
}

not sure if we want to do hand-waving saying that we can't possibly have
points-to sets mentioning those without seeing the function IL.  Well,
might be similarly hand-waving as the reference aliasing issue.

So we could drop the TREE_STATIC restriction if TREE_ADDRESSABLE is reliable
within the current TU.
Comment 14 Martin Liška 2018-03-08 11:20:51 UTC
(In reply to Richard Biener from comment #13)
> So you can loses the TREE_ADDRESSABLE restriction somewhat in requiring at
> most one decl to be TREE_ADDRESSABLE - that's the one you need to keep, the
> others may become aliases.  Given TREE_ADDRESSABLE isn't reliable for
> !TREE_STATIC vars
> we can't merge any exported decls that way.  Consider
> 
> const int foo1;
> const int foo2;
> 
> int *bar();  // in other TU, returns address of foo1
> 
> int main ()
> {
>   if (bar() != &foo2)
>     ...;
> }
> 
> not sure if we want to do hand-waving saying that we can't possibly have
> points-to sets mentioning those without seeing the function IL.  Well,
> might be similarly hand-waving as the reference aliasing issue.
> 
> So we could drop the TREE_STATIC restriction if TREE_ADDRESSABLE is reliable
> within the current TU.

Note that this issue happens only with -fmerge-all-constants. And we have caveat
in documentation that using the option, pointer comparison can be broken:

Languages like C or C++ require each variable,
           including multiple instances of the same variable in recursive calls, to have distinct locations, so using this option results in non-conforming behavior.

Thus:

$ cat test.c
const int foo1 = 3;
const int foo2 = 3;

const int *
__attribute__((noinline))
bar()
{
  return &foo1;
}

int main ()
{
  if ((bar() - &foo2) == 0)
    __builtin_abort ();

  return 0;
}

$ gcc test.c -O2 -fno-ipa-icf -fmerge-all-constants  && ./a.out 
Aborted (core dumped)

That said, would be Richi your comment in c#12 a sufficient fix?
Comment 15 Jakub Jelinek 2018-03-08 11:28:02 UTC
(In reply to Martin Liška from comment #14)
> (In reply to Richard Biener from comment #13)
> > So you can loses the TREE_ADDRESSABLE restriction somewhat in requiring at
> > most one decl to be TREE_ADDRESSABLE - that's the one you need to keep, the
> > others may become aliases.  Given TREE_ADDRESSABLE isn't reliable for
> > !TREE_STATIC vars
> > we can't merge any exported decls that way.  Consider
> > 
> > const int foo1;
> > const int foo2;
> > 
> > int *bar();  // in other TU, returns address of foo1
> > 
> > int main ()
> > {
> >   if (bar() != &foo2)
> >     ...;
> > }
> > 
> > not sure if we want to do hand-waving saying that we can't possibly have
> > points-to sets mentioning those without seeing the function IL.  Well,
> > might be similarly hand-waving as the reference aliasing issue.
> > 
> > So we could drop the TREE_STATIC restriction if TREE_ADDRESSABLE is reliable
> > within the current TU.
> 
> Note that this issue happens only with -fmerge-all-constants. And we have
> caveat
> in documentation that using the option, pointer comparison can be broken:
> 
> Languages like C or C++ require each variable,
>            including multiple instances of the same variable in recursive
> calls, to have distinct locations, so using this option results in
> non-conforming behavior.
> 
> Thus:
> 
> $ cat test.c
> const int foo1 = 3;
> const int foo2 = 3;
> 
> const int *
> __attribute__((noinline))
> bar()
> {
>   return &foo1;
> }
> 
> int main ()
> {
>   if ((bar() - &foo2) == 0)
>     __builtin_abort ();
> 
>   return 0;
> }
> 
> $ gcc test.c -O2 -fno-ipa-icf -fmerge-all-constants  && ./a.out 
> Aborted (core dumped)

Sure, the caveat of -fmerge-all-constants is that different constants can be merged.
But that doesn't imply that the #c0 failure is fine, the testcase doesn't really care if kTestCases constant arrays from the two functions are merged together or not, if not, they will be separate, if yes, they will be the same, but if it doesn't try to compare them in any way, it should make zero difference on the behavior.
Comment 16 Richard Biener 2018-03-08 11:29:58 UTC
(In reply to Martin Liška from comment #14)
> (In reply to Richard Biener from comment #13)
> > So you can loses the TREE_ADDRESSABLE restriction somewhat in requiring at
> > most one decl to be TREE_ADDRESSABLE - that's the one you need to keep, the
> > others may become aliases.  Given TREE_ADDRESSABLE isn't reliable for
> > !TREE_STATIC vars
> > we can't merge any exported decls that way.  Consider
> > 
> > const int foo1;
> > const int foo2;
> > 
> > int *bar();  // in other TU, returns address of foo1
> > 
> > int main ()
> > {
> >   if (bar() != &foo2)
> >     ...;
> > }
> > 
> > not sure if we want to do hand-waving saying that we can't possibly have
> > points-to sets mentioning those without seeing the function IL.  Well,
> > might be similarly hand-waving as the reference aliasing issue.
> > 
> > So we could drop the TREE_STATIC restriction if TREE_ADDRESSABLE is reliable
> > within the current TU.
> 
> Note that this issue happens only with -fmerge-all-constants. And we have
> caveat
> in documentation that using the option, pointer comparison can be broken:
> 
> Languages like C or C++ require each variable,
>            including multiple instances of the same variable in recursive
> calls, to have distinct locations, so using this option results in
> non-conforming behavior.
> 
> Thus:
> 
> $ cat test.c
> const int foo1 = 3;
> const int foo2 = 3;
> 
> const int *
> __attribute__((noinline))
> bar()
> {
>   return &foo1;
> }
> 
> int main ()
> {
>   if ((bar() - &foo2) == 0)
>     __builtin_abort ();
> 
>   return 0;
> }
> 
> $ gcc test.c -O2 -fno-ipa-icf -fmerge-all-constants  && ./a.out 
> Aborted (core dumped)
> 
> That said, would be Richi your comment in c#12 a sufficient fix?

Hum, isn't the bug INVALID then?  Shouldn't we restrict -fmerge-all-constants
to not address-taken variables to not make the option useless?

The suggested fix in c#12 is a band-aid only.

What's the impact of not merging TREE_ADDRESSABLE decls into other decls?

I presume -fmerge-all-constants pre-dates ICF?
Comment 17 Jakub Jelinek 2018-03-08 11:34:17 UTC
(In reply to Richard Biener from comment #16)
> Hum, isn't the bug INVALID then?  Shouldn't we restrict -fmerge-all-constants

No.

> to not address-taken variables to not make the option useless?

-fmerge-all-constants is an extension where the addresses of the constant variables may be the same even if without the option they would need to be guaranteed to be different.  That is the whole point of the option, many people just don't care about it and care more about .rodata size, so they have an option to tell the compiler about it.

> I presume -fmerge-all-constants pre-dates ICF?

Yes, by far.  -fmerge-all-constants is from 2001, ICF from 2014.
Comment 18 rguenther@suse.de 2018-03-08 13:08:02 UTC
On Thu, 8 Mar 2018, jakub at gcc dot gnu.org wrote:

> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84658
> 
> --- Comment #17 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
> (In reply to Richard Biener from comment #16)
> > Hum, isn't the bug INVALID then?  Shouldn't we restrict -fmerge-all-constants
> 
> No.
> 
> > to not address-taken variables to not make the option useless?
> 
> -fmerge-all-constants is an extension where the addresses of the constant
> variables may be the same even if without the option they would need to be
> guaranteed to be different.  That is the whole point of the option, many people
> just don't care about it and care more about .rodata size, so they have an
> option to tell the compiler about it.

That's not really an answer to the question ...

But anyway, we have precedence in points-to-set editing which we do
during RTL expansion to reflect variable coalescing.

So ... a different approach for fixing would be if ICF would keep

 a) a global bitmap of all DECL_UID that took part in any merging operation
 b) a mapping of merged DECL_UID to prevailing DECL_UID (which is also the
    DECL_PT_UID of the merged ones)

then during IPA ICF transform phase do

  FOR_EACH_DEFINED_FUNCTION (...)
    {
       FOR_EACH_SSA_NAME_FN (..., name)
         if (POINTER_TYPE_P (TREE_TYPE (name))
             && SSA_NAME_PTR_INFO (name))
           fixup_pt_set (&SSA_NAME_PTR_INFO (name)->pt);
       fixup_pt_set (fn->gimple_df->escaped);

       /* The above get's us to 99% I guess, at least catching the
          address compares.  Below also gets us aliasing correct
          but as said we're giving leeway to the situation with
          readonly vars anyway, so ... */
       FOR_EACH_BB_FN (...)
         for (each-stmt)
           if (is_gimple_call (...))
             {
               fixup_pt_set (gimple_call_use_set (call));
               fixup_pt_set (gimple_call_clobber_set (call));
             }
    }

and fixup_pt_set essentially doing

  EXECUTE_IF_AND_IN_BITMAP (pt->vars, bitmap-of-merged-decls, 0, i, bi)
    bitmap_set_bit (pt->vars, *merged_uid_to_pt_uid->get (i));

that would be a "real" fix, also allowing the forthcoming pointer
comparison optimization using two pointers (and thus two points-to
sets).

> > I presume -fmerge-all-constants pre-dates ICF?
> 
> Yes, by far.  -fmerge-all-constants is from 2001, ICF from 2014.
Comment 19 Martin Liška 2018-03-08 13:36:51 UTC
Just having chat with Honza and he is curious why IPA passes should maintain points-to-sets info as it's rebuild in pass_build_alias quite soon in post IPA passes? Another question is why the pass_rebuild_alias isn't the first one and is sitting after CCP?

Isn't also possible to release all points-to-sets before IPA passes? That can save some memory.
Comment 20 Jakub Jelinek 2018-03-08 13:38:45 UTC
How would IPA-PTA work then?
Comment 21 Martin Liška 2018-03-08 13:41:55 UTC
(In reply to Jakub Jelinek from comment #20)
> How would IPA-PTA work then?

Not having experience how that works, but I would expect a complete rebuild. Similar to what the tree PTA does?
Comment 22 Martin Liška 2018-03-08 13:50:22 UTC
(In reply to Martin Liška from comment #21)
> (In reply to Jakub Jelinek from comment #20)
> > How would IPA-PTA work then?
> 
> Not having experience how that works, but I would expect a complete rebuild.
> Similar to what the tree PTA does?

Note that the TREE PTA is just a TODO_rebuild_alias flag. Thus I would expect IPA PTA is also a rebuild of PTA information.
Comment 23 rguenther@suse.de 2018-03-08 14:34:01 UTC
On Thu, 8 Mar 2018, marxin at gcc dot gnu.org wrote:

> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84658
> 
> --- Comment #22 from Martin Liška <marxin at gcc dot gnu.org> ---
> (In reply to Martin Liška from comment #21)
> > (In reply to Jakub Jelinek from comment #20)
> > > How would IPA-PTA work then?
> > 
> > Not having experience how that works, but I would expect a complete rebuild.
> > Similar to what the tree PTA does?
> 
> Note that the TREE PTA is just a TODO_rebuild_alias flag. Thus I would expect
> IPA PTA is also a rebuild of PTA information.

IPA PTA rebuilds everything (and with -fipa-pta we should be fine).  The 
issue is the time between IPA ICF and the late pass_build_alias,
we do the "invalid" folding in pass_ccp.

And yes, we do want to do some scalar cleanup before running PTA.

If we'd decide not to then the "proper" place would probably be
pass_ipa_pta which then either would do local PTA or IPA PTA based
on the flag.

But that's too much for GCC 8 or 7.
Comment 24 Martin Liška 2018-03-13 08:20:59 UTC
Author: marxin
Date: Tue Mar 13 08:20:27 2018
New Revision: 258480

URL: https://gcc.gnu.org/viewcvs?rev=258480&root=gcc&view=rev
Log:
Fix PTA info in IPA ICF (PR ipa/84658).

2018-03-13  Martin Liska  <mliska@suse.cz>

	PR ipa/84658.
	* (sem_item_optimizer::sem_item_optimizer): Initialize new
	vector.
	(sem_item_optimizer::~sem_item_optimizer): Release it.
	(sem_item_optimizer::merge_classes): Register variable aliases.
	(sem_item_optimizer::fixup_pt_set): New function.
	(sem_item_optimizer::fixup_points_to_sets): Likewise.
	* ipa-icf.h: Declare new variables and functions.
2018-03-13  Martin Liska  <mliska@suse.cz>

	PR ipa/84658.
	* g++.dg/ipa/pr84658.C: New test.

Added:
    trunk/gcc/testsuite/g++.dg/ipa/pr84658.C
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/ipa-icf.c
    trunk/gcc/ipa-icf.h
    trunk/gcc/testsuite/ChangeLog
Comment 25 Martin Liška 2018-03-13 08:22:39 UTC
Fixed on trunk so far.
Comment 26 Martin Liška 2018-04-24 15:17:32 UTC
Author: marxin
Date: Tue Apr 24 15:17:00 2018
New Revision: 259597

URL: https://gcc.gnu.org/viewcvs?rev=259597&root=gcc&view=rev
Log:
Backport r258480

2018-04-24  Martin Liska  <mliska@suse.cz>

	Backport from mainline
	2018-03-13  Martin Liska  <mliska@suse.cz>

	PR ipa/84658.
	* (sem_item_optimizer::sem_item_optimizer): Initialize new
	vector.
	(sem_item_optimizer::~sem_item_optimizer): Release it.
	(sem_item_optimizer::merge_classes): Register variable aliases.
	(sem_item_optimizer::fixup_pt_set): New function.
	(sem_item_optimizer::fixup_points_to_sets): Likewise.
	* ipa-icf.h: Declare new variables and functions.
2018-04-24  Martin Liska  <mliska@suse.cz>

	Backport from mainline
	2018-03-13  Martin Liska  <mliska@suse.cz>

	PR ipa/84658.
	* g++.dg/ipa/pr84658.C: New test.

Added:
    branches/gcc-7-branch/gcc/testsuite/g++.dg/ipa/pr84658.C
Modified:
    branches/gcc-7-branch/gcc/ChangeLog
    branches/gcc-7-branch/gcc/ipa-icf.c
    branches/gcc-7-branch/gcc/ipa-icf.h
    branches/gcc-7-branch/gcc/testsuite/ChangeLog
Comment 27 Martin Liška 2018-04-24 15:22:49 UTC
Fixed on GCC 7 branch.