Hello, This is great! I read some patches, and it's much cleaner than mine. I'm glad we have a cool new CPS compiler now, and we can start to really use the RTL VM!
Noah On Thu, Aug 29, 2013 at 3:49 AM, Andy Wingo <wi...@pobox.com> wrote: > Hi all, > > This patchset implements the CPS compiler I've been working on over the > last couple months. At the end of it, you can > > guild compile -t rtl foo.scm > > and, if there are no bugs or unimplemented bits, at that point you have > a loadable .go with RTL code. (Try readelf -a on the .go!) > > From the console the way to do it is: > > (use-modules (system vm objcode)) > (load-thunk-from-memory (compile foo #:to 'rtl)) > > That gives you the thunk that, when called, will execute FOO. > > So with that intro, some more on CPS and the RTL VM. As you know we > have a new register-based VM, where all values have names (slots). It's > appropriate that the language that compiles to this VM also give names > to all intermediate values. CPS has this property. In addition, CPS > gives names to all control points, effectively giving a label to each > expression. > > This CPS language was inspired by Andrew Kennedy's great 2007 paper, > "Compiling with Continuations, Continued". In particular, continuations > are /local/ to a function, so they really are basic block labels, and > all values are bound to variables via continuation calls -- even > constants. > > As a little example: > > (+ 1 2) > > Here + is a primcall, so we would get: > > ($letk ((kone ($kargs (oneb) > ($letk ((ktwo ($kargs (two) > ($continue ktail > ($primcall + one two))))) > ($continue ktwo ($const 2)))))) > ($continue kone ($const 1))) > > Here all CPS language constructs are prefixed with "$". Everything else > is a variable, except the + in the primcall. > > As you can see it is incredibly verbose. At the same time it's very > simple, as there are only two kinds of terms: terms that bind > continuations, and terms that call continuations. > > $letk binds a set of mutually recursive continuations, each one an > instance of $cont. A $cont declares the name and source of a > continuation, and then contains as a subterm the particular > continuation instance: $kif for test continuations, $kargs for > continuations that bind values, etc. > > $continue nodes call continuations. The expression contained in the > $continue node determines the value or values that are passed to the > target continuation: $const to pass a constant value, $values to > pass multiple named values, etc. > > Additionally there is $letrec, a term that binds mutually recursive > functions. The contification pass will turn $letrec into $letk if > it can do so. Otherwise, the closure conversion pass will desugar > $letrec into an equivalent sequence of make-closure primcalls and > subsequent initializations of the captured variables of the > closures. You can think of $letrec as pertaining to "high CPS", > whereas later passes will only see "low CPS", which does not have > $letrec. > > There are a bunch of Guile-specific quirks in this language, mostly > related to function prologues for the different kinds of arities, and > for things like multiple-value truncation and prompts. Check out > (language cps) for all the deal. > > So, after that patch is the Tree-IL->CPS compiler. It simplifies a > number of Tree-IL concepts, fixing argument order, turning toplevel > references to primcalls, transforming prompts, assignment conversion, > etc. For this reason it's a bit hairy, but it seems to work fine. This > compiler runs *after* optimization passes on Tree-IL, so you still have > peval that runs over tree-il. > > After that follow a bunch of passes to build up an RTL compiler. The > idea is to compile by incremental source-to-source passes, and at the > end you just assign slots to all variables and emit code directly. > > If you ever worked with the old (language tree-il compile-glil) module, > you know it's very hairy, mostly because it's mixing code emission with > semantic transformations. Nowhere is this more evident than the > so-called "labels allocation" strategy, in which we try to allocate > procedures as basic blocks, if they all return to the same place. It's > a funky pass. It turns out this concept is well-studied and has a name, > "contification", and is cleanly expressed as a source-to-source pass > over CPS. So compile-rtl.scm is dumb: it just loops over all > expressions, emitting code for each of them, and emitting jumps and > shuffling registers as needed (based on a prior analysis pass). > > In the end you can ,disassemble the code, thanks to the earlier RTL > work. > > I don't want people to benchmark this stuff yet -- it's buggy and not > optimized. Don't use this work for anything serious. But if you're in > to hacking on it, that's cool. There are a number of optimization > passes that are needed (see compile-rtl.scm for a list), but currently > it's looking like the RTL compiler does significantly better on loops, > but struggles to keep up with the old VM for calls. This is > unsurprising, as calls really do work like stacks, and a stack VM has > many advantages there. But we think that with better slot allocation we > can probably be faster for calls as well. > > Thank you, thank you, thank you to Mark Weaver for helping out with this > work! Without him there would be many more bugs. I've folded all of > his patches into this patchset, so please consider him the joint author > of all of this. In any case the bugs have forced him to page much of > this code into his head so we are better equipped as a project because > of that ;-) > > Thank you also to Noah Lavine, who did an earlier pass at CPS > conversion. I considered starting from his work but it became clear > that many aspects of CPS would be nicer with changes in Tree-IL -- so I > took advantage of my maintenance of the old compiler to make various > changes there and in other parts of the runtime to get a cleaner CPS > compiler. In the end we took advantage of his vanguard-hacking, though > as ideas rather than as code. Thank you Noah! > > There are not as many tests and documentation as one would like. > Ultimately it all just came together in the last couple of weeks, so I > think the next step is to write more tests and try the compiler on new > pieces of code. There are a couple bugs that we know about at this > point, and surely many more that we don't know about. I ask for some > lenience on this front while we figure out what the compiler should look > like :) > > OK. WDYT, Ludo? Comments? OK to merge? :) > > Cheers, > > Andy > > >