public inbox for jit@gcc.gnu.org
 help / color / mirror / Atom feed
* Re: Function pointer handling
  2017-01-01  0:00 ` David Malcolm
@ 2017-01-01  0:00   ` Bartosz Szreder
  2017-01-01  0:00     ` [committed] jit: implement gcc_jit_function_get_address David Malcolm
  2017-01-01  0:00   ` [committed] jit: document function pointers David Malcolm
  1 sibling, 1 reply; 5+ messages in thread
From: Bartosz Szreder @ 2017-01-01  0:00 UTC (permalink / raw)
  To: David Malcolm; +Cc: jit

Hello David,

>> 1. The documentation doesn't mention existence of
>> gcc_jit_context_new_function_ptr_type() as a mechanism of handling
>> function pointers, yet contains
>> gcc_jit_context_new_call_through_ptr().
>
> [...]
>
> It's just missing documentation.  I'm working on fixing it.
> Have a look at gcc/testsuite/jit.dg/test-calling-function-ptr.c

Thanks, this is very helpful!

>> - What is the proper way of obtaining a function pointer to be passed
>> to gcc_jit_context_new_call_through_ptr()? There doesn't seem to be
>> any counterpart to gcc_jit_lvalue_get_address() for functions. As the
>> name suggests, gcc_jit_lvalue_get_address() works on an L-value and
>> gcc_jit_function type isn't an ancestor of gcc_jit_lvalue in the
>> internal type system, therefore upcasting is impossible.
>
> [...]
>
> If it's a function that's being compiled as part of the same
> gcc_jit_context, then I think you've identified a weakness in the
> current API.  As you say, one fix would be to make gcc_jit_function be
> a subclass of gcc_jit_lvalue (and add casting functions); I don't yet
> know how easy that would be to implement.

Yes, this is the exact use case I'm thinking of.

From an user's point of view, I believe making gcc_jit_function a
subclass of gcc_jit_lvalue makes for an awkward design. Maybe
something like this would be easier to implement without upending the
current hierarchy:

gcc_jit_rvalue *gcc_jit_context_function_get_address(gcc_jit_context
*ctxt, gcc_jit_function *fun);

Thanks,
Bartosz Szreder

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

* [committed] jit: implement gcc_jit_function_get_address
  2017-01-01  0:00   ` Bartosz Szreder
@ 2017-01-01  0:00     ` David Malcolm
  0 siblings, 0 replies; 5+ messages in thread
From: David Malcolm @ 2017-01-01  0:00 UTC (permalink / raw)
  To: Bartosz Szreder; +Cc: jit, gcc-patches, David Malcolm

On Fri, 2017-09-22 at 11:21 +0200, Bartosz Szreder wrote:
> Hello David,
> 
> > > 1. The documentation doesn't mention existence of
> > > gcc_jit_context_new_function_ptr_type() as a mechanism of
> > > handling
> > > function pointers, yet contains
> > > gcc_jit_context_new_call_through_ptr().
> > 
> > [...]
> > 
> > It's just missing documentation.  I'm working on fixing it.
> > Have a look at gcc/testsuite/jit.dg/test-calling-function-ptr.c
> 
> Thanks, this is very helpful!
> 
> > > - What is the proper way of obtaining a function pointer to be
> > > passed
> > > to gcc_jit_context_new_call_through_ptr()? There doesn't seem to
> > > be
> > > any counterpart to gcc_jit_lvalue_get_address() for functions. As
> > > the
> > > name suggests, gcc_jit_lvalue_get_address() works on an L-value
> > > and
> > > gcc_jit_function type isn't an ancestor of gcc_jit_lvalue in the
> > > internal type system, therefore upcasting is impossible.
> > 
> > [...]
> > 
> > If it's a function that's being compiled as part of the same
> > gcc_jit_context, then I think you've identified a weakness in the
> > current API.  As you say, one fix would be to make gcc_jit_function
> > be
> > a subclass of gcc_jit_lvalue (and add casting functions); I don't
> > yet
> > know how easy that would be to implement.
> 
> Yes, this is the exact use case I'm thinking of.
> 
> From an user's point of view, I believe making gcc_jit_function a
> subclass of gcc_jit_lvalue makes for an awkward design. Maybe
> something like this would be easier to implement without upending the
> current hierarchy:
> 
> gcc_jit_rvalue *gcc_jit_context_function_get_address(gcc_jit_context
> *ctxt, gcc_jit_function *fun);
> 
> Thanks,
> Bartosz Szreder

Thanks.

I ended up adding the following:

  extern gcc_jit_rvalue *
  gcc_jit_function_get_address (gcc_jit_function *fn,
                                gcc_jit_location *loc);

FWIW I initially attempted to make functions be a subclass of rvalue
internally (within jit-recording.*, but ran into difficulties with
function::write_reproducer, which was having to do double-duty:
printing the body of the function AND printing the name of the function);
doing it all as a new API of functions ended up being simpler.

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu;
takes jit.sum from 9789 to 9889 PASS results.

Committed to trunk as r253244.

gcc/jit/ChangeLog:
	* docs/cp/topics/expressions.rst (Function pointers): New section.
	* docs/topics/compatibility.rst (LIBGCCJIT_ABI_9): New tag.
	* docs/topics/expressions.rst (Function pointers): New section.
	* docs/_build/texinfo/libgccjit.texi: Regenerate.
	* jit-common.h (class gcc::jit::recording::function_pointer): New
	forward decl.
	* jit-playback.c (gcc::jit::playback::function::get_address): New
	method.
	* jit-playback.h (gcc::jit::playback::function::get_address): New
	method decl.
	* jit-recording.c: Within namespace gcc::jit::recording...
	(function::function): Initialize new field "m_fn_ptr_type".
	(function::get_address): New method.
	(function_pointer::replay_into): New method.
	(function_pointer::visit_children): New method.
	(function_pointer::make_debug_string): New method.
	(function_pointer::write_reproducer): New method.
	* jit-recording.h: Within namespace gcc::jit::recording...
	(function::get_address): New method.
	(function): Add field "m_fn_ptr_type".
	(class function_pointer): New subclass of rvalue.
	* libgccjit++.h (gccjit::function::get_address): New method.
	* libgccjit.c (gcc_jit_function_get_address): New function.
	* libgccjit.h (LIBGCCJIT_HAVE_gcc_jit_function_get_address): New
	macro.
	(gcc_jit_function_get_address): New API entrypoint.
	* libgccjit.map (LIBGCCJIT_ABI_9): New tag.

gcc/testsuite/ChangeLog:
	* jit.dg/all-non-failing-tests.h: Add
	test-returning-function-ptr.c.
	* jit.dg/test-returning-function-ptr.c: New test case.
---
 gcc/jit/docs/cp/topics/expressions.rst             |   9 ++
 gcc/jit/docs/topics/compatibility.rst              |   7 +
 gcc/jit/docs/topics/expressions.rst                |  17 +++
 gcc/jit/jit-common.h                               |   1 +
 gcc/jit/jit-playback.c                             |  14 ++
 gcc/jit/jit-playback.h                             |   3 +
 gcc/jit/jit-recording.c                            |  77 ++++++++++-
 gcc/jit/jit-recording.h                            |  29 +++++
 gcc/jit/libgccjit++.h                              |   9 ++
 gcc/jit/libgccjit.c                                |  20 +++
 gcc/jit/libgccjit.h                                |  15 +++
 gcc/jit/libgccjit.map                              |   5 +
 gcc/testsuite/jit.dg/all-non-failing-tests.h       |  10 ++
 gcc/testsuite/jit.dg/test-returning-function-ptr.c | 143 +++++++++++++++++++++
 14 files changed, 358 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/jit.dg/test-returning-function-ptr.c

diff --git a/gcc/jit/docs/cp/topics/expressions.rst b/gcc/jit/docs/cp/topics/expressions.rst
index 2f317fff..147d065 100644
--- a/gcc/jit/docs/cp/topics/expressions.rst
+++ b/gcc/jit/docs/cp/topics/expressions.rst
@@ -459,6 +459,15 @@ Function calls
          /* Add "(void)printf (arg0, arg1);".  */
          block.add_eval (ctxt.new_call (printf_func, arg0, arg1));
 
+Function pointers
+*****************
+
+.. function:: gccjit::rvalue \
+	      gccjit::function::get_address (gccjit::location loc)
+
+   Get the address of a function as an rvalue, of function pointer
+   type.
+
 Type-coercion
 *************
 
diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst
index 1d5fbc2..8408939 100644
--- a/gcc/jit/docs/topics/compatibility.rst
+++ b/gcc/jit/docs/topics/compatibility.rst
@@ -156,3 +156,10 @@ entrypoints:
 -------------------
 ``LIBGCCJIT_ABI_8`` covers the addition of
 :func:`gcc_jit_type_get_vector`
+
+.. _LIBGCCJIT_ABI_9:
+
+``LIBGCCJIT_ABI_9``
+-------------------
+``LIBGCCJIT_ABI_9`` covers the addition of
+:func:`gcc_jit_function_get_address`
diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst
index 2534699..f5c2d0f 100644
--- a/gcc/jit/docs/topics/expressions.rst
+++ b/gcc/jit/docs/topics/expressions.rst
@@ -449,6 +449,23 @@ Function calls
 
       #ifdef LIBGCCJIT_HAVE_gcc_jit_rvalue_set_bool_require_tail_call
 
+Function pointers
+*****************
+
+.. function:: gcc_jit_rvalue *\
+	      gcc_jit_function_get_address (gcc_jit_function *fn,\
+                                            gcc_jit_location *loc)
+
+   Get the address of a function as an rvalue, of function pointer
+   type.
+
+   This entrypoint was added in :ref:`LIBGCCJIT_ABI_9`; you can test
+   for its presence using
+
+   .. code-block:: c
+
+      #ifdef LIBGCCJIT_HAVE_gcc_jit_function_get_address
+
 Type-coercion
 *************
 
diff --git a/gcc/jit/jit-common.h b/gcc/jit/jit-common.h
index 1fc558c..c931b3f 100644
--- a/gcc/jit/jit-common.h
+++ b/gcc/jit/jit-common.h
@@ -127,6 +127,7 @@ namespace recording {
 	class global;
         class param;
       class base_call;
+      class function_pointer;
     class statement;
     class case_;
 
diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
index 19b6fe2..5798179 100644
--- a/gcc/jit/jit-playback.c
+++ b/gcc/jit/jit-playback.c
@@ -1356,6 +1356,20 @@ new_block (const char *name)
   return result;
 }
 
+/* Construct a playback::rvalue instance wrapping an ADDR_EXPR for
+   this playback::function.  */
+
+playback::rvalue *
+playback::function::get_address (location *loc)
+{
+  tree t_fndecl = as_fndecl ();
+  tree t_fntype = TREE_TYPE (t_fndecl);
+  tree t_fnptr = build1 (ADDR_EXPR, build_pointer_type (t_fntype), t_fndecl);
+  if (loc)
+    m_ctxt->set_tree_location (t_fnptr, loc);
+  return new rvalue (m_ctxt, t_fnptr);
+}
+
 /* Build a statement list for the function as a whole out of the
    lists of statements for the individual blocks, building labels
    for each block.  */
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
index 7dc7315..746f5da 100644
--- a/gcc/jit/jit-playback.h
+++ b/gcc/jit/jit-playback.h
@@ -443,6 +443,9 @@ public:
   block*
   new_block (const char *name);
 
+  rvalue *
+  get_address (location *loc);
+
   void
   build_stmt_list ();
 
diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c
index 0e7f46e0..8481280 100644
--- a/gcc/jit/jit-recording.c
+++ b/gcc/jit/jit-recording.c
@@ -3452,7 +3452,8 @@ recording::function::function (context *ctxt,
   m_is_variadic (is_variadic),
   m_builtin_id (builtin_id),
   m_locals (),
-  m_blocks ()
+  m_blocks (),
+  m_fn_ptr_type (NULL)
 {
   for (int i = 0; i< num_params; i++)
     {
@@ -3725,6 +3726,35 @@ recording::function::dump_to_dot (const char *path)
   fclose (fp);
 }
 
+/* Implements the post-error-checking part of
+   gcc_jit_function_get_address.  */
+
+recording::rvalue *
+recording::function::get_address (recording::location *loc)
+{
+  /* Lazily create and cache the function pointer type.  */
+  if (!m_fn_ptr_type)
+    {
+      /* Make a recording::function_type for this function.  */
+      auto_vec <recording::type *> param_types (m_params.length ());
+      unsigned i;
+      recording::param *param;
+      FOR_EACH_VEC_ELT (m_params, i, param)
+	param_types.safe_push (param->get_type ());
+      recording::function_type *fn_type
+	= m_ctxt->new_function_type (m_return_type,
+				     m_params.length (),
+				     param_types.address (),
+				     m_is_variadic);
+      m_fn_ptr_type = fn_type->get_pointer ();
+    }
+  gcc_assert (m_fn_ptr_type);
+
+  rvalue *result = new function_pointer (get_context (), loc, this, m_fn_ptr_type);
+  m_ctxt->record (result);
+  return result;
+}
+
 /* Implementation of recording::memento::make_debug_string for
    functions.  */
 
@@ -5400,6 +5430,51 @@ recording::get_address_of_lvalue::write_reproducer (reproducer &r)
 	   r.get_identifier (m_loc));
 }
 
+/* The implementation of class gcc::jit::recording::function_pointer.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::function_pointer.  */
+
+void
+recording::function_pointer::replay_into (replayer *r)
+{
+  set_playback_obj (
+    m_fn->playback_function ()->
+      get_address (playback_location (r, m_loc)));
+}
+
+void
+recording::function_pointer::visit_children (rvalue_visitor *)
+{
+  /* Empty.  */
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   getting the address of an lvalue.  */
+
+recording::string *
+recording::function_pointer::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s",
+			      m_fn->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+   function_pointer.  */
+
+void
+recording::function_pointer::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "address_of");
+  r.write ("  gcc_jit_rvalue *%s =\n"
+	   "    gcc_jit_function_get_address (%s, /* gcc_jit_function *fn */\n"
+	   "                                  %s); /* gcc_jit_location *loc */\n",
+	   id,
+	   r.get_identifier (m_fn),
+	   r.get_identifier (m_loc));
+}
+
 /* The implementation of class gcc::jit::recording::local.  */
 
 /* Implementation of pure virtual hook recording::memento::replay_into
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index 248765d..8918124 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -1145,6 +1145,8 @@ public:
 
   void dump_to_dot (const char *path);
 
+  rvalue *get_address (location *loc);
+
 private:
   string * make_debug_string () FINAL OVERRIDE;
   void write_reproducer (reproducer &r) FINAL OVERRIDE;
@@ -1159,6 +1161,7 @@ private:
   enum built_in_function m_builtin_id;
   auto_vec<local *> m_locals;
   auto_vec<block *> m_blocks;
+  type *m_fn_ptr_type;
 };
 
 class block : public memento
@@ -1699,6 +1702,32 @@ private:
   lvalue *m_lvalue;
 };
 
+class function_pointer : public rvalue
+{
+public:
+  function_pointer (context *ctxt,
+		    location *loc,
+		    function *fn,
+		    type *type)
+  : rvalue (ctxt, loc, type),
+    m_fn (fn) {}
+
+  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_UNARY;
+  }
+
+private:
+  function *m_fn;
+};
+
 class local : public lvalue
 {
 public:
diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h
index a83ccf6..82997c3 100644
--- a/gcc/jit/libgccjit++.h
+++ b/gcc/jit/libgccjit++.h
@@ -368,6 +368,8 @@ namespace gccjit
 		      const std::string &name,
 		      location loc = location ());
 
+    rvalue get_address (location loc = location ());
+
     /* A series of overloaded operator () with various numbers of arguments
        for a very terse way of creating a call to this function.  The call
        is created within the same context as the function itself, which may
@@ -1392,6 +1394,13 @@ function::new_local (type type_,
 					     name.c_str ()));
 }
 
+inline rvalue
+function::get_address (location loc)
+{
+  return rvalue (gcc_jit_function_get_address (get_inner_function (),
+					       loc.get_inner_location ()));
+}
+
 inline function
 block::get_function () const
 {
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index 6e352c6..37cb695 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -3022,3 +3022,23 @@ gcc_jit_type_get_vector (gcc_jit_type *type, size_t num_units)
 
   return (gcc_jit_type *)type->get_vector (num_units);
 }
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::function::get_address method, in
+   jit-recording.c.  */
+
+gcc_jit_rvalue *
+gcc_jit_function_get_address (gcc_jit_function *fn,
+			      gcc_jit_location *loc)
+{
+  RETURN_NULL_IF_FAIL (fn, NULL, NULL, "NULL function");
+
+  gcc::jit::recording::context *ctxt = fn->m_ctxt;
+
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  /* LOC can be NULL.  */
+
+  return (gcc_jit_rvalue *)fn->get_address (loc);
+}
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index b863b07..18c03fb 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -1418,6 +1418,21 @@ gcc_jit_type_get_aligned (gcc_jit_type *type,
 extern gcc_jit_type *
 gcc_jit_type_get_vector (gcc_jit_type *type, size_t num_units);
 
+
+#define LIBGCCJIT_HAVE_gcc_jit_function_get_address
+
+/* Get the address of a function as an rvalue, of function pointer
+   type.
+
+   This API entrypoint was added in LIBGCCJIT_ABI_9; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_gcc_jit_function_get_address
+*/
+extern gcc_jit_rvalue *
+gcc_jit_function_get_address (gcc_jit_function *fn,
+			      gcc_jit_location *loc);
+
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index 08760e3..616e364 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -160,3 +160,8 @@ LIBGCCJIT_ABI_8 {
   global:
     gcc_jit_type_get_vector;
 } LIBGCCJIT_ABI_7;
+
+LIBGCCJIT_ABI_9 {
+  global:
+    gcc_jit_function_get_address;
+} LIBGCCJIT_ABI_8;
diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h
index acfcc40..bf02e12 100644
--- a/gcc/testsuite/jit.dg/all-non-failing-tests.h
+++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h
@@ -71,6 +71,13 @@
 #undef create_code
 #undef verify_code
 
+/* test-returning-function-ptr.c */
+#define create_code create_code_calling_internal_function
+#define verify_code verify_code_calling_internal_function
+#include "test-returning-function-ptr.c"
+#undef create_code
+#undef verify_code
+
 /* test-compound-assignment.c */
 #define create_code create_code_compound_assignment
 #define verify_code verify_code_compound_assignment
@@ -283,6 +290,9 @@ const struct testcase testcases[] = {
   {"calling_function_ptr",
    create_code_calling_function_ptr,
    verify_code_calling_function_ptr},
+  {"calling_internal_function",
+   create_code_calling_internal_function,
+   verify_code_calling_internal_function},
   {"compound_assignment",
    create_code_compound_assignment,
    verify_code_compound_assignment},
diff --git a/gcc/testsuite/jit.dg/test-returning-function-ptr.c b/gcc/testsuite/jit.dg/test-returning-function-ptr.c
new file mode 100644
index 0000000..2d4f01e
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-returning-function-ptr.c
@@ -0,0 +1,143 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  extern void
+  internally_called_function (int i, int j, int k);
+
+#ifdef __cplusplus
+}
+#endif
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+     extern void internally_called_function (int i, int j, int k);
+
+     static void
+     internal_test_caller (int a)
+     {
+        internally_called_function (a * 3, a * 4, a * 5);
+     }
+
+     void (*) (int)
+     get_test_caller (void)
+     {
+       return internal_test_caller;
+     }
+  */
+  int i;
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  /* Declare the imported function.  */
+  gcc_jit_param *params[3];
+  params[0] =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
+  params[1] =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "j");
+  params[2] =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "k");
+  gcc_jit_function *called_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+				  GCC_JIT_FUNCTION_IMPORTED,
+				  void_type,
+				  "internally_called_function",
+				  3, params,
+				  0);
+
+  /* Build the test_caller fn.  */
+  gcc_jit_param *param_a =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "a");
+  gcc_jit_function *test_caller =
+    gcc_jit_context_new_function (ctxt, NULL,
+				  GCC_JIT_FUNCTION_EXPORTED,
+				  void_type,
+				  "internal_test_caller",
+				  1, &param_a,
+				  0);
+  /* "a * 3, a * 4, a * 5"  */
+  gcc_jit_rvalue *args[3];
+  for (i = 0; i < 3; i++)
+    args[i]
+      = gcc_jit_context_new_binary_op
+	  (ctxt, NULL,
+	   GCC_JIT_BINARY_OP_MULT,
+	   int_type,
+	   gcc_jit_param_as_rvalue (param_a),
+	   gcc_jit_context_new_rvalue_from_int (ctxt,
+						int_type,
+						(i + 3) ));
+  gcc_jit_block *block = gcc_jit_function_new_block (test_caller, NULL);
+  gcc_jit_block_add_eval (
+    block, NULL,
+    gcc_jit_context_new_call (ctxt,
+			      NULL,
+			      called_fn,
+			      3, args));
+  gcc_jit_block_end_with_void_return (block, NULL);
+
+  gcc_jit_rvalue *fn_ptr
+    = gcc_jit_function_get_address (test_caller, NULL);
+
+  gcc_jit_type *fn_ptr_type
+    = gcc_jit_rvalue_get_type (fn_ptr);
+
+  /* Build the get_test_caller fn.  */
+  gcc_jit_function *get_test_caller =
+    gcc_jit_context_new_function (ctxt, NULL,
+				  GCC_JIT_FUNCTION_EXPORTED,
+				  fn_ptr_type,
+				  "get_test_caller",
+				  0, NULL,
+				  0);
+  block = gcc_jit_function_new_block (get_test_caller, NULL);
+  gcc_jit_block_end_with_return (block, NULL, fn_ptr);
+}
+
+static int called_with[3];
+
+extern void
+internally_called_function (int i, int j, int k)
+{
+  called_with[0] = i;
+  called_with[1] = j;
+  called_with[2] = k;
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef void (*test_caller_type) (int);
+  typedef test_caller_type (*get_test_caller_type) (void);
+  CHECK_NON_NULL (result);
+
+  get_test_caller_type get_test_caller =
+    (get_test_caller_type)gcc_jit_result_get_code (result, "get_test_caller");
+  CHECK_NON_NULL (get_test_caller);
+
+  test_caller_type test_caller = (test_caller_type)get_test_caller ();
+  CHECK_NON_NULL (test_caller);
+
+  called_with[0] = 0;
+  called_with[1] = 0;
+  called_with[2] = 0;
+
+  /* Call the JIT-generated function.  */
+  test_caller (5);
+
+  /* Verify that it correctly called "internally_called_function".  */
+  CHECK_VALUE (called_with[0], 15);
+  CHECK_VALUE (called_with[1], 20);
+  CHECK_VALUE (called_with[2], 25);
+}
-- 
1.8.5.3

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

* Re: Function pointer handling
  2017-01-01  0:00 Function pointer handling Bartosz Szreder
@ 2017-01-01  0:00 ` David Malcolm
  2017-01-01  0:00   ` Bartosz Szreder
  2017-01-01  0:00   ` [committed] jit: document function pointers David Malcolm
  0 siblings, 2 replies; 5+ messages in thread
From: David Malcolm @ 2017-01-01  0:00 UTC (permalink / raw)
  To: Bartosz Szreder, jit

On Thu, 2017-09-21 at 17:43 +0200, Bartosz Szreder wrote:
> I have some questions regarding pointers to functions in current
> (7.2)
> version of GCC-JIT.
> 
> 1. The documentation doesn't mention existence of
> gcc_jit_context_new_function_ptr_type() as a mechanism of handling
> function pointers, yet contains
> gcc_jit_context_new_call_through_ptr().

Oops; looks like I forgot to document the former.

> - Is the former function unsupported/buggy in some way and is not
> indented for general use, or just lacks proper documentation?

It's just missing documentation.  I'm working on fixing it.

Have a look at gcc/testsuite/jit.dg/test-calling-function-ptr.c
e.g.:
https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/testsuite/jit.dg/test-calling-function-ptr.c;h=e21bd15e303f8cfcd37d2eeb294188cc6702066f;hb=HEAD


> - What is the proper way of obtaining a function pointer to be passed
> to gcc_jit_context_new_call_through_ptr()? There doesn't seem to be
> any counterpart to gcc_jit_lvalue_get_address() for functions. As the
> name suggests, gcc_jit_lvalue_get_address() works on an L-value and
> gcc_jit_function type isn't an ancestor of gcc_jit_lvalue in the
> internal type system, therefore upcasting is impossible.

If it's a pre-existing function, then you can take its address in your
C code, and then use gcc_jit_context_new_rvalue_from_ptr, which assumes
that function pointers can be cast to void *, but it's very rare for
that not to hold (Harvard architecture, where code and data are
disjoint).

If it's a function that's being compiled as part of the same
gcc_jit_context, then I think you've identified a weakness in the
current API.  As you say, one fix would be to make gcc_jit_function be
a subclass of gcc_jit_lvalue (and add casting functions); I don't yet
know how easy that would be to implement.

> 2. Is it safe to pass a function pointer as a GCC_JIT_TYPE_VOID_PTR
> and use gcc_jit_context_new_call_through_ptr() on such value?

It uses the type of the function pointer when building the call, so the
function pointer needs to be of a type created using
gcc_jit_context_new_function_ptr_type.  You may be able to get away
with adding casts, but the casting API is rather fussy compared to the
rules in C.

Hope this is helpful

Dave

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

* [committed] jit: document function pointers
  2017-01-01  0:00 ` David Malcolm
  2017-01-01  0:00   ` Bartosz Szreder
@ 2017-01-01  0:00   ` David Malcolm
  1 sibling, 0 replies; 5+ messages in thread
From: David Malcolm @ 2017-01-01  0:00 UTC (permalink / raw)
  To: jit, gcc-patches; +Cc: David Malcolm

This patch adds a new function-pointers.rst topic page to the libgccjit
docs.

Committed to trunk as r253257.

gcc/jit/ChangeLog:
	* docs/topics/expressions.rst (Function calls): Add link to
	gcc_jit_context_new_function_ptr_type.
	(Function pointers): Convert to cross-references to
	function-pointers.rst, moving material there.
	* docs/topics/function-pointers.rst: New page.
	* docs/topics/index.rst: Add function-pointers.rst.
	* docs/topics/types.rst (Function pointer types): New section.
	* docs/_build/texinfo/libgccjit.texi: Regenerate.
---
 gcc/jit/docs/topics/expressions.rst       | 21 ++++----
 gcc/jit/docs/topics/function-pointers.rst | 80 +++++++++++++++++++++++++++++++
 gcc/jit/docs/topics/index.rst             |  1 +
 gcc/jit/docs/topics/types.rst             |  6 +++
 4 files changed, 96 insertions(+), 12 deletions(-)
 create mode 100644 gcc/jit/docs/topics/function-pointers.rst

diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst
index f5c2d0f..76aa4eb 100644
--- a/gcc/jit/docs/topics/expressions.rst
+++ b/gcc/jit/docs/topics/expressions.rst
@@ -416,7 +416,8 @@ Function calls
                                                     int numargs, \
                                                     gcc_jit_rvalue **args)
 
-   Given an rvalue of function pointer type, and the given table of
+   Given an rvalue of function pointer type (e.g. from
+   :c:func:`gcc_jit_context_new_function_ptr_type`), and the given table of
    argument rvalues, construct a call to the function pointer, with the
    result as an rvalue.
 
@@ -452,19 +453,15 @@ Function calls
 Function pointers
 *****************
 
-.. function:: gcc_jit_rvalue *\
-	      gcc_jit_function_get_address (gcc_jit_function *fn,\
-                                            gcc_jit_location *loc)
-
-   Get the address of a function as an rvalue, of function pointer
-   type.
+Function pointers can be obtained:
 
-   This entrypoint was added in :ref:`LIBGCCJIT_ABI_9`; you can test
-   for its presence using
-
-   .. code-block:: c
+  * from a :c:type:`gcc_jit_function` using
+    :c:func:`gcc_jit_function_get_address`, or
 
-      #ifdef LIBGCCJIT_HAVE_gcc_jit_function_get_address
+  * from an existing function using
+    :c:func:`gcc_jit_context_new_rvalue_from_ptr`,
+    using a function pointer type obtained using
+    :c:func:`gcc_jit_context_new_function_ptr_type`.
 
 Type-coercion
 *************
diff --git a/gcc/jit/docs/topics/function-pointers.rst b/gcc/jit/docs/topics/function-pointers.rst
new file mode 100644
index 0000000..b5b9d1b
--- /dev/null
+++ b/gcc/jit/docs/topics/function-pointers.rst
@@ -0,0 +1,80 @@
+.. Copyright (C) 2017 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+.. default-domain:: c
+
+Function pointers
+=================
+
+You can generate calls that use a function pointer via
+:c:func:`gcc_jit_context_new_call_through_ptr`.
+
+To do requires a :c:type:`gcc_jit_rvalue` of the correct function pointer type.
+
+Function pointers for a :c:type:`gcc_jit_function` can be obtained
+via :c:func:`gcc_jit_function_get_address`.
+
+.. function:: gcc_jit_rvalue *\
+	      gcc_jit_function_get_address (gcc_jit_function *fn,\
+                                            gcc_jit_location *loc)
+
+   Get the address of a function as an rvalue, of function pointer
+   type.
+
+   This entrypoint was added in :ref:`LIBGCCJIT_ABI_9`; you can test
+   for its presence using
+
+   .. code-block:: c
+
+      #ifdef LIBGCCJIT_HAVE_gcc_jit_function_get_address
+
+Alternatively, given an existing function, you can obtain a pointer
+to it in :c:type:`gcc_jit_rvalue` form using
+:c:func:`gcc_jit_context_new_rvalue_from_ptr`, using a function pointer
+type obtained using :c:func:`gcc_jit_context_new_function_ptr_type`.
+
+Here's an example of creating a function pointer type corresponding to C's
+:c:type:`void (*) (int, int, int)`:
+
+.. code-block:: c
+
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  /* Build the function ptr type.  */
+  gcc_jit_type *param_types[3];
+  param_types[0] = int_type;
+  param_types[1] = int_type;
+  param_types[2] = int_type;
+
+  gcc_jit_type *fn_ptr_type =
+    gcc_jit_context_new_function_ptr_type (ctxt, NULL,
+					   void_type,
+					   3, param_types, 0);
+
+.. function:: gcc_jit_type *\
+	      gcc_jit_context_new_function_ptr_type (gcc_jit_context *ctxt,\
+				       gcc_jit_location *loc,\
+				       gcc_jit_type *return_type,\
+				       int num_params,\
+				       gcc_jit_type **param_types,\
+				       int is_variadic)
+
+   Generate a :c:type:`gcc_jit_type` for a function pointer with the
+   given return type and parameters.
diff --git a/gcc/jit/docs/topics/index.rst b/gcc/jit/docs/topics/index.rst
index 890f21c..a912a6d 100644
--- a/gcc/jit/docs/topics/index.rst
+++ b/gcc/jit/docs/topics/index.rst
@@ -26,6 +26,7 @@ Topic Reference
    types.rst
    expressions.rst
    functions.rst
+   function-pointers.rst
    locations.rst
    compilation.rst
    compatibility.rst
diff --git a/gcc/jit/docs/topics/types.rst b/gcc/jit/docs/topics/types.rst
index c279222..35a8231 100644
--- a/gcc/jit/docs/topics/types.rst
+++ b/gcc/jit/docs/topics/types.rst
@@ -309,3 +309,9 @@ You can model C `struct` types by creating :c:type:`gcc_jit_struct *` and
        :start-after: /* Quote from here in docs/topics/types.rst.  */
        :end-before: /* Quote up to here in docs/topics/types.rst.  */
        :language: c
+
+Function pointer types
+----------------------
+
+Function pointer types can be created using
+:c:func:`gcc_jit_context_new_function_ptr_type`.
-- 
1.8.5.3

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

* Function pointer handling
@ 2017-01-01  0:00 Bartosz Szreder
  2017-01-01  0:00 ` David Malcolm
  0 siblings, 1 reply; 5+ messages in thread
From: Bartosz Szreder @ 2017-01-01  0:00 UTC (permalink / raw)
  To: jit

I have some questions regarding pointers to functions in current (7.2)
version of GCC-JIT.

1. The documentation doesn't mention existence of
gcc_jit_context_new_function_ptr_type() as a mechanism of handling
function pointers, yet contains
gcc_jit_context_new_call_through_ptr().

- Is the former function unsupported/buggy in some way and is not
indented for general use, or just lacks proper documentation?

- What is the proper way of obtaining a function pointer to be passed
to gcc_jit_context_new_call_through_ptr()? There doesn't seem to be
any counterpart to gcc_jit_lvalue_get_address() for functions. As the
name suggests, gcc_jit_lvalue_get_address() works on an L-value and
gcc_jit_function type isn't an ancestor of gcc_jit_lvalue in the
internal type system, therefore upcasting is impossible.

2. Is it safe to pass a function pointer as a GCC_JIT_TYPE_VOID_PTR
and use gcc_jit_context_new_call_through_ptr() on such value?

Thanks,
Bartosz Szreder

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

end of thread, other threads:[~2017-09-28 17:15 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-01-01  0:00 Function pointer handling Bartosz Szreder
2017-01-01  0:00 ` David Malcolm
2017-01-01  0:00   ` Bartosz Szreder
2017-01-01  0:00     ` [committed] jit: implement gcc_jit_function_get_address David Malcolm
2017-01-01  0:00   ` [committed] jit: document function pointers David Malcolm

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