public inbox for jit@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 1/2] jit: structs/unions: bring the C++ API more on par with C
@ 2022-01-31 16:34 Marc Nieper-Wisskirchen
  2022-01-31 16:34 ` [PATCH 2/2] jit: function pointers: " Marc Nieper-Wisskirchen
  0 siblings, 1 reply; 2+ messages in thread
From: Marc Nieper-Wisskirchen @ 2022-01-31 16:34 UTC (permalink / raw)
  To: gcc-patches, jit

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


^ permalink raw reply	[flat|nested] 2+ messages in thread

* [PATCH 2/2] jit: function pointers: bring the C++ API more on par with C
  2022-01-31 16:34 [PATCH 1/2] jit: structs/unions: bring the C++ API more on par with C Marc Nieper-Wisskirchen
@ 2022-01-31 16:34 ` Marc Nieper-Wisskirchen
  0 siblings, 0 replies; 2+ messages in thread
From: Marc Nieper-Wisskirchen @ 2022-01-31 16:34 UTC (permalink / raw)
  To: gcc-patches, jit

This patch adds yet missing support for creating function pointer
types and to call functions through functions pointers in the C++ API
of libgccjit.

The method gccjit::context::new_call is overloaded so that it accepts
an rvalue instead of a function argument.  Instead of creating ad-hoc
specializations for 0 to 6 arguments, another overload taking an
initializer list instead of a vector is added.

gcc/jit/ChangeLog:

	* docs/cp/topics/expressions.rst: Updated.
	* docs/cp/topics/types.rst: Updated.
	* libgccjit++.h (context::new_function_ptr_type):
          New method.
	  (context::new_call): New method overloads.

gcc/testsuite/ChangeLog:

	* jit.dg/test-calling-function-ptr.cc: New test.
---
 gcc/jit/docs/cp/topics/expressions.rst        | 34 +++++--
 gcc/jit/docs/cp/topics/types.rst              | 16 ++++
 gcc/jit/libgccjit++.h                         | 70 ++++++++++++++
 .../jit.dg/test-calling-function-ptr.cc       | 93 +++++++++++++++++++
 4 files changed, 204 insertions(+), 9 deletions(-)
 create mode 100644 gcc/testsuite/jit.dg/test-calling-function-ptr.cc

diff --git a/gcc/jit/docs/cp/topics/expressions.rst b/gcc/jit/docs/cp/topics/expressions.rst
index 3e9534790a3..d6c8f0de156 100644
--- a/gcc/jit/docs/cp/topics/expressions.rst
+++ b/gcc/jit/docs/cp/topics/expressions.rst
@@ -119,8 +119,8 @@ Vector expressions
 ******************
 
 .. function:: gccjit::rvalue \
-	      gccjit::context::new_rvalue (gccjit::type vector_type, \
-	                                   std::vector<gccjit::rvalue> elements) const
+              gccjit::context::new_rvalue (gccjit::type vector_type, \
+                                           std::vector<gccjit::rvalue> elements) const
 
    Given a vector type, and a vector of scalar rvalue elements, generate a
    vector rvalue.
@@ -454,13 +454,13 @@ The most concise way to spell them is with overloaded operators:
 
 Function calls
 **************
-.. function:: gcc_jit_rvalue *\
-              gcc_jit_context_new_call (gcc_jit_context *ctxt,\
-                                        gcc_jit_location *loc,\
-                                        gcc_jit_function *func,\
-                                        int numargs , gcc_jit_rvalue **args)
 
-   Given a function and the given table of argument rvalues, construct a
+.. function:: gccjit::rvalue \
+              gccjit::context::new_call (gccjit::function func, \
+                                         std::vector <gccjit::rvalue> &args, \
+                                         gccjit::location loc)
+
+   Given a function and the given vector of argument rvalues, construct a
    call to the function, with the result as an rvalue.
 
    .. note::
@@ -480,11 +480,27 @@ Function calls
          /* Add "(void)printf (arg0, arg1);".  */
          block.add_eval (ctxt.new_call (printf_func, arg0, arg1));
 
+.. function:: gccjit::rvalue \
+              gccjit::context::new_call (gccjit::rvalue fn_ptr, \
+                                         std::vector <gccjit::rvalue> &args, \
+                                         gccjit::location loc)
+
+   Given a function and the given vector of argument rvalues, construct a
+   call to the function, with the result as an rvalue.
+
+.. function:: gccjit::rvalue \
+   gccjit::context::new_call (gccjit::rvalue fn_ptr, \
+                              std::initializer_list <gccjit::rvalue> args, \
+                              gccjit::location loc)
+
+   Given a function and the given list of argument rvalues, construct a
+   call to the function, with the result as an rvalue.
+
 Function pointers
 *****************
 
 .. function:: gccjit::rvalue \
-	      gccjit::function::get_address (gccjit::location loc)
+              gccjit::function::get_address (gccjit::location loc)
 
    Get the address of a function as an rvalue, of function pointer
    type.
diff --git a/gcc/jit/docs/cp/topics/types.rst b/gcc/jit/docs/cp/topics/types.rst
index f41f504da6a..8c677d74834 100644
--- a/gcc/jit/docs/cp/topics/types.rst
+++ b/gcc/jit/docs/cp/topics/types.rst
@@ -216,3 +216,19 @@ You can model C `struct` types by creating :class:`gccjit::struct_` and
 					       gccjit::location loc)
 
    Construct a new union type, with the given name and fields.
+
+
+Function pointer types
+----------------------
+
+.. function::  gccjit::type \
+   gccjit::context::new_function_ptr_type (gccjit::type return_type, \
+                                           std::vector <type> &param_types, \
+                                           int is_variadic, \
+                                           gccjit::location loc)
+
+   Generate a :class:`type` for a function pointer with the given
+   return type and parameters.
+
+   Each of `param_types` must be non-`void`; `return_type` may be
+   `void`.
diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h
index 17b10bc55c3..fa06c9cc4e1 100644
--- a/gcc/jit/libgccjit++.h
+++ b/gcc/jit/libgccjit++.h
@@ -169,6 +169,11 @@ namespace gccjit
 			 std::vector <field> &fields,
 			 location loc = location ());
 
+    type new_function_ptr_type (type return_type,
+				std::vector <type> &param_types,
+				int is_variadic,
+				location loc = location ());
+
     param new_param (type type_,
 		     const std::string &name,
 		     location loc = location ());
@@ -324,6 +329,11 @@ namespace gccjit
 		     rvalue arg3, rvalue arg4, rvalue arg5,
 		     location loc = location ());
 
+    rvalue new_call (rvalue fn_ptr, std::vector <rvalue> &args,
+		     location loc = location ());
+    rvalue new_call (rvalue fn_ptr, std::initializer_list <rvalue> args,
+		     location loc = location ());
+
     rvalue new_cast (rvalue expr,
 		     type type_,
 		     location loc = location ());
@@ -893,6 +903,29 @@ context::new_union_type (const std::string &name,
 					       as_array_of_ptrs));
 }
 
+inline type
+context::new_function_ptr_type (type return_type,
+				std::vector <type> &param_types,
+				int is_variadic,
+				location loc)
+{
+  /* Treat std::vector as an array, relying on it not being resized: */
+  type *as_array_of_wrappers = &param_types[0];
+
+  /* Treat the array as being of the underlying pointers, relying on
+     the wrapper type being such a pointer internally.	*/
+  gcc_jit_type **as_array_of_ptrs =
+    reinterpret_cast<gcc_jit_type **> (as_array_of_wrappers);
+
+  return type
+    (gcc_jit_context_new_function_ptr_type (m_inner_ctxt,
+					    loc.get_inner_location (),
+					    return_type.get_inner_type (),
+					    param_types.size (),
+					    as_array_of_ptrs,
+					    is_variadic));
+}
+
 inline param
 context::new_param (type type_,
 		    const std::string &name,
@@ -1241,6 +1274,7 @@ context::new_call (function func,
 				   args.size (),
 				   as_array_of_ptrs);
 }
+
 inline rvalue
 context::new_call (function func,
 		   location loc)
@@ -1322,6 +1356,42 @@ context::new_call (function func,
   return new_call (func, args, loc);
 }
 
+inline rvalue
+context::new_call (rvalue fn_ptr, std::vector <rvalue> &args,
+		   location loc)
+{
+  /* Treat std::vector as an array, relying on it not being resized: */
+  rvalue *as_array_of_wrappers = &args[0];
+
+  /* Treat the array as being of the underlying pointers, relying on
+     the wrapper type being such a pointer internally.	*/
+  gcc_jit_rvalue **as_array_of_ptrs =
+    reinterpret_cast<gcc_jit_rvalue **> (as_array_of_wrappers);
+  return gcc_jit_context_new_call_through_ptr (m_inner_ctxt,
+					       loc.get_inner_location (),
+					       fn_ptr.get_inner_rvalue (),
+					       args.size (),
+					       as_array_of_ptrs);
+}
+
+inline rvalue
+context::new_call (rvalue fn_ptr, std::initializer_list <rvalue> args,
+		   location loc)
+{
+  /* We rely on the underlying C API not modifying the values. */
+  rvalue *as_array_of_wrappers = const_cast <rvalue *> (args.begin ());
+
+  /* Treat the array as being of the underlying pointers, relying on
+     the wrapper type being such a pointer internally.	*/
+  gcc_jit_rvalue **as_array_of_ptrs =
+    reinterpret_cast<gcc_jit_rvalue **> (as_array_of_wrappers);
+  return gcc_jit_context_new_call_through_ptr (m_inner_ctxt,
+					       loc.get_inner_location (),
+					       fn_ptr.get_inner_rvalue (),
+					       args.size (),
+					       as_array_of_ptrs);
+}
+
 inline rvalue
 context::new_cast (rvalue expr,
 		   type type_,
diff --git a/gcc/testsuite/jit.dg/test-calling-function-ptr.cc b/gcc/testsuite/jit.dg/test-calling-function-ptr.cc
new file mode 100644
index 00000000000..f83b08b8869
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-calling-function-ptr.cc
@@ -0,0 +1,93 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit++.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *c_ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+
+     void
+     test_calling_function_ptr (void (*fn_ptr) (int, int, int) fn_ptr,
+                                int a)
+     {
+        fn_ptr (a * 3, a * 4, a * 5);
+     }
+  */
+
+  gccjit::context ctxt (c_ctxt);
+
+  int i;
+  gccjit::type void_type =
+    ctxt.get_type (GCC_JIT_TYPE_VOID);
+  gccjit::type int_type =
+    ctxt.get_type (GCC_JIT_TYPE_INT);
+
+  /* Build the function ptr type.  */
+  std::vector param_types {
+    int_type,
+    int_type,
+    int_type
+  };
+  gccjit::type fn_ptr_type =
+    ctxt.new_function_ptr_type (void_type, param_types, 0);
+
+  /* Build the test_fn.  */
+  gccjit::param param_fn_ptr =
+    ctxt.new_param (fn_ptr_type, "fn_ptr");
+  gccjit::param param_a =
+    ctxt.new_param (int_type, "a");
+
+  std::vector params {param_fn_ptr, param_a};
+  gccjit::function test_fn =
+    ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
+                       void_type,
+                       "test_calling_function_ptr",
+                       params,
+                       0);
+  /* "a * 3, a * 4, a * 5"  */
+  gccjit::rvalue args[3];
+  for (i = 0; i < 3; i++)
+    args[i] = param_a * ctxt.new_rvalue (int_type, i + 3);
+  gccjit::block block = test_fn.new_block ();
+  block.add_eval (ctxt.new_call (param_fn_ptr,
+                                 {args[0], args[1], args[2]}));
+  block.end_with_return ();
+}
+
+static int called_through_ptr_with[3];
+
+static void
+function_called_through_fn_ptr (int i, int j, int k)
+{
+  called_through_ptr_with[0] = i;
+  called_through_ptr_with[1] = j;
+  called_through_ptr_with[2] = k;
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef void (*fn_type) (void (*fn_ptr) (int, int, int),
+			   int);
+  CHECK_NON_NULL (result);
+
+  fn_type test_caller =
+    (fn_type)gcc_jit_result_get_code (result, "test_calling_function_ptr");
+  CHECK_NON_NULL (test_caller);
+
+  called_through_ptr_with[0] = 0;
+  called_through_ptr_with[1] = 0;
+  called_through_ptr_with[2] = 0;
+
+  /* Call the JIT-generated function.  */
+  test_caller (function_called_through_fn_ptr, 5);
+
+  /* Verify that it correctly called "function_called_through_fn_ptr".  */
+  CHECK_VALUE (called_through_ptr_with[0], 15);
+  CHECK_VALUE (called_through_ptr_with[1], 20);
+  CHECK_VALUE (called_through_ptr_with[2], 25);
+}
-- 
2.32.0


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2022-01-31 16:35 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-01-31 16:34 [PATCH 1/2] jit: structs/unions: bring the C++ API more on par with C Marc Nieper-Wisskirchen
2022-01-31 16:34 ` [PATCH 2/2] jit: function pointers: " Marc Nieper-Wisskirchen

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).