char *foo (void) { char *p = __builtin_malloc (64); char *q = __builtin_malloc (64); __builtin_strcat (q, "abcde"); __builtin_strcat (p, "ab"); p[1] = q[3]; __builtin_strcat (p, q); return q; } gives > ../../obj2/gcc/cc1 -quiet -O2 t.c t.c: In function ‘foo’: t.c:1:7: internal compiler error: in get_string_length, at tree-ssa-strlen.c:417 char *foo (void) ^ 0x876c3d2 get_string_length /space/rguenther/tramp3d/trunk/gcc/tree-ssa-strlen.c:417 0x8772b02 get_string_length /space/rguenther/tramp3d/trunk/gcc/tree.h:2731 0x8772b02 handle_builtin_strlen /space/rguenther/tramp3d/trunk/gcc/tree-ssa-strlen.c:899 (gdb) up #1 0x0876c3d3 in get_string_length (si=0x3c) at /space/rguenther/tramp3d/trunk/gcc/tree-ssa-strlen.c:417 417 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY)); while trying to write a testcase that shows that handle_char_store should handle a character copy from a known non-zero value. Well, while really trying to incrementally teach handle_char_store to handle arbitrary stores.
Seems to not ICE with 4.9 for me.
Fixed with adding a prototype char *stpcpy (char*, const char *);
Proper testcase (string init was missing): char *stpcpy (char*, const char *); char *foo (void) { char *p = __builtin_calloc (64, 1); char *q = __builtin_calloc (64, 1); __builtin_strcat (q, "abcde"); __builtin_strcat (p, "ab"); p[1] = 'a'; __builtin_strcat (p, q); return q; } this isn't optimized either, only when p[0] = 'a'; is there the last strcat will be optimized with known strlen of p. Hmm, a p[1] = '\0' isn't optimized either. Unfortunately strlen isn't very verbose in its -details dump.
(In reply to Richard Biener from comment #3) > Proper testcase (string init was missing): > > char *stpcpy (char*, const char *); > char *foo (void) > { > char *p = __builtin_calloc (64, 1); > char *q = __builtin_calloc (64, 1); > __builtin_strcat (q, "abcde"); > __builtin_strcat (p, "ab"); > p[1] = 'a'; > __builtin_strcat (p, q); > return q; > } > > this isn't optimized either, only when p[0] = 'a'; is there the last > strcat will be optimized with known strlen of p. Hmm, a p[1] = '\0' > isn't optimized either. > > Unfortunately strlen isn't very verbose in its -details dump. Ok, those are all because the store is MEM[ptr, 1] = ... while only a zero offset MEM is handled in handle_char_store. For non-constant offset this gets handled by handle_pointer_plus. It seems to me that all builtin handling will have a similar issue when faced with arguments of &MEM[ptr_1, <nonzero-offset>] (zero-offset should be folded to plain ptr_1 of course, so doesn't happen). Simple char *stpcpy (char*, const char *); char *foo (void) { char *p = __builtin_calloc (64, 1); char *q = __builtin_calloc (64, 1); __builtin_strcat (q, "abcde"); __builtin_strcat (p, "ab"); p = p + 1; __builtin_strcat (p, q); return q; } isn't optimized because we get _10 = p_3 + _9; __builtin_memcpy (_10, "ab", 3); p_12 = p_3 + 1; __builtin_strcat (p_12, q_5); and likely p_3 string-info is invalidated instead of made a copy of that of _10 (as _9 is zero). char *stpcpy (char*, const char *); char *foo (char *q) { char *p = __builtin_strdup ("abcde"); p = p + 1; __builtin_strcat (p, "blah"); return q; } is also not handled well as we don't seem to recognize strdup?
Also happens during PGO/LTO bootstrap: markus@x4 gcc % /var/tmp/gcc_build_dir/./stage1-gcc/xg++ -B/var/tmp/gcc_build_dir/./stage1-gcc/ -B/usr/x86_64-pc-linux-gnu/bin/ -nostdinc++ -B/var/tmp/gcc_build_dir/stage1-x86_64-pc-linux-gnu/libstdc++-v3/src/.libs -B/var/tmp/gcc_build_dir/stage1-x86_64-pc-linux-gnu/libstdc++-v3/libsupc++/.libs -I/var/tmp/gcc_build_dir/stage1-x86_64-pc-linux-gnu/libstdc++-v3/include/x86_64-pc-linux-gnu -I/var/tmp/gcc_build_dir/stage1-x86_64-pc-linux-gnu/libstdc++-v3/include -I/var/tmp/gcc/libstdc++-v3/libsupc++ -L/var/tmp/gcc_build_dir/stage1-x86_64-pc-linux-gnu/libstdc++-v3/src/.libs -L/var/tmp/gcc_build_dir/stage1-x86_64-pc-linux-gnu/libstdc++-v3/libsupc++/.libs -march=native -O3 -pipe -flto=jobserver -frandom-seed=1 -fprofile-use -DIN_GCC -fno-exceptions -fno-rtti -fasynchronous-unwind-tables -W -Wall -Wno-narrowing -Wwrite-strings -Wcast-qual -Wmissing-format-attribute -Woverloaded-virtual -pedantic -Wno-long-long -Wno-variadic-macros -Wno-overlength-strings -DHAVE_CONFIG_H -DGENERATOR_FILE -Wl,-O1,--hash-style=gnu,--as-needed,--gc-sections,--icf=safe,--icf-iterations=3 -o build/gengtype build/gengtype.o build/errors.o build/gengtype-lex.o build/gengtype-parse.o build/gengtype-state.o build/version.o .././libiberty/libiberty.a ../../gcc/gcc/gengtype.c: In function ‘output_mangled_typename’: ../../gcc/gcc/gengtype.c:2625:1: internal compiler error: in get_string_length, at tree-ssa-strlen.c:417 output_mangled_typename (outf_p of, const_type_p t) ^ Please submit a full bug report,
The ICE started with r211956, before that it was assumed that any non-NULL si->stmt is something to be optimized with stpcpy and friends, so has to be guarded when creating it so that such optimization isn't attempted if stpcpy isn't declared. So, for the ICE I'd like to fix it with: --- gcc/tree-ssa-strlen.c.jj 2014-11-19 18:47:59.000000000 +0100 +++ gcc/tree-ssa-strlen.c 2014-11-20 09:46:33.949017462 +0100 @@ -430,7 +430,6 @@ get_string_length (strinfo si) callee = gimple_call_fndecl (stmt); gcc_assert (callee && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL); lhs = gimple_call_lhs (stmt); - gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY)); /* unshare_strinfo is intentionally not called here. The (delayed) transformation of strcpy or strcat into stpcpy is done at the place of the former strcpy/strcat call and so can affect all the strinfos @@ -479,6 +478,7 @@ get_string_length (strinfo si) case BUILT_IN_STRCPY_CHK: case BUILT_IN_STRCPY_CHKP: case BUILT_IN_STRCPY_CHK_CHKP: + gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY)); if (gimple_call_num_args (stmt) == (with_bounds ? 4 : 2)) fn = builtin_decl_implicit (BUILT_IN_STPCPY); else now that BUILT_IN_MALLOC uses si->stmt non-NULL too and obviously isn't in any way related to stpcpy. I'll look at the missed optimizations.
Created attachment 34048 [details] gcc5-pr61773.patch Full (untested) patch. Let's split this PR into the ICE part and another one for the enhancement request, which isn't a regression.
Author: jakub Date: Fri Nov 21 09:27:19 2014 New Revision: 217910 URL: https://gcc.gnu.org/viewcvs?rev=217910&root=gcc&view=rev Log: PR tree-optimization/61773 * tree-ssa-strlen.c (get_string_length): Don't assert stpcpy has been prototyped if si->stmt is BUILT_IN_MALLOC. * gcc.dg/pr61773.c: New test. Added: trunk/gcc/testsuite/gcc.dg/pr61773.c Modified: trunk/gcc/ChangeLog trunk/gcc/testsuite/ChangeLog trunk/gcc/tree-ssa-strlen.c
Fixed.