[PATCH] Add -fopt-builtin optimization option
Richard Biener
richard.guenther@gmail.com
Tue Nov 2 13:06:13 GMT 2021
On Sun, Oct 31, 2021 at 11:13 AM Keith Packard via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> This option (enabled by default) controls optimizations which convert
> a sequence of operations into an equivalent sequence that includes
> calls to builtin functions. Typical cases here are code which matches
> memcpy, calloc, sincos.
>
> The -ftree-loop-distribute-patterns flag only covers converting loops
> into builtin calls, not numerous other places where knowledge of
> builtin function semantics changes the generated code.
>
> The goal is to allow built-in functions to be declared by the compiler
> and used directly by the application, but to disable optimizations
> which create new calls to them, and to allow this optimization
> behavior to be changed for individual functions by decorating the
> function definition like this:
>
> void
> attribute((optimize("no-opt-builtin")))
> sincos(double x, double *s, double *c)
> {
> *s = sin(x);
> *c = cos(x);
> }
>
> This also avoids converting loops into library calls like this:
>
> void *
> attribute((optimize("no-opt-builtin")))
> memcpy(void *__restrict__ dst, const void *__restrict__ src, size_t n)
> {
> char *d = dst;
> const char *s = src;
>
> while (n--)
> *d++ = *s++;
> return dst;
> }
>
> As well as disabling analysis of memory lifetimes around free as in
> this example:
>
> void *
> attribute((optimize("no-opt-builtin")))
> erase_and_free(void *ptr)
> {
> memset(ptr, '\0', malloc_usable_size(ptr));
> free(ptr);
> }
>
> Clang has a more sophisticated version of this mechanism which
> can disable all builtins, or disable a specific builtin:
>
> double
> attribute((no_builtin("exp2")))
> exp2(double x)
> {
> return pow (2.0, x);
> }
I don't think it reliably works the way you implement it. It's also having
more side-effects than what you document, in particular
pow (2.0, x);
will now clobber and use global memory (besides errno).
I think you may want to instead change builtin_decl_implicit
to avoid code-generating a specific builtin.
Generally we'd also want sth like the clang attribute and _not_
use optimize("") for this or a global flag_*, so the behavior can
be more readily encoded in the IL. In fact a flag on the call
statement could be added to denote the desired effect on it.
I also don't see the advantage compared to -fno-builtin[-foo].
Declaring the function should be something that's already done.
Richard.
> Signed-off-by: Keith Packard <keithp@keithp.com>
> ---
> gcc/builtins.c | 6 ++++++
> gcc/common.opt | 4 ++++
> gcc/gimple.c | 3 +++
> gcc/tree-loop-distribution.c | 2 ++
> 4 files changed, 15 insertions(+)
>
> diff --git a/gcc/builtins.c b/gcc/builtins.c
> index 7d0f61fc98b..7aae57deab5 100644
> --- a/gcc/builtins.c
> +++ b/gcc/builtins.c
> @@ -1922,6 +1922,9 @@ mathfn_built_in_2 (tree type, combined_fn fn)
> built_in_function fcodef64x = END_BUILTINS;
> built_in_function fcodef128x = END_BUILTINS;
>
> + if (flag_no_opt_builtin)
> + return END_BUILTINS;
> +
> switch (fn)
> {
> #define SEQ_OF_CASE_MATHFN \
> @@ -2125,6 +2128,9 @@ mathfn_built_in_type (combined_fn fn)
> case CFN_BUILT_IN_##MATHFN##L_R: \
> return long_double_type_node;
>
> + if (flag_no_opt_builtin)
> + return NULL_TREE;
> +
> switch (fn)
> {
> SEQ_OF_CASE_MATHFN
> diff --git a/gcc/common.opt b/gcc/common.opt
> index eeba1a727f2..d6111cc776a 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -2142,6 +2142,10 @@ fomit-frame-pointer
> Common Var(flag_omit_frame_pointer) Optimization
> When possible do not generate stack frames.
>
> +fopt-builtin
> +Common Var(flag_no_opt_builtin, 0) Optimization
> +Match code sequences equivalent to builtin functions
> +
> fopt-info
> Common Var(flag_opt_info) Optimization
> Enable all optimization info dumps on stderr.
> diff --git a/gcc/gimple.c b/gcc/gimple.c
> index 22dd6417d19..5b82b9409c0 100644
> --- a/gcc/gimple.c
> +++ b/gcc/gimple.c
> @@ -2790,6 +2790,9 @@ gimple_builtin_call_types_compatible_p (const gimple *stmt, tree fndecl)
> {
> gcc_checking_assert (DECL_BUILT_IN_CLASS (fndecl) != NOT_BUILT_IN);
>
> + if (flag_no_opt_builtin)
> + return false;
> +
> tree ret = gimple_call_lhs (stmt);
> if (ret
> && !useless_type_conversion_p (TREE_TYPE (ret),
> diff --git a/gcc/tree-loop-distribution.c b/gcc/tree-loop-distribution.c
> index 583c01a42d8..43f22a3c7ce 100644
> --- a/gcc/tree-loop-distribution.c
> +++ b/gcc/tree-loop-distribution.c
> @@ -1859,6 +1859,7 @@ loop_distribution::classify_partition (loop_p loop,
>
> /* Perform general partition disqualification for builtins. */
> if (volatiles_p
> + || flag_no_opt_builtin
> || !flag_tree_loop_distribute_patterns)
> return has_reduction;
>
> @@ -3764,6 +3765,7 @@ loop_distribution::execute (function *fun)
> /* Don't distribute multiple exit edges loop, or cold loop when
> not doing pattern detection. */
> if (!single_exit (loop)
> + || flag_no_opt_builtin
> || (!flag_tree_loop_distribute_patterns
> && !optimize_loop_for_speed_p (loop)))
> continue;
> --
> 2.33.0
>
More information about the Gcc
mailing list