Commit 15a65e63 by David Malcolm Committed by David Malcolm

jit: implement gcc_jit_function_get_address

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.

From-SVN: r253244
parent a509c571
2017-09-27 David Malcolm <dmalcolm@redhat.com>
* 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.
2017-09-14 David Malcolm <dmalcolm@redhat.com> 2017-09-14 David Malcolm <dmalcolm@redhat.com>
PR jit/82174 PR jit/82174
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -459,6 +459,15 @@ Function calls ...@@ -459,6 +459,15 @@ Function calls
/* Add "(void)printf (arg0, arg1);". */ /* Add "(void)printf (arg0, arg1);". */
block.add_eval (ctxt.new_call (printf_func, 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 Type-coercion
************* *************
......
...@@ -156,3 +156,10 @@ entrypoints: ...@@ -156,3 +156,10 @@ entrypoints:
------------------- -------------------
``LIBGCCJIT_ABI_8`` covers the addition of ``LIBGCCJIT_ABI_8`` covers the addition of
:func:`gcc_jit_type_get_vector` :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`
...@@ -449,6 +449,23 @@ Function calls ...@@ -449,6 +449,23 @@ Function calls
#ifdef LIBGCCJIT_HAVE_gcc_jit_rvalue_set_bool_require_tail_call #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 Type-coercion
************* *************
......
...@@ -127,6 +127,7 @@ namespace recording { ...@@ -127,6 +127,7 @@ namespace recording {
class global; class global;
class param; class param;
class base_call; class base_call;
class function_pointer;
class statement; class statement;
class case_; class case_;
......
...@@ -1356,6 +1356,20 @@ new_block (const char *name) ...@@ -1356,6 +1356,20 @@ new_block (const char *name)
return result; 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 /* Build a statement list for the function as a whole out of the
lists of statements for the individual blocks, building labels lists of statements for the individual blocks, building labels
for each block. */ for each block. */
......
...@@ -443,6 +443,9 @@ public: ...@@ -443,6 +443,9 @@ public:
block* block*
new_block (const char *name); new_block (const char *name);
rvalue *
get_address (location *loc);
void void
build_stmt_list (); build_stmt_list ();
......
...@@ -3452,7 +3452,8 @@ recording::function::function (context *ctxt, ...@@ -3452,7 +3452,8 @@ recording::function::function (context *ctxt,
m_is_variadic (is_variadic), m_is_variadic (is_variadic),
m_builtin_id (builtin_id), m_builtin_id (builtin_id),
m_locals (), m_locals (),
m_blocks () m_blocks (),
m_fn_ptr_type (NULL)
{ {
for (int i = 0; i< num_params; i++) for (int i = 0; i< num_params; i++)
{ {
...@@ -3725,6 +3726,35 @@ recording::function::dump_to_dot (const char *path) ...@@ -3725,6 +3726,35 @@ recording::function::dump_to_dot (const char *path)
fclose (fp); 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 /* Implementation of recording::memento::make_debug_string for
functions. */ functions. */
...@@ -5400,6 +5430,51 @@ recording::get_address_of_lvalue::write_reproducer (reproducer &r) ...@@ -5400,6 +5430,51 @@ recording::get_address_of_lvalue::write_reproducer (reproducer &r)
r.get_identifier (m_loc)); 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. */ /* The implementation of class gcc::jit::recording::local. */
/* Implementation of pure virtual hook recording::memento::replay_into /* Implementation of pure virtual hook recording::memento::replay_into
......
...@@ -1145,6 +1145,8 @@ public: ...@@ -1145,6 +1145,8 @@ public:
void dump_to_dot (const char *path); void dump_to_dot (const char *path);
rvalue *get_address (location *loc);
private: private:
string * make_debug_string () FINAL OVERRIDE; string * make_debug_string () FINAL OVERRIDE;
void write_reproducer (reproducer &r) FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE;
...@@ -1159,6 +1161,7 @@ private: ...@@ -1159,6 +1161,7 @@ private:
enum built_in_function m_builtin_id; enum built_in_function m_builtin_id;
auto_vec<local *> m_locals; auto_vec<local *> m_locals;
auto_vec<block *> m_blocks; auto_vec<block *> m_blocks;
type *m_fn_ptr_type;
}; };
class block : public memento class block : public memento
...@@ -1699,6 +1702,32 @@ private: ...@@ -1699,6 +1702,32 @@ private:
lvalue *m_lvalue; 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 class local : public lvalue
{ {
public: public:
......
...@@ -368,6 +368,8 @@ namespace gccjit ...@@ -368,6 +368,8 @@ namespace gccjit
const std::string &name, const std::string &name,
location loc = location ()); location loc = location ());
rvalue get_address (location loc = location ());
/* A series of overloaded operator () with various numbers of arguments /* A series of overloaded operator () with various numbers of arguments
for a very terse way of creating a call to this function. The call 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 is created within the same context as the function itself, which may
...@@ -1392,6 +1394,13 @@ function::new_local (type type_, ...@@ -1392,6 +1394,13 @@ function::new_local (type type_,
name.c_str ())); 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 inline function
block::get_function () const block::get_function () const
{ {
......
...@@ -3022,3 +3022,23 @@ gcc_jit_type_get_vector (gcc_jit_type *type, size_t num_units) ...@@ -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); 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);
}
...@@ -1418,6 +1418,21 @@ gcc_jit_type_get_aligned (gcc_jit_type *type, ...@@ -1418,6 +1418,21 @@ gcc_jit_type_get_aligned (gcc_jit_type *type,
extern gcc_jit_type * extern gcc_jit_type *
gcc_jit_type_get_vector (gcc_jit_type *type, size_t num_units); 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 #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
......
...@@ -160,3 +160,8 @@ LIBGCCJIT_ABI_8 { ...@@ -160,3 +160,8 @@ LIBGCCJIT_ABI_8 {
global: global:
gcc_jit_type_get_vector; gcc_jit_type_get_vector;
} LIBGCCJIT_ABI_7; } LIBGCCJIT_ABI_7;
LIBGCCJIT_ABI_9 {
global:
gcc_jit_function_get_address;
} LIBGCCJIT_ABI_8;
2017-09-27 David Malcolm <dmalcolm@redhat.com>
* jit.dg/all-non-failing-tests.h: Add
test-returning-function-ptr.c.
* jit.dg/test-returning-function-ptr.c: New test case.
2017-09-27 Christophe Lyon <christophe.lyon@linaro.org> 2017-09-27 Christophe Lyon <christophe.lyon@linaro.org>
PR target/71727 PR target/71727
......
...@@ -71,6 +71,13 @@ ...@@ -71,6 +71,13 @@
#undef create_code #undef create_code
#undef verify_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 */ /* test-compound-assignment.c */
#define create_code create_code_compound_assignment #define create_code create_code_compound_assignment
#define verify_code verify_code_compound_assignment #define verify_code verify_code_compound_assignment
...@@ -283,6 +290,9 @@ const struct testcase testcases[] = { ...@@ -283,6 +290,9 @@ const struct testcase testcases[] = {
{"calling_function_ptr", {"calling_function_ptr",
create_code_calling_function_ptr, create_code_calling_function_ptr,
verify_code_calling_function_ptr}, verify_code_calling_function_ptr},
{"calling_internal_function",
create_code_calling_internal_function,
verify_code_calling_internal_function},
{"compound_assignment", {"compound_assignment",
create_code_compound_assignment, create_code_compound_assignment,
verify_code_compound_assignment}, verify_code_compound_assignment},
......
#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);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment