Hi! When one puts incorrect const or pure attributes on declarations of various C APIs which have corresponding builtins (vs. what they actually do), we can get tons of ICEs in gimple-fold.cc.
The following patch fixes it by giving up gimple_fold_builtin_* folding if the functions don't have gimple_vdef (or for pure functions like bcmp/strchr/strstr gimple_vuse) when in SSA form (during gimplification they will surely have both of those NULL even when declared correctly, yet it is highly desirable to fold them). Or shall I replace !gimple_vdef (stmt) && gimple_in_ssa_p (cfun) tests with (gimple_call_flags (stmt) & (ECF_CONST | ECF_PURE | ECF_NOVOPS)) != 0 and !gimple_vuse (stmt) && gimple_in_ssa_p (cfun) with (gimple_call_flags (stmt) & (ECF_CONST | ECF_NOVOPS)) != 0 ? Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk as is or go with the above tests instead? 2024-11-28 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/117358 * gimple-fold.cc (gimple_fold_builtin_memory_op): Punt if stmt has no vdef in ssa form. (gimple_fold_builtin_bcmp): Punt if stmt has no vuse in ssa form. (gimple_fold_builtin_bcopy): Punt if stmt has no vdef in ssa form. (gimple_fold_builtin_bzero): Likewise. (gimple_fold_builtin_memset): Likewise. Use return false instead of return NULL_TREE. (gimple_fold_builtin_strcpy): Punt if stmt has no vdef in ssa form. (gimple_fold_builtin_strncpy): Likewise. (gimple_fold_builtin_strchr): Punt if stmt has no vuse in ssa form. (gimple_fold_builtin_strstr): Likewise. (gimple_fold_builtin_strcat): Punt if stmt has no vdef in ssa form. (gimple_fold_builtin_strcat_chk): Likewise. (gimple_fold_builtin_strncat): Likewise. (gimple_fold_builtin_strncat_chk): Likewise. (gimple_fold_builtin_string_compare): Likewise. (gimple_fold_builtin_fputs): Likewise. (gimple_fold_builtin_memory_chk): Likewise. (gimple_fold_builtin_stxcpy_chk): Likewise. (gimple_fold_builtin_stxncpy_chk): Likewise. (gimple_fold_builtin_stpcpy): Likewise. (gimple_fold_builtin_snprintf_chk): Likewise. (gimple_fold_builtin_sprintf_chk): Likewise. (gimple_fold_builtin_sprintf): Likewise. (gimple_fold_builtin_snprintf): Likewise. (gimple_fold_builtin_fprintf): Likewise. (gimple_fold_builtin_printf): Likewise. (gimple_fold_builtin_realloc): Likewise. * gcc.c-torture/compile/pr117358.c: New test. --- gcc/gimple-fold.cc.jj 2024-11-23 13:00:29.566010380 +0100 +++ gcc/gimple-fold.cc 2024-11-28 09:09:31.184314115 +0100 @@ -1061,6 +1061,8 @@ gimple_fold_builtin_memory_op (gimple_st } goto done; } + else if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun)) + return false; else { /* We cannot (easily) change the type of the copy if it is a storage @@ -1511,6 +1513,8 @@ gimple_fold_builtin_bcmp (gimple_stmt_it /* Transform bcmp (a, b, len) into memcmp (a, b, len). */ gimple *stmt = gsi_stmt (*gsi); + if (!gimple_vuse (stmt) && gimple_in_ssa_p (cfun)) + return false; tree a = gimple_call_arg (stmt, 0); tree b = gimple_call_arg (stmt, 1); tree len = gimple_call_arg (stmt, 2); @@ -1537,6 +1541,8 @@ gimple_fold_builtin_bcopy (gimple_stmt_i len) into memmove (dest, src, len). */ gimple *stmt = gsi_stmt (*gsi); + if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun)) + return false; tree src = gimple_call_arg (stmt, 0); tree dest = gimple_call_arg (stmt, 1); tree len = gimple_call_arg (stmt, 2); @@ -1562,6 +1568,8 @@ gimple_fold_builtin_bzero (gimple_stmt_i /* Transform bzero (dest, len) into memset (dest, 0, len). */ gimple *stmt = gsi_stmt (*gsi); + if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun)) + return false; tree dest = gimple_call_arg (stmt, 0); tree len = gimple_call_arg (stmt, 1); @@ -1591,6 +1599,9 @@ gimple_fold_builtin_memset (gimple_stmt_ return true; } + if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun)) + return false; + if (! tree_fits_uhwi_p (len)) return false; @@ -1613,20 +1624,20 @@ gimple_fold_builtin_memset (gimple_stmt_ if ((!INTEGRAL_TYPE_P (etype) && !POINTER_TYPE_P (etype)) || TREE_CODE (etype) == BITINT_TYPE) - return NULL_TREE; + return false; if (! var_decl_component_p (var)) - return NULL_TREE; + return false; length = tree_to_uhwi (len); if (GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (etype)) != length || (GET_MODE_PRECISION (SCALAR_INT_TYPE_MODE (etype)) != GET_MODE_BITSIZE (SCALAR_INT_TYPE_MODE (etype))) || get_pointer_alignment (dest) / BITS_PER_UNIT < length) - return NULL_TREE; + return false; if (length > HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT) - return NULL_TREE; + return false; if (!type_has_mode_precision_p (etype)) etype = lang_hooks.types.type_for_mode (SCALAR_INT_TYPE_MODE (etype), @@ -2240,7 +2251,7 @@ gimple_fold_builtin_strcpy (gimple_stmt_ return false; } - if (!len) + if (!len || (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun))) return false; len = fold_convert_loc (loc, size_type_node, len); @@ -2315,7 +2326,7 @@ gimple_fold_builtin_strncpy (gimple_stmt /* OK transform into builtin memcpy. */ tree fn = builtin_decl_implicit (BUILT_IN_MEMCPY); - if (!fn) + if (!fn || (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun))) return false; len = fold_convert_loc (loc, size_type_node, len); @@ -2369,7 +2380,7 @@ gimple_fold_builtin_strchr (gimple_stmt_ return true; } - if (!integer_zerop (c)) + if (!integer_zerop (c) || (!gimple_vuse (stmt) && gimple_in_ssa_p (cfun))) return false; /* Transform strrchr (s, 0) to strchr (s, 0) when optimizing for size. */ @@ -2467,6 +2478,9 @@ gimple_fold_builtin_strstr (gimple_stmt_ return true; } + if (!gimple_vuse (stmt) && gimple_in_ssa_p (cfun)) + return false; + /* Transform strstr (x, "c") into strchr (x, 'c'). */ if (q[1] == '\0') { @@ -2519,6 +2533,9 @@ gimple_fold_builtin_strcat (gimple_stmt_ if (!optimize_bb_for_speed_p (gimple_bb (stmt))) return false; + if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun)) + return false; + /* See if we can store by pieces into (dst + strlen(dst)). */ tree newdst; tree strlen_fn = builtin_decl_implicit (BUILT_IN_STRLEN); @@ -2588,7 +2605,6 @@ gimple_fold_builtin_strcat_chk (gimple_s tree fn; const char *p; - p = c_getstr (src); /* If the SRC parameter is "", return DEST. */ if (p && *p == '\0') @@ -2600,6 +2616,9 @@ gimple_fold_builtin_strcat_chk (gimple_s if (! tree_fits_uhwi_p (size) || ! integer_all_onesp (size)) return false; + if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun)) + return false; + /* If __builtin_strcat_chk is used, assume strcat is available. */ fn = builtin_decl_explicit (BUILT_IN_STRCAT); if (!fn) @@ -2690,7 +2709,7 @@ gimple_fold_builtin_strncat (gimple_stmt /* If the replacement _DECL isn't initialized, don't do the transformation. */ - if (!fn) + if (!fn || (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun))) return false; /* Otherwise, emit a call to strcat. */ @@ -2722,6 +2741,9 @@ gimple_fold_builtin_strncat_chk (gimple_ return true; } + if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun)) + return false; + if (! integer_all_onesp (size)) { tree src_len = c_strlen (src, 1); @@ -2812,6 +2834,9 @@ gimple_fold_builtin_string_compare (gimp return true; } + if (!gimple_vuse (stmt) && gimple_in_ssa_p (cfun)) + return false; + /* Initially set to the number of characters, including the terminating nul if each array has one. LENx == strnlen (Sx, LENx) implies that the array Sx is not terminated by a nul. @@ -3104,7 +3129,7 @@ gimple_fold_builtin_fputs (gimple_stmt_i const char *p = c_getstr (arg0); if (p != NULL) { - if (!fn_fputc) + if (!fn_fputc || (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun))) return false; gimple *repl @@ -3123,7 +3148,7 @@ gimple_fold_builtin_fputs (gimple_stmt_i return false; /* New argument list transforming fputs(string, stream) to fwrite(string, 1, len, stream). */ - if (!fn_fwrite) + if (!fn_fwrite || (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun))) return false; gimple *repl @@ -3174,6 +3199,9 @@ gimple_fold_builtin_memory_chk (gimple_s } } + if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun)) + return false; + tree maxlen = get_maxval_strlen (len, SRK_INT_VALUE); if (! integer_all_onesp (size) && !known_lower (stmt, len, size) @@ -3262,6 +3290,9 @@ gimple_fold_builtin_stxcpy_chk (gimple_s return true; } + if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun)) + return false; + tree maxlen = get_maxval_strlen (src, SRK_STRLENMAX); if (! integer_all_onesp (size)) { @@ -3354,7 +3385,7 @@ gimple_fold_builtin_stxncpy_chk (gimple_ /* If __builtin_st{r,p}ncpy_chk is used, assume st{r,p}ncpy is available. */ fn = builtin_decl_explicit (fcode == BUILT_IN_STPNCPY_CHK && !ignore ? BUILT_IN_STPNCPY : BUILT_IN_STRNCPY); - if (!fn) + if (!fn || (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun))) return false; gcall *repl = gimple_build_call (fn, 3, dest, src, len); @@ -3374,6 +3405,9 @@ gimple_fold_builtin_stpcpy (gimple_stmt_ tree src = gimple_call_arg (stmt, 1); tree fn, lenp1; + if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun)) + return false; + /* If the result is unused, replace stpcpy with strcpy. */ if (gimple_call_lhs (stmt) == NULL_TREE) { @@ -3491,7 +3525,7 @@ gimple_fold_builtin_snprintf_chk (gimple available. */ fn = builtin_decl_explicit (fcode == BUILT_IN_VSNPRINTF_CHK ? BUILT_IN_VSNPRINTF : BUILT_IN_SNPRINTF); - if (!fn) + if (!fn || (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun))) return false; /* Replace the called function and the first 5 argument by 3 retaining @@ -3578,7 +3612,7 @@ gimple_fold_builtin_sprintf_chk (gimple_ /* If __builtin_{,v}sprintf_chk is used, assume {,v}sprintf is available. */ fn = builtin_decl_explicit (fcode == BUILT_IN_VSPRINTF_CHK ? BUILT_IN_VSPRINTF : BUILT_IN_SPRINTF); - if (!fn) + if (!fn || (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun))) return false; /* Replace the called function and the first 4 argument by 2 retaining @@ -3627,7 +3661,7 @@ gimple_fold_builtin_sprintf (gimple_stmt return false; tree fn = builtin_decl_implicit (BUILT_IN_STRCPY); - if (!fn) + if (!fn || (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun))) return false; /* If the format doesn't contain % args or %%, use strcpy. */ @@ -3740,7 +3774,8 @@ gimple_fold_builtin_snprintf (gimple_stm tree orig = NULL_TREE; const char *fmt_str = NULL; - if (gimple_call_num_args (stmt) > 4) + if (gimple_call_num_args (stmt) > 4 + || (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun))) return false; if (gimple_call_num_args (stmt) == 4) @@ -3898,6 +3933,9 @@ gimple_fold_builtin_fprintf (gimple_stmt if (!init_target_chars ()) return false; + if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun)) + return false; + /* If the format doesn't contain % args or %%, use strcpy. */ if (strchr (fmt_str, target_percent) == NULL) { @@ -3977,6 +4015,9 @@ gimple_fold_builtin_printf (gimple_stmt_ if (gimple_call_lhs (stmt) != NULL_TREE) return false; + if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun)) + return false; + /* Check whether the format is a literal string constant. */ fmt_str = c_getstr (fmt); if (fmt_str == NULL) @@ -4235,6 +4276,9 @@ gimple_fold_builtin_realloc (gimple_stmt tree arg = gimple_call_arg (stmt, 0); tree size = gimple_call_arg (stmt, 1); + if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun)) + return false; + if (operand_equal_p (arg, null_pointer_node, 0)) { tree fn_malloc = builtin_decl_implicit (BUILT_IN_MALLOC); --- gcc/testsuite/gcc.c-torture/compile/pr117358.c.jj 2024-11-27 19:05:19.769389180 +0100 +++ gcc/testsuite/gcc.c-torture/compile/pr117358.c 2024-11-27 19:05:02.643627376 +0100 @@ -0,0 +1,17 @@ +/* PR tree-optimization/117358 */ + +char a; +/* This attribute is bogus, snprintf isn't const. Just verify we don't ICE on it. */ +int __attribute__((const)) snprintf (char *, __SIZE_TYPE__, const char *, ...); + +long +foo (long d) +{ + return snprintf (&a, d, ""); +} + +int +bar (void) +{ + return foo (1); +} Jakub