Signed-off-by: Keith Packard <kei...@keithp.com>
---
gcc/builtins.c | 12 +++---
gcc/c-family/c-attribs.c | 68 ++++++++++++++++++++++++++++++++++
gcc/common.opt | 4 ++
gcc/gimple-fold.c | 72 ++++++++++++++++++------------------
gcc/gimple-match-head.c | 2 +-
gcc/tree-loop-distribution.c | 7 ++++
gcc/tree-ssa-alias.c | 3 +-
gcc/tree-ssa-strlen.c | 48 ++++++++++++++----------
gcc/tree-ssa-structalias.c | 3 +-
gcc/tree.h | 39 +++++++++++++++++++
10 files changed, 194 insertions(+), 64 deletions(-)
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 7d0f61fc98b..d665ee716e8 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -2061,7 +2061,7 @@ mathfn_built_in_1 (tree type, combined_fn fn, bool
implicit_p)
if (fcode2 == END_BUILTINS)
return NULL_TREE;
- if (implicit_p && !builtin_decl_implicit_p (fcode2))
+ if (implicit_p && !builtin_decl_implicit_opt_p (fcode2))
return NULL_TREE;
return builtin_decl_explicit (fcode2);
@@ -3481,9 +3481,9 @@ expand_builtin_stpcpy_1 (tree exp, rtx target,
machine_mode mode)
src = CALL_EXPR_ARG (exp, 1);
/* If return value is ignored, transform stpcpy into strcpy. */
- if (target == const0_rtx && builtin_decl_implicit (BUILT_IN_STRCPY))
+ if (target == const0_rtx && builtin_decl_implicit_opt (BUILT_IN_STRCPY))
{
- tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
+ tree fn = builtin_decl_implicit_opt (BUILT_IN_STRCPY);
tree result = build_call_nofold_loc (loc, fn, 2, dst, src);
return expand_expr (result, target, mode, EXPAND_NORMAL);
}
@@ -8258,7 +8258,7 @@ fold_builtin_sincos (location_t loc,
if (!call)
{
if (!targetm.libc_has_function (function_c99_math_complex, type)
- || !builtin_decl_implicit_p (fn))
+ || !builtin_decl_implicit_opt_p (fn))
return NULL_TREE;
fndecl = builtin_decl_explicit (fn);
call = build_call_expr_loc (loc, fndecl, 1, arg0);
@@ -9717,7 +9717,7 @@ fold_builtin_strpbrk (location_t loc, tree, tree s1, tree
s2, tree type)
if (p2[1] != '\0')
return NULL_TREE; /* Really call strpbrk. */
- fn = builtin_decl_implicit (BUILT_IN_STRCHR);
+ fn = builtin_decl_implicit_opt (BUILT_IN_STRCHR);
if (!fn)
return NULL_TREE;
@@ -9810,7 +9810,7 @@ fold_builtin_strcspn (location_t loc, tree expr, tree s1, tree s2)
const char *p2 = c_getstr (s2);
if (p2 && *p2 == '\0')
{
- tree fn = builtin_decl_implicit (BUILT_IN_STRLEN);
+ tree fn = builtin_decl_implicit_opt (BUILT_IN_STRLEN);
/* If the replacement _DECL isn't initialized, don't do the
transformation. */
diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index 007b928c54b..d5cfa9bc70d 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -130,6 +130,7 @@ static tree handle_vector_size_attribute (tree *, tree,
tree, int,
bool *) ATTRIBUTE_NONNULL(3);
static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *);
static tree handle_nonstring_attribute (tree *, tree, tree, int, bool *);
+static tree handle_no_builtin_attribute (tree *, tree, tree, int, bool *);
static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *);
static tree handle_cleanup_attribute (tree *, tree, tree, int, bool *);
static tree handle_warn_unused_result_attribute (tree *, tree, tree, int,
@@ -536,6 +537,8 @@ const struct attribute_spec c_common_attribute_table[] =
handle_special_var_sec_attribute,
attr_section_exclusions },
{ "access", 1, 3, false, true, true, false,
handle_access_attribute, NULL },
+ { "no_builtin", 0, 0, true, false, false, false,
+ handle_no_builtin_attribute, NULL },
/* Attributes used by Objective-C. */
{ "NSObject", 0, 0, true, false, false, false,
handle_nsobject_attribute, NULL },
@@ -5512,6 +5515,71 @@ handle_optimize_attribute (tree *node, tree name, tree
args,
return NULL_TREE;
}
+/* Handle a "no_builtin" attribute */
+
+static tree
+handle_no_builtin_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ /* Ensure we have a function type. */
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+ else
+ {
+ struct cl_optimization cur_opts;
+ tree old_opts = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node);
+
+ /* Save current options. */
+ cl_optimization_save (&cur_opts, &global_options, &global_options_set);
+ tree prev_target_node = build_target_option_node (&global_options,
+ &global_options_set);
+
+ /* If we previously had some optimization options, use them as the
+ default. */
+ gcc_options *saved_global_options = NULL;
+
+ /* When #pragma GCC optimize pragma is used, it modifies global_options
+ without calling targetm.override_options_after_change. That can leave
+ target flags inconsistent for comparison. */
+ if (flag_checking && optimization_current_node ==
optimization_default_node)
+ {
+ saved_global_options = XNEW (gcc_options);
+ *saved_global_options = global_options;
+ }
+
+ if (old_opts)
+ cl_optimization_restore (&global_options, &global_options_set,
+ TREE_OPTIMIZATION (old_opts));
+
+ /* Set no_builtin option */
+ flag_no_opt_builtin = TRUE;
+
+ DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node)
+ = build_optimization_node (&global_options, &global_options_set);
+ tree target_node = build_target_option_node (&global_options,
+ &global_options_set);
+ if (prev_target_node != target_node)
+ DECL_FUNCTION_SPECIFIC_TARGET (*node) = target_node;
+
+ /* Restore current options. */
+ cl_optimization_restore (&global_options, &global_options_set,
+ &cur_opts);
+ cl_target_option_restore (&global_options, &global_options_set,
+ TREE_TARGET_OPTION (prev_target_node));
+
+ if (saved_global_options != NULL)
+ {
+ cl_optimization_compare (saved_global_options, &global_options);
+ free (saved_global_options);
+ }
+ }
+
+ return NULL_TREE;
+}
+
/* Handle a "no_split_stack" attribute. */
static tree
diff --git a/gcc/common.opt b/gcc/common.opt
index eeba1a727f2..a5ec18e82f5 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2154,6 +2154,10 @@ fsave-optimization-record
Common Var(flag_save_optimization_record) Optimization
Write a SRCFILE.opt-record.json file detailing what optimizations were
performed.
+foptimize-builtin
+Common Var(flag_no_opt_builtin, 0) Optimization
+Enable optimizations based on known semantics for builtin functions.
+
foptimize-register-move
Common Ignore
Does nothing. Preserved for backward compatibility.
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 6e25a7c05db..b054f4248ce 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -1071,7 +1071,7 @@ gimple_fold_builtin_memory_op (gimple_stmt_iterator *gsi,
&& (MIN (src_align, dest_align) / BITS_PER_UNIT
>= tree_to_uhwi (len))))
{
- tree fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
+ tree fn = builtin_decl_implicit_opt (BUILT_IN_MEMCPY);
if (!fn)
return false;
gimple_call_set_fndecl (stmt, fn);
@@ -1125,7 +1125,7 @@ gimple_fold_builtin_memory_op (gimple_stmt_iterator *gsi,
else
return false;
- fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
+ fn = builtin_decl_implicit_opt (BUILT_IN_MEMCPY);
if (!fn)
return false;
gimple_call_set_fndecl (stmt, fn);
@@ -1148,7 +1148,7 @@ gimple_fold_builtin_memory_op (gimple_stmt_iterator *gsi,
if (!refs_may_alias_p_1 (&destr, &srcr, false))
{
tree fn;
- fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
+ fn = builtin_decl_implicit_opt (BUILT_IN_MEMCPY);
if (!fn)
return false;
gimple_call_set_fndecl (stmt, fn);
@@ -1360,7 +1360,7 @@ done:
static bool
gimple_fold_builtin_bcmp (gimple_stmt_iterator *gsi)
{
- tree fn = builtin_decl_implicit (BUILT_IN_MEMCMP);
+ tree fn = builtin_decl_implicit_opt (BUILT_IN_MEMCMP);
if (!fn)
return false;
@@ -1384,7 +1384,7 @@ gimple_fold_builtin_bcmp (gimple_stmt_iterator *gsi)
static bool
gimple_fold_builtin_bcopy (gimple_stmt_iterator *gsi)
{
- tree fn = builtin_decl_implicit (BUILT_IN_MEMMOVE);
+ tree fn = builtin_decl_implicit_opt (BUILT_IN_MEMMOVE);
if (!fn)
return false;
@@ -1411,7 +1411,7 @@ gimple_fold_builtin_bcopy (gimple_stmt_iterator *gsi)
static bool
gimple_fold_builtin_bzero (gimple_stmt_iterator *gsi)
{
- tree fn = builtin_decl_implicit (BUILT_IN_MEMSET);
+ tree fn = builtin_decl_implicit_opt (BUILT_IN_MEMSET);
if (!fn)
return false;
@@ -2067,7 +2067,7 @@ gimple_fold_builtin_strcpy (gimple_stmt_iterator *gsi,
if (optimize_function_for_size_p (cfun))
return false;
- fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
+ fn = builtin_decl_implicit_opt (BUILT_IN_MEMCPY);
if (!fn)
return false;
@@ -2158,7 +2158,7 @@ gimple_fold_builtin_strncpy (gimple_stmt_iterator *gsi,
maybe_diag_stxncpy_trunc (*gsi, src, len);
/* OK transform into builtin memcpy. */
- tree fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
+ tree fn = builtin_decl_implicit_opt (BUILT_IN_MEMCPY);
if (!fn)
return false;
@@ -2219,7 +2219,7 @@ gimple_fold_builtin_strchr (gimple_stmt_iterator *gsi, bool is_strrchr)
/* Transform strrchr (s, 0) to strchr (s, 0) when optimizing for size. */
if (is_strrchr && optimize_function_for_size_p (cfun))
{
- tree strchr_fn = builtin_decl_implicit (BUILT_IN_STRCHR);
+ tree strchr_fn = builtin_decl_implicit_opt (BUILT_IN_STRCHR);
if (strchr_fn)
{
@@ -2232,7 +2232,7 @@ gimple_fold_builtin_strchr (gimple_stmt_iterator *gsi,
bool is_strrchr)
}
tree len;
- tree strlen_fn = builtin_decl_implicit (BUILT_IN_STRLEN);
+ tree strlen_fn = builtin_decl_implicit_opt (BUILT_IN_STRLEN);
if (!strlen_fn)
return false;
@@ -2314,7 +2314,7 @@ gimple_fold_builtin_strstr (gimple_stmt_iterator *gsi)
/* Transform strstr (x, "c") into strchr (x, 'c'). */
if (q[1] == '\0')
{
- tree strchr_fn = builtin_decl_implicit (BUILT_IN_STRCHR);
+ tree strchr_fn = builtin_decl_implicit_opt (BUILT_IN_STRCHR);
if (strchr_fn)
{
tree c = build_int_cst (integer_type_node, q[0]);
@@ -2365,8 +2365,8 @@ gimple_fold_builtin_strcat (gimple_stmt_iterator *gsi,
tree dst, tree src)
/* See if we can store by pieces into (dst + strlen(dst)). */
tree newdst;
- tree strlen_fn = builtin_decl_implicit (BUILT_IN_STRLEN);
- tree memcpy_fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
+ tree strlen_fn = builtin_decl_implicit_opt (BUILT_IN_STRLEN);
+ tree memcpy_fn = builtin_decl_implicit_opt (BUILT_IN_MEMCPY);
if (!strlen_fn || !memcpy_fn)
return false;
@@ -2445,7 +2445,7 @@ gimple_fold_builtin_strcat_chk (gimple_stmt_iterator *gsi)
return false;
/* If __builtin_strcat_chk is used, assume strcat is available. */
- fn = builtin_decl_explicit (BUILT_IN_STRCAT);
+ fn = builtin_decl_explicit_opt (BUILT_IN_STRCAT);
if (!fn)
return false;
@@ -2530,7 +2530,7 @@ gimple_fold_builtin_strncat (gimple_stmt_iterator *gsi)
suppress_warning (stmt, OPT_Wstringop_overflow_);
}
- tree fn = builtin_decl_implicit (BUILT_IN_STRCAT);
+ tree fn = builtin_decl_implicit_opt (BUILT_IN_STRCAT);
/* If the replacement _DECL isn't initialized, don't do the
transformation. */
@@ -2578,7 +2578,7 @@ gimple_fold_builtin_strncat_chk (gimple_stmt_iterator
*gsi)
&& ! tree_int_cst_lt (len, src_len))
{
/* If LEN >= strlen (SRC), optimize into __strcat_chk. */
- fn = builtin_decl_explicit (BUILT_IN_STRCAT_CHK);
+ fn = builtin_decl_explicit_opt (BUILT_IN_STRCAT_CHK);
if (!fn)
return false;
@@ -2590,7 +2590,7 @@ gimple_fold_builtin_strncat_chk (gimple_stmt_iterator *gsi)
}
/* If __builtin_strncat_chk is used, assume strncat is available. */
- fn = builtin_decl_explicit (BUILT_IN_STRNCAT);
+ fn = builtin_decl_explicit_opt (BUILT_IN_STRNCAT);
if (!fn)
return false;
@@ -2829,7 +2829,7 @@ gimple_fold_builtin_string_compare (gimple_stmt_iterator *gsi)
&& ((p2 && len2 < bound && len2 == nulpos2)
|| (p1 && len1 < bound && len1 == nulpos1)))
{
- tree fn = builtin_decl_implicit (BUILT_IN_STRCMP);
+ tree fn = builtin_decl_implicit_opt (BUILT_IN_STRCMP);
if (!fn)
return false;
gimple *repl = gimple_build_call (fn, 2, str1, str2);
@@ -2927,11 +2927,11 @@ gimple_fold_builtin_fputs (gimple_stmt_iterator *gsi,
/* If we're using an unlocked function, assume the other unlocked
functions exist explicitly. */
tree const fn_fputc = (unlocked
- ? builtin_decl_explicit (BUILT_IN_FPUTC_UNLOCKED)
- : builtin_decl_implicit (BUILT_IN_FPUTC));
+ ? builtin_decl_explicit_opt (BUILT_IN_FPUTC_UNLOCKED)
+ : builtin_decl_implicit_opt (BUILT_IN_FPUTC));
tree const fn_fwrite = (unlocked
- ? builtin_decl_explicit (BUILT_IN_FWRITE_UNLOCKED)
- : builtin_decl_implicit (BUILT_IN_FWRITE));
+ ? builtin_decl_explicit_opt (BUILT_IN_FWRITE_UNLOCKED)
+ : builtin_decl_implicit_opt (BUILT_IN_FWRITE));
/* If the return value is used, don't do the transformation. */
if (gimple_call_lhs (stmt))
@@ -3041,7 +3041,7 @@ gimple_fold_builtin_memory_chk (gimple_stmt_iterator *gsi,
{
/* (void) __mempcpy_chk () can be optimized into
(void) __memcpy_chk (). */
- fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
+ fn = builtin_decl_explicit_opt (BUILT_IN_MEMCPY_CHK);
if (!fn)
return false;
@@ -3269,7 +3269,7 @@ gimple_fold_builtin_stpcpy (gimple_stmt_iterator *gsi)
/* If the result is unused, replace stpcpy with strcpy. */
if (gimple_call_lhs (stmt) == NULL_TREE)
{
- tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
+ tree fn = builtin_decl_implicit_opt (BUILT_IN_STRCPY);
if (!fn)
return false;
gimple_call_set_fndecl (stmt, fn);
@@ -3309,7 +3309,7 @@ gimple_fold_builtin_stpcpy (gimple_stmt_iterator *gsi)
return false;
/* If the source has a known length replace stpcpy with memcpy. */
- fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
+ fn = builtin_decl_implicit_opt (BUILT_IN_MEMCPY);
if (!fn)
return false;
@@ -3544,7 +3544,7 @@ gimple_fold_builtin_sprintf (gimple_stmt_iterator *gsi)
if (!init_target_chars ())
return false;
- tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
+ tree fn = builtin_decl_implicit_opt (BUILT_IN_STRCPY);
if (!fn)
return false;
@@ -3679,7 +3679,7 @@ gimple_fold_builtin_snprintf (gimple_stmt_iterator *gsi)
/* If the format doesn't contain % args or %%, use strcpy. */
if (strchr (fmt_str, target_percent) == NULL)
{
- tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
+ tree fn = builtin_decl_implicit_opt (BUILT_IN_STRCPY);
if (!fn)
return false;
@@ -3726,7 +3726,7 @@ gimple_fold_builtin_snprintf (gimple_stmt_iterator *gsi)
/* If the format is "%s", use strcpy if the result isn't used. */
else if (fmt_str && strcmp (fmt_str, target_percent_s) == 0)
{
- tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
+ tree fn = builtin_decl_implicit_opt (BUILT_IN_STRCPY);
if (!fn)
return false;
@@ -3809,13 +3809,13 @@ gimple_fold_builtin_fprintf (gimple_stmt_iterator *gsi,
{
/* If we're using an unlocked function, assume the other
unlocked functions exist explicitly. */
- fn_fputc = builtin_decl_explicit (BUILT_IN_FPUTC_UNLOCKED);
- fn_fputs = builtin_decl_explicit (BUILT_IN_FPUTS_UNLOCKED);
+ fn_fputc = builtin_decl_explicit_opt (BUILT_IN_FPUTC_UNLOCKED);
+ fn_fputs = builtin_decl_explicit_opt (BUILT_IN_FPUTS_UNLOCKED);
}
else
{
- fn_fputc = builtin_decl_implicit (BUILT_IN_FPUTC);
- fn_fputs = builtin_decl_implicit (BUILT_IN_FPUTS);
+ fn_fputc = builtin_decl_implicit_opt (BUILT_IN_FPUTC);
+ fn_fputs = builtin_decl_implicit_opt (BUILT_IN_FPUTS);
}
if (!init_target_chars ())
@@ -3909,13 +3909,13 @@ gimple_fold_builtin_printf (gimple_stmt_iterator *gsi,
tree fmt,
{
/* If we're using an unlocked function, assume the other
unlocked functions exist explicitly. */
- fn_putchar = builtin_decl_explicit (BUILT_IN_PUTCHAR_UNLOCKED);
- fn_puts = builtin_decl_explicit (BUILT_IN_PUTS_UNLOCKED);
+ fn_putchar = builtin_decl_explicit_opt (BUILT_IN_PUTCHAR_UNLOCKED);
+ fn_puts = builtin_decl_explicit_opt (BUILT_IN_PUTS_UNLOCKED);
}
else
{
- fn_putchar = builtin_decl_implicit (BUILT_IN_PUTCHAR);
- fn_puts = builtin_decl_implicit (BUILT_IN_PUTS);
+ fn_putchar = builtin_decl_implicit_opt (BUILT_IN_PUTCHAR);
+ fn_puts = builtin_decl_implicit_opt (BUILT_IN_PUTS);
}
if (!init_target_chars ())
diff --git a/gcc/gimple-match-head.c b/gcc/gimple-match-head.c
index 9d88b2f8551..82bdad1380e 100644
--- a/gcc/gimple-match-head.c
+++ b/gcc/gimple-match-head.c
@@ -630,7 +630,7 @@ maybe_push_res_to_seq (gimple_match_op *res_op, gimple_seq
*seq, tree res)
else
{
/* Find the function we want to call. */
- tree decl = builtin_decl_implicit (as_builtin_fn (fn));
+ tree decl = builtin_decl_implicit_opt (as_builtin_fn (fn));
if (!decl)
return NULL;
diff --git a/gcc/tree-loop-distribution.c b/gcc/tree-loop-distribution.c
index 583c01a42d8..469c22d63cb 100644
--- a/gcc/tree-loop-distribution.c
+++ b/gcc/tree-loop-distribution.c
@@ -1716,6 +1716,9 @@ classify_builtin_st (loop_p loop, partition *partition,
data_reference_p dr)
gimple *stmt = DR_STMT (dr);
tree base, size, rhs = gimple_assign_rhs1 (stmt);
+ if (!builtin_decl_implicit_opt_p(BUILT_IN_MEMSET))
+ return;
+
if (const_with_all_bytes_same (rhs) == -1
&& (!INTEGRAL_TYPE_P (TREE_TYPE (rhs))
|| (TYPE_MODE (TREE_TYPE (rhs))
@@ -1762,6 +1765,10 @@ loop_distribution::classify_builtin_ldst (loop_p loop,
struct graph *rdg,
tree base, size, src_base, src_size;
auto_vec<tree> dst_steps, src_steps;
+ if (!builtin_decl_implicit_opt_p(BUILT_IN_MEMMOVE) ||
+ !builtin_decl_implicit_opt_p(BUILT_IN_MEMCPY))
+ return;
+
/* Compute access range of both load and store. */
int res = compute_access_range (loop, dst_dr, &base, &size, &dst_steps);
if (res != 2)
diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
index ce667ff32b9..77cf209b235 100644
--- a/gcc/tree-ssa-alias.c
+++ b/gcc/tree-ssa-alias.c
@@ -3370,7 +3370,8 @@ stmt_kills_ref_p (gimple *stmt, ao_ref *ref)
{
tree callee = gimple_call_fndecl (stmt);
if (callee != NULL_TREE
- && gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
+ && gimple_call_builtin_p (stmt, BUILT_IN_NORMAL)
+ && builtin_decl_implicit_opt_p(DECL_FUNCTION_CODE (callee)))
switch (DECL_FUNCTION_CODE (callee))
{
case BUILT_IN_FREE:
diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
index 2de7cb1a6a0..050d0573936 100644
--- a/gcc/tree-ssa-strlen.c
+++ b/gcc/tree-ssa-strlen.c
@@ -860,12 +860,17 @@ get_string_length (strinfo *si)
with the same stmt. If they were unshared before and transformation
has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
just compute the right length. */
+ if (!builtin_decl_implicit_opt_p (DECL_FUNCTION_CODE (callee)))
+ return NULL;
+
switch (DECL_FUNCTION_CODE (callee))
{
case BUILT_IN_STRCAT:
case BUILT_IN_STRCAT_CHK:
gsi = gsi_for_stmt (stmt);
- fn = builtin_decl_implicit (BUILT_IN_STRLEN);
+ fn = builtin_decl_implicit_opt (BUILT_IN_STRLEN);
+ if (!fn)
+ return NULL;
gcc_assert (lhs == NULL_TREE);
tem = unshare_expr (gimple_call_arg (stmt, 0));
lenstmt = gimple_build_call (fn, 1, tem);
@@ -889,11 +894,12 @@ get_string_length (strinfo *si)
/* FALLTHRU */
case BUILT_IN_STRCPY:
case BUILT_IN_STRCPY_CHK:
- gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY));
if (gimple_call_num_args (stmt) == 2)
- fn = builtin_decl_implicit (BUILT_IN_STPCPY);
+ fn = builtin_decl_implicit_opt (BUILT_IN_STPCPY);
else
- fn = builtin_decl_explicit (BUILT_IN_STPCPY_CHK);
+ fn = builtin_decl_explicit_opt (BUILT_IN_STPCPY_CHK);
+ if (!fn)
+ return NULL;
gcc_assert (lhs == NULL_TREE);
if (dump_file && (dump_flags & TDF_DETAILS) != 0)
{
@@ -1689,6 +1695,9 @@ valid_builtin_call (gimple *stmt)
&& !gimple_builtin_call_types_compatible_p (stmt, decl))
return false;
+ if (!builtin_decl_implicit_opt_p(DECL_FUNCTION_CODE (callee)))
+ return false;
+
switch (DECL_FUNCTION_CODE (callee))
{
case BUILT_IN_MEMCMP:
@@ -2519,7 +2528,7 @@ strlen_pass::handle_builtin_strcpy (built_in_function
bcode)
{
case BUILT_IN_STRCPY:
case BUILT_IN_STRCPY_CHK:
- if (lhs != NULL_TREE || !builtin_decl_implicit_p (BUILT_IN_STPCPY))
+ if (lhs != NULL_TREE || !builtin_decl_implicit_opt_p (BUILT_IN_STPCPY))
return;
break;
case BUILT_IN_STPCPY:
@@ -2640,12 +2649,12 @@ strlen_pass::handle_builtin_strcpy (built_in_function
bcode)
switch (bcode)
{
case BUILT_IN_STRCPY:
- fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
+ fn = builtin_decl_implicit_opt (BUILT_IN_MEMCPY);
if (lhs)
ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
break;
case BUILT_IN_STRCPY_CHK:
- fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
+ fn = builtin_decl_explicit_opt (BUILT_IN_MEMCPY_CHK);
if (lhs)
ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
break;
@@ -2653,7 +2662,7 @@ strlen_pass::handle_builtin_strcpy (built_in_function
bcode)
/* This would need adjustment of the lhs (subtract one),
or detection that the trailing '\0' doesn't need to be
written, if it will be immediately overwritten.
- fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
+ fn = builtin_decl_explicit_opt (BUILT_IN_MEMPCPY); */
if (lhs)
{
dsi->endptr = lhs;
@@ -2664,7 +2673,7 @@ strlen_pass::handle_builtin_strcpy (built_in_function
bcode)
/* This would need adjustment of the lhs (subtract one),
or detection that the trailing '\0' doesn't need to be
written, if it will be immediately overwritten.
- fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
+ fn = builtin_decl_explicit_opt (BUILT_IN_MEMPCPY_CHK); */
if (lhs)
{
dsi->endptr = lhs;
@@ -3540,7 +3549,7 @@ strlen_pass::handle_builtin_strcat (built_in_function
bcode)
with length endptr - p if we need to compute the length
later on. Don't do this transformation if we don't need
it. */
- if (builtin_decl_implicit_p (BUILT_IN_STPCPY) && lhs == NULL_TREE)
+ if (builtin_decl_implicit_opt_p (BUILT_IN_STPCPY) && lhs == NULL_TREE)
{
if (didx == 0)
{
@@ -3590,7 +3599,7 @@ strlen_pass::handle_builtin_strcat (built_in_function
bcode)
{
dsi->nonzero_chars = NULL;
dsi->full_string_p = false;
- if (lhs == NULL_TREE && builtin_decl_implicit_p (BUILT_IN_STPCPY))
+ if (lhs == NULL_TREE && builtin_decl_implicit_opt_p (BUILT_IN_STPCPY))
dsi->dont_invalidate = true;
}
@@ -3610,15 +3619,15 @@ strlen_pass::handle_builtin_strcat (built_in_function bcode)
{
case BUILT_IN_STRCAT:
if (srclen != NULL_TREE)
- fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
+ fn = builtin_decl_implicit_opt (BUILT_IN_MEMCPY);
else
- fn = builtin_decl_implicit (BUILT_IN_STRCPY);
+ fn = builtin_decl_implicit_opt (BUILT_IN_STRCPY);
break;
case BUILT_IN_STRCAT_CHK:
if (srclen != NULL_TREE)
- fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
+ fn = builtin_decl_explicit_opt (BUILT_IN_MEMCPY_CHK);
else
- fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK);
+ fn = builtin_decl_explicit_opt (BUILT_IN_STRCPY_CHK);
objsz = gimple_call_arg (stmt, 2);
break;
default:
@@ -3798,11 +3807,12 @@ strlen_pass::handle_builtin_memset (bool *zero_write)
if (code1 == BUILT_IN_CALLOC)
/* Not touching alloc_stmt */ ;
else if (code1 == BUILT_IN_MALLOC
- && operand_equal_p (memset_size, alloc_size, 0))
+ && operand_equal_p (memset_size, alloc_size, 0)
+ && builtin_decl_implicit_opt_p (BUILT_IN_CALLOC))
{
/* Replace the malloc + memset calls with calloc. */
gimple_stmt_iterator gsi1 = gsi_for_stmt (si1->stmt);
- update_gimple_call (&gsi1, builtin_decl_implicit (BUILT_IN_CALLOC), 2,
+ update_gimple_call (&gsi1, builtin_decl_implicit_opt (BUILT_IN_CALLOC),
2,
alloc_size, build_one_cst (size_type_node));
si1->nonzero_chars = build_int_cst (size_type_node, 0);
si1->full_string_p = true;
@@ -4367,8 +4377,8 @@ strlen_pass::handle_builtin_string_cmp ()
/* If the known length is less than the size of the other array
and the strcmp result is only used to test equality to zero,
transform the call to the equivalent _eq call. */
- if (tree fn = builtin_decl_implicit (bound < 0 ? BUILT_IN_STRCMP_EQ
- : BUILT_IN_STRNCMP_EQ))
+ if (tree fn = builtin_decl_implicit_opt (bound < 0 ? BUILT_IN_STRCMP_EQ
+ : BUILT_IN_STRNCMP_EQ))
{
tree n = build_int_cst (size_type_node, cmpsiz);
update_gimple_call (&m_gsi, fn, 3, arg1, arg2, n);
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index 99072df0768..c88ac432331 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -4415,7 +4415,8 @@ find_func_aliases_for_builtin_call (struct function *fn,
gcall *t)
auto_vec<ce_s, 4> rhsc;
varinfo_t fi;
- if (gimple_call_builtin_p (t, BUILT_IN_NORMAL))
+ if (gimple_call_builtin_p (t, BUILT_IN_NORMAL) &&
+ builtin_decl_implicit_opt_p (DECL_FUNCTION_CODE (fndecl)))
/* ??? All builtins that are handled here need to be handled
in the alias-oracle query functions explicitly! */
switch (DECL_FUNCTION_CODE (fndecl))
diff --git a/gcc/tree.h b/gcc/tree.h
index 7542d97ce12..72b969e1684 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -5728,6 +5728,20 @@ builtin_decl_explicit (enum built_in_function fncode)
return builtin_info[(size_t)fncode].decl;
}
+/* Return the tree node for an explicit builtin function if the
+ optimizer is allowed to use it or NULL. Use this instead of
+ builtin_decl_implicit in code that could introduce a new builtin
+ call to perform optimization, but where such a call is not
+ required */
+
+static inline tree
+builtin_decl_explicit_opt (enum built_in_function fncode)
+{
+ if (flag_no_opt_builtin)
+ return NULL_TREE;
+ return builtin_decl_explicit (fncode);
+}
+
/* Return the tree node for an implicit builtin function or NULL. */
static inline tree
builtin_decl_implicit (enum built_in_function fncode)
@@ -5741,6 +5755,20 @@ builtin_decl_implicit (enum built_in_function fncode)
return builtin_info[uns_fncode].decl;
}
+/* Return the tree node for an implicit builtin function if the
+ optimizer is allowed to use it or NULL. Use this instead of
+ builtin_decl_implicit in code that could introduce a new builtin
+ call to perform optimization, but where such a call is not
+ required */
+
+static inline tree
+builtin_decl_implicit_opt (enum built_in_function fncode)
+{
+ if (flag_no_opt_builtin)
+ return NULL_TREE;
+ return builtin_decl_implicit (fncode);
+}
+
/* Set explicit builtin function nodes and whether it is an implicit
function. */
@@ -5805,6 +5833,17 @@ builtin_decl_implicit_p (enum built_in_function fncode)
&& builtin_info[uns_fncode].implicit_p);
}
+/* Return whether the standard builtin function can be used
+ implicitly. Use this instead of builtin_decl_implicit_p in code
+ that could introduce a new builtin call to perform optimization,
+ but where such a call is not required */
+
+static inline bool
+builtin_decl_implicit_opt_p (enum built_in_function fncode)
+{
+ return !flag_no_opt_builtin && builtin_decl_implicit_p(fncode);
+}
+
/* Return whether the standard builtin function was declared. */
static inline bool