public inbox for jit@gcc.gnu.org
 help / color / mirror / Atom feed
* gcc_jit_context (was Re: Python API (was Re: Build errors))
  2013-01-01  0:00 ` Simon Feltman
@ 2013-01-01  0:00   ` David Malcolm
  2013-01-01  0:00     ` Basile Starynkevitch
  0 siblings, 1 reply; 5+ messages in thread
From: David Malcolm @ 2013-01-01  0:00 UTC (permalink / raw)
  To: Simon Feltman; +Cc: jit

On Thu, 2013-10-24 at 03:36 -0700, Simon Feltman wrote:
> On Wed, Oct 23, 2013 at 10:20 PM, Simon Feltman <s.feltman@gmail.com> wrote:
> > ... This is well beyond my knowledge of compiler architecture,
> > but it seems like this could be cleaner?
> >
> >     the_type = ctxt.get_type(gccjit.Type.INT)
> >     local_i = fn.new_local(the_type, b"i")
> >
> > could be:
> >     local_i = fn.new_local(gccjit.Type.INT, b"i")
> 
> Digging into this a bit more, it looks like the gccjit API is sort of
> synthesizing the context dependence for types anyhow. e.g. gcc
> internals already seem to be defining the type nodes as globals
> (uint64_type_node). So perhaps the API is attempting to present a new
> model which the implementation may morph into?

Yes: as well as the JIT work, I'm also trying to modularize the core of
GCC: in the future I want to support multiple contexts of GCC state
within one process; there's now a "gcc::context" object in GCC proper,
though currently it only has one field (the pass manager). [1]

Hence I want the API to avoid a concept of "the" int type within the
process, instead, merely a given context's int type.  As you found out,
that part is currently somewhat smoke-and-mirrors.

BTW, internally most of the objects in the library already "know" which
context they belong to, and it would be easy to add that to the rest, so
it's not strictly necessary for many of the C entrypoints to be passed a
context pointer.  Some of the more recent entrypoints don't bother e.g.:
gcc_jit_rvalue_dereference.

So I've been thinking about reworking some of the existing C API to do
this, eliminating the context ptr from them.  So e.g. 

  extern gcc_jit_rvalue *
  gcc_jit_context_new_rvalue_from_int (gcc_jit_context *ctxt,
                                       gcc_jit_type *type,
                                       int value);
  extern gcc_jit_rvalue *
  gcc_jit_context_zero (gcc_jit_context *ctxt,
                        gcc_jit_type *type);

might become:

  extern gcc_jit_rvalue *
  gcc_jit_type_rvalue_from_int (gcc_jit_type *type,
                                int value);
  extern gcc_jit_rvalue *
  gcc_jit_type_zero (gcc_jit_type *type);

That way you'd generally go from a context to make your types, globals
and functions, and then you'd invoke methods on the types to make
rvalues, and on the functions to add statements (with a few exceptions
e.g. perhaps a rvalue *gcc_jit_function_make_call?)

The above may be my Python background speaking (in that in Python
there's such a strong relationship between types and making instances);
I wonder how natural such an API sounds to others on the list?

As another example, for binary ops; currently we have:

  extern gcc_jit_rvalue *
  gcc_jit_context_new_binary_op (gcc_jit_context *ctxt,
                                 gcc_jit_location *loc,
                                 enum gcc_jit_binary_op op,
                                 gcc_jit_type *result_type,
                                 gcc_jit_rvalue *a, gcc_jit_rvalue *b);

which might become:

  extern gcc_jit_rvalue *
  gcc_jit_type_binary_op (gcc_jit_type *result_type,
                          gcc_jit_location *loc,
                          enum gcc_jit_binary_op op,
                          gcc_jit_rvalue *a, gcc_jit_rvalue *b);

which itself raises issues of casts, which I've been mostly ignoring for
now.  FWIW gcc_jit_function_add_assignment currently adds a
type-coercion if the types of the LHS and RHS are different, but I'm
thinking of dropping that, and requiring an explicit cast (with a new
API entrypoint for that).  The testsuite fully passes if I drop the
implicit casts.

Thoughts?

Dave
[1] fwiw the gcc::context in GCC proper is independent from the
gcc::jit::context in gcc/jit/internal-api.[hc].  One day a jit context
might own a gcc::context, perhaps.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Python API (was Re: Build errors)
@ 2013-01-01  0:00 Simon Feltman
  2013-01-01  0:00 ` David Malcolm
  2013-01-01  0:00 ` Simon Feltman
  0 siblings, 2 replies; 5+ messages in thread
From: Simon Feltman @ 2013-01-01  0:00 UTC (permalink / raw)
  To: jit

On Wed, Oct 23, 2013 at 9:07 AM, David Malcolm <dmalcolm@redhat.com> wrote:
> I'm thinking of maybe rewriting the Python bindings to use cffi rather
> than Cython - that way they would work with PyPy.  As a potential user,
> any thoughts on that?
> (alternatively, we could have two different implementations; not sure if
> that's sane).

cffi might also make the bindings a bit easier to write/flush out the
API with as well? I have a little experience with cffi, the obvious
thing is it will be slower than static bindings. But this doesn't
really mean anything until it is tested along with the jit compilation
times in a real project. In this regard, I guess flushing out the API
with whatever you think is easier or initially more benifitial is the
way to go (this could also mean sticking with cython bindings since
they already exists). How much larger do you think the API will grow?

>> Some additional thoughts on pygccjit: In terms of API for the enums, I
>> think it would nice to follow more of a hierarchy. So instead of:
>>     gccjit.FUNCTION_EXPORTED
>> It could be:
>>     gccjit.FunctionKind.EXPORTED
>
> (nods).   I'm actually thinking of changing that enum so it applies to
> visibility in general e.g. for globals.  So that specific one might
> become GCC_JIT_VISIBILITY_EXPORTED or somesuch in the C API (not sold on
> that yet).  So would that become gccjit.Visibility.EXPORTED ?

Seems nice to generalize it for usage with globals as well. It
probably goes without saying but arguments of this type should also be
named "visibility" or better yet annotated with
"visibility:gccjit.Visibility" or documented as such.

> I think it's logical for the user to (optionally) specify the signature
> when creating the function, within the callback, but we need to use it
> when wrapping the (void*) from the result object.   So I think we need
> the Context wrapper object to store a dict, mapping from function names
> to ctypes signatures, which it would then hand off to the Result wrapper
> object.   The latter could then use this to create the ctypes wrapper
> around the (void*) in Result.get_code (or maybe "get_callable"?), thus
> handing a python callable back to the client code - if that makes sense.

That makes sense, so as noted in the code comments below?:

def cb(ctxt):
    sig = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int)
    # the following will store sig in a table on ctxt
    fn = ctxt.new_function_from_ctypes("foo", sig)
result = ctxt.compile()  # result needs to store a ref to ctxt
# result uses sig from ctxt table to contruct ctypes callable
code = result.get_code(b"square")

With this scheme, I guess the standard API of ctxt.new_function would
internally create a CFUNCTYPE with a signature mapped from the gccjit
types for use as a callable later on.

I think "get_callable" or even "get_pycallable" might be a bit more
understandable to a reader. The "py" prefix, albeit somewhat ugly,
gives a sense of orientation in regards to a jit construct vs a python
construct.

One thing I've noticed (this also stood out to me when playing with
llvmpy in the past) is types need to be created (and bound?) to a
context. This is well beyond my knowledge of compiler architecture,
but it seems like this could be cleaner?

    the_type = ctxt.get_type(gccjit.Type.INT)
    local_i = fn.new_local(the_type, b"i")

could be:
    local_i = fn.new_local(gccjit.Type.INT, b"i")

I'm sure there are performance and reference cycle implications with
this, and would probably convolute the internals. fn would need a
reference to the context which would need to hold a table of type
instances, etc.. (actually similar to the function building problem
above). It also might be too divergent from the C API which can be a
hard thing to balance with bindings. So I guess it depends how much
you want to diverge from the C API for Python convience.

-Simon

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Python API (was Re: Build errors)
  2013-01-01  0:00 Python API (was Re: Build errors) Simon Feltman
@ 2013-01-01  0:00 ` David Malcolm
  2013-01-01  0:00 ` Simon Feltman
  1 sibling, 0 replies; 5+ messages in thread
From: David Malcolm @ 2013-01-01  0:00 UTC (permalink / raw)
  To: Simon Feltman; +Cc: jit

On Wed, 2013-10-23 at 22:20 -0700, Simon Feltman wrote:
> On Wed, Oct 23, 2013 at 9:07 AM, David Malcolm <dmalcolm@redhat.com> wrote:
> > I'm thinking of maybe rewriting the Python bindings to use cffi rather
> > than Cython - that way they would work with PyPy.  As a potential user,
> > any thoughts on that?
> > (alternatively, we could have two different implementations; not sure if
> > that's sane).
> 
> cffi might also make the bindings a bit easier to write/flush out the
> API with as well? I have a little experience with cffi, the obvious
> thing is it will be slower than static bindings. 

I primarily went with Cython due to my familiarity with it (although I
realized as I went along that I'd forgotten most of it :)

> But this doesn't
> really mean anything until it is tested along with the jit compilation
> times in a real project.

I suspect any arguments about speed of Python bindings are moot compared
to the CPython vs PyPy question, cffi enabling the latter.

That said, I've only ever run the libgccjit.so in "debug" mode (GCC has
lots of internal selftests, which get disabled for speed if you
configure with --enable-checking=release iirc), and there's the huge
internal kludge I'm using to convert from assembler to machine code,
which shows up as taking about half the wallclock time.

>  In this regard, I guess flushing out the API
> with whatever you think is easier or initially more benifitial is the
> way to go (this could also mean sticking with cython bindings since
> they already exists). How much larger do you think the API will grow?

Difficult to say.  I'm conscious that so far I've only tried the API
with a method JIT, and I think supporting a tracing JIT may require some
extra things for supporting patching code after-the-fact.

> >> Some additional thoughts on pygccjit: In terms of API for the enums, I
> >> think it would nice to follow more of a hierarchy. So instead of:
> >>     gccjit.FUNCTION_EXPORTED
> >> It could be:
> >>     gccjit.FunctionKind.EXPORTED
> >
> > (nods).   I'm actually thinking of changing that enum so it applies to
> > visibility in general e.g. for globals.  So that specific one might
> > become GCC_JIT_VISIBILITY_EXPORTED or somesuch in the C API (not sold on
> > that yet).  So would that become gccjit.Visibility.EXPORTED ?
> 
> Seems nice to generalize it for usage with globals as well. It
> probably goes without saying but arguments of this type should also be
> named "visibility" or better yet annotated with
> "visibility:gccjit.Visibility" or documented as such.

(nods)

> > I think it's logical for the user to (optionally) specify the signature
> > when creating the function, within the callback, but we need to use it
> > when wrapping the (void*) from the result object.   So I think we need
> > the Context wrapper object to store a dict, mapping from function names
> > to ctypes signatures, which it would then hand off to the Result wrapper
> > object.   The latter could then use this to create the ctypes wrapper
> > around the (void*) in Result.get_code (or maybe "get_callable"?), thus
> > handing a python callable back to the client code - if that makes sense.
> 
> That makes sense, so as noted in the code comments below?:
> 
> def cb(ctxt):
>     sig = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int)
>     # the following will store sig in a table on ctxt
>     fn = ctxt.new_function_from_ctypes("foo", sig)
> result = ctxt.compile()  # result needs to store a ref to ctxt
> # result uses sig from ctxt table to contruct ctypes callable
> code = result.get_code(b"square")
> 
> With this scheme, I guess the standard API of ctxt.new_function would
> internally create a CFUNCTYPE with a signature mapped from the gccjit
> types for use as a callable later on.
So it uses the ctypes types to get at gccjit types?  Would need a way to
get at the params also.

> I think "get_callable" or even "get_pycallable" might be a bit more
> understandable to a reader. The "py" prefix, albeit somewhat ugly,
> gives a sense of orientation in regards to a jit construct vs a python
> construct.

Sounds sane.

> One thing I've noticed (this also stood out to me when playing with
> llvmpy in the past) is types need to be created (and bound?) to a
> context. This is well beyond my knowledge of compiler architecture,
> but it seems like this could be cleaner?
> 
>     the_type = ctxt.get_type(gccjit.Type.INT)
>     local_i = fn.new_local(the_type, b"i")
> 
> could be:
>     local_i = fn.new_local(gccjit.Type.INT, b"i")
In the second syntax, is gccjit.Type.INT actually giving back a
gccjit.Type object, calling gcc_jit_get_type under the covers?


> I'm sure there are performance and reference cycle implications with
> this, and would probably convolute the internals. fn would need a
> reference to the context which would need to hold a table of type
> instances, etc.. (actually similar to the function building problem
> above). It also might be too divergent from the C API which can be a
> hard thing to balance with bindings. So I guess it depends how much
> you want to diverge from the C API for Python convience.

(nods)   I'm not sure.

Thanks
Dave

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Python API (was Re: Build errors)
  2013-01-01  0:00 Python API (was Re: Build errors) Simon Feltman
  2013-01-01  0:00 ` David Malcolm
@ 2013-01-01  0:00 ` Simon Feltman
  2013-01-01  0:00   ` gcc_jit_context (was Re: Python API (was Re: Build errors)) David Malcolm
  1 sibling, 1 reply; 5+ messages in thread
From: Simon Feltman @ 2013-01-01  0:00 UTC (permalink / raw)
  To: jit

On Wed, Oct 23, 2013 at 10:20 PM, Simon Feltman <s.feltman@gmail.com> wrote:
> ... This is well beyond my knowledge of compiler architecture,
> but it seems like this could be cleaner?
>
>     the_type = ctxt.get_type(gccjit.Type.INT)
>     local_i = fn.new_local(the_type, b"i")
>
> could be:
>     local_i = fn.new_local(gccjit.Type.INT, b"i")

Digging into this a bit more, it looks like the gccjit API is sort of
synthesizing the context dependence for types anyhow. e.g. gcc
internals already seem to be defining the type nodes as globals
(uint64_type_node). So perhaps the API is attempting to present a new
model which the implementation may morph into?

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: gcc_jit_context (was Re: Python API (was Re: Build errors))
  2013-01-01  0:00   ` gcc_jit_context (was Re: Python API (was Re: Build errors)) David Malcolm
@ 2013-01-01  0:00     ` Basile Starynkevitch
  0 siblings, 0 replies; 5+ messages in thread
From: Basile Starynkevitch @ 2013-01-01  0:00 UTC (permalink / raw)
  To: David Malcolm; +Cc: Simon Feltman, jit

On Thu, 2013-10-24 at 14:20 -0400, David Malcolm wrote:
[...]
> So I've been thinking about reworking some of the existing C API to do
> this, eliminating the context ptr from them.  So e.g. 
> 
>   extern gcc_jit_rvalue *
>   gcc_jit_context_new_rvalue_from_int (gcc_jit_context *ctxt,
>                                        gcc_jit_type *type,
>                                        int value);
>   extern gcc_jit_rvalue *
>   gcc_jit_context_zero (gcc_jit_context *ctxt,
>                         gcc_jit_type *type);
> 
> might become:
> 
>   extern gcc_jit_rvalue *
>   gcc_jit_type_rvalue_from_int (gcc_jit_type *type,
>                                 int value);
>   extern gcc_jit_rvalue *
>   gcc_jit_type_zero (gcc_jit_type *type);


For readability reasons, I am not sure it is a good decision. Having one
argument passing the full context of the compilation everywhere is
probably more readable. (It might be preferable for performance reasons,
but you'll need to benchmark to be sure).

But it is really a matter of taste. At least if you don't pass a
gcc_jit_context explicitly document very loudly that it is getting
wrapped in gcc_jit_type, and perhaps publish a function retrieving the
context from a type, etc etc.

Cheers.


-- 
Basile STARYNKEVITCH         http://starynkevitch.net/Basile/
email: basile<at>starynkevitch<dot>net mobile: +33 6 8501 2359
8, rue de la Faiencerie, 92340 Bourg La Reine, France
*** opinions {are only mine, sont seulement les miennes} ***


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2013-10-24 20:29 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-01-01  0:00 Python API (was Re: Build errors) Simon Feltman
2013-01-01  0:00 ` David Malcolm
2013-01-01  0:00 ` Simon Feltman
2013-01-01  0:00   ` gcc_jit_context (was Re: Python API (was Re: Build errors)) David Malcolm
2013-01-01  0:00     ` Basile Starynkevitch

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).