Hi! If users use attributes like const or pure incorrectly on stringops builtins, the tree-ssa-strlen.c pass can ICE, because it expects it can e.g. replace a strcpy (which should not be const or pure) with memcpy (which also shouldn't be const/pure) etc. The patch just pretends the calls aren't builtins for the purpose of tree-ssa-strlen.c pass if they have unexpected const/pure-ness.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk/6.2? 2016-06-20 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/71588 * tree-ssa-strlen.c (valid_builtin_call): New function. (adjust_last_stmt, handle_builtin_memset, strlen_optimize_stmt): Use it. * gcc.dg/pr71558.c: New test. --- gcc/tree-ssa-strlen.c.jj 2016-06-08 14:51:25.000000000 +0200 +++ gcc/tree-ssa-strlen.c 2016-06-20 13:30:23.576556803 +0200 @@ -860,6 +860,66 @@ find_equal_ptrs (tree ptr, int idx) } } +/* Return true if STMT is a call to a builtin function with the right + arguments and attributes that should be considered for optimization + by this pass. */ + +static bool +valid_builtin_call (gimple *stmt) +{ + if (!gimple_call_builtin_p (stmt, BUILT_IN_NORMAL)) + return false; + + tree callee = gimple_call_fndecl (stmt); + switch (DECL_FUNCTION_CODE (callee)) + { + case BUILT_IN_MEMCMP: + case BUILT_IN_MEMCMP_EQ: + case BUILT_IN_STRCHR: + case BUILT_IN_STRCHR_CHKP: + case BUILT_IN_STRLEN: + case BUILT_IN_STRLEN_CHKP: + /* The above functions should be pure. Punt if they aren't. */ + if (gimple_vdef (stmt) || gimple_vuse (stmt) == NULL_TREE) + return false; + break; + + case BUILT_IN_CALLOC: + case BUILT_IN_MALLOC: + case BUILT_IN_MEMCPY: + case BUILT_IN_MEMCPY_CHK: + case BUILT_IN_MEMCPY_CHKP: + case BUILT_IN_MEMCPY_CHK_CHKP: + case BUILT_IN_MEMPCPY: + case BUILT_IN_MEMPCPY_CHK: + case BUILT_IN_MEMPCPY_CHKP: + case BUILT_IN_MEMPCPY_CHK_CHKP: + case BUILT_IN_MEMSET: + case BUILT_IN_STPCPY: + case BUILT_IN_STPCPY_CHK: + case BUILT_IN_STPCPY_CHKP: + case BUILT_IN_STPCPY_CHK_CHKP: + case BUILT_IN_STRCAT: + case BUILT_IN_STRCAT_CHK: + case BUILT_IN_STRCAT_CHKP: + case BUILT_IN_STRCAT_CHK_CHKP: + case BUILT_IN_STRCPY: + case BUILT_IN_STRCPY_CHK: + case BUILT_IN_STRCPY_CHKP: + case BUILT_IN_STRCPY_CHK_CHKP: + /* The above functions should be neither const nor pure. Punt if they + aren't. */ + if (gimple_vdef (stmt) == NULL_TREE || gimple_vuse (stmt) == NULL_TREE) + return false; + break; + + default: + break; + } + + return true; +} + /* If the last .MEM setter statement before STMT is memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to @@ -935,7 +995,7 @@ adjust_last_stmt (strinfo *si, gimple *s return; } - if (!gimple_call_builtin_p (last.stmt, BUILT_IN_NORMAL)) + if (!valid_builtin_call (last.stmt)) return; callee = gimple_call_fndecl (last.stmt); @@ -1811,7 +1871,7 @@ handle_builtin_memset (gimple_stmt_itera if (!stmt1 || !is_gimple_call (stmt1)) return true; tree callee1 = gimple_call_fndecl (stmt1); - if (!gimple_call_builtin_p (stmt1, BUILT_IN_NORMAL)) + if (!valid_builtin_call (stmt1)) return true; enum built_in_function code1 = DECL_FUNCTION_CODE (callee1); tree size = gimple_call_arg (stmt2, 2); @@ -2140,7 +2200,7 @@ strlen_optimize_stmt (gimple_stmt_iterat if (is_gimple_call (stmt)) { tree callee = gimple_call_fndecl (stmt); - if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL)) + if (valid_builtin_call (stmt)) switch (DECL_FUNCTION_CODE (callee)) { case BUILT_IN_STRLEN: --- gcc/testsuite/gcc.dg/pr71558.c.jj 2016-06-20 13:52:15.491591442 +0200 +++ gcc/testsuite/gcc.dg/pr71558.c 2016-06-20 13:51:59.000000000 +0200 @@ -0,0 +1,17 @@ +/* PR tree-optimization/71588 */ + +/* strcpy must not be pure, but make sure we don't ICE even when + it is declared incorrectly. */ +char *strcpy (char *, const char *) __attribute__ ((__pure__)); +__SIZE_TYPE__ strlen (const char *); +void *malloc (__SIZE_TYPE__); + +char a[20]; + +char * +foo (void) +{ + __SIZE_TYPE__ b = strlen (a); + char *c = malloc (b); + return strcpy (c, a); +} Jakub