On Thu, 28 Nov 2024, Jakub Jelinek wrote: > 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 > ?
I think this doesn't work since a wrong pure/const attribute will override this. We'd have to check the flags against the builtins.def attributes only. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk as > is or go with the above tests instead? The patch is OK. Richard. > 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 > > -- Richard Biener <rguent...@suse.de> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg, Germany; GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)