@@ -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.
@@ -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> ¶m_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`.
@@ -169,6 +169,11 @@ namespace gccjit
std::vector <field> &fields,
location loc = location ());
+ type new_function_ptr_type (type return_type,
+ std::vector <type> ¶m_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> ¶m_types,
+ int is_variadic,
+ location loc)
+{
+ /* Treat std::vector as an array, relying on it not being resized: */
+ type *as_array_of_wrappers = ¶m_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_,
new file mode 100644
@@ -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);
+}