From: Reini U. <ru...@x-...> - 2008-01-22 15:59:05
|
FYI: For a project in my company I am evaluating optimized native JIT compilation right now. I started with the perl compiler, which is a VM of about 300 complex C-functions with pure stack handling, no registers. Simple but slow. The perl op interpreter is a simple loop traversing the op-tree while ((PL_op = CALL_FPTR(PL_op->op_ppaddr)(aTHX))) { PERL_ASYNC_CHECK(); } (see http://www.faqs.org/docs/perl5int/ops.html) where the ops are already compiled, just the arg handling and traversal is dynamic/interpreted. So this can be easily assembled JIT to native code. But what would be the performance gains? Perl5 has no type system and is very hard to optimize. There's a very simple peephole optimizer which rewrites the tree inplace, superflous ops are just NULLed and skipped. Most of the time it is just pushing/popping args from the stack. This should be optimized to handle registers somehow. CLISP has a much better type-system, e.g. we would know most of the time if we can do integer or double arithmetic. (handle overflows and upgrades with exceptions or with an extra pre-check or after-check?) CLISP also has the same advantage with perl that the bytecode interpreter can call optimized native implementations of the opcodes, very similar to perl (by calling the bytecode.d table functions). But much better with numbers than perl of course. So I'm also looking into JIT'ing and compiling clisp bytecode with the GNU lightning library. http://en.wikipedia.org/wiki/GNU_lightning (i386, sparc and ppc only) Does the CLISP VM uses only stack vars, no virtual registers? I've seen none. Has anyone looked into this before? Am I missing an important point? I'd need it for real-time within a system called INtime (on win32) where our formula interpreter can only do 125 cycles per second (125Hz), and I assume with native code compilation (dumping to dll's) or JIT at init-time it will be able do 1-5 KHz at run-time. Most of the time is sitting waiting for stupid global variables being written to shared memory with 1KHz (so copy-on-write would be more promising), but fast execution and lexicals would be nice to have anyway. I'll keep you informed. -- Reini Urban |
From: Sam S. <sd...@gn...> - 2008-01-22 16:17:43
|
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Reini Urban wrote: | So I'm also looking into JIT'ing and compiling clisp bytecode with the | GNU lightning library. | http://en.wikipedia.org/wiki/GNU_lightning | (i386, sparc and ppc only) | Does the CLISP VM uses only stack vars, no virtual registers? I've seen | none. CLISP passes arguments via STACK which is kept in a register (when possible, see STACK_register in lispbibl.d). I hope Bruno will answer your other questions. Sam. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFHlhavPp1Qsf2qnMcRAp25AJ45QqeoJc+xWf8/+eSi2wtO3kw0SgCfViD0 PZKS2Vm8oKLjWa23iXtwKWE= =trQa -----END PGP SIGNATURE----- |
From: Bruno H. <br...@cl...> - 2008-01-22 22:46:58
|
Reini Urban wrote: > | So I'm also looking into JIT'ing and compiling clisp bytecode with the > | GNU lightning library. > | http://en.wikipedia.org/wiki/GNU_lightning > | (i386, sparc and ppc only) I would also look into the libjit used by the GNU pnet project. http://ftp.gnu.org/gnu/dotgnu/pnet/ http://cvs.savannah.gnu.org/viewvc/libjit/?root=dotgnu-pnet The main difference between lightning and libjit appears to be that libjit is higher level: - lightning is some kind of portable in-memory assembler; it leaves you full control over registers. - libjit also contains register allocation and a connection to the type system. (Apologies if you already considered it.) > | Does the CLISP VM uses only stack vars, no virtual registers? I've seen > | none. http://clisp.cons.org/impnotes/vm.html answers this: The main virtual registers are mv_count and value1. If you look into interpret_bytecode_, you will see: There is also the "private_SP" area, used for creating particular kinds of stack frames. And the closure being currently executed also needs to be stored somewhere; IIRC this is used by the mechanism that throws and catches conditions, and also by generic functions dispatch code. Bruno |