Tutorial for calling back into app code
David Malcolm
dmalcolm@redhat.com
Thu Jan 1 00:00:00 GMT 2015
On Sat, 2015-05-09 at 15:05 -0700, Ed Hutchins wrote:
> I cooked up this example of calling back into parent code, it would be
> great if something like this was in the tutorials.
Thanks for writing this!
This is indeed a way to call back into parent code, using
GCC_JIT_FUNCTION_IMPORTED and the name of the function. Your approach
uses the dynamic linker to resolve the function, which is sane.
For the case where the function being called is in the same DSO as
"create_code" (as you have here), it's possible to be slightly more
efficient and to directly call the function without going through the
dynamic linker, by constructing a function ptr, using the address of
"parent".
Something like:
fn_ptr_type = gcc_jit_context_new_function_ptr_type (...);
fn_ptr = \
gcc_jit_context_new_rvalue_from_ptr (ctxt,
fn_ptr_type,
&parent);
/* though strictly speaking, we can't necessarily cast from a function
ptr to a void *; see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66074
) */
call = \
gcc_jit_context_new_call_through_ptr (ctxt, NULL,
fn_ptr,
numargs, args);
which would enable "parent" to be a static function, and perhaps also be
slightly more efficient. The downside of doing it this way is that the
address of "parent" becomes baked-in, which is OK for the JIT use-case,
but not for ahead-of-time compilation.
The docs are also missing info on calling fns from other DSOs, which I
filed as https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64201 fwiw.
and it looks like I didn't document
gcc_jit_context_new_function_ptr_type or
gcc_jit_context_new_call_through_ptr. Sorry. Maybe we need a topic
reference concerning function calls, discussing the various kinds of
calls that can be made?
Note that GCC has some legal formalities that need to be observed for
anything other than the smallest contributions (and yours is
sufficiently large): specifically, do you have a copyright assignment on
file with the FSF?
See https://gcc.gnu.org/contribute.html for the gory details.
Thanks
Dave
>
> - Ed
>
> ----------------------------
>
> /* Usage example for libgccjit.so
> Copyright (C) 2014-2015 Free Software Foundation, Inc.
>
> This file is part of GCC.
>
> GCC is free software; you can redistribute it and/or modify it
> under the terms of the GNU General Public License as published by
> the Free Software Foundation; either version 3, or (at your option)
> any later version.
>
> GCC is distributed in the hope that it will be useful, but
> WITHOUT ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> General Public License for more details.
>
> You should have received a copy of the GNU General Public License
> along with GCC; see the file COPYING3. If not see
> <http://www.gnu.org/licenses/>. */
>
> #include <libgccjit.h>
>
> #include <stdlib.h>
> #include <stdio.h>
>
> void
> create_code (gcc_jit_context *ctxt)
> {
> /* Let's try to inject the equivalent of:
>
> extern int parent(int i);
>
> int square (int i)
> {
> (void)parent(i);
> return i * i;
> }
> (requires compiling with -Wl,--export-dynamic to resolve parent)
> */
> gcc_jit_type *int_type =
> gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
>
> gcc_jit_param *parent_param_i =
> gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
> gcc_jit_function *parent =
> gcc_jit_context_new_function (ctxt, NULL,
> GCC_JIT_FUNCTION_IMPORTED,
> int_type,
> "parent",
> 1, &parent_param_i,
> 0);
>
> gcc_jit_param *param_i =
> gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
> gcc_jit_function *func =
> gcc_jit_context_new_function (ctxt, NULL,
> GCC_JIT_FUNCTION_EXPORTED,
> int_type,
> "square",
> 1, ¶m_i,
> 0);
>
> gcc_jit_block *block =
> gcc_jit_function_new_block (func, NULL);
>
> // call (void)parent(i)
> gcc_jit_rvalue *parent_args = gcc_jit_param_as_rvalue(param_i);
> gcc_jit_block_add_eval (
> block, NULL,
> gcc_jit_context_new_call (
> ctxt,
> NULL,
> parent,
> 1, &parent_args));
>
> gcc_jit_rvalue *expr =
> gcc_jit_context_new_binary_op (
> ctxt, NULL,
> GCC_JIT_BINARY_OP_MULT, int_type,
> gcc_jit_param_as_rvalue (param_i),
> gcc_jit_param_as_rvalue (param_i));
> gcc_jit_block_end_with_return (block, NULL, expr);
> }
>
> int parent(int i)
> {
> printf("Called parent %d\n", i);
> }
>
> int
> main (int argc, char **argv)
> {
> gcc_jit_context *ctxt = NULL;
> gcc_jit_result *result = NULL;
>
> /* Get a "context" object for working with the library. */
> ctxt = gcc_jit_context_acquire ();
> if (!ctxt)
> {
> fprintf (stderr, "NULL ctxt");
> goto error;
> }
>
> /* Set some options on the context.
> Let's see the code being generated, in assembler form. */
> gcc_jit_context_set_bool_option (
> ctxt,
> GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
> 0);
>
> /* Populate the context. */
> create_code (ctxt);
>
> /* Compile the code. */
> result = gcc_jit_context_compile (ctxt);
> if (!result)
> {
> fprintf (stderr, "NULL result");
> goto error;
> }
>
> /* We're done with the context; we can release it: */
> gcc_jit_context_release (ctxt);
> ctxt = NULL;
>
> /* Extract the generated code from "result". */
> void *fn_ptr = gcc_jit_result_get_code (result, "square");
> if (!fn_ptr)
> {
> fprintf (stderr, "NULL fn_ptr");
> goto error;
> }
>
> typedef int (*fn_type) (int);
> fn_type square = (fn_type)fn_ptr;
> printf ("result: %d\n", square (5));
>
> error:
> if (ctxt)
> gcc_jit_context_release (ctxt);
> if (result)
> gcc_jit_result_release (result);
> return 0;
> }
More information about the Jit
mailing list