> Am 01.03.2025 um 09:41 schrieb Jakub Jelinek <ja...@redhat.com>:
> 
> Hi!
> 
> As analyzed by Andrew/David/Richi/Sam in the PR, the reason for the
> libgccjit ICE is that there are GC allocations with finalizers and we
> still mark ggc_internal_{,cleared_}alloc with ATTRIBUTE_MALLOC, which
> to the optimizers hints that nothing will actually read the state
> of the objects when they get out of lifetime.  The finalizer actually
> inspects those though.  So that we don't lose ATTRIBUTE_MALLOC for
> the common case when no finalization is needed, the following patch
> uses the approach used e.g. for glibc error function which can sometimes
> be noreturn but at other times just return normally.
> If possible, it uses __attribute__((alias ("..."))) to add an alias
> to the function, where one is without ATTRIBUTE_MALLOC and one
> (with _no_dtor suffix) is with ATTRIBUTE_MALLOC (note, as this is
> C++ and I didn't want to hardcode particular mangling I used an
> extern "C" function with 2 aliases to it), and otherwise adds a wrapper
> (for the ggc-page/ggc-common case with noinline attribute if possible,
> for ggc-none that doesn't matter because ggc-none doesn't support
> finalizers).
> The *_no_dtor aliases/wrappers are then used in inline functions which
> pass unconditional NULL, 0 as the f/s pair.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

Ok

Thanks,
Richard 

> 2025-03-01  Jakub Jelinek  <ja...@redhat.com>
> 
>    PR jit/117047
>    * acinclude.m4 (gcc_CHECK_ATTRIBUTE_ALIAS): New.
>    * configure.ac: Add gcc_CHECK_ATTRIBUTE_ALIAS.
>    * ggc.h (ggc_internal_alloc): Remove ATTRIBUTE_MALLOC from
>    overload with finalizer pointer.  Call ggc_internal_alloc_no_dtor
>    in inline overload without finalizer pointer.
>    (ggc_internal_alloc_no_dtor): Declare.
>    (ggc_internal_cleared_alloc): Remove ATTRIBUTE_MALLOC from
>    overload with finalizer pointer.  Call
>    ggc_internal_cleared_alloc_no_dtor in inline overload without
>    finalizer pointer.
>    (ggc_internal_cleared_alloc_no_dtor): Declare.
>    (ggc_alloc): Call ggc_internal_alloc_no_dtor if no finalization
>    is needed.
>    (ggc_alloc_no_dtor): Call ggc_internal_alloc_no_dtor.
>    (ggc_cleared_alloc): Call ggc_internal_cleared_alloc_no_dtor if no
>    finalization is needed.
>    (ggc_vec_alloc): Call ggc_internal_alloc_no_dtor if no finalization
>    is needed.
>    (ggc_cleared_vec_alloc): Call ggc_internal_cleared_alloc_no_dtor if no
>    finalization is needed.
>    * ggc-page.cc (ggc_internal_alloc): If HAVE_ATTRIBUTE_ALIAS, turn
>    overload with finalizer into alias to ggc_internal_alloc_ and
>    rename it to ...
>    (ggc_internal_alloc_): ... this, make it extern "C".
>    (ggc_internal_alloc_no_dtor): New alias if HAVE_ATTRIBUTE_ALIAS,
>    otherwise new noinline wrapper.
>    * ggc-common.cc (ggc_internal_cleared_alloc): If HAVE_ATTRIBUTE_ALIAS,
>    turn overload with finalizer into alias to ggc_internal_alloc_ and
>    rename it to ...
>    (ggc_internal_cleared_alloc_): ... this, make it extern "C".
>    (ggc_internal_cleared_alloc_no_dtor): New alias if
>    HAVE_ATTRIBUTE_ALIAS, otherwise new noinline wrapper.
>    * ggc-none.cc (ggc_internal_alloc): If HAVE_ATTRIBUTE_ALIAS, turn
>    overload with finalizer into alias to ggc_internal_alloc_ and
>    rename it to ...
>    (ggc_internal_alloc_): ... this, make it extern "C".
>    (ggc_internal_alloc_no_dtor): New alias if HAVE_ATTRIBUTE_ALIAS,
>    otherwise new wrapper.
>    (ggc_internal_cleared_alloc): If HAVE_ATTRIBUTE_ALIAS, turn overload
>    with finalizer into alias to ggc_internal_alloc_ and rename it to ...
>    (ggc_internal_cleared_alloc_): ... this, make it extern "C".
>    (ggc_internal_cleared_alloc_no_dtor): New alias if
>    HAVE_ATTRIBUTE_ALIAS, otherwise new wrapper.
>    * genmatch.cc (ggc_internal_cleared_alloc, ggc_free): Formatting fix.
>    (ggc_internal_cleared_alloc_no_dtor): Define.
>    * config.in: Regenerate.
>    * configure: Regenerate.
> 
> --- gcc/acinclude.m4.jj    2025-01-02 11:23:32.759290106 +0100
> +++ gcc/acinclude.m4    2025-02-28 11:13:42.246850464 +0100
> @@ -442,6 +442,23 @@ AC_DEFINE_UNQUOTED(HAVE_INITFINI_ARRAY_S
>   [Define 0/1 if .init_array/.fini_array sections are available and working.])
> ])
> 
> +dnl Check whether the host supports symbol aliases.
> +AC_DEFUN([gcc_CHECK_ATTRIBUTE_ALIAS], [
> +  AC_CACHE_CHECK([whether the host/build supports symbol aliases],
> +                 gcc_cv_have_attribute_alias, [
> +  if test "x${build}" = "x${host}"; then
> +    AC_TRY_LINK([
> +extern "C" void foo(void) { }
> +extern void bar(void) __attribute__((alias("foo")));],
> +    [bar();], gcc_cv_have_attribute_alias=yes, 
> gcc_cv_have_attribute_alias=no)
> +  else
> +    gcc_cv_have_attribute_alias=no
> +  fi])
> +  if test $gcc_cv_have_attribute_alias = yes; then
> +    AC_DEFINE(HAVE_ATTRIBUTE_ALIAS, 1,
> +      [Define to 1 if the host/build supports __attribute__((alias(...))).])
> +  fi])
> +
> dnl # gcc_GAS_FLAGS
> dnl # Used by gcc_GAS_CHECK_FEATURE
> dnl #
> --- gcc/configure.ac.jj    2025-02-13 10:20:55.475762996 +0100
> +++ gcc/configure.ac    2025-02-28 10:39:54.738638413 +0100
> @@ -3296,6 +3296,8 @@ AC_MSG_RESULT($gcc_cv_ld_ro_rw_mix)
> 
> gcc_AC_INITFINI_ARRAY
> 
> +gcc_CHECK_ATTRIBUTE_ALIAS
> +
> # Some assemblers (GNU as for LoongArch) generates relocations for
> # leb128 symbol arithmetic for relaxation, we need to disable relaxation
> # probing leb128 support then.
> --- gcc/ggc.h.jj    2025-01-02 11:23:22.192437625 +0100
> +++ gcc/ggc.h    2025-02-28 12:05:26.920274765 +0100
> @@ -127,13 +127,18 @@ extern void gt_pch_save (FILE *f);
> 
> /* The internal primitive.  */
> extern void *ggc_internal_alloc (size_t, void (*)(void *), size_t,
> -                 size_t CXX_MEM_STAT_INFO)
> +                 size_t CXX_MEM_STAT_INFO);
> +/* If the second argument is non-NULL, it can't be marked ATTRIBUTE_MALLOC,
> +   because ggc_free performs finalization.  Add an alias or wrapper used just
> +   for the NULL finalizer which can be marked with ATTRIBUTE_MALLOC.  */
> +extern void *ggc_internal_alloc_no_dtor (size_t, void (*)(void *), size_t,
> +                     size_t CXX_MEM_STAT_INFO)
>      ATTRIBUTE_MALLOC;
> 
> inline void *
> ggc_internal_alloc (size_t s CXX_MEM_STAT_INFO)
> {
> -  return ggc_internal_alloc (s, NULL, 0, 1 PASS_MEM_STAT);
> +  return ggc_internal_alloc_no_dtor (s, NULL, 0, 1 PASS_MEM_STAT);
> }
> 
> extern size_t ggc_round_alloc_size (size_t requested_size);
> @@ -141,12 +146,16 @@ extern size_t ggc_round_alloc_size (size
> /* Allocates cleared memory.  */
> extern void *ggc_internal_cleared_alloc (size_t, void (*)(void *),
>                     size_t, size_t
> -                     CXX_MEM_STAT_INFO) ATTRIBUTE_MALLOC;
> +                     CXX_MEM_STAT_INFO);
> +extern void *ggc_internal_cleared_alloc_no_dtor (size_t, void (*)(void *),
> +                         size_t, size_t
> +                         CXX_MEM_STAT_INFO)
> +     ATTRIBUTE_MALLOC;
> 
> inline void *
> ggc_internal_cleared_alloc (size_t s CXX_MEM_STAT_INFO)
> {
> -  return ggc_internal_cleared_alloc (s, NULL, 0, 1 PASS_MEM_STAT);
> +  return ggc_internal_cleared_alloc_no_dtor (s, NULL, 0, 1 PASS_MEM_STAT);
> }
> 
> /* Resize a block.  */
> @@ -187,8 +196,8 @@ ggc_alloc (ALONE_CXX_MEM_STAT_INFO)
>     return static_cast<T *> (ggc_internal_alloc (sizeof (T), finalize<T>, 0, 1
>                         PASS_MEM_STAT));
>   else
> -    return static_cast<T *> (ggc_internal_alloc (sizeof (T), NULL, 0, 1
> -                         PASS_MEM_STAT));
> +    return static_cast<T *> (ggc_internal_alloc_no_dtor (sizeof (T), NULL,
> +                             0, 1 PASS_MEM_STAT));
> }
> 
> /* GGC allocation function that does not call finalizer for type
> @@ -199,8 +208,8 @@ template<typename T>
> inline T *
> ggc_alloc_no_dtor (ALONE_CXX_MEM_STAT_INFO)
> {
> -  return static_cast<T *> (ggc_internal_alloc (sizeof (T), NULL, 0, 1
> -                           PASS_MEM_STAT));
> +  return static_cast<T *> (ggc_internal_alloc_no_dtor (sizeof (T), NULL, 0, 1
> +                               PASS_MEM_STAT));
> }
> 
> template<typename T>
> @@ -212,8 +221,9 @@ ggc_cleared_alloc (ALONE_CXX_MEM_STAT_IN
>                             finalize<T>, 0, 1
>                             PASS_MEM_STAT));
>   else
> -    return static_cast<T *> (ggc_internal_cleared_alloc (sizeof (T), NULL, 
> 0, 1
> -                             PASS_MEM_STAT));
> +    return static_cast<T *> (ggc_internal_cleared_alloc_no_dtor (sizeof (T),
> +                                 NULL, 0, 1
> +                                 PASS_MEM_STAT));
> }
> 
> template<typename T>
> @@ -224,8 +234,9 @@ ggc_vec_alloc (size_t c CXX_MEM_STAT_INF
>     return static_cast<T *> (ggc_internal_alloc (c * sizeof (T), finalize<T>,
>                         sizeof (T), c PASS_MEM_STAT));
>   else
> -    return static_cast<T *> (ggc_internal_alloc (c * sizeof (T), NULL, 0, 0
> -                         PASS_MEM_STAT));
> +    return static_cast<T *> (ggc_internal_alloc_no_dtor (c * sizeof (T),
> +                             NULL, 0, 0
> +                             PASS_MEM_STAT));
> }
> 
> template<typename T>
> @@ -238,8 +249,10 @@ ggc_cleared_vec_alloc (size_t c CXX_MEM_
>                             sizeof (T), c
>                             PASS_MEM_STAT));
>   else
> -    return static_cast<T *> (ggc_internal_cleared_alloc (c * sizeof (T), 
> NULL,
> -                             0, 0 PASS_MEM_STAT));
> +    return static_cast<T *> (ggc_internal_cleared_alloc_no_dtor (c
> +                                 * sizeof (T),
> +                                 NULL, 0, 0
> +                                 PASS_MEM_STAT));
> }
> 
> inline void *
> --- gcc/ggc-page.cc.jj    2025-01-02 11:23:31.973301079 +0100
> +++ gcc/ggc-page.cc    2025-02-28 12:10:36.257026356 +0100
> @@ -1273,9 +1273,15 @@ add_finalizer (void *result, void (*f)(v
> 
> /* Allocate a chunk of memory of SIZE bytes.  Its contents are undefined.  */
> 
> +#ifdef HAVE_ATTRIBUTE_ALIAS
> +extern "C" void *
> +ggc_internal_alloc_ (size_t size, void (*f)(void *), size_t s, size_t n
> +             MEM_STAT_DECL)
> +#else
> void *
> ggc_internal_alloc (size_t size, void (*f)(void *), size_t s, size_t n
>            MEM_STAT_DECL)
> +#endif
> {
>   size_t order, word, bit, object_offset, object_size;
>   struct page_entry *entry;
> @@ -1458,6 +1464,27 @@ ggc_internal_alloc (size_t size, void (*
>   return result;
> }
> 
> +#ifdef HAVE_ATTRIBUTE_ALIAS
> +extern void *
> +ggc_internal_alloc (size_t size, void (*f)(void *), size_t s,
> +            size_t n MEM_STAT_DECL)
> +     __attribute__((__alias__ ("ggc_internal_alloc_")));
> +extern void *
> +ggc_internal_alloc_no_dtor (size_t size, void (*f)(void *), size_t s,
> +                size_t n MEM_STAT_DECL)
> +     __attribute__((__alias__ ("ggc_internal_alloc_")));
> +#else
> +#ifdef __GNUC__
> +__attribute__ ((__noinline__))
> +#endif
> +void *
> +ggc_internal_alloc_no_dtor (size_t size, void (*f)(void *), size_t s,
> +                size_t n MEM_STAT_DECL)
> +{
> +  return ggc_internal_alloc (size, f, s, n PASS_MEM_STAT);
> +}
> +#endif
> +
> /* Mark function for strings.  */
> 
> void
> --- gcc/ggc-common.cc.jj    2025-01-02 11:23:32.505293652 +0100
> +++ gcc/ggc-common.cc    2025-02-28 12:12:20.207598711 +0100
> @@ -119,6 +119,25 @@ ggc_mark_roots (void)
> }
> 
> /* Allocate a block of memory, then clear it.  */
> +#ifdef HAVE_ATTRIBUTE_ALIAS
> +extern "C" void *
> +ggc_internal_cleared_alloc_ (size_t size, void (*f)(void *), size_t s, 
> size_t n
> +                 MEM_STAT_DECL)
> +{
> +  void *buf = ggc_internal_alloc (size, f, s, n PASS_MEM_STAT);
> +  memset (buf, 0, size);
> +  return buf;
> +}
> +
> +extern void *
> +ggc_internal_cleared_alloc (size_t size, void (*f)(void *), size_t s,
> +                size_t n MEM_STAT_DECL)
> +     __attribute__((__alias__ ("ggc_internal_cleared_alloc_")));
> +extern void *
> +ggc_internal_cleared_alloc_no_dtor (size_t size, void (*f)(void *),
> +                    size_t s, size_t n MEM_STAT_DECL)
> +     __attribute__((__alias__ ("ggc_internal_cleared_alloc_")));
> +#else
> void *
> ggc_internal_cleared_alloc (size_t size, void (*f)(void *), size_t s, size_t n
>                MEM_STAT_DECL)
> @@ -128,6 +147,17 @@ ggc_internal_cleared_alloc (size_t size,
>   return buf;
> }
> 
> +#ifdef __GNUC__
> +__attribute__ ((__noinline__))
> +#endif
> +void *
> +ggc_internal_cleared_alloc_no_dtor (size_t size, void (*f)(void *),
> +                    size_t s, size_t n MEM_STAT_DECL)
> +{
> +  return ggc_internal_cleared_alloc (s, f, s, n PASS_MEM_STAT);
> +}
> +#endif
> +
> /* Resize a block of memory, possibly re-allocating it.  */
> void *
> ggc_realloc (void *x, size_t size MEM_STAT_DECL)
> --- gcc/ggc-none.cc.jj    2025-01-02 11:23:28.208353640 +0100
> +++ gcc/ggc-none.cc    2025-02-28 12:11:13.904509308 +0100
> @@ -40,6 +40,40 @@ ggc_round_alloc_size (size_t requested_s
>   return requested_size;
> }
> 
> +#ifdef HAVE_ATTRIBUTE_ALIAS
> +extern "C" void *
> +ggc_internal_alloc_ (size_t size, void (*f)(void *), size_t, size_t
> +             MEM_STAT_DECL)
> +{
> +  gcc_assert (!f); // ggc-none doesn't support finalizers
> +  return xmalloc (size);
> +}
> +
> +extern "C" void *
> +ggc_internal_cleared_alloc_ (size_t size, void (*f)(void *), size_t, size_t
> +                 MEM_STAT_DECL)
> +{
> +  gcc_assert (!f); // ggc-none doesn't support finalizers
> +  return xcalloc (size, 1);
> +}
> +
> +extern void *
> +ggc_internal_alloc (size_t size, void (*f)(void *), size_t s,
> +                size_t n MEM_STAT_DECL)
> +     __attribute__((__alias__ ("ggc_internal_alloc_")));
> +extern void *
> +ggc_internal_alloc_no_dtor (size_t size, void (*f)(void *), size_t s,
> +                size_t n MEM_STAT_DECL)
> +     __attribute__((__alias__ ("ggc_internal_alloc_")));
> +extern void *
> +ggc_internal_cleared_alloc (size_t size, void (*f)(void *),
> +                size_t s, size_t n MEM_STAT_DECL)
> +     __attribute__((__alias__ ("ggc_internal_cleared_alloc_")));
> +extern void *
> +ggc_internal_cleared_alloc_no_dtor (size_t size, void (*f)(void *),
> +                    size_t s, size_t n MEM_STAT_DECL)
> +     __attribute__((__alias__ ("ggc_internal_cleared_alloc_")));
> +#else
> void *
> ggc_internal_alloc (size_t size, void (*f)(void *), size_t, size_t
>            MEM_STAT_DECL)
> @@ -57,6 +91,21 @@ ggc_internal_cleared_alloc (size_t size,
> }
> 
> void *
> +ggc_internal_alloc_no_dtor (size_t size, void (*f)(void *), size_t s,
> +                size_t n MEM_STAT_DECL)
> +{
> +  return ggc_internal_alloc (size, f, s, n PASS_MEM_STAT);
> +}
> +
> +void *
> +ggc_internal_cleared_alloc_no_dtor (size_t size, void (*f)(void *),
> +                    size_t s, size_t n MEM_STAT_DECL)
> +{
> +  return ggc_internal_cleared_alloc (size, f, s, n PASS_MEM_STAT);
> +}
> +#endif
> +
> +void *
> ggc_realloc_stat (void *x, size_t size MEM_STAT_DECL)
> {
>   return xrealloc (x, size);
> --- gcc/genmatch.cc.jj    2025-01-15 16:51:49.450087669 +0100
> +++ gcc/genmatch.cc    2025-02-28 12:12:37.971354745 +0100
> @@ -34,12 +34,22 @@ along with GCC; see the file COPYING3.
> 
> 
> /* Stubs for GGC referenced through instantiations triggered by hash-map.  */
> -void *ggc_internal_cleared_alloc (size_t, void (*)(void *),
> -                  size_t, size_t MEM_STAT_DECL)
> +void *
> +ggc_internal_cleared_alloc (size_t, void (*)(void *),
> +                size_t, size_t MEM_STAT_DECL)
> {
>   return NULL;
> }
> -void ggc_free (void *)
> +
> +void *
> +ggc_internal_cleared_alloc_no_dtor (size_t, void (*)(void *),
> +                    size_t, size_t MEM_STAT_DECL)
> +{
> +  return NULL;
> +}
> +
> +void
> +ggc_free (void *)
> {
> }
> 
> --- gcc/config.in.jj    2025-02-13 10:20:55.419763773 +0100
> +++ gcc/config.in    2025-02-28 10:40:13.463380814 +0100
> @@ -851,6 +851,12 @@
> #endif
> 
> 
> +/* Define to 1 if the host/build supports __attribute__((alias(...))). */
> +#ifndef USED_FOR_TARGET
> +#undef HAVE_ATTRIBUTE_ALIAS
> +#endif
> +
> +
> /* Define to 1 if you have the Mac OS X function
>    CFLocaleCopyPreferredLanguages in the CoreFoundation framework. */
> #ifndef USED_FOR_TARGET
> --- gcc/configure.jj    2025-02-13 10:20:55.459763218 +0100
> +++ gcc/configure    2025-02-28 11:14:22.696296991 +0100
> @@ -26412,6 +26412,46 @@ _ACEOF
> 
> 
> 
> +
> +  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the host/build 
> supports symbol aliases" >&5
> +$as_echo_n "checking whether the host/build supports symbol aliases... " 
> >&6; }
> +if ${gcc_cv_have_attribute_alias+:} false; then :
> +  $as_echo_n "(cached) " >&6
> +else
> +
> +  if test "x${build}" = "x${host}"; then
> +    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
> +/* end confdefs.h.  */
> +
> +extern "C" void foo(void) { }
> +extern void bar(void) __attribute__((alias("foo")));
> +int
> +main ()
> +{
> +bar();
> +  ;
> +  return 0;
> +}
> +_ACEOF
> +if ac_fn_cxx_try_link "$LINENO"; then :
> +  gcc_cv_have_attribute_alias=yes
> +else
> +  gcc_cv_have_attribute_alias=no
> +fi
> +rm -f core conftest.err conftest.$ac_objext \
> +    conftest$ac_exeext conftest.$ac_ext
> +  else
> +    gcc_cv_have_attribute_alias=no
> +  fi
> +fi
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: 
> $gcc_cv_have_attribute_alias" >&5
> +$as_echo "$gcc_cv_have_attribute_alias" >&6; }
> +  if test $gcc_cv_have_attribute_alias = yes; then
> +
> +$as_echo "#define HAVE_ATTRIBUTE_ALIAS 1" >>confdefs.h
> +
> +  fi
> +
> # Some assemblers (GNU as for LoongArch) generates relocations for
> # leb128 symbol arithmetic for relaxation, we need to disable relaxation
> # probing leb128 support then.
> 
>    Jakub
> 

Reply via email to