On Sun, Oct 31, 2021 at 11:13 AM Keith Packard via Gcc-patches <gcc-patc...@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 <kei...@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 >