public inbox for jit@gcc.gnu.org
 help / color / mirror / Atom feed
From: Antoni Boucher <bouanto@zoho.com>
To: David Malcolm <dmalcolm@redhat.com>,
	gcc-patches@gcc.gnu.org,  jit@gcc.gnu.org
Subject: Re: [PATCH] libgccjit: Add support for bitcasts [PR104071]
Date: Fri, 21 Jan 2022 18:41:17 -0500	[thread overview]
Message-ID: <1cb2b6d3e9a1afb6135a9dc1a97e85ba8c3a4a0d.camel@zoho.com> (raw)
In-Reply-To: <fc15339e599b97ecbbc61f40b1ceaf8fd15cee0b.camel@redhat.com>

[-- Attachment #1: Type: text/plain, Size: 17161 bytes --]

Hi.
Here's the updated patch.

See comments below.

Le mardi 18 janvier 2022 à 18:06 -0500, David Malcolm a écrit :
> On Mon, 2022-01-17 at 19:30 -0500, Antoni Boucher via Gcc-patches
> wrote:
> > I was missing the define, so I added it.
> > Here's the new patch with it.
> 
> Thanks for the patch.
> 
> > Le lundi 17 janvier 2022 à 17:18 -0500, Antoni Boucher via Jit a
> > écrit :
> > > Hi.
> > > This patch add support for bitcasts in libgccjit.
> > > 
> > > It passes the JIT tests, but since I added a function in tree.c,
> > > I
> > > wonder if I should run the whole testsuite.
> 
> We're in stage 4 for GCC 12 now, so we need to be especially careful
> and conservative about every change.  A strict reading on the rules
> is
> that we shouldn't be adding new features - but if they're confined to
> libgccjit we may be able to get release manager approval.

Ok, if the 4 patches currently being reviewed (and listed here:
https://github.com/antoyo/libgccjit-patches) were included in gcc 12,
I'd be able to build rustc_codegen_gcc with an unpatched gcc.

It is to be noted however, that I'll need more patches for future work.
Off the top of my head, I'll at least need a patch for the inline
attribute, try/catch and target-specific builtins.
The last 2 features will probably take some time to implement, so I'll
let you judge if you think it's worth merging the 4 patches currently
being reviewed for gcc 12.

> 
> > > 
> > > David, you can now disregard my question in my email about 128-
> > > bit
> > > integers regarding my issue with initialize_sizetypes being
> > > called
> > > multiple times because this patch fix this issue.
> > > I turns out there was a cache of types that needed to be cleared
> > > when
> > > you initialize the JIT.
> > > 
> > > The check for sizes is pending, because it requires the updates
> > > to
> > > get_size I made in my patch for 128-bit integers.
> 
> Sorry, I seem to have mislaid that patch; do you have the "Subject"
> line handy?

I recently sent an email with that patch updated, but here's the
subject line:
[PATCH] libgccjit: Add support for sized integer types, including 128-
bit integers [PR95325]

> 
> Do you have a list of the patches I need to review?

Yes, on this repo:
https://github.com/antoyo/libgccjit-patches

They are outdated but I can update them if you want.

> 
> As for this patch, overall I like it, but there are various nits...
> 
> > > 
> > > Thanks for the review!
> 
> > 2022-01-17  Antoni Boucher <bouanto@zoho.com>
> > 
> > gcc/jit/
> >         PR target/104071
> 
> Should be "jit" rather than "target".
> 
> Various source files are now .cc rather than .c after yesterday's big
> renaming.
> 
> >         * docs/topics/compatibility.rst (LIBGCCJIT_ABI_20): New ABI
> > tag.
> >         * docs/topics/expressions.rst: Add documentation for the
> >         function gcc_jit_context_new_bitcast.
> >         * dummy-frontend.c: clear the cache of non-standard integer
> >         types to avoid having issues with some optimizations of
> >         bitcast where the SSA_NAME will have a size of a cached
> >         integer type that should have been invalidated, causing a
> >         comparison of integer constant to fail.
> >         * jit-playback.c: New function (new_bitcast).
> >         * jit-playback.h: New function (new_bitcast).
> >         * jit-recording.c: New functions (new_bitcast,
> >         bitcast::replay_into, bitcast::visit_children,
> >         bitcast::make_debug_string, bitcast::write_reproducer).
> >         * jit-recording.h: New calss (bitcast) and new function
> >         (new_bitcast, bitcast::replay_into,
> > bitcast::visit_children,
> >         bitcast::make_debug_string, bitcast::write_reproducer,
> >         bitcast::get_precedence).
> >         * libgccjit.c: New function (gcc_jit_context_new_bitcast)
> >         * libgccjit.h: New function (gcc_jit_context_new_bitcast)
> >         * libgccjit.map (LIBGCCJIT_ABI_20): New ABI tag.
> > 
> > gcc/testsuite/
> >         PR target/104071
> >         * jit.dg/all-non-failing-tests.h: Add new test-bitcast.
> >         * jit.dg/test-bitcast.c: New test.
> > 
> > gcc/
> >         PR target/104071
> >         * tree.c: New function
> > (clear_nonstandard_integer_type_cache).
> >         * tree.h: New function
> > (clear_nonstandard_integer_type_cache).
> > ---
> >  gcc/jit/docs/topics/compatibility.rst        |  9 +++
> >  gcc/jit/docs/topics/expressions.rst          | 17 +++++
> >  gcc/jit/dummy-frontend.c                     |  2 +
> >  gcc/jit/jit-playback.c                       | 13 ++++
> >  gcc/jit/jit-playback.h                       |  5 ++
> >  gcc/jit/jit-recording.c                      | 66
> > ++++++++++++++++++++
> >  gcc/jit/jit-recording.h                      | 32 ++++++++++
> >  gcc/jit/libgccjit.c                          | 28 +++++++++
> >  gcc/jit/libgccjit.h                          | 15 +++++
> >  gcc/jit/libgccjit.map                        |  6 ++
> >  gcc/testsuite/jit.dg/all-non-failing-tests.h | 10 +++
> >  gcc/testsuite/jit.dg/test-bitcast.c          | 60
> > ++++++++++++++++++
> >  gcc/tree.c                                   |  8 +++
> >  gcc/tree.h                                   |  1 +
> >  14 files changed, 272 insertions(+)
> >  create mode 100644 gcc/testsuite/jit.dg/test-bitcast.c
> > 
> > diff --git a/gcc/jit/docs/topics/compatibility.rst
> > b/gcc/jit/docs/topics/compatibility.rst
> > index 16cebe31a10..b5a6b704dda 100644
> > --- a/gcc/jit/docs/topics/compatibility.rst
> > +++ b/gcc/jit/docs/topics/compatibility.rst
> > @@ -302,3 +302,12 @@ thread-local storage model of a variable:
> >  section of a variable:
> >  
> >    * :func:`gcc_jit_lvalue_set_link_section`
> > +
> > +.. _LIBGCCJIT_ABI_20:
> > +
> > +``LIBGCCJIT_ABI_20``
> > +-----------------------
> > +``LIBGCCJIT_ABI_20`` covers the addition of an API entrypoint to
> > bitcast a
> > +value from one type to another:
> > +
> > +  * :func:`gcc_jit_context_new_bitcast`
> > diff --git a/gcc/jit/docs/topics/expressions.rst
> > b/gcc/jit/docs/topics/expressions.rst
> > index 791a20398ca..1328a53f70f 100644
> > --- a/gcc/jit/docs/topics/expressions.rst
> > +++ b/gcc/jit/docs/topics/expressions.rst
> > @@ -649,6 +649,23 @@ Type-coercion
> >       * int <-> bool
> >       * P*  <-> Q*, for pointer types P and Q
> >  
> > +.. function:: gcc_jit_rvalue *\
> > +              gcc_jit_context_new_bitcast (gcc_jit_context *ctxt,\
> > +                                           gcc_jit_location *loc,\
> > +                                           gcc_jit_rvalue
> > *rvalue,\
> > +                                           gcc_jit_type *type)
> > +
> > +   Given an rvalue of T, bitcast it to another type.
> 
> I think it's worth defining what "bitcast" means in the docs here;
> presumably you mean something like "generating a new rvalue by
> interpreting the bits of the input rvalue according to the layout of
> type" or somesuch.

Done.

> 
> 
> > +
> > +   The type of rvalue must be the same size as the size of
> > ``type``.
> > +
> > +   This entrypoint was added in :ref:`LIBGCCJIT_ABI_20`; you can
> > test for
> > +   its presence using
> > +
> > +   .. code-block:: c
> > +
> > +      #ifdef LIBGCCJIT_HAVE_gcc_jit_context_new_bitcast
> > +
> >  Lvalues
> >  -------
> >  
> > diff --git a/gcc/jit/dummy-frontend.c b/gcc/jit/dummy-frontend.c
> > index 84ff359bfe3..c3da97642e3 100644
> > --- a/gcc/jit/dummy-frontend.c
> > +++ b/gcc/jit/dummy-frontend.c
> > @@ -592,6 +592,8 @@ jit_langhook_init (void)
> >    global_dc->begin_diagnostic = jit_begin_diagnostic;
> >    global_dc->end_diagnostic = jit_end_diagnostic;
> >  
> > +  clear_nonstandard_integer_type_cache ();
> > +
> 
> I've been putting code to cleanup global state in foo.c into
> foo_c_finalize functions; I'm testing a patch right now to rename
> these
> to foo_cc_finalize functions to reflect the renaming of .c to .cc
> These cleanup functions are called from toplev::finalize.
> 
> I think it would be better to invoke this cleanup from a new
> tree_cc_finalize that follows that pattern.

Done.

> 
> >    build_common_tree_nodes (false);
> >  
> >    /* I don't know why this has to be done explicitly.  */
> 
> [...snip...]
> 
> > diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
> > index 03704ef10b8..cd8516d1c4d 100644
> > --- a/gcc/jit/libgccjit.c
> > +++ b/gcc/jit/libgccjit.c
> > @@ -2405,6 +2405,34 @@ gcc_jit_context_new_cast (gcc_jit_context
> > *ctxt,
> >    return static_cast <gcc_jit_rvalue *> (ctxt->new_cast (loc,
> > rvalue, type));
> >  }
> >  
> > +/* Public entrypoint.  See description in libgccjit.h.
> > +
> > +   After error-checking, the real work is done by the
> > +   gcc::jit::recording::context::new_bitcast method in jit-
> > recording.c.  */
> > +
> > +gcc_jit_rvalue *
> > +gcc_jit_context_new_bitcast (gcc_jit_context *ctxt,
> > +                            gcc_jit_location *loc,
> > +                            gcc_jit_rvalue *rvalue,
> > +                            gcc_jit_type *type)
> > +{
> > +  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
> > +  JIT_LOG_FUNC (ctxt->get_logger ());
> > +  /* LOC can be NULL.  */
> > +  RETURN_NULL_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
> > +  RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
> > +  // TODO: check the sizes.
> > +  /*RETURN_NULL_IF_FAIL_PRINTF3 (
> > +    is_valid_cast (rvalue->get_type (), type),
> > +    ctxt, loc,
> > +    "cannot cast %s from type: %s to type: %s",
> > +    rvalue->get_debug_string (),
> > +    rvalue->get_type ()->get_debug_string (),
> > +    type->get_debug_string ());*/
> 
> I belive that in general we can't do the checking for equal size
> until
> we have trees i.e. at playback time.  I suspect that if the user gets
> this wrong, it will lead to an internal compiler error at playback
> time.

Done.

> 
> Please can you add a testcase that tests mismatching sizes e.g.
> trying
> to interpret an int as a array of 4096 bytes, or something similar
> that's wildly wrong (ideally coverage for casting in both
> directions).

Done.

>  
> Ideally we can generate a useful error message, or, at least, not
> crash.
> 
> > +
> > +  return static_cast <gcc_jit_rvalue *> (ctxt->new_bitcast (loc,
> > rvalue, type));
> > +}
> > +
> >  /* Public entrypoint.  See description in libgccjit.h.
> >  
> >     After error-checking, the real work is done by the
> 
> [...snip...]
> 
> > diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h
> > b/gcc/testsuite/jit.dg/all-non-failing-tests.h
> > index 29afe064db6..656351edce1 100644
> > --- a/gcc/testsuite/jit.dg/all-non-failing-tests.h
> > +++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h
> > @@ -77,6 +77,13 @@
> >  /* test-builtin-unreachable.c: We don't add this one, since it
> > touches
> >     the optimization level of the context as a whole.  */
> >  
> > +/* test-bitcast.c */
> > +#define create_code create_code_bitcast
> > +#define verify_code verify_code_bitcast
> > +#include "test-bitcast.c"
> > +#undef create_code
> > +#undef verify_code
> > +
> >  /* test-calling-external-function.c */
> >  #define create_code create_code_calling_external_function
> >  #define verify_code verify_code_calling_external_function
> > @@ -400,6 +407,9 @@ const struct testcase testcases[] = {
> >    {"builtin-memcpy",
> >     create_code_builtin_memcpy,
> >     verify_code_builtin_memcpy},
> > +  {"bitcast",
> > +   create_code_bitcast,
> > +   verify_code_bitcast},
> >    {"calling_external_function",
> >     create_code_calling_external_function,
> >     verify_code_calling_external_function},
> > diff --git a/gcc/testsuite/jit.dg/test-bitcast.c
> > b/gcc/testsuite/jit.dg/test-bitcast.c
> > new file mode 100644
> > index 00000000000..2d70622051a
> > --- /dev/null
> > +++ b/gcc/testsuite/jit.dg/test-bitcast.c
> > @@ -0,0 +1,60 @@
> > +#include <stdlib.h>
> > +#include <stdio.h>
> > +#include <string.h>
> > +
> > +#include "libgccjit.h"
> > +
> > +#include "harness.h"
> > +
> > +void
> > +create_code (gcc_jit_context *ctxt, void *user_data)
> > +{
> > +  /* Let's try to inject the equivalent of:
> > +int
> > +my_bitcast (double x)
> > +{
> > +   return bitcast(x, int);
> > +}
> > +   */
> > +  gcc_jit_type *int_type =
> > +    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
> > +  gcc_jit_type *double_type =
> > +    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT);
> 
> This says "double_type" but is GCC_JIT_TYPE_FLOAT.
> 
> I don't think we're guaranteed that sizeof(int) == sizeof(float) on
> all targets.

I switched to using `gcc_jit_context_get_int_type (ctxt, 4, 1)` for the
integer type.

> 
> > +
> > +  gcc_jit_param *x =
> > +    gcc_jit_context_new_param (
> > +      ctxt,
> > +      NULL,
> > +      double_type, "x");
> > +  gcc_jit_param *params[1] = {x};
> > +  gcc_jit_function *func =
> > +    gcc_jit_context_new_function (ctxt,
> > +                                 NULL,
> > +                                 GCC_JIT_FUNCTION_EXPORTED,
> > +                                 int_type,
> > +                                 "my_bitcast",
> > +                                 1, params, 0);
> > +
> > +  gcc_jit_block *initial =
> > +    gcc_jit_function_new_block (func, "initial");
> > +
> > +  gcc_jit_block_end_with_return(initial, NULL,
> > +    gcc_jit_context_new_bitcast(ctxt,
> > +        NULL,
> > +        gcc_jit_param_as_rvalue(x),
> > +        int_type
> > +    ));
> > +}
> > +
> > +void
> > +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
> > +{
> > +  typedef int (*my_bitcast_fn_type) (double);
> > +  CHECK_NON_NULL (result);
> > +  my_bitcast_fn_type my_bitcast =
> > +    (my_bitcast_fn_type)gcc_jit_result_get_code (result,
> "my_bitcast");
> > +  CHECK_NON_NULL (my_bitcast);
> > +  int val = my_bitcast (-5.1298714);
> > +  note ("my_bitcast returned: %d", val);
> > +  CHECK_VALUE (val, 35569201);
> > +}
> > diff --git a/gcc/tree.c b/gcc/tree.c
> > index d98b77db50b..e4bf4e84675 100644
> > --- a/gcc/tree.c
> > +++ b/gcc/tree.c
> > @@ -6963,6 +6963,14 @@ build_reference_type (tree to_type)
> >    (HOST_BITS_PER_WIDE_INT > 64 ? HOST_BITS_PER_WIDE_INT : 64)
> >  static GTY(()) tree nonstandard_integer_type_cache[2 *
> MAX_INT_CACHED_PREC + 2];
> >  
> > +void clear_nonstandard_integer_type_cache (void)
> > +{
> > +  for (size_t i = 0 ; i < 2 * MAX_INT_CACHED_PREC + 2 ; i++)
> > +  {
> > +    nonstandard_integer_type_cache[i] = NULL;
> > +  }
> > +}
> > +
> 
> As noted above (for gcc/jit/dummy-frontend.c), make this static, and
> call it from a new tree_cc_finalize function, and call that from
> toplev::finalize.
> 
> >  /* Builds a signed or unsigned integer type of precision
> > PRECISION.
> >     Used for C bitfields whose precision does not match that of
> >     built-in target types.  */
> > diff --git a/gcc/tree.h b/gcc/tree.h
> > index 318019c4dc5..640b492802c 100644
> > --- a/gcc/tree.h
> > +++ b/gcc/tree.h
> > @@ -5385,6 +5385,7 @@ extern bool real_minus_onep (const_tree);
> >  extern void init_ttree (void);
> >  extern void build_common_tree_nodes (bool);
> >  extern void build_common_builtin_nodes (void);
> > +extern void clear_nonstandard_integer_type_cache (void);
> 
> ...and get rid of this in favor of a tree_cc_finalize.
> 
> >  extern tree build_nonstandard_integer_type (unsigned
> > HOST_WIDE_INT,
> int);
> >  extern tree build_nonstandard_boolean_type (unsigned
> > HOST_WIDE_INT);
> >  extern tree build_range_type (tree, tree, tree);
> > -- 
> > 2.26.2.7.g19db9cfb68.dirty
> > 
> 
> Hope this is constructive; thanks again for the patch
> Dave
> 


[-- Attachment #2: 0001-libgccjit-Add-support-for-bitcasts-PR104071.patch --]
[-- Type: text/x-patch, Size: 20830 bytes --]

From d7f49170394de78471164a9fb8d08ad92508b42a Mon Sep 17 00:00:00 2001
From: Antoni Boucher <bouanto@zoho.com>
Date: Wed, 9 Jun 2021 18:29:14 -0400
Subject: [PATCH] libgccjit: Add support for bitcasts [PR104071]

2022-01-21  Antoni Boucher <bouanto@zoho.com>

gcc/jit/
	PR jit/104071
	* docs/topics/compatibility.rst (LIBGCCJIT_ABI_21): New ABI tag.
	* docs/topics/expressions.rst: Add documentation for the
	function gcc_jit_context_new_bitcast.
	* jit-playback.cc: New function (new_bitcast).
	* jit-playback.h: New function (new_bitcast).
	* jit-recording.cc: New functions (new_bitcast,
	bitcast::replay_into, bitcast::visit_children,
	bitcast::make_debug_string, bitcast::write_reproducer).
	* jit-recording.h: New calss (bitcast) and new function
	(new_bitcast, bitcast::replay_into, bitcast::visit_children,
	bitcast::make_debug_string, bitcast::write_reproducer,
	bitcast::get_precedence).
	* libgccjit.cc: New function (gcc_jit_context_new_bitcast)
	* libgccjit.h: New function (gcc_jit_context_new_bitcast)
	* libgccjit.map (LIBGCCJIT_ABI_21): New ABI tag.

gcc/testsuite/
	PR jit/104071
	* jit.dg/all-non-failing-tests.h: Add new test-bitcast.
	* jit.dg/test-bitcast.c: New test.
	* jit.dg/test-error-bad-bitcast.c: New test.
	* jit.dg/test-error-bad-bitcast2.c: New test.

gcc/
	PR jit/104071
	* toplev.cc: Call the new function tree_cc_finalize in
	toplev::finalize.
	* tree.cc: New functions (clear_nonstandard_integer_type_cache
	and tree_cc_finalize) to clear the cache of non-standard integer
	types to avoid having issues with some optimizations of
	bitcast where the SSA_NAME will have a size of a cached
	integer type that should have been invalidated, causing a
	comparison of integer constant to fail.
	* tree.h: New function (tree_cc_finalize).
---
 gcc/jit/docs/topics/compatibility.rst         |  9 +++
 gcc/jit/docs/topics/expressions.rst           | 19 ++++++
 gcc/jit/jit-playback.cc                       | 27 ++++++++
 gcc/jit/jit-playback.h                        |  5 ++
 gcc/jit/jit-recording.cc                      | 66 +++++++++++++++++++
 gcc/jit/jit-recording.h                       | 32 +++++++++
 gcc/jit/libgccjit.cc                          | 28 ++++++++
 gcc/jit/libgccjit.h                           | 15 +++++
 gcc/jit/libgccjit.map                         |  9 +++
 gcc/testsuite/jit.dg/all-non-failing-tests.h  | 10 +++
 gcc/testsuite/jit.dg/test-bitcast.c           | 60 +++++++++++++++++
 gcc/testsuite/jit.dg/test-error-bad-bitcast.c | 62 +++++++++++++++++
 .../jit.dg/test-error-bad-bitcast2.c          | 62 +++++++++++++++++
 gcc/toplev.cc                                 |  1 +
 gcc/tree.cc                                   | 15 +++++
 gcc/tree.h                                    |  1 +
 16 files changed, 421 insertions(+)
 create mode 100644 gcc/testsuite/jit.dg/test-bitcast.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-bad-bitcast.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-bad-bitcast2.c

diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst
index 16cebe31a10..610d9dc175f 100644
--- a/gcc/jit/docs/topics/compatibility.rst
+++ b/gcc/jit/docs/topics/compatibility.rst
@@ -302,3 +302,12 @@ thread-local storage model of a variable:
 section of a variable:
 
   * :func:`gcc_jit_lvalue_set_link_section`
+
+.. _LIBGCCJIT_ABI_21:
+
+``LIBGCCJIT_ABI_21``
+-----------------------
+``LIBGCCJIT_ABI_21`` covers the addition of an API entrypoint to bitcast a
+value from one type to another:
+
+  * :func:`gcc_jit_context_new_bitcast`
diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst
index 791a20398ca..e0b6f426aee 100644
--- a/gcc/jit/docs/topics/expressions.rst
+++ b/gcc/jit/docs/topics/expressions.rst
@@ -649,6 +649,25 @@ Type-coercion
      * int <-> bool
      * P*  <-> Q*, for pointer types P and Q
 
+.. function:: gcc_jit_rvalue *\
+              gcc_jit_context_new_bitcast (gcc_jit_context *ctxt,\
+                                           gcc_jit_location *loc,\
+                                           gcc_jit_rvalue *rvalue,\
+                                           gcc_jit_type *type)
+
+   Given an rvalue of T, bitcast it to another type, meaning that this will
+   generate a new rvalue by interpreting the bits of ``rvalue`` to the layout
+   of ``type``.
+
+   The type of rvalue must be the same size as the size of ``type``.
+
+   This entrypoint was added in :ref:`LIBGCCJIT_ABI_21`; you can test for
+   its presence using
+
+   .. code-block:: c
+
+      #ifdef LIBGCCJIT_HAVE_gcc_jit_context_new_bitcast
+
 Lvalues
 -------
 
diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc
index d1835c79863..d2efae1c163 100644
--- a/gcc/jit/jit-playback.cc
+++ b/gcc/jit/jit-playback.cc
@@ -1390,6 +1390,33 @@ new_cast (playback::location *loc,
   return new rvalue (this, t_cast);
 }
 
+playback::rvalue *
+playback::context::
+new_bitcast (location *loc,
+		       rvalue *expr,
+		       type *type_)
+{
+  tree expr_size = TYPE_SIZE (expr->get_type ()->as_tree ());
+  tree type_size = TYPE_SIZE (type_->as_tree ());
+  tree t_expr = expr->as_tree ();
+  tree t_dst_type = type_->as_tree ();
+  if (expr_size != type_size)
+  {
+    active_playback_ctxt->add_error (loc,
+      "bitcast with types of different sizes");
+    fprintf (stderr, "input expression (size: %ld):\n",
+      tree_to_uhwi (expr_size));
+    debug_tree (t_expr);
+    fprintf (stderr, "requested type (size: %ld):\n",
+      tree_to_uhwi (type_size));
+    debug_tree (t_dst_type);
+  }
+  tree t_bitcast = build1 (VIEW_CONVERT_EXPR, t_dst_type, t_expr);
+  if (loc)
+    set_tree_location (t_bitcast, loc);
+  return new rvalue (this, t_bitcast);
+}
+
 /* Construct a playback::lvalue instance (wrapping a tree) for an
    array access.  */
 
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
index c93d7055d43..5b107be9d69 100644
--- a/gcc/jit/jit-playback.h
+++ b/gcc/jit/jit-playback.h
@@ -180,6 +180,11 @@ public:
 	    rvalue *expr,
 	    type *type_);
 
+  rvalue *
+  new_bitcast (location *loc,
+	       rvalue *expr,
+	       type *type_);
+
   lvalue *
   new_array_access (location *loc,
 		    rvalue *ptr,
diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc
index 1e3fadfacd7..e1029086da8 100644
--- a/gcc/jit/jit-recording.cc
+++ b/gcc/jit/jit-recording.cc
@@ -1242,6 +1242,22 @@ recording::context::new_cast (recording::location *loc,
   return result;
 }
 
+/* Create a recording::bitcast instance and add it to this context's list
+   of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_bitcast.  */
+
+recording::rvalue *
+recording::context::new_bitcast (location *loc,
+				 rvalue *expr,
+				 type *type_)
+{
+  recording::rvalue *result = new bitcast (this, loc, expr, type_);
+  record (result);
+  return result;
+}
+
 /* Create a recording::call instance and add it to this context's list
    of mementos.
 
@@ -5740,6 +5756,56 @@ recording::cast::write_reproducer (reproducer &r)
 	   r.get_identifier_as_type (get_type ()));
 }
 
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::bitcast.  */
+
+void
+recording::bitcast::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_bitcast (playback_location (r, m_loc),
+				    m_rvalue->playback_rvalue (),
+				    get_type ()->playback_type ()));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+   for recording::bitcast.  */
+void
+recording::bitcast::visit_children (rvalue_visitor *v)
+{
+  v->visit (m_rvalue);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   casts.  */
+
+recording::string *
+recording::bitcast::make_debug_string ()
+{
+  enum precedence prec = get_precedence ();
+  return string::from_printf (m_ctxt,
+			      "bitcast(%s, %s)",
+			      m_rvalue->get_debug_string_parens (prec),
+			      get_type ()->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for casts.  */
+
+void
+recording::bitcast::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "rvalue");
+  r.write ("  gcc_jit_rvalue *%s =\n"
+	   "    gcc_jit_context_new_bitcast (%s,\n"
+	   "                                 %s, /* gcc_jit_location *loc */\n"
+	   "                                 %s, /* gcc_jit_rvalue *rvalue */\n"
+	   "                                 %s); /* gcc_jit_type *type */\n",
+	   id,
+	   r.get_identifier (get_context ()),
+	   r.get_identifier (m_loc),
+	   r.get_identifier_as_rvalue (m_rvalue),
+	   r.get_identifier_as_type (get_type ()));
+}
+
 /* The implementation of class gcc::jit::recording::base_call.  */
 
 /* The constructor for gcc::jit::recording::base_call.  */
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index 846d65cb202..ed03b3a24c8 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -205,6 +205,11 @@ public:
 	    rvalue *expr,
 	    type *type_);
 
+  rvalue *
+  new_bitcast (location *loc,
+	       rvalue *expr,
+	       type *type_);
+
   lvalue *
   new_array_access (location *loc,
 		    rvalue *ptr,
@@ -1691,6 +1696,33 @@ private:
   rvalue *m_rvalue;
 };
 
+class bitcast : public rvalue
+{
+public:
+  bitcast (context *ctxt,
+	   location *loc,
+	   rvalue *a,
+	   type *type_)
+  : rvalue (ctxt, loc, type_),
+    m_rvalue (a)
+  {}
+
+  void replay_into (replayer *r) FINAL OVERRIDE;
+
+  void visit_children (rvalue_visitor *v) FINAL OVERRIDE;
+
+private:
+  string * make_debug_string () FINAL OVERRIDE;
+  void write_reproducer (reproducer &r) FINAL OVERRIDE;
+  enum precedence get_precedence () const FINAL OVERRIDE
+  {
+    return PRECEDENCE_CAST;
+  }
+
+private:
+  rvalue *m_rvalue;
+};
+
 class base_call : public rvalue
 {
  public:
diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc
index 4c352e8c93d..6bf1e1ceee0 100644
--- a/gcc/jit/libgccjit.cc
+++ b/gcc/jit/libgccjit.cc
@@ -2405,6 +2405,34 @@ gcc_jit_context_new_cast (gcc_jit_context *ctxt,
   return static_cast <gcc_jit_rvalue *> (ctxt->new_cast (loc, rvalue, type));
 }
 
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::new_bitcast method in jit-recording.c.  */
+
+gcc_jit_rvalue *
+gcc_jit_context_new_bitcast (gcc_jit_context *ctxt,
+			     gcc_jit_location *loc,
+			     gcc_jit_rvalue *rvalue,
+			     gcc_jit_type *type)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  /* LOC can be NULL.  */
+  RETURN_NULL_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
+  RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
+  // TODO: check the sizes.
+  /*RETURN_NULL_IF_FAIL_PRINTF3 (
+    is_valid_cast (rvalue->get_type (), type),
+    ctxt, loc,
+    "cannot cast %s from type: %s to type: %s",
+    rvalue->get_debug_string (),
+    rvalue->get_type ()->get_debug_string (),
+    type->get_debug_string ());*/
+
+  return static_cast <gcc_jit_rvalue *> (ctxt->new_bitcast (loc, rvalue, type));
+}
+
 /* 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 2a5ffacb1fe..960e4f4261e 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -1206,6 +1206,21 @@ gcc_jit_context_new_cast (gcc_jit_context *ctxt,
 			  gcc_jit_rvalue *rvalue,
 			  gcc_jit_type *type);
 
+/* Reinterpret a value as another type.
+
+#define LIBGCCJIT_HAVE_gcc_jit_context_new_bitcast
+
+   The types must be of the same size.
+
+   This API entrypoint was added in LIBGCCJIT_ABI_21; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_gcc_jit_context_new_bitcast  */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_bitcast (gcc_jit_context *ctxt,
+			     gcc_jit_location *loc,
+			     gcc_jit_rvalue *rvalue,
+			     gcc_jit_type *type);
+
 extern gcc_jit_lvalue *
 gcc_jit_context_new_array_access (gcc_jit_context *ctxt,
 				  gcc_jit_location *loc,
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index f373fd39ac7..38c355437bf 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -238,8 +238,17 @@ LIBGCCJIT_ABI_18 {
 } LIBGCCJIT_ABI_17;
 
 LIBGCCJIT_ABI_19 {
+  global:
     gcc_jit_context_new_array_constructor;
     gcc_jit_context_new_struct_constructor;
     gcc_jit_context_new_union_constructor;
     gcc_jit_global_set_initializer_rvalue;
 } LIBGCCJIT_ABI_18;
+
+LIBGCCJIT_ABI_20 {
+} LIBGCCJIT_ABI_19;
+
+LIBGCCJIT_ABI_21 {
+  global:
+    gcc_jit_context_new_bitcast;
+} LIBGCCJIT_ABI_20;
diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h
index 29afe064db6..656351edce1 100644
--- a/gcc/testsuite/jit.dg/all-non-failing-tests.h
+++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h
@@ -77,6 +77,13 @@
 /* test-builtin-unreachable.c: We don't add this one, since it touches
    the optimization level of the context as a whole.  */
 
+/* test-bitcast.c */
+#define create_code create_code_bitcast
+#define verify_code verify_code_bitcast
+#include "test-bitcast.c"
+#undef create_code
+#undef verify_code
+
 /* test-calling-external-function.c */
 #define create_code create_code_calling_external_function
 #define verify_code verify_code_calling_external_function
@@ -400,6 +407,9 @@ const struct testcase testcases[] = {
   {"builtin-memcpy",
    create_code_builtin_memcpy,
    verify_code_builtin_memcpy},
+  {"bitcast",
+   create_code_bitcast,
+   verify_code_bitcast},
   {"calling_external_function",
    create_code_calling_external_function,
    verify_code_calling_external_function},
diff --git a/gcc/testsuite/jit.dg/test-bitcast.c b/gcc/testsuite/jit.dg/test-bitcast.c
new file mode 100644
index 00000000000..a092fa117e6
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-bitcast.c
@@ -0,0 +1,60 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+int
+my_bitcast (double x)
+{
+   return bitcast(x, int);
+}
+   */
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_int_type (ctxt, 4, 1);
+  gcc_jit_type *float_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT);
+
+  gcc_jit_param *x =
+    gcc_jit_context_new_param (
+      ctxt,
+      NULL,
+      float_type, "x");
+  gcc_jit_param *params[1] = {x};
+  gcc_jit_function *func =
+    gcc_jit_context_new_function (ctxt,
+				  NULL,
+				  GCC_JIT_FUNCTION_EXPORTED,
+				  int_type,
+				  "my_bitcast",
+				  1, params, 0);
+
+  gcc_jit_block *initial =
+    gcc_jit_function_new_block (func, "initial");
+
+  gcc_jit_block_end_with_return(initial, NULL,
+    gcc_jit_context_new_bitcast(ctxt,
+        NULL,
+        gcc_jit_param_as_rvalue(x),
+        int_type
+    ));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef int (*my_bitcast_fn_type) (double);
+  CHECK_NON_NULL (result);
+  my_bitcast_fn_type my_bitcast =
+    (my_bitcast_fn_type)gcc_jit_result_get_code (result, "my_bitcast");
+  CHECK_NON_NULL (my_bitcast);
+  int val = my_bitcast (-5.1298714);
+  note ("my_bitcast returned: %d", val);
+  CHECK_VALUE (val, 35569201);
+}
diff --git a/gcc/testsuite/jit.dg/test-error-bad-bitcast.c b/gcc/testsuite/jit.dg/test-error-bad-bitcast.c
new file mode 100644
index 00000000000..642890605ad
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-bad-bitcast.c
@@ -0,0 +1,62 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+
+     int
+     test_fn ()
+     {
+       char f[4096];
+       return bitcast(f, int);
+     }
+
+     and verify that the API complains about the bad cast.
+  */
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *char_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR);
+
+
+  gcc_jit_type *array_type =
+    gcc_jit_context_new_array_type (ctxt, NULL, char_type, 4096);
+
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  int_type,
+                                  "test_fn",
+                                  0, NULL,
+                                  0);
+  gcc_jit_lvalue *f =
+    gcc_jit_function_new_local (
+      test_fn,
+      NULL,
+      array_type, "f");
+
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+  gcc_jit_block_end_with_return (
+    block, NULL,
+    gcc_jit_context_new_bitcast (ctxt, NULL,
+			      gcc_jit_lvalue_as_rvalue (f),
+			      int_type));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+		      "bitcast with types of different sizes");
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-bad-bitcast2.c b/gcc/testsuite/jit.dg/test-error-bad-bitcast2.c
new file mode 100644
index 00000000000..602ae407076
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-bad-bitcast2.c
@@ -0,0 +1,62 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+
+     char[4096]
+     test_fn ()
+     {
+       int f;
+       return bitcast(f, char[4096]);
+     }
+
+     and verify that the API complains about the bad cast.
+  */
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *char_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR);
+
+
+  gcc_jit_type *array_type =
+    gcc_jit_context_new_array_type (ctxt, NULL, char_type, 4096);
+
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  array_type,
+                                  "test_fn",
+                                  0, NULL,
+                                  0);
+  gcc_jit_lvalue *f =
+    gcc_jit_function_new_local (
+      test_fn,
+      NULL,
+      int_type, "f");
+
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+  gcc_jit_block_end_with_return (
+    block, NULL,
+    gcc_jit_context_new_bitcast (ctxt, NULL,
+			      gcc_jit_lvalue_as_rvalue (f),
+			      array_type));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+		      "bitcast with types of different sizes");
+}
+
diff --git a/gcc/toplev.cc b/gcc/toplev.cc
index 534da1462e8..bc4921974eb 100644
--- a/gcc/toplev.cc
+++ b/gcc/toplev.cc
@@ -2368,6 +2368,7 @@ toplev::finalize (void)
   gcse_c_finalize ();
   ipa_cp_c_finalize ();
   ira_costs_c_finalize ();
+  tree_cc_finalize ();
 
   /* save_decoded_options uses opts_obstack, so these must
      be cleaned up together.  */
diff --git a/gcc/tree.cc b/gcc/tree.cc
index ae159ee20ce..fe9d9083026 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -6963,6 +6963,15 @@ build_reference_type (tree to_type)
   (HOST_BITS_PER_WIDE_INT > 64 ? HOST_BITS_PER_WIDE_INT : 64)
 static GTY(()) tree nonstandard_integer_type_cache[2 * MAX_INT_CACHED_PREC + 2];
 
+static void
+clear_nonstandard_integer_type_cache (void)
+{
+  for (size_t i = 0 ; i < 2 * MAX_INT_CACHED_PREC + 2 ; i++)
+  {
+    nonstandard_integer_type_cache[i] = NULL;
+  }
+}
+
 /* Builds a signed or unsigned integer type of precision PRECISION.
    Used for C bitfields whose precision does not match that of
    built-in target types.  */
@@ -14565,6 +14574,12 @@ get_attr_nonstring_decl (tree expr, tree *ref)
   return NULL_TREE;
 }
 
+void
+tree_cc_finalize (void)
+{
+  clear_nonstandard_integer_type_cache ();
+}
+
 #if CHECKING_P
 
 namespace selftest {
diff --git a/gcc/tree.h b/gcc/tree.h
index 30bc53c2996..bf886fc2472 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -5385,6 +5385,7 @@ extern bool real_minus_onep (const_tree);
 extern void init_ttree (void);
 extern void build_common_tree_nodes (bool);
 extern void build_common_builtin_nodes (void);
+extern void tree_cc_finalize (void);
 extern tree build_nonstandard_integer_type (unsigned HOST_WIDE_INT, int);
 extern tree build_nonstandard_boolean_type (unsigned HOST_WIDE_INT);
 extern tree build_range_type (tree, tree, tree);
-- 
2.26.2.7.g19db9cfb68.dirty


  reply	other threads:[~2022-01-21 23:41 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-01-17 22:18 Antoni Boucher
2022-01-18  0:30 ` Antoni Boucher
2022-01-18 23:06   ` David Malcolm
2022-01-21 23:41     ` Antoni Boucher [this message]
2022-04-08 19:22       ` David Malcolm
2022-04-09 18:05         ` Antoni Boucher
2022-04-12 21:39           ` David Malcolm

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=1cb2b6d3e9a1afb6135a9dc1a97e85ba8c3a4a0d.camel@zoho.com \
    --to=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).