@@ -1,3 +1,50 @@
+2014-08-08 David Malcolm <dmalcolm@redhat.com>
+
+ * TODO.rst: Function ptrs are done.
+ * internal-api.c
+ (gcc::jit::recording::context::new_function_ptr_type): New method.
+ (gcc::jit::recording::context::new_call_through_ptr): New method.
+ (gcc::jit::recording::memento_of_get_pointer::make_debug_string):
+ Add special-case handling of function pointer types.
+ (gcc::jit::recording::function_type::make_debug_string_with_ptr):
+ New method.
+ (gcc::jit::recording::function_type::make_debug_string):
+ Reimplement in terms of...
+ (gcc::jit::recording::function_type::make_debug_string_with): New
+ method, based on make_debug_string, but allowing for arbitrary
+ text between the return type and the parameters.
+ (gcc::jit::recording::call_through_ptr::call_through_ptr): New
+ method.
+ (gcc::jit::recording::call_through_ptr::replay_into): New method.
+ (gcc::jit::recording::call_through_ptr::make_debug_string): New
+ method.
+ (gcc::jit::playback::context::new_call): Reimplement in terms of...
+ (gcc::jit::playback::context::build_call): New method, using parts
+ of old implementation of new_call, so that we can share this
+ with...
+ (gcc::jit::playback::context::new_call_through_ptr): New method.
+ * internal-api.h
+ (gcc::jit::recording::context::new_function_ptr_type): New method.
+ (gcc::jit::recording::context::new_call_through_ptr): New method.
+ (gcc::jit::recording::type::dyn_cast_function_type): New method.
+ (gcc::jit::recording::function_type::dyn_cast_function_type): New
+ method.
+ (gcc::jit::recording::function_type::make_debug_string_with_ptr):
+ New method.
+ (gcc::jit::recording::function_type::make_debug_string_with): New
+ method.
+ (gcc::jit::recording::call_through_ptr): New subclass of rvalue.
+ (gcc::jit::playback::context::new_call_through_ptr): New method.
+ (gcc::jit::playback::context::build_call): New method.
+ * libgccjit.c (gcc_jit_context_new_function_ptr_type): New
+ function.
+ (gcc_jit_context_new_call_through_ptr): New function.
+ * libgccjit.h (gcc_jit_context_new_function_ptr_type): New
+ function.
+ (gcc_jit_context_new_call_through_ptr): New function.
+ * libgccjit.map (gcc_jit_context_new_call_through_ptr): New function.
+ (gcc_jit_context_new_function_ptr_type): New function.
+
2014-07-25 David Malcolm <dmalcolm@redhat.com>
* TODO.rst (error-checking): Remove various items that either
@@ -17,7 +17,6 @@ Initial Release
* more types:
* unions
- * function ptrs
* expose the statements in the API? (mostly so they can be stringified?)
@@ -31,10 +30,6 @@ Initial Release
so you can access "static" fns in your code.
-* ability to call an rvalue function pointer, perhaps keeping the
- existing API to avoid needing to build a function ptr from a
- function.
-
* ability to turn a function into a function pointer::
gcc_jit_function_as_rvalue ()
@@ -381,6 +381,24 @@ recording::context::new_struct_type (recording::location *loc,
return result;
}
+recording::type *
+recording::context::new_function_ptr_type (recording::location *, /* unused loc */
+ recording::type *return_type,
+ int num_params,
+ recording::type **param_types,
+ int is_variadic)
+{
+ recording::function_type *fn_type =
+ new function_type (this,
+ return_type,
+ num_params,
+ param_types,
+ is_variadic);
+ record (fn_type);
+
+ /* Return a pointer-type to the the function type. */
+ return fn_type->get_pointer ();
+}
recording::param *
recording::context::new_param (recording::location *loc,
@@ -528,6 +546,17 @@ recording::context::new_call (recording::location *loc,
return result;
}
+recording::rvalue *
+recording::context::new_call_through_ptr (recording::location *loc,
+ recording::rvalue *fn_ptr,
+ int numargs,
+ recording::rvalue **args)
+ {
+ recording::rvalue *result = new call_through_ptr (this, loc, fn_ptr, numargs, args);
+ record (result);
+ return result;
+}
+
recording::lvalue *
recording::context::new_array_access (recording::location *loc,
recording::rvalue *ptr,
@@ -1076,6 +1105,12 @@ recording::memento_of_get_pointer::replay_into (replayer *)
recording::string *
recording::memento_of_get_pointer::make_debug_string ()
{
+ /* Special-case function pointer types, to put the "*" in parens between
+ the return type and the params (for one level of dereferencing, at
+ least). */
+ if (function_type *fn_type = m_other_type->dyn_cast_function_type ())
+ return fn_type->make_debug_string_with_ptr ();
+
return string::from_printf (m_ctxt,
"%s *", m_other_type->get_debug_string ());
}
@@ -1173,8 +1208,20 @@ recording::function_type::replay_into (replayer *r)
}
recording::string *
+recording::function_type::make_debug_string_with_ptr ()
+{
+ return make_debug_string_with ("(*) ");
+}
+
+recording::string *
recording::function_type::make_debug_string ()
{
+ return make_debug_string_with ("");
+}
+
+recording::string *
+recording::function_type::make_debug_string_with (const char *insert)
+{
/* First, build a buffer for the arguments. */
/* Calculate length of said buffer. */
size_t sz = 1; /* nil terminator */
@@ -1214,8 +1261,9 @@ recording::function_type::make_debug_string ()
/* ...and use it to get the string for the call as a whole. */
string *result = string::from_printf (m_ctxt,
- "%s (%s)",
+ "%s %s(%s)",
m_return_type->get_debug_string (),
+ insert,
argbuf);
delete[] argbuf;
@@ -2092,6 +2140,73 @@ recording::call::make_debug_string ()
return result;
}
+recording::call_through_ptr::call_through_ptr (recording::context *ctxt,
+ recording::location *loc,
+ recording::rvalue *fn_ptr,
+ int numargs,
+ rvalue **args)
+: rvalue (ctxt, loc,
+ fn_ptr->get_type ()->dereference ()
+ ->as_a_function_type ()->get_return_type ()),
+ m_fn_ptr (fn_ptr),
+ m_args ()
+{
+ for (int i = 0; i< numargs; i++)
+ m_args.safe_push (args[i]);
+}
+
+void
+recording::call_through_ptr::replay_into (replayer *r)
+{
+ vec<playback::rvalue *> playback_args;
+ playback_args.create (m_args.length ());
+ for (unsigned i = 0; i< m_args.length (); i++)
+ playback_args.safe_push (m_args[i]->playback_rvalue ());
+
+ set_playback_obj (r->new_call_through_ptr (playback_location (r, m_loc),
+ m_fn_ptr->playback_rvalue (),
+ playback_args));
+}
+
+recording::string *
+recording::call_through_ptr::make_debug_string ()
+{
+ /* First, build a buffer for the arguments. */
+ /* Calculate length of said buffer. */
+ size_t sz = 1; /* nil terminator */
+ for (unsigned i = 0; i< m_args.length (); i++)
+ {
+ sz += strlen (m_args[i]->get_debug_string ());
+ sz += 2; /* ", " separator */
+ }
+
+ /* Now allocate and populate the buffer. */
+ char *argbuf = new char[sz];
+ size_t len = 0;
+
+ for (unsigned i = 0; i< m_args.length (); i++)
+ {
+ strcpy (argbuf + len, m_args[i]->get_debug_string ());
+ len += strlen (m_args[i]->get_debug_string ());
+ if (i + 1 < m_args.length ())
+ {
+ strcpy (argbuf + len, ", ");
+ len += 2;
+ }
+ }
+ argbuf[len] = '\0';
+
+ /* ...and use it to get the string for the call as a whole. */
+ string *result = string::from_printf (m_ctxt,
+ "%s (%s)",
+ m_fn_ptr->get_debug_string (),
+ argbuf);
+
+ delete[] argbuf;
+
+ return result;
+}
+
void
recording::array_access::replay_into (replayer *r)
{
@@ -3034,33 +3149,25 @@ new_comparison (location *loc,
playback::rvalue *
playback::context::
-new_call (location *loc,
- function *func,
- vec<rvalue *> args)
+build_call (location *loc,
+ tree fn_ptr,
+ vec<rvalue *> args)
{
- tree fndecl;
vec<tree, va_gc> *tree_args;
-
- gcc_assert (func);
-
- // FIXME: type checking
- // FIXME: check num args and types
-
- fndecl = func->as_fndecl ();
-
vec_alloc (tree_args, args.length ());
for (unsigned i = 0; i < args.length (); i++)
tree_args->quick_push (args[i]->as_tree ());
- tree fntype = TREE_TYPE (fndecl);
- tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
-
if (loc)
- set_tree_location (fn, loc);
+ set_tree_location (fn_ptr, loc);
+
+ tree fn = TREE_TYPE (fn_ptr);
+ tree fn_type = TREE_TYPE (fn);
+ tree return_type = TREE_TYPE (fn_type);
return new rvalue (this,
- build_call_vec (func->get_return_type_as_tree (),
- fn, tree_args));
+ build_call_vec (return_type,
+ fn_ptr, tree_args));
/* see c-typeck.c: build_function_call
which calls build_function_call_vec
@@ -3073,6 +3180,37 @@ new_call (location *loc,
*/
}
+playback::rvalue *
+playback::context::
+new_call (location *loc,
+ function *func,
+ vec<rvalue *> args)
+{
+ tree fndecl;
+
+ gcc_assert (func);
+
+ fndecl = func->as_fndecl ();
+
+ tree fntype = TREE_TYPE (fndecl);
+
+ tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
+
+ return build_call (loc, fn, args);
+}
+
+playback::rvalue *
+playback::context::
+new_call_through_ptr (location *loc,
+ rvalue *fn_ptr,
+ vec<rvalue *> args)
+{
+ gcc_assert (fn_ptr);
+ tree t_fn_ptr = fn_ptr->as_tree ();
+
+ return build_call (loc, t_fn_ptr, args);
+}
+
tree
playback::context::build_cast (playback::location *loc,
playback::rvalue *expr,
@@ -192,6 +192,13 @@ public:
new_struct_type (location *loc,
const char *name);
+ type *
+ new_function_ptr_type (location *loc,
+ type *return_type,
+ int num_params,
+ type **param_types,
+ int is_variadic);
+
param *
new_param (location *loc,
type *type,
@@ -253,6 +260,11 @@ public:
int numargs, rvalue **args);
rvalue *
+ new_call_through_ptr (location *loc,
+ rvalue *fn_ptr,
+ int numargs, rvalue **args);
+
+ rvalue *
new_cast (location *loc,
rvalue *expr,
type *type_);
@@ -478,6 +490,7 @@ public:
virtual type *dereference () = 0;
/* Dynamic casts. */
+ virtual function_type *dyn_cast_function_type () { return NULL; }
virtual function_type *as_a_function_type() { gcc_unreachable (); return NULL; }
virtual struct_ *dyn_cast_struct () { return NULL; }
@@ -692,6 +705,7 @@ public:
int is_variadic);
type *dereference ();
+ function_type *dyn_cast_function_type () { return this; }
function_type *as_a_function_type () { return this; }
bool is_int () const { return false; }
@@ -706,8 +720,11 @@ public:
vec<type *> get_param_types () const { return m_param_types; }
int is_variadic () const { return m_is_variadic; }
+ string * make_debug_string_with_ptr ();
+
private:
string * make_debug_string ();
+ string * make_debug_string_with (const char *);
private:
type *m_return_type;
@@ -1262,6 +1279,25 @@ private:
vec<rvalue *> m_args;
};
+class call_through_ptr : public rvalue
+{
+public:
+ call_through_ptr (context *ctxt,
+ location *loc,
+ rvalue *fn_ptr,
+ int numargs,
+ rvalue **args);
+
+ void replay_into (replayer *r);
+
+private:
+ string * make_debug_string ();
+
+private:
+ rvalue *m_fn_ptr;
+ vec<rvalue *> m_args;
+};
+
class array_access : public lvalue
{
public:
@@ -1704,6 +1740,11 @@ public:
vec<rvalue *> args);
rvalue *
+ new_call_through_ptr (location *loc,
+ rvalue *fn_ptr,
+ vec<rvalue *> args);
+
+ rvalue *
new_cast (location *loc,
rvalue *expr,
type *type_);
@@ -1779,6 +1820,11 @@ public:
private:
void dump_generated_code ();
+ rvalue *
+ build_call (location *loc,
+ tree fn_ptr,
+ vec<rvalue *> args);
+
tree
build_cast (location *loc,
rvalue *expr,
@@ -461,6 +461,33 @@ gcc_jit_struct_set_fields (gcc_jit_struct *struct_type,
(gcc::jit::recording::field **)fields);
}
+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)
+{
+ RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+ RETURN_NULL_IF_FAIL (return_type, ctxt, loc, "NULL return_type");
+ RETURN_NULL_IF_FAIL (
+ (num_params == 0) || param_types,
+ ctxt, loc,
+ "NULL param_types creating function pointer type");
+ for (int i = 0; i < num_params; i++)
+ RETURN_NULL_IF_FAIL_PRINTF1 (
+ param_types[i],
+ ctxt, loc,
+ "NULL parameter type %i creating function pointer type", i);
+
+ return (gcc_jit_type*)
+ ctxt->new_function_ptr_type (loc, return_type,
+ num_params,
+ (gcc::jit::recording::type **)param_types,
+ is_variadic);
+}
+
/* Constructing functions. */
gcc_jit_param *
gcc_jit_context_new_param (gcc_jit_context *ctxt,
@@ -889,6 +916,88 @@ gcc_jit_context_new_call (gcc_jit_context *ctxt,
(gcc::jit::recording::rvalue **)args);
}
+gcc_jit_rvalue *
+gcc_jit_context_new_call_through_ptr (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ gcc_jit_rvalue *fn_ptr,
+ int numargs, gcc_jit_rvalue **args)
+{
+ RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+ RETURN_NULL_IF_FAIL (fn_ptr, ctxt, loc, "NULL fn_ptr");
+ if (numargs)
+ RETURN_NULL_IF_FAIL (args, ctxt, loc, "NULL args");
+
+ gcc::jit::recording::type *ptr_type = fn_ptr->get_type ()->dereference ();
+ RETURN_NULL_IF_FAIL_PRINTF2 (
+ ptr_type, ctxt, loc,
+ "fn_ptr is not a ptr: %s"
+ " type: %s",
+ fn_ptr->get_debug_string (),
+ fn_ptr->get_type ()->get_debug_string ());
+
+ gcc::jit::recording::function_type *fn_type =
+ ptr_type->dyn_cast_function_type();
+ RETURN_NULL_IF_FAIL_PRINTF2 (
+ fn_type, ctxt, loc,
+ "fn_ptr is not a function ptr: %s"
+ " type: %s",
+ fn_ptr->get_debug_string (),
+ fn_ptr->get_type ()->get_debug_string ());
+
+ int min_num_params = fn_type->get_param_types ().length ();
+ bool is_variadic = fn_type->is_variadic ();
+
+ RETURN_NULL_IF_FAIL_PRINTF3 (
+ numargs >= min_num_params,
+ ctxt, loc,
+ "not enough arguments to fn_ptr: %s"
+ " (got %i args, expected %i)",
+ fn_ptr->get_debug_string (),
+ numargs, min_num_params);
+
+ RETURN_NULL_IF_FAIL_PRINTF3 (
+ (numargs == min_num_params || is_variadic),
+ ctxt, loc,
+ "too many arguments to fn_ptr: %s"
+ " (got %i args, expected %i)",
+ fn_ptr->get_debug_string (),
+ numargs, min_num_params);
+
+ for (int i = 0; i < min_num_params; i++)
+ {
+ gcc::jit::recording::type *param_type = fn_type->get_param_types ()[i];
+ gcc_jit_rvalue *arg = args[i];
+
+ RETURN_NULL_IF_FAIL_PRINTF3 (
+ arg,
+ ctxt, loc,
+ "NULL argument %i to fn_ptr: %s"
+ " (type: %s)",
+ i + 1,
+ fn_ptr->get_debug_string (),
+ param_type->get_debug_string ());
+
+ RETURN_NULL_IF_FAIL_PRINTF6 (
+ compatible_types (param_type,
+ arg->get_type ()),
+ ctxt, loc,
+ "mismatching types for argument %d of fn_ptr: %s:"
+ " assignment to param %d (type: %s) from %s (type: %s)",
+ i + 1,
+ fn_ptr->get_debug_string (),
+ i + 1,
+ param_type->get_debug_string (),
+ arg->get_debug_string (),
+ arg->get_type ()->get_debug_string ());
+ }
+
+ return (gcc_jit_rvalue *)(
+ ctxt->new_call_through_ptr (loc,
+ fn_ptr,
+ numargs,
+ (gcc::jit::recording::rvalue **)args));
+}
+
static bool
is_valid_cast (gcc::jit::recording::type *src_type,
gcc_jit_type *dst_type)
@@ -436,6 +436,16 @@ gcc_jit_struct_set_fields (gcc_jit_struct *struct_type,
int num_fields,
gcc_jit_field **fields);
+/* Function pointers. */
+
+extern 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);
+
/**********************************************************************
Constructing functions.
**********************************************************************/
@@ -704,12 +714,22 @@ gcc_jit_context_new_comparison (gcc_jit_context *ctxt,
enum gcc_jit_comparison op,
gcc_jit_rvalue *a, gcc_jit_rvalue *b);
+/* Function calls. */
+
+/* Call of a specific function. */
extern 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);
+/* Call through a function pointer. */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_call_through_ptr (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ gcc_jit_rvalue *fn_ptr,
+ int numargs, gcc_jit_rvalue **args);
+
/* Type-coercion.
Currently only a limited set of conversions are possible:
@@ -23,11 +23,13 @@
gcc_jit_context_new_array_type;
gcc_jit_context_new_binary_op;
gcc_jit_context_new_call;
+ gcc_jit_context_new_call_through_ptr;
gcc_jit_context_new_cast;
gcc_jit_context_new_child_context;
gcc_jit_context_new_comparison;
gcc_jit_context_new_field;
gcc_jit_context_new_function;
+ gcc_jit_context_new_function_ptr_type;
gcc_jit_context_new_global;
gcc_jit_context_new_location;
gcc_jit_context_new_opaque_struct;
@@ -1,3 +1,16 @@
+2014-08-08 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-calling-function-ptr.c: New test case.
+ * jit.dg/test-combination.c: Add test-calling-function-ptr.c.
+ * jit.dg/test-error-call-through-ptr-with-mismatching-args.c: New
+ test case.
+ * jit.dg/test-error-call-through-ptr-with-non-function.c: New test
+ case.
+ * jit.dg/test-error-call-through-ptr-with-non-pointer.c: New test
+ case.
+ * jit.dg/test-error-call-through-ptr-with-not-enough-args.c: New
+ test case.
+
2014-07-25 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-error-index-not-a-numeric-type.c: New test case.
new file mode 100644
@@ -0,0 +1,118 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *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);
+ }
+ */
+
+ 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);
+
+ /* 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);
+
+ /* Ensure that function ptr types have sane debug strings. */
+
+ CHECK_STRING_VALUE (
+ gcc_jit_object_get_debug_string (gcc_jit_type_as_object (fn_ptr_type)),
+ "void (*) (int, int, int)");
+
+ /* Build the test_fn. */
+ gcc_jit_param *param_fn_ptr =
+ gcc_jit_context_new_param (ctxt, NULL, fn_ptr_type, "fn_ptr");
+ gcc_jit_param *param_a =
+ gcc_jit_context_new_param (ctxt, NULL, int_type, "a");
+
+ gcc_jit_param *params[2];
+ params[0] = param_fn_ptr;
+ params[1] = param_a;
+
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_calling_function_ptr",
+ 2, params,
+ 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_fn, NULL);
+ gcc_jit_block_add_eval (
+ block, NULL,
+ gcc_jit_context_new_call_through_ptr (
+ ctxt,
+ NULL,
+ gcc_jit_param_as_rvalue (param_fn_ptr),
+ 3, args));
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+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);
+}
+
@@ -35,6 +35,13 @@
#undef create_code
#undef verify_code
+/* test-calling-function-ptr.c */
+#define create_code create_code_calling_function_ptr
+#define verify_code verify_code_calling_function_ptr
+#include "test-calling-function-ptr.c"
+#undef create_code
+#undef verify_code
+
/* test-dot-product.c */
#define create_code create_code_dot_product
#define verify_code verify_code_dot_product
@@ -151,6 +158,7 @@ create_code (gcc_jit_context *ctxt, void * user_data)
create_code_array_as_pointer (ctxt, user_data);
create_code_arrays (ctxt, user_data);
create_code_calling_external_function (ctxt, user_data);
+ create_code_calling_function_ptr (ctxt, user_data);
create_code_dot_product (ctxt, user_data);
create_code_expressions (ctxt, user_data);
create_code_factorial (ctxt, user_data);
@@ -172,6 +180,7 @@ verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
verify_code_array_as_pointer (ctxt, result);
verify_code_arrays (ctxt, result);
verify_code_calling_external_function (ctxt, result);
+ verify_code_calling_function_ptr (ctxt, result);
verify_code_dot_product (ctxt, result);
verify_code_expressions (ctxt, result);
verify_code_factorial (ctxt, result);
new file mode 100644
@@ -0,0 +1,74 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+
+ void
+ test_fn (void (*some_fn_ptr) (void *))
+ {
+ some_fn_ptr (42);
+ }
+
+ and verify that the API complains about the mismatching argument
+ type ("int" vs "void *"). */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *void_ptr_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ /* Build the function ptr type. */
+ gcc_jit_type *fn_ptr_type =
+ gcc_jit_context_new_function_ptr_type (ctxt, NULL,
+ void_type,
+ 1, &void_ptr_type, 0);
+
+ /* Build the test_fn. */
+ gcc_jit_param *param_fn_ptr =
+ gcc_jit_context_new_param (ctxt, NULL, fn_ptr_type, "some_fn_ptr");
+
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_fn",
+ 1, ¶m_fn_ptr,
+ 0);
+ /* some_fn_ptr (42); */
+ gcc_jit_rvalue *arg =
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42);
+
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+ gcc_jit_block_add_eval (
+ block, NULL,
+ gcc_jit_context_new_call_through_ptr (
+ ctxt,
+ NULL,
+ gcc_jit_param_as_rvalue (param_fn_ptr),
+ 1, &arg));
+ /* the above has the wrong type for argument 1. */
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_VALUE (result, NULL);
+
+ /* Verify that the correct error message was emitted. */
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ ("gcc_jit_context_new_call_through_ptr:"
+ " mismatching types for argument 1 of fn_ptr:"
+ " some_fn_ptr:"
+ " assignment to param 1 (type: void *)"
+ " from (int)42 (type: int)"));
+}
+
new file mode 100644
@@ -0,0 +1,65 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+
+ void
+ test_fn (void *some_ptr)
+ {
+ ((some_unspecified_fn_ptr_type)some_ptr) (42);
+ }
+
+ and verify that the API complains about the 42 not being a
+ function pointer. */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *void_ptr_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ /* Build the test_fn. */
+ gcc_jit_param *some_ptr =
+ gcc_jit_context_new_param (ctxt, NULL, void_ptr_type, "some_ptr");
+
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_fn",
+ 1, &some_ptr,
+ 0);
+ gcc_jit_rvalue *arg =
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42);
+
+ /* ((some_unspecified_fn_ptr_type)some_ptr) (42); */
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+ gcc_jit_block_add_eval (
+ block, NULL,
+ gcc_jit_context_new_call_through_ptr (
+ ctxt,
+ NULL,
+ /* This is not a function pointer. */
+ gcc_jit_param_as_rvalue (some_ptr),
+ 1, &arg));
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_VALUE (result, NULL);
+
+ /* Verify that the correct error message was emitted. */
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ ("gcc_jit_context_new_call_through_ptr:"
+ " fn_ptr is not a function ptr: some_ptr type: void *"));
+}
+
new file mode 100644
@@ -0,0 +1,62 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+
+ void
+ test_fn ()
+ {
+ ((some_unspecified_fn_ptr_type)42) (43);
+ }
+
+ and verify that the API complains about the 42 not being a
+ function pointer. */
+ 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 test_fn. */
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_fn",
+ 0, NULL,
+ 0);
+ gcc_jit_rvalue *not_a_function =
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42);
+ gcc_jit_rvalue *arg =
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 43);
+
+ /* ((some_unspecified_fn_ptr_type)42) (43); */
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+ gcc_jit_block_add_eval (
+ block, NULL,
+ gcc_jit_context_new_call_through_ptr (
+ ctxt,
+ NULL,
+ /* This is not even a pointer, let alone a function pointer. */
+ not_a_function,
+ 1, &arg));
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_VALUE (result, NULL);
+
+ /* Verify that the correct error message was emitted. */
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ ("gcc_jit_context_new_call_through_ptr:"
+ " fn_ptr is not a ptr: (int)42 type: int"));
+}
+
new file mode 100644
@@ -0,0 +1,70 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+
+ void
+ test_caller (void (*some_fn_ptr) (int p))
+ {
+ called_function (); // missing arg
+ }
+
+ and verify that the API complains about the missing argument.
+ */
+ 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 *fn_ptr_type =
+ gcc_jit_context_new_function_ptr_type (ctxt, NULL,
+ void_type,
+ 1, &int_type, 0);
+
+ /* Build the test_fn. */
+ gcc_jit_param *param_fn_ptr =
+ gcc_jit_context_new_param (ctxt, NULL, fn_ptr_type, "some_fn_ptr");
+
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_caller",
+ 1, ¶m_fn_ptr,
+ 0);
+
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+ /* called_function (); */
+ gcc_jit_block_add_eval (
+ block, NULL,
+ gcc_jit_context_new_call_through_ptr (
+ ctxt,
+ NULL,
+ gcc_jit_param_as_rvalue (param_fn_ptr),
+ 0, NULL));
+ /* the above has not enough args. */
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ /* Ensure that mismatching arg count leads to the API giving a NULL
+ result back. */
+ CHECK_VALUE (result, NULL);
+
+ /* Verify that the correct error message was emitted. */
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ ("gcc_jit_context_new_call_through_ptr:"
+ " not enough arguments to fn_ptr: some_fn_ptr"
+ " (got 0 args, expected 1)"));
+}
+
new file mode 100644
@@ -0,0 +1,87 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ extern void
+ called_function (void);
+
+#ifdef __cplusplus
+}
+#endif
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+ void
+ test_caller (void (*some_fn_ptr) (void), int a)
+ {
+ some_fn_ptr (a);
+ }
+
+ and verify that the API complains about the mismatching arg
+ counts.
+ */
+ 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 *fn_ptr_type =
+ gcc_jit_context_new_function_ptr_type (ctxt, NULL,
+ void_type,
+ 0, NULL, 0);
+
+ /* Build the test_fn. */
+ gcc_jit_param *param_fn_ptr =
+ gcc_jit_context_new_param (ctxt, NULL, fn_ptr_type, "some_fn_ptr");
+ gcc_jit_param *param_a =
+ gcc_jit_context_new_param (ctxt, NULL, int_type, "a");
+ gcc_jit_param *params[2];
+ params[0] = param_fn_ptr;
+ params[1] = param_a;
+
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_caller",
+ 2, params,
+ 0);
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+ /* some_fn_ptr (a); */
+ gcc_jit_rvalue *arg = gcc_jit_param_as_rvalue (param_a);
+ gcc_jit_block_add_eval (
+ block, NULL,
+ gcc_jit_context_new_call_through_ptr (
+ ctxt,
+ NULL,
+ gcc_jit_param_as_rvalue (param_fn_ptr),
+ 1, &arg));
+ /* the above has too many args. */
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ /* Ensure that mismatching arg count leads to the API giving a NULL
+ result back. */
+ CHECK_VALUE (result, NULL);
+
+ /* Verify that the correct error message was emitted. */
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ "gcc_jit_context_new_call_through_ptr:"
+ " too many arguments to fn_ptr:"
+ " some_fn_ptr (got 1 args, expected 0)");
+}
+