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>
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
/* 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
*************
......
......@@ -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`
......@@ -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
*************
......
......@@ -127,6 +127,7 @@ namespace recording {
class global;
class param;
class base_call;
class function_pointer;
class statement;
class case_;
......
......@@ -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. */
......
......@@ -443,6 +443,9 @@ public:
block*
new_block (const char *name);
rvalue *
get_address (location *loc);
void
build_stmt_list ();
......
......@@ -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
......
......@@ -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:
......
......@@ -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
{
......
......@@ -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);
}
......@@ -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 */
......
......@@ -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;
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>
PR target/71727
......
......@@ -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},
......
#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