
On Sat, Mar 27, 2010 at 07:30:30PM -0300, Rafael Cunha de Almeida wrote:
John Meacham wrote:
Here are jhc's timings for the same programs on my machine. gcc and ghc both used -O3 and jhc had its full standard optimizations turned on.
jhc: ./hs.out 5.12s user 0.07s system 96% cpu 5.380 total
gcc: ./a.out 5.58s user 0.00s system 97% cpu 5.710 total
ghc: ./try 31.11s user 0.00s system 96% cpu 32.200 total
As you can see, jhc shines at this example, actually beating gcc -O3. It isn't too surprising, this is exactly the sort of haskell code that jhc excels at.
I have not thoroughly checked it, but I think there are a couple things going on here: jhc is able to determine that all the arguments to the various functions are strict, so it can avoid all heap allocations and evaluations. ghc also benefits from this optimization. jhc sees that all the functions are fully applied to all their arguments, this means that they can always be directly called with optimized calling conventions as they will never have to represent generic 'eval' thunks or partial applications. it sees that all the functions are local to 'main' and not exported, so it can actually translate them to local functions in main in grin, allowing some more useful optimizations. Now the most important one, after optimizing the local functions, jhc sees that they are only called in tail-call position, so jhc is able to turn the function calls into direct jumps, turning them directly into C while/for loops operating fully on automatic variables on the stack. These last two optimizations are enabled by an incredibly useful extension to boquist's GRIN which is to allow a form of local function definitions, which solve a number of issues raised in his paper. Via a series of Grin->Grin transformations I am able to turn these local funciton definitions into direct conditional jumps in the resulting code. (which translate to looping constructs, if's and goto's in C) John -- John Meacham - ⑆repetae.net⑆john⑈ - http://notanumber.net/