From: Guillaume Gomez <guillaume1.gomez@gmail.com>
To: David Malcolm <dmalcolm@redhat.com>
Cc: jit@gcc.gnu.org, Antoni <bouanto@zoho.com>, gcc-patches@gcc.gnu.org
Subject: Re: [PATCH] Add support for function attributes and variable attributes
Date: Fri, 12 Jan 2024 14:47:02 +0100 [thread overview]
Message-ID: <CAAOQCfQ6UYhN1SoE=j9YXp46BQ+YHUxCMq42U4CafmtyBKw4yA@mail.gmail.com> (raw)
In-Reply-To: <CAAOQCfTTsKeaJr4NXmThtbBHdj11tjPi4+2cvtjT8rPiT1X4Uw@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 17709 bytes --]
Just realized that you were asking for the patch I forgot to join...
Here it is.
Le ven. 12 janv. 2024 à 11:09, Guillaume Gomez
<guillaume1.gomez@gmail.com> a écrit :
>
> > It sounds like the patch you have locally is ready, but it has some
> > nontrivial changes compared to the last version you posted to the list.
> > Please post your latest version to the list.
>
> Sure!
>
> This patch adds the support for attributes on functions and variables. It does
> so by adding the following functions:
>
> * gcc_jit_function_add_attribute
> * gcc_jit_function_add_string_attribute
> * gcc_jit_function_add_integer_array_attribute
> * gcc_jit_lvalue_add_string_attribute
>
> It adds the following types:
>
> * gcc_jit_fn_attribute
> * gcc_jit_variable_attribute
>
> It adds tests to ensure that the attributes are correctly applied.
>
> > Do you have push rights, or do you need me to push it for you?
>
> I have push rights so I'll merge the patch myself. But thanks for offering to
> do it.
>
> Le jeu. 11 janv. 2024 à 23:38, David Malcolm <dmalcolm@redhat.com> a écrit :
> >
> > On Thu, 2024-01-11 at 22:40 +0100, Guillaume Gomez wrote:
> > > Hi David,
> > >
> > > > The above looks correct, but the patch adds the entrypoint
> > > > descriptions
> > > > to topics/types.rst, which seems like the wrong place. The
> > > > function-
> > > > related ones should be in topics/functions.rst in the "Functions"
> > > > section and the lvalue/variable one in topics/expression.rst after
> > > > the
> > > > "Global variables" section.
> > >
> > > Ah indeed. Mix-up on my end. Fixed it.
> > >
> > > > test-restrict.c is a pre-existing testcase, so please don't delete
> > > > its
> > > > entry.
> > >
> > > Ah indeed, I went too quickly and thought it was a test I renamed...
> > >
> > > > BTW, the ChangeLog entry mentions adding test-restrict.c, but the
> > > > patch
> > > > doesn't add it, so that part of the proposed ChangeLog is wrong.
> > > >
> > > > Does the patch pass ./contrib/gcc-changelog/git_check_commit.py ?
> > >
> > > I messed up a bit, fixed it thanks to you. I didn't run the script in
> > > my last
> > > update but just did:
> > >
> > > ```
> > > $ contrib/gcc-changelog/git_check_commit.py $(git log -1 --format=%h)
> > > Checking 3849ee2eadf0eeec2b0080a5142ced00be96a60d: OK
> > > ```
> > >
> > > > Otherwise, looks good, assuming that the patch has been tested with
> > > > the
> > > > full jit testsuite.
> > >
> > > When rebasing on upstream yesterday I discovered that two tests
> > > were not working anymore. For the first one, it was simply because of
> > > the changes in `dummy-frontend.cc`. For the second one
> > > (test-noinline-attribute.c), it was because the rules for inlining
> > > changed
> > > since we wrote this patch apparently (our fork is very late). Antoni
> > > discovered
> > > that we could just add a call to `asm` to prevent this from happening
> > > so I
> > > added it.
> > >
> > > So yes, all jit tests are passing as expected. :)
> >
> > Good.
> >
> > It sounds like the patch you have locally is ready, but it has some
> > nontrivial changes compared to the last version you posted to the list.
> > Please post your latest version to the list.
> >
> > Do you have push rights, or do you need me to push it for you?
> >
> > Thanks
> > Dave
> >
> > >
> > > Le jeu. 11 janv. 2024 à 19:46, David Malcolm <dmalcolm@redhat.com> a
> > > écrit :
> > > >
> > > > On Thu, 2024-01-11 at 01:00 +0100, Guillaume Gomez wrote:
> > > > > Hi David.
> > > > >
> > > > > Thanks for the review!
> > > > >
> > > > > > > +.. function:: void\
> > > > > > > + gcc_jit_lvalue_add_string_attribute
> > > > > > > (gcc_jit_lvalue *variable,
> > > > > > > + enum
> > > > > > > gcc_jit_fn_attribute attribute,
> > > > > >
> > > > > > ^^
> > > > > >
> > > > > > This got out of sync with the declaration in the header file;
> > > > > > it
> > > > > > should
> > > > > > be enum gcc_jit_variable_attribute attribute
> > > > >
> > > > > Indeed, good catch!
> > > > >
> > > > > > I took a brief look through the handler functions and with the
> > > > > > above
> > > > > > caveat I didn't see anything obviously wrong. I'm going to
> > > > > > assume
> > > > > > this
> > > > > > code is OK given that presumably you've been testing it within
> > > > > > rustc,
> > > > > > right?
> > > > >
> > > > > Both in rustc and in the JIT tests we added.
> > > > >
> > > > > [..snip...]
> > > > >
> > > > > I added all the missing `RETURN_IF_FAIL` you mentioned. None of
> > > > > the
> > > > > arguments should be `NULL` so it was a mistake not to check it.
> > > > >
> > > > > [..snip...]
> > > > >
> > > > > I removed the tests comments as you mentioned.
> > > > >
> > > > > > Please update jit.dg/all-non-failing-tests.h for the new tests;
> > > > > > it's
> > > > > > meant to list all of the (non failing) tests alphabetically.
> > > > >
> > > > > It's not always correctly sorted. Might be worth sending a patch
> > > > > after this
> > > > > one gets merged to fix that.
> > > > >
> > > > > > I *think* all of the new tests aren't suitable to be run as
> > > > > > part of
> > > > > > a
> > > > > > shared context (e.g. due to touching the optimization level or
> > > > > > examining generated asm), so they should be listed in that
> > > > > > header
> > > > > > with
> > > > > > comments explaining why.
> > > > >
> > > > > I added them with a comment on top of each of them.
> > > > >
> > > > > I joined the new patch version.
> > > > >
> > > > > Thanks again for the review!
> > > >
> > > > Thanks for the updated patch. I noticed a few minor issues:
> > > >
> > > > > diff --git a/gcc/jit/docs/topics/types.rst
> > > > > b/gcc/jit/docs/topics/types.rst
> > > > > index bb51f037b7e..b1aedc03787 100644
> > > > > --- a/gcc/jit/docs/topics/types.rst
> > > > > +++ b/gcc/jit/docs/topics/types.rst
> > > > > @@ -553,3 +553,80 @@ Reflection API
> > > > > .. code-block:: c
> > > > >
> > > > > #ifdef LIBGCCJIT_HAVE_gcc_jit_type_get_restrict
> > > > > +
> > > > > +.. function:: void\
> > > > > + gcc_jit_function_add_attribute (gcc_jit_function
> > > > > *func,
> > > > > + enum
> > > > > gcc_jit_fn_attribute attribute)
> > > > > +
> > > > > + Add an attribute ``attribute`` to a function ``func``.
> > > > > +
> > > > > + This is equivalent to the following code:
> > > > > +
> > > > > + .. code-block:: c
> > > > > +
> > > > > + __attribute__((always_inline))
> > > > > +
> > > > > + This entrypoint was added in :ref:`LIBGCCJIT_ABI_26`; you can
> > > > > test for
> > > > > + its presence using
> > > > > +
> > > > > + .. code-block:: c
> > > > > +
> > > > > + #ifdef LIBGCCJIT_HAVE_ATTRIBUTES
> > > > > +
> > > > > +.. function:: void\
> > > > > + gcc_jit_function_add_string_attribute
> > > > > (gcc_jit_function *func,
> > > > > + enum
> > > > > gcc_jit_fn_attribute attribute,
> > > > > + const char
> > > > > *value)
> > > > > +
> > > > > + Add a string attribute ``attribute`` with value ``value``
> > > > > to a function
> > > > > + ``func``.
> > > > > +
> > > > > + This is equivalent to the following code:
> > > > > +
> > > > > + .. code-block:: c
> > > > > +
> > > > > + __attribute__ ((alias ("xxx")))
> > > > > +
> > > > > + This entrypoint was added in :ref:`LIBGCCJIT_ABI_26`; you can
> > > > > test for
> > > > > + its presence using
> > > > > +
> > > > > + .. code-block:: c
> > > > > +
> > > > > + #ifdef LIBGCCJIT_HAVE_ATTRIBUTES
> > > > > +
> > > > > +.. function:: void\
> > > > > + gcc_jit_function_add_integer_array_attribute
> > > > > (gcc_jit_function *func,
> > > > > +
> > > > > enum gcc_jit_fn_attribute attribute,
> > > > > +
> > > > > const int *value,
> > > > > +
> > > > > size_t length)
> > > > > +
> > > > > + Add an attribute ``attribute`` with ``length`` integer
> > > > > values ``value`` to a
> > > > > + function ``func``. The integer values must be the same as
> > > > > you would write
> > > > > + them in a C code.
> > > > > +
> > > > > + This is equivalent to the following code:
> > > > > +
> > > > > + .. code-block:: c
> > > > > +
> > > > > + __attribute__ ((nonnull (1, 2)))
> > > > > +
> > > > > + This entrypoint was added in :ref:`LIBGCCJIT_ABI_26`; you can
> > > > > test for
> > > > > + its presence using
> > > > > +
> > > > > + .. code-block:: c
> > > > > +
> > > > > + #ifdef LIBGCCJIT_HAVE_ATTRIBUTES
> > > > > +
> > > > > +.. function:: void\
> > > > > + gcc_jit_lvalue_add_string_attribute
> > > > > (gcc_jit_lvalue *variable,
> > > > > + enum
> > > > > gcc_jit_variable_attribute attribute,
> > > > > + const char
> > > > > *value)
> > > > > +
> > > > > + Add an attribute ``attribute`` with value ``value`` to a
> > > > > variable ``variable``.
> > > > > +
> > > > > + This entrypoint was added in :ref:`LIBGCCJIT_ABI_26`; you can
> > > > > test for
> > > > > + its presence using
> > > > > +
> > > > > + .. code-block:: c
> > > > > +
> > > > > + #ifdef LIBGCCJIT_HAVE_ATTRIBUTES
> > > >
> > > > The above looks correct, but the patch adds the entrypoint
> > > > descriptions
> > > > to topics/types.rst, which seems like the wrong place. The
> > > > function-
> > > > related ones should be in topics/functions.rst in the "Functions"
> > > > section and the lvalue/variable one in topics/expression.rst after
> > > > the
> > > > "Global variables" section.
> > > >
> > > > > diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h
> > > > b/gcc/testsuite/jit.dg/all-non-failing-tests.h
> > > > > index e762563f9bd..84001203352 100644
> > > > > --- a/gcc/testsuite/jit.dg/all-non-failing-tests.h
> > > > > +++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h
> > > >
> > > > [...snip...]
> > > >
> > > > > @@ -313,7 +334,7 @@
> > > > > #undef create_code
> > > > > #undef verify_code
> > > > >
> > > > > -/* test-restrict.c: This can't be in the testcases array as it
> > > > > needs
> > > > > +/* test-restrict-attribute.c: This can't be in the testcases
> > > > > array as it needs
> > > > > the `-O3` flag. */
> > > >
> > > > test-restrict.c is a pre-existing testcase, so please don't delete
> > > > its
> > > > entry.
> > > > BTW, the ChangeLog entry mentions adding test-restrict.c, but the
> > > > patch
> > > > doesn't add it, so that part of the proposed ChangeLog is wrong.
> > > >
> > > > Does the patch pass ./contrib/gcc-changelog/git_check_commit.py ?
> > > >
> > > > [...snip...]
> > > >
> > > > > diff --git a/gcc/testsuite/jit.dg/test-cold-attribute.c
> > > > > b/gcc/testsuite/jit.dg/test-cold-attribute.c
> > > > > new file mode 100644
> > > > > index 00000000000..8dc7ec5a34b
> > > > > --- /dev/null
> > > > > +++ b/gcc/testsuite/jit.dg/test-cold-attribute.c
> > > > > @@ -0,0 +1,54 @@
> > > > > +/* { dg-do compile { target x86_64-*-* } } */
> > > > > +
> > > > > +#include <stdlib.h>
> > > > > +#include <stdio.h>
> > > > > +
> > > > > +#include "libgccjit.h"
> > > > > +
> > > > > +/* We don't want set_options() in harness.h to set -O2 to see
> > > > > that the cold
> > > > > + attribute affects the optimizations. */
> > > >
> > > > Please delete the above comment.
> > > >
> > > > > +#define TEST_ESCHEWS_SET_OPTIONS
> > > > > +static void set_options (gcc_jit_context *ctxt, const char
> > > > > *argv0)
> > > > > +{
> > > > > + // Set "-O2".
> > > > > + gcc_jit_context_set_int_option(ctxt,
> > > > > GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 2);
> > > > > +}
> > > >
> > > > [...snip...]
> > > >
> > > > > diff --git a/gcc/testsuite/jit.dg/test-const-attribute.c
> > > > > b/gcc/testsuite/jit.dg/test-const-attribute.c
> > > > > new file mode 100644
> > > > > index 00000000000..c06742d163f
> > > > > --- /dev/null
> > > > > +++ b/gcc/testsuite/jit.dg/test-const-attribute.c
> > > > > @@ -0,0 +1,134 @@
> > > > > +/* { dg-do compile { target x86_64-*-* } } */
> > > > > +
> > > > > +#include <stdlib.h>
> > > > > +#include <stdio.h>
> > > > > +
> > > > > +#include "libgccjit.h"
> > > > > +
> > > > > +/* We don't want set_options() in harness.h to set -O3 to see
> > > > > that the const
> > > > > + attribute affects the optimizations. */
> > > >
> > > > Please delete the above comment.
> > > >
> > > > > +#define TEST_ESCHEWS_SET_OPTIONS
> > > > > +static void set_options (gcc_jit_context *ctxt, const char
> > > > > *argv0)
> > > > > +{
> > > > > + // Set "-O3".
> > > > > + gcc_jit_context_set_int_option(ctxt,
> > > > > GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 3);
> > > > > +}
> > > >
> > > > [...snip...]
> > > >
> > > > > diff --git a/gcc/testsuite/jit.dg/test-noinline-attribute.c
> > > > > b/gcc/testsuite/jit.dg/test-noinline-attribute.c
> > > > > new file mode 100644
> > > > > index 00000000000..a455b4493fd
> > > > > --- /dev/null
> > > > > +++ b/gcc/testsuite/jit.dg/test-noinline-attribute.c
> > > > > @@ -0,0 +1,121 @@
> > > > > +/* { dg-do compile { target x86_64-*-* } } */
> > > > > +
> > > > > +#include <stdlib.h>
> > > > > +#include <stdio.h>
> > > > > +
> > > > > +#include "libgccjit.h"
> > > > > +
> > > > > +/* We don't want set_options() in harness.h to set -O2 to see
> > > > > that the `noinline`
> > > > > + attribute affects the optimizations. */
> > > >
> > > > Please delete the above comment.
> > > >
> > > > > +#define TEST_ESCHEWS_SET_OPTIONS
> > > > > +static void set_options (gcc_jit_context *ctxt, const char
> > > > > *argv0)
> > > > > +{
> > > > > + // Set "-O2".
> > > > > + gcc_jit_context_set_int_option(ctxt,
> > > > > GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 2);
> > > > > +}
> > > >
> > > > [...snip...]
> > > >
> > > > > diff --git a/gcc/testsuite/jit.dg/test-nonnull-attribute.c
> > > > > b/gcc/testsuite/jit.dg/test-nonnull-attribute.c
> > > > > new file mode 100644
> > > > > index 00000000000..3306f890657
> > > > > --- /dev/null
> > > > > +++ b/gcc/testsuite/jit.dg/test-nonnull-attribute.c
> > > > > @@ -0,0 +1,94 @@
> > > > > +/* { dg-do compile { target x86_64-*-* } } */
> > > > > +
> > > > > +#include <stdlib.h>
> > > > > +#include <stdio.h>
> > > > > +
> > > > > +#include "libgccjit.h"
> > > > > +
> > > > > +/* We don't want set_options() in harness.h to set -O2 to see
> > > > > that the nonnull
> > > > > + attribute affects the optimizations. */
> > > >
> > > > Please delete the above comment.
> > > >
> > > >
> > > > > +#define TEST_ESCHEWS_SET_OPTIONS
> > > > > +static void set_options (gcc_jit_context *ctxt, const char
> > > > > *argv0)
> > > > > +{
> > > > > + // Set "-O2".
> > > > > + gcc_jit_context_set_int_option(ctxt,
> > > > > GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 2);
> > > > > +}
> > > >
> > > > [...snip...]
> > > >
> > > > > diff --git a/gcc/testsuite/jit.dg/test-pure-attribute.c
> > > > > b/gcc/testsuite/jit.dg/test-pure-attribute.c
> > > > > new file mode 100644
> > > > > index 00000000000..0c9ba1366e0
> > > > > --- /dev/null
> > > > > +++ b/gcc/testsuite/jit.dg/test-pure-attribute.c
> > > > > @@ -0,0 +1,134 @@
> > > > > +/* { dg-do compile { target x86_64-*-* } } */
> > > > > +
> > > > > +#include <stdlib.h>
> > > > > +#include <stdio.h>
> > > > > +
> > > > > +#include "libgccjit.h"
> > > > > +
> > > > > +/* We don't want set_options() in harness.h to set -O3 to see
> > > > > that the pure
> > > > > + attribute affects the optimizations. */
> > > >
> > > > Please delete the above comment.
> > > >
> > > > > +#define TEST_ESCHEWS_SET_OPTIONS
> > > > > +static void set_options (gcc_jit_context *ctxt, const char
> > > > > *argv0)
> > > > > +{
> > > > > + // Set "-O3".
> > > > > + gcc_jit_context_set_int_option(ctxt,
> > > > > GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 3);
> > > > > +}
> > > > > +
> > > >
> > > > [...snip...]
> > > >
> > > > > diff --git a/gcc/testsuite/jit.dg/test-restrict-attribute.c
> > > > > b/gcc/testsuite/jit.dg/test-restrict-attribute.c
> > > > > new file mode 100644
> > > > > index 00000000000..7d7444b624f
> > > > > --- /dev/null
> > > > > +++ b/gcc/testsuite/jit.dg/test-restrict-attribute.c
> > > > > @@ -0,0 +1,77 @@
> > > > > +/* { dg-do compile { target x86_64-*-* } } */
> > > > > +
> > > > > +#include <stdlib.h>
> > > > > +#include <stdio.h>
> > > > > +
> > > > > +#include "libgccjit.h"
> > > > > +
> > > > > +/* We don't want set_options() in harness.h to set -O3 to see
> > > > > that the restrict
> > > > > + attribute affects the optimizations. */
> > > >
> > > > Please delete this comment.
> > > >
> > > > > +#define TEST_ESCHEWS_SET_OPTIONS
> > > > > +static void set_options (gcc_jit_context *ctxt, const char
> > > > > *argv0)
> > > > > +{
> > > > > + // Set "-O3".
> > > > > + gcc_jit_context_set_int_option(ctxt,
> > > > > GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 3);
> > > > > +}
> > > > > +
> > > >
> > > > [...snip...]
> > > >
> > > > Otherwise, looks good, assuming that the patch has been tested with
> > > > the
> > > > full jit testsuite.
> > > >
> > > > Thanks again
> > > > Dave
> > > >
> > >
> >
[-- Attachment #2: 0001-PATCH-libgccjit-Add-support-for-function-attributes-.patch --]
[-- Type: text/x-patch, Size: 95130 bytes --]
From 3849ee2eadf0eeec2b0080a5142ced00be96a60d Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Wed, 10 Jan 2024 15:23:37 +0100
Subject: [PATCH] [PATCH] libgccjit: Add support for function attributes and
variable attributes.
gcc/jit/ChangeLog:
* dummy-frontend.cc (handle_alias_attribute): New function.
(handle_always_inline_attribute): New function.
(handle_cold_attribute): New function.
(handle_fnspec_attribute): New function.
(handle_format_arg_attribute): New function.
(handle_format_attribute): New function.
(handle_noinline_attribute): New function.
(handle_target_attribute): New function.
(handle_used_attribute): New function.
(handle_visibility_attribute): New function.
(handle_weak_attribute): New function.
(handle_alias_ifunc_attribute): New function.
* jit-playback.cc (fn_attribute_to_string): New function.
(variable_attribute_to_string): New function.
(global_new_decl): Add attributes support.
(set_variable_attribute): New function.
(new_global): Add attributes support.
(new_global_initialized): Add attributes support.
(new_local): Add attributes support.
* jit-playback.h (fn_attribute_to_string): New function.
(set_variable_attribute): New function.
* jit-recording.cc (recording::lvalue::add_attribute): New function.
(recording::function::function): New function.
(recording::function::write_to_dump): Add attributes support.
(recording::function::add_attribute): New function.
(recording::function::add_string_attribute): New function.
(recording::function::add_integer_array_attribute): New function.
(recording::global::replay_into): Add attributes support.
(recording::local::replay_into): Add attributes support.
* jit-recording.h: Add attributes support.
* libgccjit.cc (gcc_jit_function_add_attribute): New function.
(gcc_jit_function_add_string_attribute): New function.
(gcc_jit_function_add_integer_array_attribute): New function.
(gcc_jit_lvalue_add_attribute): New function.
* libgccjit.h (enum gcc_jit_fn_attribute): New enum.
(gcc_jit_function_add_attribute): New function.
(gcc_jit_function_add_string_attribute): New function.
(gcc_jit_function_add_integer_array_attribute): New function.
(enum gcc_jit_variable_attribute): New function.
(gcc_jit_lvalue_add_string_attribute): New function.
* libgccjit.map: Declare new functions.
gcc/testsuite/ChangeLog:
* jit.dg/all-non-failing-tests.h: Add new attributes tests.
* jit.dg/jit.exp: Add `jit-verify-assembler-output-not` test command.
* jit.dg/test-restrict-attribute.c: New test.
* jit.dg/test-alias-attribute.c: New test.
* jit.dg/test-always_inline-attribute.c: New test.
* jit.dg/test-cold-attribute.c: New test.
* jit.dg/test-const-attribute.c: New test.
* jit.dg/test-noinline-attribute.c: New test.
* jit.dg/test-nonnull-attribute.c: New test.
* jit.dg/test-pure-attribute.c: New test.
* jit.dg/test-used-attribute.c: New test.
* jit.dg/test-variable-attribute.c: New test.
* jit.dg/test-weak-attribute.c: New test.
gcc/jit/ChangeLog:
* docs/topics/compatibility.rst: Add documentation for LIBGCCJIT_ABI_26.
* docs/topics/functions.rst: Add documentation for new functions.
* docs/topics/expressions.rst: Add documentation for new functions.
Co-authored-by: Antoni Boucher <bouanto@zoho.com>
Signed-off-by: Guillaume Gomez <guillaume1.gomez@gmail.com>
---
gcc/jit/docs/topics/compatibility.rst | 12 +
gcc/jit/docs/topics/expressions.rst | 17 +
gcc/jit/docs/topics/functions.rst | 63 +++
gcc/jit/dummy-frontend.cc | 512 ++++++++++++++++--
gcc/jit/jit-playback.cc | 169 +++++-
gcc/jit/jit-playback.h | 37 +-
gcc/jit/jit-recording.cc | 166 +++++-
gcc/jit/jit-recording.h | 22 +-
gcc/jit/libgccjit.cc | 67 +++
gcc/jit/libgccjit.h | 55 ++
gcc/jit/libgccjit.map | 8 +
gcc/testsuite/jit.dg/all-non-failing-tests.h | 33 ++
gcc/testsuite/jit.dg/jit.exp | 33 ++
gcc/testsuite/jit.dg/test-alias-attribute.c | 50 ++
.../jit.dg/test-always_inline-attribute.c | 153 ++++++
gcc/testsuite/jit.dg/test-cold-attribute.c | 52 ++
gcc/testsuite/jit.dg/test-const-attribute.c | 132 +++++
.../jit.dg/test-noinline-attribute.c | 119 ++++
gcc/testsuite/jit.dg/test-nonnull-attribute.c | 92 ++++
gcc/testsuite/jit.dg/test-pure-attribute.c | 132 +++++
.../jit.dg/test-restrict-attribute.c | 75 +++
gcc/testsuite/jit.dg/test-used-attribute.c | 112 ++++
.../jit.dg/test-variable-attribute.c | 46 ++
gcc/testsuite/jit.dg/test-weak-attribute.c | 41 ++
24 files changed, 2125 insertions(+), 73 deletions(-)
create mode 100644 gcc/testsuite/jit.dg/test-alias-attribute.c
create mode 100644 gcc/testsuite/jit.dg/test-always_inline-attribute.c
create mode 100644 gcc/testsuite/jit.dg/test-cold-attribute.c
create mode 100644 gcc/testsuite/jit.dg/test-const-attribute.c
create mode 100644 gcc/testsuite/jit.dg/test-noinline-attribute.c
create mode 100644 gcc/testsuite/jit.dg/test-nonnull-attribute.c
create mode 100644 gcc/testsuite/jit.dg/test-pure-attribute.c
create mode 100644 gcc/testsuite/jit.dg/test-restrict-attribute.c
create mode 100644 gcc/testsuite/jit.dg/test-used-attribute.c
create mode 100644 gcc/testsuite/jit.dg/test-variable-attribute.c
create mode 100644 gcc/testsuite/jit.dg/test-weak-attribute.c
diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst
index 704de1b51ed..cbf5b414d8c 100644
--- a/gcc/jit/docs/topics/compatibility.rst
+++ b/gcc/jit/docs/topics/compatibility.rst
@@ -378,3 +378,15 @@ alignment of a variable:
--------------------
``LIBGCCJIT_ABI_25`` covers the addition of
:func:`gcc_jit_type_get_restrict`
+
+.. _LIBGCCJIT_ABI_26:
+
+``LIBGCCJIT_ABI_26``
+--------------------
+``LIBGCCJIT_ABI_26`` covers the addition of functions to set attributes
+on functions and variables:
+
+ * :func:`gcc_jit_function_add_attribute`
+ * :func:`gcc_jit_function_add_string_attribute`
+ * :func:`gcc_jit_function_add_integer_array_attribute`
+ * :func:`gcc_jit_lvalue_add_string_attribute`
diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst
index cee6a308582..35ee05ca597 100644
--- a/gcc/jit/docs/topics/expressions.rst
+++ b/gcc/jit/docs/topics/expressions.rst
@@ -944,6 +944,23 @@ Global variables
#ifdef LIBGCCJIT_HAVE_CTORS
+Variables
+*********
+
+.. function:: void\
+ gcc_jit_lvalue_add_string_attribute (gcc_jit_lvalue *variable,
+ enum gcc_jit_variable_attribute attribute,
+ const char *value)
+
+ Add an attribute ``attribute`` with value ``value`` to a variable ``variable``.
+
+ This entrypoint was added in :ref:`LIBGCCJIT_ABI_26`; you can test for
+ its presence using
+
+ .. code-block:: c
+
+ #ifdef LIBGCCJIT_HAVE_ATTRIBUTES
+
Working with pointers, structs and unions
-----------------------------------------
diff --git a/gcc/jit/docs/topics/functions.rst b/gcc/jit/docs/topics/functions.rst
index 127bc0e56cf..804605ea939 100644
--- a/gcc/jit/docs/topics/functions.rst
+++ b/gcc/jit/docs/topics/functions.rst
@@ -197,6 +197,69 @@ Functions
.. type:: gcc_jit_case
+.. function:: void\
+ gcc_jit_function_add_attribute (gcc_jit_function *func,
+ enum gcc_jit_fn_attribute attribute)
+
+ Add an attribute ``attribute`` to a function ``func``.
+
+ This is equivalent to the following code:
+
+ .. code-block:: c
+
+ __attribute__((always_inline))
+
+ This entrypoint was added in :ref:`LIBGCCJIT_ABI_26`; you can test for
+ its presence using
+
+ .. code-block:: c
+
+ #ifdef LIBGCCJIT_HAVE_ATTRIBUTES
+
+.. function:: void\
+ gcc_jit_function_add_string_attribute (gcc_jit_function *func,
+ enum gcc_jit_fn_attribute attribute,
+ const char *value)
+
+ Add a string attribute ``attribute`` with value ``value`` to a function
+ ``func``.
+
+ This is equivalent to the following code:
+
+ .. code-block:: c
+
+ __attribute__ ((alias ("xxx")))
+
+ This entrypoint was added in :ref:`LIBGCCJIT_ABI_26`; you can test for
+ its presence using
+
+ .. code-block:: c
+
+ #ifdef LIBGCCJIT_HAVE_ATTRIBUTES
+
+.. function:: void\
+ gcc_jit_function_add_integer_array_attribute (gcc_jit_function *func,
+ enum gcc_jit_fn_attribute attribute,
+ const int *value,
+ size_t length)
+
+ Add an attribute ``attribute`` with ``length`` integer values ``value`` to a
+ function ``func``. The integer values must be the same as you would write
+ them in a C code.
+
+ This is equivalent to the following code:
+
+ .. code-block:: c
+
+ __attribute__ ((nonnull (1, 2)))
+
+ This entrypoint was added in :ref:`LIBGCCJIT_ABI_26`; you can test for
+ its presence using
+
+ .. code-block:: c
+
+ #ifdef LIBGCCJIT_HAVE_ATTRIBUTES
+
Blocks
------
.. type:: gcc_jit_block
diff --git a/gcc/jit/dummy-frontend.cc b/gcc/jit/dummy-frontend.cc
index 211f1be98fa..dbeeacd17a8 100644
--- a/gcc/jit/dummy-frontend.cc
+++ b/gcc/jit/dummy-frontend.cc
@@ -29,30 +29,42 @@ along with GCC; see the file COPYING3. If not see
#include "options.h"
#include "stringpool.h"
#include "attribs.h"
+#include "cgraph.h"
+#include "target.h"
#include <mpfr.h>
/* Attribute handling. */
-static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *);
-static tree handle_leaf_attribute (tree *, tree, tree, int, bool *);
+static tree handle_alias_attribute (tree *, tree, tree, int, bool *);
+static tree handle_always_inline_attribute (tree *, tree, tree, int,
+ bool *);
+static tree handle_cold_attribute (tree *, tree, tree, int, bool *);
static tree handle_const_attribute (tree *, tree, tree, int, bool *);
+static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *);
+static tree handle_format_arg_attribute (tree *, tree, tree, int, bool *);
+static tree handle_format_attribute (tree *, tree, tree, int, bool *);
+static tree handle_leaf_attribute (tree *, tree, tree, int, bool *);
static tree handle_malloc_attribute (tree *, tree, tree, int, bool *);
-static tree handle_pure_attribute (tree *, tree, tree, int, bool *);
-static tree handle_novops_attribute (tree *, tree, tree, int, bool *);
+static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *);
+static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *);
static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *);
-static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *);
-static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *);
-static tree handle_transaction_pure_attribute (tree *, tree, tree, int, bool *);
-static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *);
+static tree handle_novops_attribute (tree *, tree, tree, int, bool *);
static tree handle_patchable_function_entry_attribute (tree *, tree, tree,
int, bool *);
-static tree ignore_attribute (tree *, tree, tree, int, bool *);
+static tree handle_pure_attribute (tree *, tree, tree, int, bool *);
+static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *);
+static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *);
+static tree handle_target_attribute (tree *, tree, tree, int, bool *);
+static tree handle_transaction_pure_attribute (tree *, tree, tree, int, bool *);
+static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *);
+static tree handle_used_attribute (tree *, tree, tree, int, bool *);
+static tree handle_visibility_attribute (tree *, tree, tree, int,
+ bool *);
+static tree handle_weak_attribute (tree *, tree, tree, int, bool *) ;
-static tree handle_format_attribute (tree *, tree, tree, int, bool *);
-static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *);
-static tree handle_format_arg_attribute (tree *, tree, tree, int, bool *);
+static tree ignore_attribute (tree *, tree, tree, int, bool *);
/* Helper to define attribute exclusions. */
#define ATTR_EXCL(name, function, type, variable) \
@@ -61,7 +73,6 @@ static tree handle_format_arg_attribute (tree *, tree, tree, int, bool *);
/* Define attributes that are mutually exclusive with one another. */
static const struct attribute_spec::exclusions attr_noreturn_exclusions[] =
{
- ATTR_EXCL ("noreturn", true, true, true),
ATTR_EXCL ("alloc_align", true, true, true),
ATTR_EXCL ("alloc_size", true, true, true),
ATTR_EXCL ("const", true, true, true),
@@ -78,57 +89,117 @@ static const struct attribute_spec::exclusions attr_returns_twice_exclusions[] =
ATTR_EXCL (NULL, false, false, false),
};
+/* Exclusions that apply to attribute alloc_align, alloc_size, and malloc. */
+static const struct attribute_spec::exclusions attr_alloc_exclusions[] =
+{
+ ATTR_EXCL ("const", true, true, true),
+ ATTR_EXCL ("noreturn", true, true, true),
+ ATTR_EXCL ("pure", true, true, true),
+ ATTR_EXCL (NULL, false, false, false),
+};
+
static const struct attribute_spec::exclusions attr_const_pure_exclusions[] =
{
ATTR_EXCL ("const", true, true, true),
+ ATTR_EXCL ("alloc_align", true, true, true),
+ ATTR_EXCL ("alloc_size", true, true, true),
+ ATTR_EXCL ("malloc", true, true, true),
ATTR_EXCL ("noreturn", true, true, true),
ATTR_EXCL ("pure", true, true, true),
ATTR_EXCL (NULL, false, false, false)
};
+static const struct attribute_spec::exclusions attr_always_inline_exclusions[] =
+{
+ ATTR_EXCL ("noinline", true, true, true),
+ ATTR_EXCL ("target_clones", true, true, true),
+ ATTR_EXCL (NULL, false, false, false),
+};
+
+extern const struct attribute_spec::exclusions attr_cold_hot_exclusions[] =
+{
+ ATTR_EXCL ("cold", true, true, true),
+ ATTR_EXCL ("hot", true, true, true),
+ ATTR_EXCL (NULL, false, false, false)
+};
+
+static const struct attribute_spec::exclusions attr_noinline_exclusions[] =
+{
+ ATTR_EXCL ("always_inline", true, true, true),
+ ATTR_EXCL ("gnu_inline", true, true, true),
+ ATTR_EXCL (NULL, false, false, false),
+};
+
+static const struct attribute_spec::exclusions attr_target_exclusions[] =
+{
+ ATTR_EXCL ("target_clones", TARGET_HAS_FMV_TARGET_ATTRIBUTE,
+ TARGET_HAS_FMV_TARGET_ATTRIBUTE, TARGET_HAS_FMV_TARGET_ATTRIBUTE),
+ ATTR_EXCL (NULL, false, false, false),
+};
+
/* Table of machine-independent attributes supported in libgccjit. */
static const attribute_spec jit_gnu_attributes[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req,
affects_type_identity, handler, exclude } */
- { "noreturn", 0, 0, true, false, false, false,
- handle_noreturn_attribute,
- attr_noreturn_exclusions },
- { "leaf", 0, 0, true, false, false, false,
- handle_leaf_attribute, NULL },
+ { "alias", 1, 1, true, false, false, false,
+ handle_alias_attribute, NULL },
+ { "always_inline", 0, 0, true, false, false, false,
+ handle_always_inline_attribute,
+ attr_always_inline_exclusions },
+ { "cold", 0, 0, true, false, false, false,
+ handle_cold_attribute,
+ attr_cold_hot_exclusions },
/* The same comments as for noreturn attributes apply to const ones. */
- { "const", 0, 0, true, false, false, false,
+ { "const", 0, 0, true, false, false, false,
handle_const_attribute,
attr_const_pure_exclusions },
- { "malloc", 0, 0, true, false, false, false,
- handle_malloc_attribute, NULL },
- { "pure", 0, 0, true, false, false, false,
- handle_pure_attribute,
- attr_const_pure_exclusions },
- { "no vops", 0, 0, true, false, false, false,
+ { "fn spec", 1, 1, false, true, true, false,
+ handle_fnspec_attribute, NULL },
+
+ { "leaf", 0, 0, true, false, false, false,
+ handle_leaf_attribute, NULL },
+ { "malloc", 0, 0, true, false, false, false,
+ handle_malloc_attribute, attr_alloc_exclusions },
+ { "noreturn", 0, 0, true, false, false, false,
+ handle_noreturn_attribute,
+ attr_noreturn_exclusions },
+ { "no vops", 0, 0, true, false, false, false,
handle_novops_attribute, NULL },
- { "nonnull", 0, -1, false, true, true, false,
+ { "noinline", 0, 0, true, false, false, false,
+ handle_noinline_attribute,
+ attr_noinline_exclusions },
+ { "nonnull", 0, -1, false, true, true, false,
handle_nonnull_attribute, NULL },
- { "nothrow", 0, 0, true, false, false, false,
+ { "nothrow", 0, 0, true, false, false, false,
handle_nothrow_attribute, NULL },
{ "patchable_function_entry", 1, 2, true, false, false, false,
handle_patchable_function_entry_attribute,
NULL },
- { "returns_twice", 0, 0, true, false, false, false,
+ { "pure", 0, 0, true, false, false, false,
+ handle_pure_attribute,
+ attr_const_pure_exclusions },
+ { "returns_twice", 0, 0, true, false, false, false,
handle_returns_twice_attribute,
attr_returns_twice_exclusions },
- { "sentinel", 0, 1, false, true, true, false,
+ { "sentinel", 0, 1, false, true, true, false,
handle_sentinel_attribute, NULL },
- { "type generic", 0, 0, false, true, true, false,
+ { "target", 1, -1, true, false, false, false,
+ handle_target_attribute, attr_target_exclusions },
+ { "type generic", 0, 0, false, true, true, false,
handle_type_generic_attribute, NULL },
- { "fn spec", 1, 1, false, true, true, false,
- handle_fnspec_attribute, NULL },
{ "transaction_pure", 0, 0, false, true, true, false,
handle_transaction_pure_attribute, NULL },
+ { "used", 0, 0, true, false, false, false,
+ handle_used_attribute, NULL },
+ { "visibility", 1, 1, false, false, false, false,
+ handle_visibility_attribute, NULL },
+ { "weak", 0, 0, true, false, false, false,
+ handle_weak_attribute, NULL },
/* For internal use only. The leading '*' both prevents its usage in
source code and signals that it may be overridden by machine tables. */
{ "*tm regparm", 0, 0, false, true, true, false,
- ignore_attribute, NULL }
+ ignore_attribute, NULL },
};
static const scoped_attribute_specs jit_gnu_attribute_table =
@@ -143,7 +214,7 @@ static const attribute_spec jit_format_attributes[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req,
affects_type_identity, handler, exclude } */
- { "format", 3, 3, false, true, true, false,
+ { "format", 3, 3, false, true, true, false,
handle_format_attribute, NULL },
{ "format_arg", 1, 1, false, true, true, false,
handle_format_arg_attribute, NULL }
@@ -212,14 +283,9 @@ handle_leaf_attribute (tree *node, tree name,
struct attribute_spec.handler. */
static tree
-handle_const_attribute (tree *node, tree ARG_UNUSED (name),
- tree ARG_UNUSED (args), int ARG_UNUSED (flags),
- bool * ARG_UNUSED (no_add_attrs))
+handle_const_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
- if (TREE_CODE (*node) != FUNCTION_DECL
- || !fndecl_built_in_p (*node))
- inform (UNKNOWN_LOCATION, "%s:%s: %E: %E", __FILE__, __func__, *node, name);
-
tree type = TREE_TYPE (*node);
/* See FIXME comment on noreturn in c_common_attribute_table. */
@@ -228,11 +294,16 @@ handle_const_attribute (tree *node, tree ARG_UNUSED (name),
else if (TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
TREE_TYPE (*node)
- = build_pointer_type
- (build_type_variant (TREE_TYPE (type), 1,
- TREE_THIS_VOLATILE (TREE_TYPE (type))));
+ = (build_qualified_type
+ (build_pointer_type
+ (build_type_variant (TREE_TYPE (type), 1,
+ TREE_THIS_VOLATILE (TREE_TYPE (type)))),
+ TYPE_QUALS (type)));
else
- gcc_unreachable ();
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
return NULL_TREE;
}
@@ -494,6 +565,357 @@ handle_fnspec_attribute (tree *node ATTRIBUTE_UNUSED, tree ARG_UNUSED (name),
return NULL_TREE;
}
+/* Handle an "visibility" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_visibility_attribute (tree *node, tree name, tree args,
+ int ARG_UNUSED (flags),
+ bool *ARG_UNUSED (no_add_attrs))
+{
+ tree decl = *node;
+ tree id = TREE_VALUE (args);
+ enum symbol_visibility vis;
+
+ if (TYPE_P (*node))
+ {
+ if (TREE_CODE (*node) == ENUMERAL_TYPE)
+ /* OK. */;
+ else if (!RECORD_OR_UNION_TYPE_P (*node))
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored on non-class types",
+ name);
+ return NULL_TREE;
+ }
+ else if (TYPE_FIELDS (*node))
+ {
+ error ("%qE attribute ignored because %qT is already defined",
+ name, *node);
+ return NULL_TREE;
+ }
+ }
+ else if (decl_function_context (decl) != 0 || !TREE_PUBLIC (decl))
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ return NULL_TREE;
+ }
+
+ if (TREE_CODE (id) != STRING_CST)
+ {
+ error ("visibility argument not a string");
+ return NULL_TREE;
+ }
+
+ /* If this is a type, set the visibility on the type decl. */
+ if (TYPE_P (decl))
+ {
+ decl = TYPE_NAME (decl);
+ if (!decl)
+ return NULL_TREE;
+ if (TREE_CODE (decl) == IDENTIFIER_NODE)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored on types",
+ name);
+ return NULL_TREE;
+ }
+ }
+
+ if (strcmp (TREE_STRING_POINTER (id), "default") == 0)
+ vis = VISIBILITY_DEFAULT;
+ else if (strcmp (TREE_STRING_POINTER (id), "internal") == 0)
+ vis = VISIBILITY_INTERNAL;
+ else if (strcmp (TREE_STRING_POINTER (id), "hidden") == 0)
+ vis = VISIBILITY_HIDDEN;
+ else if (strcmp (TREE_STRING_POINTER (id), "protected") == 0)
+ vis = VISIBILITY_PROTECTED;
+ else
+ {
+ error ("attribute %qE argument must be one of %qs, %qs, %qs, or %qs",
+ name, "default", "hidden", "protected", "internal");
+ vis = VISIBILITY_DEFAULT;
+ }
+
+ if (DECL_VISIBILITY_SPECIFIED (decl)
+ && vis != DECL_VISIBILITY (decl))
+ {
+ tree attributes = (TYPE_P (*node)
+ ? TYPE_ATTRIBUTES (*node)
+ : DECL_ATTRIBUTES (decl));
+ if (lookup_attribute ("visibility", attributes))
+ error ("%qD redeclared with different visibility", decl);
+ else if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
+ && lookup_attribute ("dllimport", attributes))
+ error ("%qD was declared %qs which implies default visibility",
+ decl, "dllimport");
+ else if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
+ && lookup_attribute ("dllexport", attributes))
+ error ("%qD was declared %qs which implies default visibility",
+ decl, "dllexport");
+ }
+
+ DECL_VISIBILITY (decl) = vis;
+ DECL_VISIBILITY_SPECIFIED (decl) = 1;
+
+ /* Go ahead and attach the attribute to the node as well. This is needed
+ so we can determine whether we have VISIBILITY_DEFAULT because the
+ visibility was not specified, or because it was explicitly overridden
+ from the containing scope. */
+
+ return NULL_TREE;
+}
+
+/* Handle a "always_inline" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_always_inline_attribute (tree *node, tree name,
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags),
+ bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) == FUNCTION_DECL)
+ {
+ /* Set the attribute and mark it for disregarding inline
+ limits. */
+ DECL_DISREGARD_INLINE_LIMITS (*node) = 1;
+ }
+ else
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "cold" and attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_cold_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) == FUNCTION_DECL
+ || TREE_CODE (*node) == LABEL_DECL)
+ {
+ /* Attribute cold processing is done later with lookup_attribute. */
+ }
+ else
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "noinline" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_noinline_attribute (tree *node, tree name,
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) == FUNCTION_DECL)
+ DECL_UNINLINABLE (*node) = 1;
+ else
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "weak" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_weak_attribute (tree *node, tree name,
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags),
+ bool * ARG_UNUSED (no_add_attrs))
+{
+ if (TREE_CODE (*node) == FUNCTION_DECL
+ && DECL_DECLARED_INLINE_P (*node))
+ {
+ warning (OPT_Wattributes, "inline function %q+D declared weak", *node);
+ *no_add_attrs = true;
+ }
+ else if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (*node)))
+ {
+ error ("indirect function %q+D cannot be declared weak", *node);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ else if (VAR_OR_FUNCTION_DECL_P (*node))
+ declare_weak (*node);
+ else
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+
+ return NULL_TREE;
+}
+
+/* Handle a "target" attribute. */
+
+static tree
+handle_target_attribute (tree *node, tree name, tree args, int flags,
+ bool *no_add_attrs)
+{
+ /* Ensure we have a function declaration. */
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+ else if (! targetm.target_option.valid_attribute_p (*node, name, args,
+ flags))
+ *no_add_attrs = true;
+
+ /* Check that there's no empty string in values of the attribute. */
+ for (tree t = args; t != NULL_TREE; t = TREE_CHAIN (t))
+ {
+ tree value = TREE_VALUE (t);
+ if (TREE_CODE (value) == STRING_CST
+ && TREE_STRING_LENGTH (value) == 1
+ && TREE_STRING_POINTER (value)[0] == '\0')
+ {
+ warning (OPT_Wattributes, "empty string in attribute %<target%>");
+ *no_add_attrs = true;
+ }
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "used" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_used_attribute (tree *pnode, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ tree node = *pnode;
+
+ if (TREE_CODE (node) == FUNCTION_DECL
+ || (VAR_P (node) && TREE_STATIC (node))
+ || (TREE_CODE (node) == TYPE_DECL))
+ {
+ TREE_USED (node) = 1;
+ DECL_PRESERVE_P (node) = 1;
+ if (VAR_P (node))
+ DECL_READ_P (node) = 1;
+ }
+ else
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle an "alias" or "ifunc" attribute; arguments as in
+ struct attribute_spec.handler, except that IS_ALIAS tells us
+ whether this is an alias as opposed to ifunc attribute. */
+
+static tree
+handle_alias_ifunc_attribute (bool is_alias, tree *node, tree name, tree args,
+ bool *no_add_attrs)
+{
+ tree decl = *node;
+
+ if (TREE_CODE (decl) != FUNCTION_DECL
+ && (!is_alias || !VAR_P (decl)))
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+ else if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl))
+ || (TREE_CODE (decl) != FUNCTION_DECL
+ && TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl))
+ /* A static variable declaration is always a tentative definition,
+ but the alias is a non-tentative definition which overrides. */
+ || (TREE_CODE (decl) != FUNCTION_DECL
+ && ! TREE_PUBLIC (decl) && DECL_INITIAL (decl)))
+ {
+ error ("%q+D defined both normally and as %qE attribute", decl, name);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ else if (!is_alias
+ && (lookup_attribute ("weak", DECL_ATTRIBUTES (decl))
+ || lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))))
+ {
+ error ("weak %q+D cannot be defined %qE", decl, name);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ /* Note that the very first time we process a nested declaration,
+ decl_function_context will not be set. Indeed, *would* never
+ be set except for the DECL_INITIAL/DECL_EXTERNAL frobbery that
+ we do below. After such frobbery, pushdecl would set the context.
+ In any case, this is never what we want. */
+ else if (decl_function_context (decl) == 0 && current_function_decl == NULL)
+ {
+ tree id;
+
+ id = TREE_VALUE (args);
+ if (TREE_CODE (id) != STRING_CST)
+ {
+ error ("attribute %qE argument not a string", name);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ id = get_identifier (TREE_STRING_POINTER (id));
+ /* This counts as a use of the object pointed to. */
+ TREE_USED (id) = 1;
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ DECL_INITIAL (decl) = error_mark_node;
+ else
+ TREE_STATIC (decl) = 1;
+
+ if (!is_alias)
+ {
+ /* ifuncs are also aliases, so set that attribute too. */
+ DECL_ATTRIBUTES (decl)
+ = tree_cons (get_identifier ("alias"), args,
+ DECL_ATTRIBUTES (decl));
+ DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("ifunc"),
+ NULL, DECL_ATTRIBUTES (decl));
+ }
+ }
+ else
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ if (decl_in_symtab_p (*node))
+ {
+ struct symtab_node *n = symtab_node::get (decl);
+ if (n && n->refuse_visibility_changes)
+ error ("%+qD declared %qs after being used",
+ decl, is_alias ? "alias" : "ifunc");
+ }
+
+
+ return NULL_TREE;
+}
+
+/* Handle an "alias" or "ifunc" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_alias_attribute (tree *node, tree name, tree args,
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ return handle_alias_ifunc_attribute (true, node, name, args, no_add_attrs);
+}
+
/* (end of attribute-handling). */
/* Language-dependent contents of a type. */
diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc
index f87351eaf82..84df6c100e6 100644
--- a/gcc/jit/jit-playback.cc
+++ b/gcc/jit/jit-playback.cc
@@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
#include "config.h"
#define INCLUDE_MUTEX
+#include "libgccjit.h"
#include "system.h"
#include "coretypes.h"
#include "target.h"
@@ -499,6 +500,54 @@ new_param (location *loc,
return new param (this, inner);
}
+const char* fn_attribute_to_string (gcc_jit_fn_attribute attr)
+{
+ switch (attr)
+ {
+ case GCC_JIT_FN_ATTRIBUTE_ALIAS:
+ return "alias";
+ case GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE:
+ return "always_inline";
+ case GCC_JIT_FN_ATTRIBUTE_INLINE:
+ return NULL;
+ case GCC_JIT_FN_ATTRIBUTE_NOINLINE:
+ return "noinline";
+ case GCC_JIT_FN_ATTRIBUTE_TARGET:
+ return "target";
+ case GCC_JIT_FN_ATTRIBUTE_USED:
+ return "used";
+ case GCC_JIT_FN_ATTRIBUTE_VISIBILITY:
+ return "visibility";
+ case GCC_JIT_FN_ATTRIBUTE_COLD:
+ return "cold";
+ case GCC_JIT_FN_ATTRIBUTE_RETURNS_TWICE:
+ return "returns_twice";
+ case GCC_JIT_FN_ATTRIBUTE_PURE:
+ return "pure";
+ case GCC_JIT_FN_ATTRIBUTE_CONST:
+ return "const";
+ case GCC_JIT_FN_ATTRIBUTE_WEAK:
+ return "weak";
+ case GCC_JIT_FN_ATTRIBUTE_NONNULL:
+ return "nonnull";
+ case GCC_JIT_FN_ATTRIBUTE_MAX:
+ return NULL;
+ }
+ return NULL;
+}
+
+const char* variable_attribute_to_string (gcc_jit_variable_attribute attr)
+{
+ switch (attr)
+ {
+ case GCC_JIT_VARIABLE_ATTRIBUTE_VISIBILITY:
+ return "visibility";
+ case GCC_JIT_VARIABLE_ATTRIBUTE_MAX:
+ return NULL;
+ }
+ return NULL;
+}
+
/* Construct a playback::function instance. */
playback::function *
@@ -509,7 +558,13 @@ new_function (location *loc,
const char *name,
const auto_vec<param *> *params,
int is_variadic,
- enum built_in_function builtin_id)
+ enum built_in_function builtin_id,
+ const std::vector<gcc_jit_fn_attribute> &attributes,
+ const std::vector<std::pair<gcc_jit_fn_attribute,
+ std::string>> &string_attributes,
+ const std::vector<std::pair<gcc_jit_fn_attribute,
+ std::vector<int>>>
+ &int_array_attributes)
{
int i;
param *param;
@@ -543,6 +598,8 @@ new_function (location *loc,
DECL_RESULT (fndecl) = resdecl;
DECL_CONTEXT (resdecl) = fndecl;
+ tree fn_attributes = NULL_TREE;
+
if (builtin_id)
{
gcc_assert (loc == NULL);
@@ -588,12 +645,62 @@ new_function (location *loc,
DECL_DECLARED_INLINE_P (fndecl) = 1;
/* Add attribute "always_inline": */
- DECL_ATTRIBUTES (fndecl) =
- tree_cons (get_identifier ("always_inline"),
- NULL,
- DECL_ATTRIBUTES (fndecl));
+ fn_attributes = tree_cons (get_identifier ("always_inline"),
+ NULL,
+ fn_attributes);
}
+ /* All attributes need to be declared in `dummy-frontend.cc` and more
+ specifically in `jit_attribute_table`. */
+ for (auto attr: attributes)
+ {
+ if (attr == GCC_JIT_FN_ATTRIBUTE_INLINE)
+ DECL_DECLARED_INLINE_P (fndecl) = 1;
+
+ const char* attribute = fn_attribute_to_string (attr);
+ if (attribute)
+ {
+ tree ident = get_identifier (attribute);
+ fn_attributes = tree_cons (ident, NULL_TREE, fn_attributes);
+ }
+ }
+
+ for (auto attr: string_attributes)
+ {
+ gcc_jit_fn_attribute& name = std::get<0>(attr);
+ std::string& value = std::get<1>(attr);
+ tree attribute_value = build_tree_list (NULL_TREE,
+ ::build_string (value.length () + 1, value.c_str ()));
+ const char* attribute = fn_attribute_to_string (name);
+ tree ident = attribute ? get_identifier (attribute) : NULL;
+
+ if (ident)
+ fn_attributes = tree_cons (ident, attribute_value, fn_attributes);
+ }
+
+ for (auto attr: int_array_attributes)
+ {
+ gcc_jit_fn_attribute& name = std::get<0>(attr);
+ std::vector<int>& values = std::get<1>(attr);
+
+ const char* attribute = fn_attribute_to_string (name);
+ tree ident = attribute ? get_identifier (attribute) : NULL;
+
+ if (!ident)
+ continue;
+
+ tree tree_list = NULL_TREE;
+ tree *p_tree_list = &tree_list;
+ for (auto value : values)
+ {
+ tree int_value = build_int_cst (integer_type_node, value);
+ *p_tree_list = build_tree_list (NULL, int_value);
+ p_tree_list = &TREE_CHAIN (*p_tree_list);
+ }
+ fn_attributes = tree_cons (ident, tree_list, fn_attributes);
+ }
+
+ decl_attributes (&fndecl, fn_attributes, 0);
function *func = new function (this, fndecl, kind);
m_functions.safe_push (func);
return func;
@@ -607,7 +714,9 @@ global_new_decl (location *loc,
enum gcc_jit_global_kind kind,
type *type,
const char *name,
- enum global_var_flags flags)
+ enum global_var_flags flags,
+ const std::vector<std::pair<gcc_jit_variable_attribute,
+ std::string>> &attributes)
{
gcc_assert (type);
gcc_assert (name);
@@ -652,9 +761,32 @@ global_new_decl (location *loc,
if (loc)
set_tree_location (inner, loc);
+ set_variable_string_attribute (attributes, inner);
+
return inner;
}
+void
+playback::
+set_variable_string_attribute (
+ const std::vector<std::pair<gcc_jit_variable_attribute,
+ std::string>> &string_attributes,
+ tree decl)
+{
+ tree var_attributes = NULL_TREE;
+ for (auto attr: string_attributes)
+ {
+ gcc_jit_variable_attribute& name = std::get<0>(attr);
+ std::string& value = std::get<1>(attr);
+ tree attribute_value = build_tree_list (NULL_TREE,
+ ::build_string (value.length () + 1, value.c_str ()));
+ tree ident = get_identifier (variable_attribute_to_string (name));
+ if (ident)
+ var_attributes = tree_cons (ident, attribute_value, var_attributes);
+ }
+ decl_attributes (&decl, var_attributes, 0);
+}
+
/* In use by new_global and new_global_initialized. */
playback::lvalue *
@@ -674,10 +806,12 @@ new_global (location *loc,
enum gcc_jit_global_kind kind,
type *type,
const char *name,
- enum global_var_flags flags)
+ enum global_var_flags flags,
+ const std::vector<std::pair<gcc_jit_variable_attribute,
+ std::string>> &attributes)
{
tree inner =
- global_new_decl (loc, kind, type, name, flags);
+ global_new_decl (loc, kind, type, name, flags, attributes);
return global_finalize_lvalue (inner);
}
@@ -818,13 +952,15 @@ playback::context::
new_global_initialized (location *loc,
enum gcc_jit_global_kind kind,
type *type,
- size_t element_size,
+ size_t element_size,
size_t initializer_num_elem,
const void *initializer,
const char *name,
- enum global_var_flags flags)
+ enum global_var_flags flags,
+ const std::vector<std::pair<gcc_jit_variable_attribute,
+ std::string>> &attributes)
{
- tree inner = global_new_decl (loc, kind, type, name, flags);
+ tree inner = global_new_decl (loc, kind, type, name, flags, attributes);
vec<constructor_elt, va_gc> *constructor_elements = NULL;
@@ -1812,7 +1948,9 @@ playback::lvalue *
playback::function::
new_local (location *loc,
type *type,
- const char *name)
+ const char *name,
+ const std::vector<std::pair<gcc_jit_variable_attribute,
+ std::string>> &attributes)
{
gcc_assert (type);
gcc_assert (name);
@@ -1825,6 +1963,8 @@ new_local (location *loc,
DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
BIND_EXPR_VARS (m_inner_bind_expr) = inner;
+ set_variable_string_attribute (attributes, inner);
+
if (loc)
set_tree_location (inner, loc);
return new lvalue (m_ctxt, inner);
@@ -1947,6 +2087,9 @@ postprocess ()
current_function_decl = NULL;
}
+ else
+ /* Add to cgraph to output aliases: */
+ rest_of_decl_compilation (m_inner_fndecl, true, 0);
}
/* Don't leak vec's internal buffer (in non-GC heap) when we are
@@ -3365,7 +3508,7 @@ void
playback::context::
init_types ()
{
- /* See lto_init() in lto-lang.cc or void visit (TypeBasic *t) in D's types.cc
+ /* See lto_init () in lto-lang.cc or void visit (TypeBasic *t) in D's types.cc
for reference. If TYPE_NAME is not set, debug info will not contain types */
#define NAME_TYPE(t,n) \
if (t) \
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
index 9654507a34d..05bafcd21c4 100644
--- a/gcc/jit/jit-playback.h
+++ b/gcc/jit/jit-playback.h
@@ -21,7 +21,9 @@ along with GCC; see the file COPYING3. If not see
#ifndef JIT_PLAYBACK_H
#define JIT_PLAYBACK_H
+#include <string>
#include <utility> // for std::pair
+#include <vector>
#include "timevar.h"
#include "varasm.h"
@@ -35,12 +37,21 @@ namespace gcc {
namespace jit {
+const char* fn_attribute_to_string (gcc_jit_fn_attribute attr);
+const char* variable_attribute_to_string (gcc_jit_variable_attribute attr);
+
/**********************************************************************
Playback.
**********************************************************************/
namespace playback {
+void
+set_variable_string_attribute (
+ const std::vector<std::pair<gcc_jit_variable_attribute,
+ std::string>> &attributes,
+ tree decl);
+
/* playback::context is an abstract base class.
The two concrete subclasses are:
@@ -104,14 +115,22 @@ public:
const char *name,
const auto_vec<param *> *params,
int is_variadic,
- enum built_in_function builtin_id);
+ enum built_in_function builtin_id,
+ const std::vector<gcc_jit_fn_attribute> &attributes,
+ const std::vector<std::pair<gcc_jit_fn_attribute,
+ std::string>> &string_attributes,
+ const std::vector<std::pair<gcc_jit_fn_attribute,
+ std::vector<int>>>
+ &int_array_attributes);
lvalue *
new_global (location *loc,
enum gcc_jit_global_kind kind,
type *type,
const char *name,
- enum global_var_flags flags);
+ enum global_var_flags flags,
+ const std::vector<std::pair<gcc_jit_variable_attribute,
+ std::string>> &attributes);
lvalue *
new_global_initialized (location *loc,
@@ -121,7 +140,11 @@ public:
size_t initializer_num_elem,
const void *initializer,
const char *name,
- enum global_var_flags flags);
+ enum global_var_flags flags,
+ const std::vector<std::pair<
+ gcc_jit_variable_attribute,
+ std::string>>
+ &attributes);
rvalue *
new_ctor (location *log,
@@ -306,7 +329,9 @@ private:
enum gcc_jit_global_kind kind,
type *type,
const char *name,
- enum global_var_flags flags);
+ enum global_var_flags flags,
+ const std::vector<std::pair<gcc_jit_variable_attribute,
+ std::string>> &attributes);
lvalue *
global_finalize_lvalue (tree inner);
@@ -500,7 +525,9 @@ public:
lvalue *
new_local (location *loc,
type *type,
- const char *name);
+ const char *name,
+ const std::vector<std::pair<gcc_jit_variable_attribute,
+ std::string>> &attributes);
block*
new_block (const char *name);
diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc
index 686c0587079..6ffadbea127 100644
--- a/gcc/jit/jit-recording.cc
+++ b/gcc/jit/jit-recording.cc
@@ -29,6 +29,7 @@ along with GCC; see the file COPYING3. If not see
#include "jit-builtins.h"
#include "jit-recording.h"
#include "jit-playback.h"
+#include <sstream>
namespace gcc {
namespace jit {
@@ -2068,7 +2069,7 @@ recording::memento::get_debug_string ()
void
recording::memento::write_to_dump (dump &d)
{
- d.write(" %s\n", get_debug_string ());
+ d.write (" %s\n", get_debug_string ());
}
/* The implementation of class gcc::jit::recording::string. */
@@ -4026,6 +4027,13 @@ void recording::lvalue::set_alignment (unsigned bytes)
m_alignment = bytes;
}
+void recording::lvalue::add_string_attribute (
+ gcc_jit_variable_attribute attribute,
+ const char* value)
+{
+ m_string_attributes.push_back (std::make_pair (attribute, std::string (value)));
+}
+
/* The implementation of class gcc::jit::recording::param. */
/* Implementation of pure virtual hook recording::memento::replay_into
@@ -4102,7 +4110,10 @@ recording::function::function (context *ctxt,
m_builtin_id (builtin_id),
m_locals (),
m_blocks (),
- m_fn_ptr_type (NULL)
+ m_fn_ptr_type (NULL),
+ m_attributes (),
+ m_string_attributes (),
+ m_int_array_attributes ()
{
for (int i = 0; i< num_params; i++)
{
@@ -4161,7 +4172,10 @@ recording::function::replay_into (replayer *r)
m_name->c_str (),
¶ms,
m_is_variadic,
- m_builtin_id));
+ m_builtin_id,
+ m_attributes,
+ m_string_attributes,
+ m_int_array_attributes));
}
/* Create a recording::local instance and add it to
@@ -4210,6 +4224,40 @@ recording::function::new_block (const char *name)
void
recording::function::write_to_dump (dump &d)
{
+ for (auto attr: m_attributes)
+ {
+ const char* attribute = fn_attribute_to_string (attr);
+ if (attribute)
+ d.write ("__attribute(%s)__\n", attribute);
+ }
+ for (auto attr: m_string_attributes)
+ {
+ gcc_jit_fn_attribute& name = std::get<0>(attr);
+ std::string& value = std::get<1>(attr);
+ const char* attribute = fn_attribute_to_string (name);
+
+ if (attribute)
+ d.write ("__attribute(%s(\"%s\"))__\n", attribute, value.c_str());
+ }
+ for (auto attr: m_int_array_attributes)
+ {
+ gcc_jit_fn_attribute& name = std::get<0>(attr);
+ std::vector<int>& values = std::get<1>(attr);
+ const char* attribute = fn_attribute_to_string (name);
+ if (attribute)
+ {
+ d.write ("__attribute(%s(", attribute);
+ for (size_t i = 0; i < values.size(); ++i)
+ {
+ if (i > 0)
+ d.write (", %d", values[i]);
+ else
+ d.write ("%d", values[i]);
+ }
+ d.write ("))__\n");
+ }
+ }
+
switch (m_kind)
{
default: gcc_unreachable ();
@@ -4404,6 +4452,31 @@ recording::function::get_address (recording::location *loc)
return result;
}
+void
+recording::function::add_attribute (gcc_jit_fn_attribute attribute)
+{
+ m_attributes.push_back (attribute);
+}
+
+void
+recording::function::add_string_attribute (gcc_jit_fn_attribute attribute,
+ const char* value)
+{
+ m_string_attributes.push_back (
+ std::make_pair (attribute, std::string (value)));
+}
+
+void
+recording::function::add_integer_array_attribute (
+ gcc_jit_fn_attribute attribute,
+ const int* value,
+ size_t length)
+{
+ m_int_array_attributes.push_back (std::make_pair (
+ attribute,
+ std::vector<int> (value, value + length)));
+}
+
/* Implementation of recording::memento::make_debug_string for
functions. */
@@ -4425,6 +4498,39 @@ static const char * const names_of_function_kinds[] = {
/* Implementation of recording::memento::write_reproducer for functions. */
+static const char * const fn_attribute_reproducer_strings[] =
+{
+ "GCC_JIT_FN_ATTRIBUTE_ALIAS",
+ "GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE",
+ "GCC_JIT_FN_ATTRIBUTE_INLINE",
+ "GCC_JIT_FN_ATTRIBUTE_NOINLINE",
+ "GCC_JIT_FN_ATTRIBUTE_TARGET",
+ "GCC_JIT_FN_ATTRIBUTE_USED",
+ "GCC_JIT_FN_ATTRIBUTE_VISIBILITY",
+ "GCC_JIT_FN_ATTRIBUTE_COLD",
+ "GCC_JIT_FN_ATTRIBUTE_RETURNS_TWICE",
+ "GCC_JIT_FN_ATTRIBUTE_PURE",
+ "GCC_JIT_FN_ATTRIBUTE_CONST",
+ "GCC_JIT_FN_ATTRIBUTE_WEAK",
+ "GCC_JIT_FN_ATTRIBUTE_NONNULL",
+};
+
+std::string
+get_vector_int_debug (std::vector<int> &values)
+{
+ std::stringstream s;
+
+ s << "{";
+ for(auto it = values.begin(); it != values.end(); ++it)
+ {
+ if (it != values.begin() )
+ s << ", ";
+ s << *it;
+ }
+ s << "}";
+ return s.str();
+}
+
void
recording::function::write_reproducer (reproducer &r)
{
@@ -4467,6 +4573,25 @@ recording::function::write_reproducer (reproducer &r)
m_params.length (),
params_id,
m_is_variadic);
+ for (auto attribute : m_attributes)
+ r.write(" gcc_jit_function_add_attribute (%s, %s);\n",
+ id,
+ fn_attribute_reproducer_strings[attribute]);
+ for (auto attribute : m_string_attributes)
+ r.write(" gcc_jit_function_add_string_attribute (%s, %s, \"%s\");\n",
+ id,
+ fn_attribute_reproducer_strings[std::get<0>(attribute)],
+ std::get<1>(attribute).c_str());
+ for (auto attribute : m_int_array_attributes) {
+ r.write(" gcc_jit_function_add_integer_array_attribute (%s,\n"
+ " %s,\n"
+ " (int[])%s,\n"
+ " %lu);\n",
+ id,
+ fn_attribute_reproducer_strings[std::get<0>(attribute)],
+ get_vector_int_debug (std::get<1>(attribute)).c_str(),
+ std::get<1>(attribute).size ());
+ }
}
@@ -4879,12 +5004,14 @@ recording::global::replay_into (replayer *r)
/ m_type->dereference ()->get_size (),
m_initializer,
playback_string (m_name),
- m_flags)
+ m_flags,
+ m_string_attributes)
: r->new_global (playback_location (r, m_loc),
m_kind,
m_type->playback_type (),
playback_string (m_name),
- m_flags);
+ m_flags,
+ m_string_attributes);
if (m_tls_model != GCC_JIT_TLS_MODEL_NONE)
global->set_tls_model (recording::tls_models[m_tls_model]);
@@ -4943,6 +5070,15 @@ recording::global::write_to_dump (dump &d)
break;
}
+ for (auto attr: m_string_attributes)
+ {
+ gcc_jit_variable_attribute& name = std::get<0>(attr);
+ std::string& value = std::get<1>(attr);
+ const char* attribute = variable_attribute_to_string (name);
+
+ if (attribute)
+ d.write ("__attribute(%s(\"%s\"))__\n", attribute, value.c_str());
+ }
d.write ("%s %s",
m_type->get_debug_string (),
get_debug_string ());
@@ -5013,6 +5149,10 @@ static const char * const tls_model_enum_strings[] = {
"GCC_JIT_TLS_MODEL_LOCAL_EXEC",
};
+static const char * const gcc_jit_variable_attribute_enum_strings[] = {
+ "GCC_JIT_VARIABLE_ATTRIBUTE_VISIBILITY",
+};
+
void
recording::global::write_reproducer (reproducer &r)
{
@@ -5042,6 +5182,13 @@ recording::global::write_reproducer (reproducer &r)
id,
m_link_section->c_str ());
+ for (auto attribute : m_string_attributes)
+ r.write(" gcc_jit_lvalue_add_string_attribute (%s, %s, \"%s\");\n",
+ id,
+ gcc_jit_variable_attribute_enum_strings[std::get<0>(attribute)],
+ std::get<1>(attribute).c_str());
+
+
if (m_initializer)
switch (m_type->dereference ()->get_size ())
{
@@ -6622,7 +6769,8 @@ recording::local::replay_into (replayer *r)
playback::lvalue *obj = m_func->playback_function ()
->new_local (playback_location (r, m_loc),
m_type->playback_type (),
- playback_string (m_name));
+ playback_string (m_name),
+ m_string_attributes);
if (m_reg_name != NULL)
obj->set_register_name (m_reg_name->c_str ());
@@ -6644,9 +6792,9 @@ recording::local::write_to_dump (dump &d)
{
if (d.update_locations ())
m_loc = d.make_location ();
- d.write(" %s %s;\n",
- m_type->get_debug_string (),
- get_debug_string ());
+ d.write (" %s %s;\n",
+ m_type->get_debug_string (),
+ get_debug_string ());
}
void
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index b951c715ca5..cd2e0adbe30 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -23,6 +23,10 @@ along with GCC; see the file COPYING3. If not see
#include "jit-common.h"
#include "jit-logging.h"
+#include "libgccjit.h"
+
+#include <string>
+#include <vector>
class timer;
@@ -1216,7 +1220,8 @@ public:
m_link_section (NULL),
m_reg_name (NULL),
m_tls_model (GCC_JIT_TLS_MODEL_NONE),
- m_alignment (0)
+ m_alignment (0),
+ m_string_attributes ()
{}
playback::lvalue *
@@ -1236,8 +1241,12 @@ public:
as_rvalue () { return this; }
const char *access_as_rvalue (reproducer &r) override;
+
+ void add_string_attribute (gcc_jit_variable_attribute attribute, const char* value);
+
virtual const char *access_as_lvalue (reproducer &r);
virtual bool is_global () const { return false; }
+ virtual bool is_local () const { return false; }
void set_tls_model (enum gcc_jit_tls_model model);
void set_link_section (const char *name);
void set_register_name (const char *reg_name);
@@ -1249,6 +1258,8 @@ protected:
string *m_reg_name;
enum gcc_jit_tls_model m_tls_model;
unsigned m_alignment;
+ std::vector<std::pair<gcc_jit_variable_attribute,
+ std::string>> m_string_attributes;
};
class param : public lvalue
@@ -1342,6 +1353,10 @@ public:
rvalue *get_address (location *loc);
+ void add_attribute (gcc_jit_fn_attribute attribute);
+ void add_string_attribute (gcc_jit_fn_attribute attribute, const char* value);
+ void add_integer_array_attribute (gcc_jit_fn_attribute attribute, const int* value, size_t length);
+
private:
string * make_debug_string () final override;
void write_reproducer (reproducer &r) final override;
@@ -1357,6 +1372,9 @@ private:
auto_vec<local *> m_locals;
auto_vec<block *> m_blocks;
type *m_fn_ptr_type;
+ std::vector<gcc_jit_fn_attribute> m_attributes;
+ std::vector<std::pair<gcc_jit_fn_attribute, std::string>> m_string_attributes;
+ std::vector<std::pair<gcc_jit_fn_attribute, std::vector<int>>> m_int_array_attributes;
};
class block : public memento
@@ -2086,6 +2104,8 @@ public:
void visit_children (rvalue_visitor *) final override {}
+ bool is_local () const final override { return true; }
+
void write_to_dump (dump &d) final override;
private:
diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc
index 8ecfe4aaa42..9616f3802b8 100644
--- a/gcc/jit/libgccjit.cc
+++ b/gcc/jit/libgccjit.cc
@@ -3965,6 +3965,73 @@ gcc_jit_type_get_aligned (gcc_jit_type *type,
return (gcc_jit_type *)type->get_aligned (alignment_in_bytes);
}
+void
+gcc_jit_function_add_attribute (gcc_jit_function *func,
+ gcc_jit_fn_attribute attribute)
+{
+ RETURN_IF_FAIL (func, NULL, NULL, "NULL func");
+ RETURN_IF_FAIL ((attribute >= 0 && attribute < GCC_JIT_FN_ATTRIBUTE_MAX),
+ NULL,
+ NULL,
+ "attribute should be a `gcc_jit_fn_attribute` enum value");
+
+ func->add_attribute (attribute);
+}
+
+void
+gcc_jit_function_add_string_attribute (gcc_jit_function *func,
+ gcc_jit_fn_attribute attribute,
+ const char* value)
+{
+ RETURN_IF_FAIL (func, NULL, NULL, "NULL func");
+ RETURN_IF_FAIL (value, NULL, NULL, "NULL value");
+ RETURN_IF_FAIL ((attribute >= 0 && attribute < GCC_JIT_FN_ATTRIBUTE_MAX),
+ NULL,
+ NULL,
+ "attribute should be a `gcc_jit_fn_attribute` enum value");
+
+ func->add_string_attribute (attribute, value);
+}
+
+/* This function adds an attribute with multiple integer values. For example
+ `nonnull(1, 2)`. The numbers in `values` are supposed to map how they
+ should be written in C code. So for `nonnull(1, 2)`, you should pass `1`
+ and `2` in `values` (and set `length` to `2`). */
+void
+gcc_jit_function_add_integer_array_attribute (gcc_jit_function *func,
+ gcc_jit_fn_attribute attribute,
+ const int* values,
+ size_t length)
+{
+ RETURN_IF_FAIL (func, NULL, NULL, "NULL func");
+ RETURN_IF_FAIL (values, NULL, NULL, "NULL values");
+ RETURN_IF_FAIL ((attribute >= 0 && attribute < GCC_JIT_FN_ATTRIBUTE_MAX),
+ NULL,
+ NULL,
+ "attribute should be a `gcc_jit_fn_attribute` enum value");
+
+ func->add_integer_array_attribute (attribute, values, length);
+}
+
+void
+gcc_jit_lvalue_add_string_attribute (gcc_jit_lvalue *variable,
+ gcc_jit_variable_attribute attribute,
+ const char* value)
+{
+ RETURN_IF_FAIL (variable, NULL, NULL, "NULL variable");
+ RETURN_IF_FAIL (value, NULL, NULL, "NULL value");
+ RETURN_IF_FAIL (variable->is_global () || variable->is_local (),
+ NULL,
+ NULL,
+ "variable should be a variable");
+ RETURN_IF_FAIL ((attribute >= 0 && attribute < GCC_JIT_VARIABLE_ATTRIBUTE_MAX),
+ NULL,
+ NULL,
+ "attribute should be a `gcc_jit_variable_attribute` enum value");
+
+ variable->add_string_attribute (attribute, value);
+}
+
/* Public entrypoint. See description in libgccjit.h.
After error-checking, the real work is done by the
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index cbcfabba3e8..235cab053e0 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -1999,6 +1999,61 @@ gcc_jit_vector_type_get_element_type (gcc_jit_vector_type *vector_type);
extern gcc_jit_type *
gcc_jit_type_unqualified (gcc_jit_type *type);
+#define LIBGCCJIT_HAVE_ATTRIBUTES
+
+/* Function attributes. */
+enum gcc_jit_fn_attribute
+{
+ GCC_JIT_FN_ATTRIBUTE_ALIAS,
+ GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE,
+ GCC_JIT_FN_ATTRIBUTE_INLINE,
+ GCC_JIT_FN_ATTRIBUTE_NOINLINE,
+ GCC_JIT_FN_ATTRIBUTE_TARGET,
+ GCC_JIT_FN_ATTRIBUTE_USED,
+ GCC_JIT_FN_ATTRIBUTE_VISIBILITY,
+ GCC_JIT_FN_ATTRIBUTE_COLD,
+ GCC_JIT_FN_ATTRIBUTE_RETURNS_TWICE,
+ GCC_JIT_FN_ATTRIBUTE_PURE,
+ GCC_JIT_FN_ATTRIBUTE_CONST,
+ GCC_JIT_FN_ATTRIBUTE_WEAK,
+ GCC_JIT_FN_ATTRIBUTE_NONNULL,
+
+ /* Maximum value of this enum, should always be last. */
+ GCC_JIT_FN_ATTRIBUTE_MAX,
+};
+
+/* Add an attribute to a function. */
+extern void
+gcc_jit_function_add_attribute (gcc_jit_function *func,
+ enum gcc_jit_fn_attribute attribute);
+
+extern void
+gcc_jit_function_add_string_attribute (gcc_jit_function *func,
+ enum gcc_jit_fn_attribute attribute,
+ const char* value);
+
+extern void
+gcc_jit_function_add_integer_array_attribute (
+ gcc_jit_function *func,
+ enum gcc_jit_fn_attribute attribute,
+ const int* value,
+ size_t length);
+
+/* Variable attributes. */
+enum gcc_jit_variable_attribute
+{
+ GCC_JIT_VARIABLE_ATTRIBUTE_VISIBILITY,
+
+ /* Maximum value of this enum, should always be last. */
+ GCC_JIT_VARIABLE_ATTRIBUTE_MAX,
+};
+
+/* Add a string attribute to a variable. */
+extern void
+gcc_jit_lvalue_add_string_attribute (gcc_jit_lvalue *variable,
+ enum gcc_jit_variable_attribute attribute,
+ const char* value);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index b62f5de72d0..dfb8a9d51fb 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -276,3 +276,11 @@ LIBGCCJIT_ABI_25 {
global:
gcc_jit_type_get_restrict;
} LIBGCCJIT_ABI_24;
+
+LIBGCCJIT_ABI_26 {
+ global:
+ gcc_jit_function_add_attribute;
+ gcc_jit_function_add_string_attribute;
+ gcc_jit_lvalue_add_string_attribute;
+ gcc_jit_function_add_integer_array_attribute;
+} LIBGCCJIT_ABI_25;
diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h
index e762563f9bd..7f97dbe7306 100644
--- a/gcc/testsuite/jit.dg/all-non-failing-tests.h
+++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h
@@ -32,6 +32,9 @@
/* test-add-driver-options.c: We don't use this one, since the extra options
affect the whole context. */
+/* test-alias-attribute.c: This can't be in the testcases array as it
+ doesn't have a verify_code implementation. */
+
/* test-alignment.c */
#define create_code create_code_alignment
#define verify_code verify_code_alignment
@@ -39,6 +42,9 @@
#undef create_code
#undef verify_code
+/* test-always_inline-attribute.c: This can't be in the testcases array as it needs
+ the `-O0` flag. */
+
/* test-arith-overflow.c */
#define create_code create_code_arith_overflow
#define verify_code verify_code_arith_overflow
@@ -119,6 +125,9 @@
#undef create_code
#undef verify_code
+/* test-cold-attribute.c: This can't be in the testcases array as it needs
+ the `-O2` flag. */
+
/* test-constants.c */
#define create_code create_code_constants
#define verify_code verify_code_constants
@@ -126,6 +135,9 @@
#undef create_code
#undef verify_code
+/* test-const-attribute.c: This can't be in the testcases array as it needs
+ the `-O3` flag. */
+
/* test-debug-strings.c */
#define create_code create_code_debug_strings
#define verify_code verify_code_debug_strings
@@ -268,6 +280,12 @@
#undef create_code
#undef verify_code
+/* test-noinline-attribute.c: This can't be in the testcases array as it needs
+ the `-O2` flag. */
+
+/* test-nonnull-attribute.c: This can't be in the testcases array as it needs
+ the `-O2` flag. */
+
/* test-pr103562.c: We don't add this one, since it touches
the optimization level of the context as a whole. */
@@ -299,6 +317,9 @@
#undef create_code
#undef verify_code
+/* test-pure-attribute.c: This can't be in the testcases array as it needs
+ the `-O3` flag. */
+
/* test-reading-struct.c */
#define create_code create_code_reading_struct
#define verify_code verify_code_reading_struct
@@ -316,6 +337,9 @@
/* test-restrict.c: This can't be in the testcases array as it needs
the `-O3` flag. */
+/* test-restrict-attribute.c: This can't be in the testcases array as it needs
+ the `-O3` flag. */
+
/* test-register-variable.c: This can't be in the testcases array as it
is target-specific. */
@@ -350,6 +374,9 @@
#undef create_code
#undef verify_code
+/* test-used-attribute.c: This can't be in the testcases array as it needs
+ the `-O2` flag. */
+
/* test-using-global.c */
#define create_code create_code_using_global
#define verify_code verify_code_using_global
@@ -361,6 +388,9 @@
of gcc_jit_context_set_bool_allow_unreachable_blocks affects the whole
context. */
+/* test-variable-attribute.c: This can't be in the testcases array as it
+ doesn't have a verify_code implementation. */
+
/* test-vector-types.cc: We don't use this, since it's C++. */
/* test-version.c */
@@ -377,6 +407,9 @@
#undef create_code
#undef verify_code
+/* test-weak-attribute.c: This can't be in the testcases array as it
+ doesn't have a verify_code implementation. */
+
/* Now expose the individual testcases as instances of this struct. */
struct testcase
diff --git a/gcc/testsuite/jit.dg/jit.exp b/gcc/testsuite/jit.dg/jit.exp
index 8bf7e51c24f..56972064d30 100644
--- a/gcc/testsuite/jit.dg/jit.exp
+++ b/gcc/testsuite/jit.dg/jit.exp
@@ -899,8 +899,41 @@ proc jit-verify-assembler-output { args } {
pass "${asm_filename} output pattern test, ${dg-output-text}"
verbose "Passed test for output pattern ${dg-output-text}" 3
}
+}
+
+# Assuming that a .s file has been written out named
+# OUTPUT_FILENAME, check that the argument doesn't match
+# the output file.
+proc jit-verify-assembler-output-not { args } {
+ verbose "jit-verify-assembler: $args"
+
+ set dg-output-text [lindex $args 0]
+ verbose "dg-output-text: ${dg-output-text}"
+
+ upvar 2 name name
+ verbose "name: $name"
+
+ upvar 2 prog prog
+ verbose "prog: $prog"
+ set asm_filename [jit-get-output-filename $prog]
+ verbose " asm_filename: ${asm_filename}"
+ # Read the assembly file.
+ set f [open $asm_filename r]
+ set content [read $f]
+ close $f
+
+ # Verify that the assembly matches the regex.
+ if { [regexp ${dg-output-text} $content] } {
+ fail "${asm_filename} output pattern test, is ${content}, should not match ${dg-output-text}"
+ verbose "Failed test for output pattern ${dg-output-text}" 3
+ } else {
+ pass "${asm_filename} output pattern test, ${dg-output-text}"
+ verbose "Passed test for output pattern ${dg-output-text}" 3
+ }
}
+
+
# Assuming that a .o file has been written out named
# OUTPUT_FILENAME, invoke the driver to try to turn it into
# an executable, and try to run the result.
diff --git a/gcc/testsuite/jit.dg/test-alias-attribute.c b/gcc/testsuite/jit.dg/test-alias-attribute.c
new file mode 100644
index 00000000000..eb29003dfc9
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-alias-attribute.c
@@ -0,0 +1,50 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#define TEST_COMPILING_TO_FILE
+#define OUTPUT_KIND GCC_JIT_OUTPUT_KIND_ASSEMBLER
+#define OUTPUT_FILENAME "output-of-test-alias-attribute.c.s"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+
+void xxx () {}
+void f () __attribute__ ((alias ("xxx")));
+ */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+
+ /* Creating the `xxx` function. */
+ gcc_jit_function *xxx_func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "xxx",
+ 0, NULL,
+ 0);
+
+ /* Creating the `f` function. */
+ gcc_jit_function *f_func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_IMPORTED,
+ void_type,
+ "f",
+ 0, NULL,
+ 0);
+ gcc_jit_function_add_string_attribute(f_func, GCC_JIT_FN_ATTRIBUTE_ALIAS, "xxx");
+
+ /* void xxx () {} */
+ gcc_jit_block *block = gcc_jit_function_new_block (xxx_func, NULL);
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+/* { dg-final { jit-verify-output-file-was-created "" } } */
+/* Check that the attribute was applied correctly */
+/* { dg-final { jit-verify-assembler-output ".set\\s+f,xxx" } } */
diff --git a/gcc/testsuite/jit.dg/test-always_inline-attribute.c b/gcc/testsuite/jit.dg/test-always_inline-attribute.c
new file mode 100644
index 00000000000..5c3f386663f
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-always_inline-attribute.c
@@ -0,0 +1,153 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#define TEST_ESCHEWS_SET_OPTIONS
+static void set_options (gcc_jit_context *ctxt, const char *argv0)
+{
+ // Set "-O0".
+ gcc_jit_context_set_int_option(ctxt, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 0);
+}
+
+#define TEST_COMPILING_TO_FILE
+#define OUTPUT_KIND GCC_JIT_OUTPUT_KIND_ASSEMBLER
+#define OUTPUT_FILENAME "output-of-test-always_inline-attribute.c.s"
+#include "harness.h"
+
+gcc_jit_function*
+create_function (gcc_jit_context *ctxt,
+ const char *func_name,
+ gcc_jit_type *int_type,
+ gcc_jit_type *pint_type)
+{
+ /* The `a` function argument */
+ gcc_jit_param *a = gcc_jit_context_new_param (ctxt, NULL, pint_type, "a");
+ gcc_jit_function *func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_INTERNAL,
+ int_type,
+ func_name,
+ 1, &a,
+ 0);
+
+ gcc_jit_block *if_cond =
+ gcc_jit_function_new_block (func, "if_cond");
+ gcc_jit_block *if_body =
+ gcc_jit_function_new_block (func, "if_body");
+ gcc_jit_block *after_if =
+ gcc_jit_function_new_block (func, "after_if");
+
+ /* if (!a) */
+ gcc_jit_block_end_with_conditional (
+ if_cond, NULL,
+ gcc_jit_context_new_comparison (
+ ctxt, NULL,
+ GCC_JIT_COMPARISON_EQ,
+ gcc_jit_param_as_rvalue (a),
+ gcc_jit_context_null (ctxt, pint_type)),
+ if_body,
+ after_if);
+ /* return -1; */
+ gcc_jit_block_end_with_return (
+ if_body, NULL,
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, -1));
+
+ /* return *a; */
+ gcc_jit_block_end_with_return (
+ after_if, NULL,
+ gcc_jit_lvalue_as_rvalue (
+ gcc_jit_rvalue_dereference (
+ gcc_jit_param_as_rvalue (a), NULL)));
+
+ return func;
+}
+
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+__attribute__ ((always_inline))
+static inline int removed (int *a) {
+ if (!a) {
+ return -1;
+ }
+ return *a;
+}
+static int not_removed (int *a) {
+ if (!a) {
+ return -1;
+ }
+ return *a;
+}
+int foo () {
+ int x = 0;
+ x += removed(NULL);
+ x += not_removed(NULL);
+ return x;
+}
+ */
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_type *pint_type = gcc_jit_type_get_pointer (int_type);
+
+ /* Creating the `removed` function. */
+ gcc_jit_function *removed_func =
+ create_function (ctxt, "removed", int_type, pint_type);
+ /* This one is to declare the function as "inline" */
+ gcc_jit_function_add_attribute(removed_func, GCC_JIT_FN_ATTRIBUTE_INLINE);
+ /* __attribute__ ((always_inline)) */
+ gcc_jit_function_add_attribute(removed_func, GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE);
+
+ /* Creating the `not_removed` function. */
+ gcc_jit_function *not_removed_func =
+ create_function (ctxt, "not_removed", int_type, pint_type);
+
+ /* Creating the `foo` function. */
+ gcc_jit_function *foo_func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ int_type,
+ "foo",
+ 0, NULL,
+ 0);
+
+ gcc_jit_block *foo_block = gcc_jit_function_new_block (foo_func, NULL);
+
+ /* Build locals: */
+ gcc_jit_lvalue *x =
+ gcc_jit_function_new_local (foo_func, NULL, int_type, "x");
+
+ /* int x = 0; */
+ gcc_jit_block_add_assignment (
+ foo_block, NULL,
+ x,
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 0));
+
+ /* x += removed(NULL); */
+ gcc_jit_rvalue *null = gcc_jit_context_null (ctxt, pint_type);
+ gcc_jit_block_add_assignment_op (
+ foo_block, NULL,
+ x,
+ GCC_JIT_BINARY_OP_PLUS,
+ gcc_jit_context_new_call (ctxt, NULL, removed_func, 1, &null));
+
+ /* x += not_removed(NULL); */
+ gcc_jit_block_add_assignment_op (
+ foo_block, NULL,
+ x,
+ GCC_JIT_BINARY_OP_PLUS,
+ gcc_jit_context_new_call (ctxt, NULL, not_removed_func, 1, &null));
+
+ /* return x; */
+ gcc_jit_block_end_with_return (foo_block, NULL, gcc_jit_lvalue_as_rvalue(x));
+}
+
+/* { dg-final { jit-verify-output-file-was-created "" } } */
+/* Check that the "removed" function was inlined, but not the others */
+/* { dg-final { jit-verify-assembler-output-not ".type\\s+removed,\\s+@function" } } */
+/* { dg-final { jit-verify-assembler-output ".type\\s+not_removed,\\s+@function" } } */
+/* { dg-final { jit-verify-assembler-output ".type\\s+foo,\\s+@function" } } */
diff --git a/gcc/testsuite/jit.dg/test-cold-attribute.c b/gcc/testsuite/jit.dg/test-cold-attribute.c
new file mode 100644
index 00000000000..0c76d3e3681
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-cold-attribute.c
@@ -0,0 +1,52 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#define TEST_ESCHEWS_SET_OPTIONS
+static void set_options (gcc_jit_context *ctxt, const char *argv0)
+{
+ // Set "-O2".
+ gcc_jit_context_set_int_option(ctxt, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 2);
+}
+
+#define TEST_COMPILING_TO_FILE
+#define OUTPUT_KIND GCC_JIT_OUTPUT_KIND_ASSEMBLER
+#define OUTPUT_FILENAME "output-of-test-cold-attribute.c.s"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+int
+__attribute__ ((cold))
+t()
+{
+ return -1;
+}
+
+ */
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ gcc_jit_function *func_t =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ int_type,
+ "t",
+ 0, NULL,
+ 0);
+ gcc_jit_function_add_attribute(func_t, GCC_JIT_FN_ATTRIBUTE_COLD);
+ gcc_jit_block *block = gcc_jit_function_new_block (func_t, NULL);
+ gcc_jit_rvalue *ret = gcc_jit_context_new_rvalue_from_int (ctxt,
+ int_type,
+ -1);
+
+ gcc_jit_block_end_with_return (block, NULL, ret);
+}
+
+/* { dg-final { jit-verify-output-file-was-created "" } } */
+/* { dg-final { jit-verify-assembler-output "orl" } } */
diff --git a/gcc/testsuite/jit.dg/test-const-attribute.c b/gcc/testsuite/jit.dg/test-const-attribute.c
new file mode 100644
index 00000000000..7b98041c9bb
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-const-attribute.c
@@ -0,0 +1,132 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#define TEST_ESCHEWS_SET_OPTIONS
+static void set_options (gcc_jit_context *ctxt, const char *argv0)
+{
+ // Set "-O3".
+ gcc_jit_context_set_int_option(ctxt, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 3);
+}
+
+#define TEST_COMPILING_TO_FILE
+#define OUTPUT_KIND GCC_JIT_OUTPUT_KIND_ASSEMBLER
+#define OUTPUT_FILENAME "output-of-test-const-attribute.c.s"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+__attribute__ ((const))
+int foo (int x);
+int xxx(void)
+{
+ int x = 45;
+ int sum = 0;
+
+ while (x >>= 1)
+ sum += foo (x) * 2;
+ return sum;
+}
+ */
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ /* Creating the `foo` function. */
+ gcc_jit_param *n =
+ gcc_jit_context_new_param (ctxt, NULL, int_type, "x");
+ gcc_jit_param *params[1] = {n};
+ gcc_jit_function *foo_func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_IMPORTED,
+ int_type,
+ "foo",
+ 1, params,
+ 0);
+ gcc_jit_function_add_attribute(foo_func, GCC_JIT_FN_ATTRIBUTE_CONST);
+
+ /* Creating the `xxx` function. */
+ gcc_jit_function *xxx_func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ int_type,
+ "xxx",
+ 0, NULL,
+ 0);
+
+ gcc_jit_block *block = gcc_jit_function_new_block (xxx_func, NULL);
+
+ /* Build locals: */
+ gcc_jit_lvalue *x =
+ gcc_jit_function_new_local (xxx_func, NULL, int_type, "x");
+ gcc_jit_lvalue *sum =
+ gcc_jit_function_new_local (xxx_func, NULL, int_type, "sum");
+
+ /* int x = 45 */
+ gcc_jit_block_add_assignment (
+ block, NULL,
+ x,
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 45));
+ /* int sum = 0 */
+ gcc_jit_block_add_assignment (
+ block, NULL,
+ sum,
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 0));
+
+ /* while (x >>= 1) { sum += foo (x) * 2; } */
+ gcc_jit_block *loop_cond =
+ gcc_jit_function_new_block (xxx_func, "loop_cond");
+ gcc_jit_block *loop_body =
+ gcc_jit_function_new_block (xxx_func, "loop_body");
+ gcc_jit_block *after_loop =
+ gcc_jit_function_new_block (xxx_func, "after_loop");
+
+ gcc_jit_block_end_with_jump (block, NULL, loop_cond);
+
+
+ /* if (x >>= 1) */
+ /* Since gccjit doesn't (yet?) have support for `>>=` operator, we will decompose it into:
+ `if (x = x >> 1)` */
+ gcc_jit_block_add_assignment_op (
+ loop_cond, NULL,
+ x,
+ GCC_JIT_BINARY_OP_RSHIFT,
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 1));
+ /* The condition itself */
+ gcc_jit_block_end_with_conditional (
+ loop_cond, NULL,
+ gcc_jit_context_new_comparison (
+ ctxt, NULL,
+ GCC_JIT_COMPARISON_NE,
+ gcc_jit_lvalue_as_rvalue (x),
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 0)),
+ after_loop,
+ loop_body);
+
+ /* sum += foo (x) * 2; */
+ gcc_jit_rvalue *arg = gcc_jit_lvalue_as_rvalue(x);
+ gcc_jit_block_add_assignment_op (
+ loop_body, NULL,
+ x,
+ GCC_JIT_BINARY_OP_PLUS,
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT, int_type,
+ gcc_jit_context_new_call (ctxt, NULL, foo_func, 1, &arg),
+ gcc_jit_context_new_rvalue_from_int (
+ ctxt,
+ int_type,
+ 2)));
+ gcc_jit_block_end_with_jump (loop_body, NULL, loop_cond);
+
+ /* return sum; */
+ gcc_jit_block_end_with_return (after_loop, NULL, gcc_jit_lvalue_as_rvalue(sum));
+}
+
+/* { dg-final { jit-verify-output-file-was-created "" } } */
+/* Check that the loop was optimized away */
+/* { dg-final { jit-verify-assembler-output-not "jne" } } */
diff --git a/gcc/testsuite/jit.dg/test-noinline-attribute.c b/gcc/testsuite/jit.dg/test-noinline-attribute.c
new file mode 100644
index 00000000000..eac6cae6b6a
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-noinline-attribute.c
@@ -0,0 +1,119 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#define TEST_ESCHEWS_SET_OPTIONS
+static void set_options (gcc_jit_context *ctxt, const char *argv0)
+{
+ // Set "-O2".
+ gcc_jit_context_set_int_option(ctxt, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 2);
+}
+
+#define TEST_COMPILING_TO_FILE
+#define OUTPUT_KIND GCC_JIT_OUTPUT_KIND_ASSEMBLER
+#define OUTPUT_FILENAME "output-of-test-noinline-attribute.c.s"
+#include "harness.h"
+
+gcc_jit_function*
+create_function (gcc_jit_context *ctxt,
+ const char *func_name,
+ gcc_jit_type *int_type,
+ int returned_value)
+{
+ gcc_jit_function *func
+ = gcc_jit_context_new_function(ctxt, NULL,
+ GCC_JIT_FUNCTION_INTERNAL,
+ int_type,
+ func_name,
+ 0, NULL,
+ 0);
+ gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
+
+ gcc_jit_block_add_extended_asm (block, NULL, "");
+ gcc_jit_block_end_with_return (block, NULL,
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, returned_value));
+
+ return func;
+}
+
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+__attribute__ ((noinline))
+static int not_removed() {
+ asm("");
+ return 1;
+}
+static int removed() {
+ asm("");
+ return 2;
+}
+int foo () {
+ int x = 0;
+ x += removed();
+ x += not_removed();
+ return x;
+}
+ */
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ /* Creating the `not_removed` function. */
+ gcc_jit_function *not_removed_func =
+ create_function (ctxt, "not_removed", int_type, 1);
+ /* __attribute__ ((no_inline)) */
+ gcc_jit_function_add_attribute(not_removed_func, GCC_JIT_FN_ATTRIBUTE_NOINLINE);
+
+ /* Creating the `removed` function. */
+ gcc_jit_function *removed_func =
+ create_function (ctxt, "removed", int_type, 2);
+
+ /* Creating the `foo` function. */
+ gcc_jit_function *foo_func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ int_type,
+ "foo",
+ 0, NULL,
+ 0);
+
+ gcc_jit_block *foo_block = gcc_jit_function_new_block (foo_func, NULL);
+
+ /* Build locals: */
+ gcc_jit_lvalue *x =
+ gcc_jit_function_new_local (foo_func, NULL, int_type, "x");
+
+ /* int x = 0; */
+ gcc_jit_block_add_assignment (
+ foo_block, NULL,
+ x,
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 0));
+
+ /* x += removed(); */
+ gcc_jit_block_add_assignment_op (
+ foo_block, NULL,
+ x,
+ GCC_JIT_BINARY_OP_PLUS,
+ gcc_jit_context_new_call (ctxt, NULL, removed_func, 0, NULL));
+
+ /* x += not_removed(); */
+ gcc_jit_block_add_assignment_op (
+ foo_block, NULL,
+ x,
+ GCC_JIT_BINARY_OP_PLUS,
+ gcc_jit_context_new_call (ctxt, NULL, not_removed_func, 0, NULL));
+
+ /* return x; */
+ gcc_jit_block_end_with_return (foo_block, NULL, gcc_jit_lvalue_as_rvalue(x));
+}
+
+/* { dg-final { jit-verify-output-file-was-created "" } } */
+/* Check that the "removed" function was inlined, but not the others */
+/* { dg-final { jit-verify-assembler-output-not ".type\\s+removed.isra.0,\\s+@function" } } */
+/* { dg-final { jit-verify-assembler-output ".type\\s+not_removed.isra.0,\\s+@function" } } */
+/* { dg-final { jit-verify-assembler-output ".type\\s+foo,\\s+@function" } } */
diff --git a/gcc/testsuite/jit.dg/test-nonnull-attribute.c b/gcc/testsuite/jit.dg/test-nonnull-attribute.c
new file mode 100644
index 00000000000..42c38acb962
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-nonnull-attribute.c
@@ -0,0 +1,92 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#define TEST_ESCHEWS_SET_OPTIONS
+static void set_options (gcc_jit_context *ctxt, const char *argv0)
+{
+ // Set "-O2".
+ gcc_jit_context_set_int_option(ctxt, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 2);
+}
+
+#define TEST_COMPILING_TO_FILE
+#define OUTPUT_KIND GCC_JIT_OUTPUT_KIND_ASSEMBLER
+#define OUTPUT_FILENAME "output-of-test-nonnull.c.s"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+
+__attribute__((nonnull(1)))
+int t(int *a) {
+ if (!a) {
+ return -1;
+ }
+ return *a;
+}
+ */
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_type *pint_type = gcc_jit_type_get_pointer(int_type);
+
+ gcc_jit_param *a =
+ gcc_jit_context_new_param (ctxt, NULL, pint_type, "a");
+
+ gcc_jit_function *func_t =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ int_type,
+ "t",
+ 1, &a,
+ 0);
+ /* Adding `nonnull(1)` attribute. */
+ int indexes[1] = {1};
+ gcc_jit_function_add_integer_array_attribute (
+ func_t,
+ GCC_JIT_FN_ATTRIBUTE_NONNULL,
+ indexes,
+ 1
+ );
+
+ /* if (!a) {
+ return -1;
+ } */
+ gcc_jit_block *if_cond =
+ gcc_jit_function_new_block (func_t, "if_cond");
+ gcc_jit_block *if_body =
+ gcc_jit_function_new_block (func_t, "if_body");
+ gcc_jit_block *after_if =
+ gcc_jit_function_new_block (func_t, "after_if");
+
+ /* if (!a) */
+ gcc_jit_block_end_with_conditional (
+ if_cond, NULL,
+ gcc_jit_context_new_comparison (
+ ctxt, NULL,
+ GCC_JIT_COMPARISON_EQ,
+ gcc_jit_param_as_rvalue (a),
+ gcc_jit_context_null (ctxt, pint_type)),
+ if_body,
+ after_if);
+ /* return -1; */
+ gcc_jit_block_end_with_return (
+ if_body, NULL,
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, -1));
+
+ /* return *a; */
+ gcc_jit_block_end_with_return (
+ after_if, NULL,
+ gcc_jit_lvalue_as_rvalue (
+ gcc_jit_rvalue_dereference (
+ gcc_jit_param_as_rvalue (a), NULL)));
+}
+
+/* { dg-final { jit-verify-output-file-was-created "" } } */
+/* Check that the "if block" was optimized away */
+/* { dg-final { jit-verify-assembler-output-not "testq" } } */
+/* { dg-final { jit-verify-assembler-output-not "-1" } } */
diff --git a/gcc/testsuite/jit.dg/test-pure-attribute.c b/gcc/testsuite/jit.dg/test-pure-attribute.c
new file mode 100644
index 00000000000..0c773bc24d5
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-pure-attribute.c
@@ -0,0 +1,132 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#define TEST_ESCHEWS_SET_OPTIONS
+static void set_options (gcc_jit_context *ctxt, const char *argv0)
+{
+ // Set "-O3".
+ gcc_jit_context_set_int_option(ctxt, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 3);
+}
+
+#define TEST_COMPILING_TO_FILE
+#define OUTPUT_KIND GCC_JIT_OUTPUT_KIND_ASSEMBLER
+#define OUTPUT_FILENAME "output-of-test-pure-attribute.c.s"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+__attribute__ ((pure))
+int foo (int x);
+int xxx(void)
+{
+ int x = 45;
+ int sum = 0;
+
+ while (x >>= 1)
+ sum += foo (x) * 2;
+ return sum;
+}
+ */
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ /* Creating the `foo` function. */
+ gcc_jit_param *n =
+ gcc_jit_context_new_param (ctxt, NULL, int_type, "x");
+ gcc_jit_param *params[1] = {n};
+ gcc_jit_function *foo_func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_IMPORTED,
+ int_type,
+ "foo",
+ 1, params,
+ 0);
+ gcc_jit_function_add_attribute(foo_func, GCC_JIT_FN_ATTRIBUTE_PURE);
+
+ /* Creating the `xxx` function. */
+ gcc_jit_function *xxx_func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ int_type,
+ "xxx",
+ 0, NULL,
+ 0);
+
+ gcc_jit_block *block = gcc_jit_function_new_block (xxx_func, NULL);
+
+ /* Build locals: */
+ gcc_jit_lvalue *x =
+ gcc_jit_function_new_local (xxx_func, NULL, int_type, "x");
+ gcc_jit_lvalue *sum =
+ gcc_jit_function_new_local (xxx_func, NULL, int_type, "sum");
+
+ /* int x = 45 */
+ gcc_jit_block_add_assignment (
+ block, NULL,
+ x,
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 45));
+ /* int sum = 0 */
+ gcc_jit_block_add_assignment (
+ block, NULL,
+ sum,
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 0));
+
+ /* while (x >>= 1) { sum += foo (x) * 2; } */
+ gcc_jit_block *loop_cond =
+ gcc_jit_function_new_block (xxx_func, "loop_cond");
+ gcc_jit_block *loop_body =
+ gcc_jit_function_new_block (xxx_func, "loop_body");
+ gcc_jit_block *after_loop =
+ gcc_jit_function_new_block (xxx_func, "after_loop");
+
+ gcc_jit_block_end_with_jump (block, NULL, loop_cond);
+
+
+ /* if (x >>= 1) */
+ /* Since gccjit doesn't (yet?) have support for `>>=` operator, we will decompose it into:
+ `if (x = x >> 1)` */
+ gcc_jit_block_add_assignment_op (
+ loop_cond, NULL,
+ x,
+ GCC_JIT_BINARY_OP_RSHIFT,
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 1));
+ /* The condition itself */
+ gcc_jit_block_end_with_conditional (
+ loop_cond, NULL,
+ gcc_jit_context_new_comparison (
+ ctxt, NULL,
+ GCC_JIT_COMPARISON_NE,
+ gcc_jit_lvalue_as_rvalue (x),
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 0)),
+ after_loop,
+ loop_body);
+
+ /* sum += foo (x) * 2; */
+ gcc_jit_rvalue *arg = gcc_jit_lvalue_as_rvalue(x);
+ gcc_jit_block_add_assignment_op (
+ loop_body, NULL,
+ x,
+ GCC_JIT_BINARY_OP_PLUS,
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT, int_type,
+ gcc_jit_context_new_call (ctxt, NULL, foo_func, 1, &arg),
+ gcc_jit_context_new_rvalue_from_int (
+ ctxt,
+ int_type,
+ 2)));
+ gcc_jit_block_end_with_jump (loop_body, NULL, loop_cond);
+
+ /* return sum; */
+ gcc_jit_block_end_with_return (after_loop, NULL, gcc_jit_lvalue_as_rvalue(sum));
+}
+
+/* { dg-final { jit-verify-output-file-was-created "" } } */
+/* Check that the loop was optimized away */
+/* { dg-final { jit-verify-assembler-output-not "jne" } } */
diff --git a/gcc/testsuite/jit.dg/test-restrict-attribute.c b/gcc/testsuite/jit.dg/test-restrict-attribute.c
new file mode 100644
index 00000000000..d724472c652
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-restrict-attribute.c
@@ -0,0 +1,75 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#define TEST_ESCHEWS_SET_OPTIONS
+static void set_options (gcc_jit_context *ctxt, const char *argv0)
+{
+ // Set "-O3".
+ gcc_jit_context_set_int_option(ctxt, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 3);
+}
+
+#define TEST_COMPILING_TO_FILE
+#define OUTPUT_KIND GCC_JIT_OUTPUT_KIND_ASSEMBLER
+#define OUTPUT_FILENAME "output-of-test-restrict-attribute.c.s"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+void t(int *__restrict__ a, int *__restrict__ b, char *__restrict__ c) {
+ *a += *c;
+ *b += *c;
+}
+ */
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_type *pint_type = gcc_jit_type_get_pointer(int_type);
+ gcc_jit_type *pint_restrict_type = gcc_jit_type_get_restrict(pint_type);
+
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+
+ gcc_jit_param *a =
+ gcc_jit_context_new_param (ctxt, NULL, pint_restrict_type, "a");
+ gcc_jit_param *b =
+ gcc_jit_context_new_param (ctxt, NULL, pint_restrict_type, "b");
+ gcc_jit_param *c =
+ gcc_jit_context_new_param (ctxt, NULL, pint_restrict_type, "c");
+ gcc_jit_param *params[3] = {a, b, c};
+
+ gcc_jit_function *func_t =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "t",
+ 3, params,
+ 0);
+
+ gcc_jit_block *block = gcc_jit_function_new_block (func_t, NULL);
+
+ /* *a += *c; */
+ gcc_jit_block_add_assignment_op (
+ block, NULL,
+ gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (a), NULL),
+ GCC_JIT_BINARY_OP_PLUS,
+ gcc_jit_lvalue_as_rvalue (
+ gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (c), NULL)));
+ /* *b += *c; */
+ gcc_jit_block_add_assignment_op (
+ block, NULL,
+ gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (b), NULL),
+ GCC_JIT_BINARY_OP_PLUS,
+ gcc_jit_lvalue_as_rvalue (
+ gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (c), NULL)));
+
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+/* { dg-final { jit-verify-output-file-was-created "" } } */
+/* { dg-final { jit-verify-assembler-output "addl\\s+%eax,\\s+(%rdi)
+\\s+addl\\s+%eax,\\s+(%rsi)" } } */
diff --git a/gcc/testsuite/jit.dg/test-used-attribute.c b/gcc/testsuite/jit.dg/test-used-attribute.c
new file mode 100644
index 00000000000..cb20952c687
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-used-attribute.c
@@ -0,0 +1,112 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#define TEST_ESCHEWS_SET_OPTIONS
+static void set_options (gcc_jit_context *ctxt, const char *argv0)
+{
+ // Set "-O2".
+ gcc_jit_context_set_int_option(ctxt, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 2);
+}
+
+#define TEST_COMPILING_TO_FILE
+#define OUTPUT_KIND GCC_JIT_OUTPUT_KIND_ASSEMBLER
+#define OUTPUT_FILENAME "output-of-test-used-attribute.c.s"
+#include "harness.h"
+
+gcc_jit_function*
+create_function (gcc_jit_context *ctxt,
+ const char *func_name,
+ gcc_jit_type *int_type,
+ int returned_value)
+{
+ gcc_jit_function *func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_INTERNAL,
+ int_type,
+ func_name,
+ 0, NULL,
+ 0);
+
+ gcc_jit_block *foo_block = gcc_jit_function_new_block (func, NULL);
+ gcc_jit_block_end_with_return (foo_block, NULL,
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, returned_value));
+
+ return func;
+}
+
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+__attribute__((used))
+static int not_removed() { return 1; }
+static int removed() { return 2; }
+int foo() {
+ int x = 0;
+ x += not_removed();
+ x += removed();
+ return x;
+}
+ */
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ /* Creating the `not_removed` function. */
+ gcc_jit_function *not_removed_func =
+ create_function (ctxt, "not_removed", int_type, 1);
+ /* __attribute__ ((used)) */
+ gcc_jit_function_add_attribute(not_removed_func, GCC_JIT_FN_ATTRIBUTE_USED);
+
+ /* Creating the `removed` function. */
+ gcc_jit_function *removed_func =
+ create_function (ctxt, "removed", int_type, 2);
+
+ /* Creating the `foo` function. */
+ gcc_jit_function *foo_func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ int_type,
+ "foo",
+ 0, NULL,
+ 0);
+
+ gcc_jit_block *foo_block = gcc_jit_function_new_block (foo_func, NULL);
+
+ /* Build locals: */
+ gcc_jit_lvalue *x =
+ gcc_jit_function_new_local (foo_func, NULL, int_type, "x");
+
+ /* int x = 0; */
+ gcc_jit_block_add_assignment (
+ foo_block, NULL,
+ x,
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 0));
+
+ /* x += removed(); */
+ gcc_jit_block_add_assignment_op (
+ foo_block, NULL,
+ x,
+ GCC_JIT_BINARY_OP_PLUS,
+ gcc_jit_context_new_call (ctxt, NULL, removed_func, 0, NULL));
+
+ /* x += not_removed(); */
+ gcc_jit_block_add_assignment_op (
+ foo_block, NULL,
+ x,
+ GCC_JIT_BINARY_OP_PLUS,
+ gcc_jit_context_new_call (ctxt, NULL, not_removed_func, 0, NULL));
+
+ /* return x; */
+ gcc_jit_block_end_with_return (foo_block, NULL, gcc_jit_lvalue_as_rvalue(x));
+}
+
+/* { dg-final { jit-verify-output-file-was-created "" } } */
+/* Check that the "removed" function was inlined, but not the others */
+/* { dg-final { jit-verify-assembler-output-not ".type\\s+removed,\\s+@function" } } */
+/* { dg-final { jit-verify-assembler-output ".type\\s+not_removed,\\s+@function" } } */
+/* { dg-final { jit-verify-assembler-output ".type\\s+foo,\\s+@function" } } */
diff --git a/gcc/testsuite/jit.dg/test-variable-attribute.c b/gcc/testsuite/jit.dg/test-variable-attribute.c
new file mode 100644
index 00000000000..ea854ff4a9f
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-variable-attribute.c
@@ -0,0 +1,46 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#define TEST_COMPILING_TO_FILE
+#define OUTPUT_KIND GCC_JIT_OUTPUT_KIND_ASSEMBLER
+#define OUTPUT_FILENAME "output-of-test-variable-attribute.c.s"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+
+int PRIVATE __attribute__ ((visibility ("hidden"))) = 42;
+int PUBLIC = 12;
+ */
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ /* Creating the `PRIVATE` variable. */
+ gcc_jit_lvalue *private = gcc_jit_context_new_global (ctxt,
+ NULL, GCC_JIT_GLOBAL_EXPORTED, int_type, "PRIVATE");
+ gcc_jit_lvalue_add_string_attribute (private,
+ GCC_JIT_VARIABLE_ATTRIBUTE_VISIBILITY, "hidden");
+ gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int (
+ ctxt, int_type, 42);
+ gcc_jit_global_set_initializer_rvalue (private, rval);
+
+ /* Creating the `PUBLIC` variable. */
+ gcc_jit_lvalue *public = gcc_jit_context_new_global (ctxt,
+ NULL, GCC_JIT_GLOBAL_EXPORTED, int_type, "PUBLIC");
+ gcc_jit_rvalue *rval2 = gcc_jit_context_new_rvalue_from_int (
+ ctxt, int_type, 12);
+ gcc_jit_global_set_initializer_rvalue (public, rval2);
+}
+
+/* { dg-final { jit-verify-output-file-was-created "" } } */
+/* Check that the attribute was applied correctly */
+/* { dg-final { jit-verify-assembler-output ".hidden\\s+PRIVATE" } } */
+/* { dg-final { jit-verify-assembler-output ".globl\\s+PRIVATE" } } */
+/* { dg-final { jit-verify-assembler-output-not ".hidden\\s+PUBLIC" } } */
+/* { dg-final { jit-verify-assembler-output ".globl\\s+PUBLIC" } } */
diff --git a/gcc/testsuite/jit.dg/test-weak-attribute.c b/gcc/testsuite/jit.dg/test-weak-attribute.c
new file mode 100644
index 00000000000..546ade1c3c4
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-weak-attribute.c
@@ -0,0 +1,41 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#define TEST_COMPILING_TO_FILE
+#define OUTPUT_KIND GCC_JIT_OUTPUT_KIND_ASSEMBLER
+#define OUTPUT_FILENAME "output-of-test-weak-attribute.c.s"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+
+__attribute__ ((weak))
+void f () {}
+ */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+
+ /* Creating the `f` function. */
+ gcc_jit_function *f_func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "f",
+ 0, NULL,
+ 0);
+ gcc_jit_function_add_attribute(f_func, GCC_JIT_FN_ATTRIBUTE_WEAK);
+
+ /* void f () {} */
+ gcc_jit_block *block = gcc_jit_function_new_block (f_func, NULL);
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+/* { dg-final { jit-verify-output-file-was-created "" } } */
+/* Check that the attribute was applied correctly */
+/* { dg-final { jit-verify-assembler-output ".weak\\s+f" } } */
--
2.34.1
prev parent reply other threads:[~2024-01-12 13:47 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-11-15 16:53 Guillaume Gomez
2023-11-15 16:56 ` Antoni Boucher
2023-11-23 21:52 ` Guillaume Gomez
2023-11-23 21:59 ` Antoni Boucher
2023-11-30 9:55 ` Guillaume Gomez
2023-12-07 17:13 ` Antoni Boucher
2023-12-09 11:12 ` Guillaume Gomez
2023-12-18 22:27 ` Guillaume Gomez
2024-01-03 13:37 ` Guillaume Gomez
2024-01-09 19:59 ` David Malcolm
2024-01-11 0:00 ` Guillaume Gomez
2024-01-11 18:46 ` David Malcolm
2024-01-11 21:40 ` Guillaume Gomez
2024-01-11 22:38 ` David Malcolm
2024-01-12 10:09 ` Guillaume Gomez
2024-01-12 13:47 ` Guillaume Gomez [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAAOQCfQ6UYhN1SoE=j9YXp46BQ+YHUxCMq42U4CafmtyBKw4yA@mail.gmail.com' \
--to=guillaume1.gomez@gmail.com \
--cc=bouanto@zoho.com \
--cc=dmalcolm@redhat.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=jit@gcc.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).