From: Marc Nieper-Wisskirchen <marc@nieper-wisskirchen.de>
To: gcc-patches@gcc.gnu.org, jit@gcc.gnu.org
Cc: Marc Nieper-Wisskirchen <marc@nieper-wisskirchen.de>
Subject: [PATCH 1/2] jit: structs/unions: bring the C++ API more on par with C
Date: Mon, 31 Jan 2022 17:34:39 +0100 [thread overview]
Message-ID: <20220131163440.8380-1-marc@nieper-wisskirchen.de> (raw)
This patch adds yet missing C++ API entry points to create union types
and to set the fields of structs previously defined as opaque. A
missing convenience method returning NULL pointer values is also added
and used in one of the two provided tests.
gcc/jit/ChangeLog:
* docs/cp/topics/expressions.rst: Update doc.
* docs/cp/topics/types.rst: Update doc.
* libgccjit++.h (context::new_union_type): New method.
(context::null): New method.
(type::null): New method.
(struct_::set_fields): New method.
gcc/testsuite/ChangeLog:
* jit.dg/test-accessing-union.cc: New test.
* jit.dg/test-linked-list.cc: New test.
---
gcc/jit/docs/cp/topics/expressions.rst | 10 ++
gcc/jit/docs/cp/topics/types.rst | 27 +++-
gcc/jit/libgccjit++.h | 61 ++++++++-
gcc/testsuite/jit.dg/test-accessing-union.cc | 86 +++++++++++++
gcc/testsuite/jit.dg/test-linked-list.cc | 128 +++++++++++++++++++
5 files changed, 304 insertions(+), 8 deletions(-)
create mode 100644 gcc/testsuite/jit.dg/test-accessing-union.cc
create mode 100644 gcc/testsuite/jit.dg/test-linked-list.cc
diff --git a/gcc/jit/docs/cp/topics/expressions.rst b/gcc/jit/docs/cp/topics/expressions.rst
index 239e004371e..3e9534790a3 100644
--- a/gcc/jit/docs/cp/topics/expressions.rst
+++ b/gcc/jit/docs/cp/topics/expressions.rst
@@ -86,6 +86,16 @@ Simple expressions
ctxt.new_rvalue (numeric_type, 1)
+.. function:: gccjit::rvalue \
+ gccjit::context::null (gccjit::type pointer_type) const
+
+ Given a pointer type, get the rvalue for the null pointer.
+ Essentially this is just a shortcut for:
+
+ .. code-block:: c++
+
+ ctxt.new_rvalue (pointer_type, (void *) 0)
+
.. function:: gccjit::rvalue \
gccjit::context::new_rvalue (gccjit::type numeric_type, \
double value) const
diff --git a/gcc/jit/docs/cp/topics/types.rst b/gcc/jit/docs/cp/topics/types.rst
index c695ceb3098..f41f504da6a 100644
--- a/gcc/jit/docs/cp/topics/types.rst
+++ b/gcc/jit/docs/cp/topics/types.rst
@@ -179,8 +179,6 @@ You can model C `struct` types by creating :class:`gccjit::struct_` and
fields.push_back (field_next);
node.set_fields (fields);
-.. FIXME: the above API doesn't seem to exist yet
-
.. function:: gccjit::field \
gccjit::context::new_field (gccjit::type type,\
const char *name, \
@@ -196,10 +194,25 @@ You can model C `struct` types by creating :class:`gccjit::struct_` and
Construct a new struct type, with the given name and fields.
.. function:: gccjit::struct_ \
- gccjit::context::new_opaque_struct (const std::string &name, \
- gccjit::location loc)
+ gccjit::context::new_opaque_struct (const std::string &name, \
+ gccjit::location loc)
Construct a new struct type, with the given name, but without
- specifying the fields. The fields can be omitted (in which case the
- size of the struct is not known), or later specified using
- :c:func:`gcc_jit_struct_set_fields`.
+ specifying the fields. The fields can be omitted (in which case
+ the size of the struct is not known), or later specified using
+ :func:`set_fields`.
+
+.. function:: void \
+ gccjit::struct_::set_fields (std::vector <field> &fields, \
+ gccjit::location loc)
+
+ Populate the fields of a formerly-opaque struct type.
+
+ This can only be called once on a given struct type.
+
+.. function:: gccjit::type \
+ gccjit::context::new_union_type (const std::string &name, \
+ std::vector<field> &fields,\
+ gccjit::location loc)
+
+ Construct a new union type, with the given name and fields.
diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h
index 4b88e877bc9..17b10bc55c3 100644
--- a/gcc/jit/libgccjit++.h
+++ b/gcc/jit/libgccjit++.h
@@ -165,6 +165,10 @@ namespace gccjit
struct_ new_opaque_struct_type (const std::string &name,
location loc = location ());
+ type new_union_type (const std::string &name,
+ std::vector <field> &fields,
+ location loc = location ());
+
param new_param (type type_,
const std::string &name,
location loc = location ());
@@ -189,6 +193,7 @@ namespace gccjit
long value) const;
rvalue zero (type numeric_type) const;
rvalue one (type numeric_type) const;
+ rvalue null (type pointer_type) const;
rvalue new_rvalue (type numeric_type,
double value) const;
rvalue new_rvalue (type pointer_type,
@@ -361,9 +366,10 @@ namespace gccjit
type get_aligned (size_t alignment_in_bytes);
type get_vector (size_t num_units);
- // Shortcuts for getting values of numeric types:
+ // Shortcuts for getting values of numeric and pointer types:
rvalue zero ();
rvalue one ();
+ rvalue null ();
};
class struct_ : public type
@@ -373,6 +379,9 @@ namespace gccjit
struct_ (gcc_jit_struct *inner);
gcc_jit_struct *get_inner_struct () const;
+
+ void set_fields (std::vector <field> &fields,
+ location loc = location ());
};
class function : public object
@@ -864,6 +873,26 @@ context::new_opaque_struct_type (const std::string &name,
name.c_str ()));
}
+inline type
+context::new_union_type (const std::string &name,
+ std::vector<field> &fields,
+ location loc)
+{
+ /* Treat std::vector as an array, relying on it not being resized: */
+ field *as_array_of_wrappers = &fields[0];
+
+ /* Treat the array as being of the underlying pointers, relying on
+ the wrapper type being such a pointer internally. */
+ gcc_jit_field **as_array_of_ptrs =
+ reinterpret_cast<gcc_jit_field **> (as_array_of_wrappers);
+
+ return type (gcc_jit_context_new_union_type (m_inner_ctxt,
+ loc.get_inner_location (),
+ name.c_str (),
+ fields.size (),
+ as_array_of_ptrs));
+}
+
inline param
context::new_param (type type_,
const std::string &name,
@@ -955,6 +984,13 @@ context::one (type numeric_type) const
numeric_type.get_inner_type ()));
}
+inline rvalue
+context::null (type pointer_type) const
+{
+ return rvalue (gcc_jit_context_null (m_inner_ctxt,
+ pointer_type.get_inner_type ()));
+}
+
inline rvalue
context::new_rvalue (type numeric_type,
double value) const
@@ -1442,6 +1478,12 @@ type::one ()
return get_context ().new_rvalue (*this, 1);
}
+inline rvalue
+type::null ()
+{
+ return get_context ().null (*this);
+}
+
// class struct_
inline struct_::struct_ () : type (NULL) {}
inline struct_::struct_ (gcc_jit_struct *inner) :
@@ -1456,6 +1498,23 @@ struct_::get_inner_struct () const
return reinterpret_cast<gcc_jit_struct *> (get_inner_object ());
}
+inline void
+struct_::set_fields (std::vector <field> &fields, location loc)
+{
+ /* Treat std::vector as an array, relying on it not being resized: */
+ field *as_array_of_wrappers = &fields[0];
+
+ /* Treat the array as being of the underlying pointers, relying on
+ the wrapper type being such a pointer internally. */
+ gcc_jit_field **as_array_of_ptrs =
+ reinterpret_cast<gcc_jit_field **> (as_array_of_wrappers);
+
+ gcc_jit_struct_set_fields (get_inner_struct (),
+ loc.get_inner_location (),
+ fields.size (),
+ as_array_of_ptrs);
+}
+
// class function
inline function::function () : object () {}
inline function::function (gcc_jit_function *inner)
diff --git a/gcc/testsuite/jit.dg/test-accessing-union.cc b/gcc/testsuite/jit.dg/test-accessing-union.cc
new file mode 100644
index 00000000000..8fa03fd209c
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-accessing-union.cc
@@ -0,0 +1,86 @@
+#include <cstdlib>
+#include <cstdio>
+#include <vector>
+
+#include "libgccjit++.h"
+
+#include "harness.h"
+
+union int_or_float
+{
+ int as_int;
+ float as_float;
+};
+
+void
+create_code (gcc_jit_context* c_ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+ float
+ test_union (int i)
+ {
+ union int_or_float u;
+ u.as_int = i;
+ return u.as_float;
+ }
+ */
+ gccjit::context ctxt (c_ctxt);
+ gccjit::type int_type =
+ ctxt.get_type (GCC_JIT_TYPE_INT);
+ gccjit::type float_type =
+ ctxt.get_type (GCC_JIT_TYPE_FLOAT);
+ gccjit::field as_int =
+ ctxt.new_field (int_type, "as_int");
+ gccjit::field as_float =
+ ctxt.new_field (float_type, "as_float");
+ std::vector <gccjit::field> fields;
+ fields.push_back (as_int);
+ fields.push_back (as_float);
+ gccjit::type union_type =
+ ctxt.new_union_type ("int_or_float", fields);
+
+ /* Build the test function. */
+ gccjit::param param_i =
+ ctxt.new_param (int_type, "i");
+ std::vector <gccjit::param> params;
+ params.push_back (param_i);
+ gccjit::function test_fn =
+ ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
+ float_type,
+ "test_union",
+ params,
+ 0);
+
+ gccjit::lvalue u =
+ test_fn.new_local (union_type, "u");
+
+ gccjit::block block = test_fn.new_block ();
+
+ /* u.as_int = i; */
+ block.add_assignment (
+ /* "u.as_int = ..." */
+ u.access_field (as_int),
+ param_i);
+
+ /* return u.as_float; */
+ block.end_with_return (u.access_field (as_float));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef float (*fn_type) (int i);
+ CHECK_NON_NULL (result);
+
+ fn_type test_union =
+ (fn_type)gcc_jit_result_get_code (result, "test_union");
+ CHECK_NON_NULL (test_union);
+
+ /* Call the JIT-generated function. */
+ float f_result = test_union (42);
+
+ union int_or_float u;
+ u.as_float = f_result;
+
+ CHECK_VALUE (u.as_int, 42);
+}
diff --git a/gcc/testsuite/jit.dg/test-linked-list.cc b/gcc/testsuite/jit.dg/test-linked-list.cc
new file mode 100644
index 00000000000..933ab706b00
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-linked-list.cc
@@ -0,0 +1,128 @@
+#include <cstdlib>
+#include <cstdio>
+#include <vector>
+
+#include "libgccjit++.h"
+
+#include "harness.h"
+
+/* A doubly-linked list, to ensure that the JIT API can cope with
+ self-referential types. */
+struct node
+{
+ struct node *prev;
+ struct node *next;
+ int value;
+};
+
+void
+create_code (gcc_jit_context *c_ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+ int
+ test_linked_list (struct node *n)
+ {
+ int total = 0;
+ while (n)
+ {
+ total += n->value;
+ n = n->next;
+ }
+ return total;
+ }
+ */
+ gccjit::context ctxt (c_ctxt);
+ gccjit::type t_int =
+ ctxt.get_type (GCC_JIT_TYPE_INT);
+ gccjit::struct_ t_node =
+ ctxt.new_opaque_struct_type ("node");
+ gccjit::type t_node_ptr =
+ t_node.get_pointer ();
+
+ gccjit::field f_prev =
+ ctxt.new_field (t_node_ptr, "prev");
+ gccjit::field f_next =
+ ctxt.new_field (t_node_ptr, "next");
+ gccjit::field f_value =
+ ctxt.new_field (t_int, "value");
+ std::vector <gccjit::field> fields;
+ fields.push_back (f_prev);
+ fields.push_back (f_next);
+ fields.push_back (f_value);
+ t_node.set_fields (fields);
+
+ /* Build the test function. */
+ gccjit::param param_n =
+ ctxt.new_param (t_node_ptr, "n");
+ std::vector <gccjit::param> params;
+ params.push_back (param_n);
+ gccjit::function fn =
+ ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
+ t_int,
+ "test_linked_list",
+ params,
+ 0);
+ /* int total; */
+ gccjit::lvalue total =
+ fn.new_local (t_int, "total");
+
+ gccjit::block initial = fn.new_block ("initial");
+ gccjit::block loop_test = fn.new_block ("loop_test");
+ gccjit::block loop_body = fn.new_block ("loop_body");
+ gccjit::block final = fn.new_block ("final");
+
+ /* total = 0; */
+ initial.add_assignment (
+ total,
+ ctxt.zero (t_int));
+ initial.end_with_jump (loop_test);
+
+ /* while (n) */
+ loop_test.end_with_conditional (param_n != t_node_ptr.null (),
+ loop_body,
+ final);
+
+ /* total += n->value; */
+ loop_body.add_assignment_op (total,
+ GCC_JIT_BINARY_OP_PLUS,
+ param_n.dereference_field (f_value));
+
+ /* n = n->next; */
+ loop_body.add_assignment (param_n,
+ param_n.dereference_field (f_next));
+
+ loop_body.end_with_jump (loop_test);
+
+ /* return total; */
+ final.end_with_return (total);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ struct node a, b, c;
+ typedef int (*fn_type) (struct node *n);
+ CHECK_NON_NULL (result);
+
+ fn_type test_linked_list =
+ (fn_type)gcc_jit_result_get_code (result, "test_linked_list");
+ CHECK_NON_NULL (test_linked_list);
+
+ /* Construct a simple linked-list on the stack: a->b->c: */
+ a.prev = NULL;
+ a.next = &b;
+ a.value = 5;
+
+ b.prev = &a;
+ b.next = &c;
+ b.value = 3;
+
+ c.prev = &b;
+ c.next = NULL;
+ c.value = 7;
+
+ CHECK_VALUE (test_linked_list (NULL), 0);
+ CHECK_VALUE (test_linked_list (&a), 15);
+ CHECK_VALUE (test_linked_list (&b), 10);
+ CHECK_VALUE (test_linked_list (&c), 7);
+}
--
2.32.0
next reply other threads:[~2022-01-31 16:35 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-01-31 16:34 Marc Nieper-Wisskirchen [this message]
2022-01-31 16:34 ` [PATCH 2/2] jit: function pointers: " Marc Nieper-Wisskirchen
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=20220131163440.8380-1-marc@nieper-wisskirchen.de \
--to=marc@nieper-wisskirchen.de \
--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).