https://gcc.gnu.org/ml/jit/2013-q4/msg00023.html
From Paulo César Pereira de Andrade <paulo.cesar.pereira.de.andrade@gmail.com>
Hello David Malcom and all, I am trying to understand what are the conceptual differences between GCC JIT (when it will be mature enough) and other JIT libraries like GNU lightning or LLVM or GNU libjit from the point of view of the developer using the JIT library. GNU lightning is probably much lower level than GCC JIT. It probably has the advantage of generating quickly rather slow machine code. It mostly gives a small set of register like variables. LLVM probably is the equivalent competitor, since both GCC JIT and LLVM are derived from ahead of time compilers (of course, for LLVM it was initially not much true). So probably both GCC JIT and LLVM would produce, a bit slowly, some good machine code. (In particular because GCC JIT is, AFAIK, emitting assembly code). BTW, I have no idea if GCC JIT has some option to set the optimization level. Libjit seems superficially similar in terms of API (to both LLVM and GCC JIT): it offers a mini-C like intermediate representation. I also believe that GCC JIT is probably the JIT library which runs on much more processors than others (because GCC has a wide set of targets). David, do you think that a libit based JIT engine could quickly switch to GCC JIT once it has matured? I am guessing it would be quite easy. Cheers -- Basile STARYNKEVITCH 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} ***
From Basile Starynkevitch <basile@starynkevitch.net>
On Tue, 2013-10-22 at 20:30 +0200, Basile Starynkevitch wrote: > Hello David Malcom and all, Hi Basile. > I am trying to understand what are the conceptual differences between > GCC JIT (when it will be mature enough) and other JIT libraries like GNU > lightning or LLVM > or GNU libjit from > the point of view of the developer using the JIT library. I was aware of lightning and LLVM; I wasn't aware of libjit - thanks for the link. My interest is in modularising GCC's code, and I've been working for the last few years on dynamic language runtimes (for Python), so turning GCC into being usable for JIT use-cases is of great interest to me. I tend to prefer fixing existing code over rewriting, hence my preference for generalizing GCC to cover JIT workloads, over having a separate JIT project: I'd prefer to have code shared between the ahead-of-time compiler and the JIT compiler. But other people may feel differently, of course. > GNU lightning is probably much lower level than GCC JIT. It probably has > the advantage of generating quickly rather slow machine code. It mostly > gives a small set of register like variables. >From what I've seen of lightning it does indeed seem to have a much lower level API compared to libgccjit. It's probably faster: certainly libgccjit isn't fast yet - for example, internally we're writing out a .s file to disk, and then having to invoke other tools as subprocesses to get that into a form we can execute. I hope to eventually eliminate that kludge (e.g. turn the GNU assembler into a library and use it in-process, or perhaps even have GCC's RTL level directly emit machine code instead of asm). I deliberately hid the kludge behind the API, so it should be possible to fix it without affecting ABI. It's possible to see timing data by setting the bool option GCC_JIT_BOOL_OPTION_DUMP_SUMMARY on the context; this is (very) roughly equivalent to running cc1 without the -quiet option. > LLVM probably is the equivalent competitor, since both GCC JIT and LLVM > are derived from ahead of time compilers (of course, for LLVM it was > initially not much true). So probably both GCC JIT and LLVM would > produce, a bit slowly, some good machine code. (In particular because > GCC JIT is, AFAIK, emitting assembly code). (nods) Yes, as described above, libgccjit does currently go through .s files internally. (my understanding of LLVM's origins are that it was for an ahead-of-time compiler for doing a radical whole-program optimization that implements pointer compression automatically) > BTW, I have no idea if GCC JIT has some option to set the optimization > level. It does: gcc_jit_context_set_int_option (ctxt, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 3); is equivalent to "-O3" i.e. -O0 through -O3 are selectable. 0 is the default. The API is simple for now. I can add options for enabling specific optimizations if people want, perhaps customization of the pass pipeline (I implemented the pass_manager code in gcc 4.9 which may help us to support such a use-case). > Libjit seems superficially similar in terms of API (to both LLVM and GCC > JIT): it offers a mini-C like intermediate representation. Yes, looking at the API it looks similar to the API I came up with, though I have rvalues vs lvalues, and there are no explicit blocks, only label placement (you can always implement blocks by placing labels). > I also believe that GCC JIT is probably the JIT library which runs on > much more processors than others (because GCC has a wide set of > targets). I'd agree with that, though I'm speculating. This is one of the reasons for the very high-level nature of the API. I'm conscious that I've only used the API to implement a method JIT, not a tracing JIT; we may need additional constructs to help deal with the kinds of dynamic code patching that a tracing JIT needs to do. > David, do you think that a libit based JIT engine could quickly switch > to GCC JIT once it has matured? I am guessing it would be quite easy. I think so. Out of interest, are you thinking of using this for MELT? i.e. embedding libgccjit inside a gcc plugin? If so, I wonder if there could be nasty interactions between the two copies of the GCC code? libgccjit has a symbol map that hides everything other than the 50 or so gcc_jit_* entrypoints, so hopefully the two copies of the code would peacefully coexist within the same address space - but it sounds like something to be wary of. Hope this is helpful Dave
From David Malcolm <dmalcolm@redhat.com>
On Wed, 2013-10-23 at 00:24 -0400, David Malcolm wrote: > Out of interest, are you thinking of using this for MELT? i.e. > embedding libgccjit inside a gcc plugin? If so, I wonder if there could > be nasty interactions between the two copies of the GCC code? (for other readers, MELT refers to a high level domain specific language to extend GCC; MELT is a GCC plugin - generating C++ code fit into GCC) Yes and no. Indeed, I am thinking of LIBJIT or GCC JIT in something remotely related to MELT, but that won't be in the MELT plugin. I am dreaming of a MELT monitor, which would be an *external* process to MELT and will : give a web interface to MELT, displaying code using Code Mirror communicate asynchronously with compilations using the MELT plugin store some persistent information That MELT monitor could use JIT techniques (but it is a separate process from cc1 or cc1plus -fplugin=melt ....). But there won't be nasty interactions between the monitor and the cc1 because they are separate processes - with some bi-directional pipes to communicate... all this is just a dream today. -- Basile STARYNKEVITCH 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} ***
From Basile Starynkevitch <basile@starynkevitch.net>
2013/10/22 Basile Starynkevitch <basile@starynkevitch.net>: > Hello David Malcom and all, > > I am trying to understand what are the conceptual differences between > GCC JIT (when it will be mature enough) and other JIT libraries like GNU > lightning or LLVM > or GNU libjit from > the point of view of the developer using the JIT library. > > GNU lightning is probably much lower level than GCC JIT. It probably has > the advantage of generating quickly rather slow machine code. It mostly > gives a small set of register like variables. GNU lightning does not use abstract "values", that may be either a register or an immediate, it is required to explicitly state if the argument is a register or an immediate, e.g. jit_addr(JIT_R0, JIT_R1, JIT_R2) and jit_addi(JIT_R0, JIT_R1, 2). When using immediates, they are always the last argument. GNU lightning major limitations are: o Can call varargs but does not create varargs jit functions o No dynamic alloca o No aggregate arguments/return by value The major advantages are: o Self contained, but binutils support is advised otherwise without disassembly, debugging may be quite difficult. o Tailored for operations that need to know if there is overflow/carry and have the values ready (carry/borrow only need to know about, but multiplication high word and division remainder are quite useful). For starters, I would suggest looking at lightning's check/*.tst files, for an overview of how to generate code. For example, bp.tst for the classic recursive Fibonacci and fib.tst for the interactive one. Other tests may be complex due to using the C preprocessor to generate complex macros to brute force test all/most register/value combinations. A more complex, still WIP, use case example of lightning is (lib/oemit*c files are the lightning interfaces) Well, enough GNU lightning advertising :-) > LLVM probably is the equivalent competitor, since both GCC JIT and LLVM > are derived from ahead of time compilers (of course, for LLVM it was > initially not much true). So probably both GCC JIT and LLVM would > produce, a bit slowly, some good machine code. (In particular because > GCC JIT is, AFAIK, emitting assembly code). > > BTW, I have no idea if GCC JIT has some option to set the optimization > level. > > Libjit seems superficially similar in terms of API (to both LLVM and GCC > JIT): it offers a mini-C like intermediate representation. > > I also believe that GCC JIT is probably the JIT library which runs on > much more processors than others (because GCC has a wide set of > targets). > > David, do you think that a libit based JIT engine could quickly switch > to GCC JIT once it has matured? I am guessing it would be quite easy. > > Cheers > -- > Basile STARYNKEVITCH > 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} *** Paulo
From Paulo César Pereira de Andrade <paulo.cesar.pereira.de.andrade@gmail.com>
On Wed, 2013-10-23 at 13:22 -0200, Paulo CÃsar Pereira de Andrade wrote: > > A more complex, still WIP, use case example of lightning is > (lib/oemit*c files are the lightning > interfaces) Thanks for your message Paulo. Actually, of all the JIT libraries I have cited, GNU lightning is probabnly the one I am the more familiar with. Long time ago, I coded ocamljit - a small JIT for ocaml bytecode - in it (but the current ocamljit2 is probably unrelated to it). I'm interested by your OWL work (did you know that as a computer language, OWL means quite often ?) But I am not able to find out some small examples of OWL code and/or some syntax (and semantic) definition of your OWL. Or is OWL a JIT for full C (e.g. able to interpret any C program)? How do you code fibionacci and hello world in OWL? How do you code a program reading a list of integers and computing the list of their square? And back to David Malcolm's GCC JIT, would you find easy to re-implement OWL in it? Cheers. -- Basile STARYNKEVITCH 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} ***
From Basile Starynkevitch <basile@starynkevitch.net>
2013/10/23 Basile Starynkevitch <basile@starynkevitch.net>: > On Wed, 2013-10-23 at 13:22 -0200, Paulo César Pereira de Andrade wrote: >> >> A more complex, still WIP, use case example of lightning is >> (lib/oemit*c files are the lightning >> interfaces) > > > Thanks for your message Paulo. Hi Basile, > Actually, of all the JIT libraries I have cited, GNU lightning is > probabnly the one I am the more familiar with. Long time ago, I coded > ocamljit - a small JIT for ocaml bytecode - in it (but the current > ocamljit2 is probably unrelated to it). I did significant changes to lightning when I became maintainer of it. Unless you used private interfaces (previously it was implemented all in one pass as C macros, so, could not hide internals), basically the main difference is that now function arguments are passed left to right, and there is a large set of new ports. > I'm interested by your OWL work (did you know that as a computer > language, OWL means quite often > ?) I did not know about it. > But I am not able to find out some small examples of OWL code and/or > some syntax (and semantic) definition of your OWL. Or is OWL a JIT for > full C (e.g. able to interpret any C program)? It is a C/C++ like language, with static and dynamic typing. The only examples so far are in check/test, that you can cut&paste under gdb, or just run "./owl check/test" to run all examples in a row. The file is quite large, and growing, to help stress test the current implementation. > How do you code fibionacci and hello world in OWL? How do you code a > program reading a list of integers and computing the list of their > square? It is still in the early stages of implementation, there are still too many incomplete features, so, the best bet is to look in check/test that is being used to slowly test code generation and correct code generation bugs. But the hello world test is easy :-) $ echo 'print("hello world!\n");' | ./owl hello world! I promise to add working Fibonacci examples to check/test in my next commit :-) There is an internal stream implementation, but only "exported" so far is the print builtin, that prints to stdout, so the example of an integer list would need to have the input encoded in a vector for now. > And back to David Malcolm's GCC JIT, would you find easy to re-implement > OWL in it? My interest is in writing a managed language with dynamic typing, and static typing for faster execution. But porting to gcc jit should not be much different from the initial code I am writing, mainly to exercise lightning, that would "optimize" when types are know, check for overflow when it can happen and otherwise fallback to calling functions to implement the vm primitives. > Cheers. > > -- > Basile STARYNKEVITCH > 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} *** Paulo
From Paulo César Pereira de Andrade <paulo.cesar.pereira.de.andrade@gmail.com>
On Wed, 2013-10-23 at 19:05 -0200, Paulo CÃsar Pereira de Andrade wrote: [...] > It is a C/C++ like language, with static and dynamic typing. The only > examples so far are in check/test, that you can cut&paste under gdb, > or just run "./owl check/test" to run all examples in a row. The file is quite > large, and growing, to help stress test the current implementation. Is OWL compiling a function at a time (a "method JIT"), or are you tracing execution paths and then optimizing hot loops (a "tracing JIT")? (I've only attempted the former so far with my work) [...] > My interest is in writing a managed language with dynamic typing, > and static typing for faster execution. But porting to gcc jit should not > be much different from the initial code I am writing, mainly to exercise > lightning, that would "optimize" when types are know, check for overflow > when it can happen and otherwise fallback to calling functions to > implement the vm primitives. BTW, does lightning support self-modifying code? (e.g. for doing inline caching of attribute lookup). Thanks Dave
From David Malcolm <dmalcolm@redhat.com>
On Thu, 2013-10-24 at 14:53 -0400, David Malcolm wrote: [...] > BTW, does lightning support self-modifying code? (e.g. for doing > inline caching of attribute lookup). But GCC does not (support self-modifying code). How would you make GCC JIT accept it if GCC does not? Cheers -- Basile STARYNKEVITCH 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} ***
From Basile Starynkevitch <basile@starynkevitch.net>
On Thu, 2013-10-24 at 21:53 +0200, Basile Starynkevitch wrote: > On Thu, 2013-10-24 at 14:53 -0400, David Malcolm wrote: > [...] > > BTW, does lightning support self-modifying code? (e.g. for doing > > inline caching of attribute lookup). > > But GCC does not (support self-modifying code). How would you make GCC > JIT accept it if GCC does not? By making GCC handle it ;) There may be things that are reasonable to do in a JIT that make little sense for an AOT compiler, and self-modifying code is one of them, e.g. for conditionals that almost always take one branch such as for guard-style conditionals inside a loop, where we're recording the assumptions about the types we're working on, with a if (expr != expected_value) and we don't expect the non-equal branch to ever be followed, but for correctness it must exist, and we need to be able to update expected_value. In such a case, we want the most efficient check for the commonly-executed case, and hardcoding expected_value inside the compare instruction and then directly modifying it in place on the rare chance it changes might be most efficient. These are vague, long-term ideas, of course.
From David Malcolm <dmalcolm@redhat.com>
2013/10/24 David Malcolm <dmalcolm@redhat.com>: > On Wed, 2013-10-23 at 19:05 -0200, Paulo César Pereira de Andrade wrote: > [...] > >> It is a C/C++ like language, with static and dynamic typing. The only >> examples so far are in check/test, that you can cut&paste under gdb, >> or just run "./owl check/test" to run all examples in a row. The file is quite >> large, and growing, to help stress test the current implementation. > > Is OWL compiling a function at a time (a "method JIT"), or are you > tracing execution paths and then optimizing hot loops (a "tracing JIT")? > (I've only attempted the former so far with my work) For now it is more of a test environment for complex code generation using lightning. It actually "compiles" a full owl script as a single C callable function, uses its own stack, and does a precise mark&sweep gc. Lightning itself can be used for either, as it only provides a kind of portable, minimal assembly. > [...] > >> My interest is in writing a managed language with dynamic typing, >> and static typing for faster execution. But porting to gcc jit should not >> be much different from the initial code I am writing, mainly to exercise >> lightning, that would "optimize" when types are know, check for overflow >> when it can happen and otherwise fallback to calling functions to >> implement the vm primitives. > > BTW, does lightning support self-modifying code? (e.g. for doing > inline caching of attribute lookup). No. Lightning does mmap memory for the jit, attempting to waste as few as possible memory, and after code generation it does mprotect it removing write permission. Also does some voodoo for architectures that need complex sequences to flush the code cache; currently it requires gcc as the compiler, but libgcc __clear_cache does not work on all ports. > Thanks > Dave Paulo
From Paulo César Pereira de Andrade <paulo.cesar.pereira.de.andrade@gmail.com>
On Fri, 2013-10-25 at 13:15 -0200, Paulo CÃsar Pereira de Andrade wrote: > 2013/10/24 David Malcolm <dmalcolm@redhat.com>: > > On Wed, 2013-10-23 at 19:05 -0200, Paulo CÃsar Pereira de Andrade wrote: > > [...] > > > >> It is a C/C++ like language, with static and dynamic typing. The only > >> examples so far are in check/test, that you can cut&paste under gdb, > >> or just run "./owl check/test" to run all examples in a row. The file is quite > >> large, and growing, to help stress test the current implementation. > > > > Is OWL compiling a function at a time (a "method JIT"), or are you > > tracing execution paths and then optimizing hot loops (a "tracing JIT")? > > (I've only attempted the former so far with my work) > > For now it is more of a test environment for complex code generation > using lightning. It actually "compiles" a full owl script as a single C > callable function, uses its own stack, and does a precise mark&sweep > gc. Lightning itself can be used for either, as it only provides a kind of > portable, minimal assembly. Nice. > > [...] > > > >> My interest is in writing a managed language with dynamic typing, > >> and static typing for faster execution. But porting to gcc jit should not > >> be much different from the initial code I am writing, mainly to exercise > >> lightning, that would "optimize" when types are know, check for overflow > >> when it can happen and otherwise fallback to calling functions to > >> implement the vm primitives. > > > > BTW, does lightning support self-modifying code? (e.g. for doing > > inline caching of attribute lookup). > > No. Lightning does mmap memory for the jit, attempting to waste as > few as possible memory, and after code generation it does mprotect > it removing write permission. Also does some voodoo for architectures > that need complex sequences to flush the code cache; currently > it requires gcc as the compiler, but libgcc __clear_cache does not > work on all ports. Thanks. FWIW one other approach I've seen is to mmap an anonymous fd twice, once as writable, once as executable, giving the same underlying pages in two different locations in the address space. IIRC libffi uses this when constructing wrappers to sidestep SELinux's restrictions on having pages that are both writable and executable. (I don't think that it has a cache-flushing mechanism, since it has clearly separated phases of "write, then execute").
From Paulo César Pereira de Andrade <paulo.cesar.pereira.de.andrade@gmail.com>
On Wed, 2013-10-23 at 13:22 -0200, Paulo CÃsar Pereira de Andrade wrote: Hi Paulo > 2013/10/22 Basile Starynkevitch <basile@starynkevitch.net>: > > Hello David Malcom and all, > > > > I am trying to understand what are the conceptual differences between > > GCC JIT (when it will be mature enough) and other JIT libraries like GNU > > lightning or LLVM > > or GNU libjit from > > the point of view of the developer using the JIT library. > > > > GNU lightning is probably much lower level than GCC JIT. It probably has > > the advantage of generating quickly rather slow machine code. It mostly > > gives a small set of register like variables. > > GNU lightning does not use abstract "values", that may be either a > register or an immediate, it is required to explicitly state if the argument > is a register or an immediate, e.g. jit_addr(JIT_R0, JIT_R1, JIT_R2) > and jit_addi(JIT_R0, JIT_R1, 2). When using immediates, they are > always the last argument. > > GNU lightning major limitations are: > o Can call varargs but does not create varargs jit functions > o No dynamic alloca > o No aggregate arguments/return by value > > The major advantages are: > o Self contained, but binutils support is advised otherwise without > disassembly, debugging may be quite difficult. > o Tailored for operations that need to know if there is overflow/carry > and have the values ready (carry/borrow only need to know about, > but multiplication high word and division remainder are quite useful). ...and I'm fairly sure that your code has a *much* lower overhead than mine (but improving GCC's startup time feels like an interesting challenge). > For starters, I would suggest looking at lightning's check/*.tst files, > for an overview of how to generate code. For example, bp.tst for > the classic recursive Fibonacci and fib.tst for the interactive one. > Other tests may be complex due to using the C preprocessor to > generate complex macros to brute force test all/most register/value > combinations. Thanks. Looks like the tests use an assembler-like syntax, which I'm guessing gets parsed by a test harness. > A more complex, still WIP, use case example of lightning is > (lib/oemit*c files are the lightning > interfaces) Thanks for the link (and indeed for the work on the code) > Well, enough GNU lightning advertising :-) :-) Cheers Dave