* [committed] jit: implement gcc_jit_function_get_address
[not found] <CACDdPnvvjxiyk4xaVHYKm_D4hkc-kcvwcSRv30oEYOnHV4WmMg@mail.gmail.com>
@ 2017-09-27 23:59 ` David Malcolm
0 siblings, 0 replies; only message in thread
From: David Malcolm @ 2017-09-27 23:59 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, ¶m_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] only message in thread
only message in thread, other threads:[~2017-09-27 23:59 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <CACDdPnvvjxiyk4xaVHYKm_D4hkc-kcvwcSRv30oEYOnHV4WmMg@mail.gmail.com>
2017-09-27 23:59 ` [committed] jit: implement gcc_jit_function_get_address 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).