Epoch JIT Compilation

Published April 04, 2012
Advertisement
What a hell of a night.


After much tinkering with the Epoch compiler and its internals, I decided to take some time and explore a diversion, just for fun. While the core language is much better off than it was a couple of weeks ago, I've spent so much energy on mundane bug fixes and tiny feature reimplementations that I needed a break.

I'd previously experimented with native code generation via LLVM, but only on a minuscule scale and with the simplest of programs. My project for tonight (yes, I know it's 7AM) was to build out a JIT compilation mode for the Epoch virtual machine, and get at least rudimentary native code execution working.

I'm proud to announce that this project - while taxing and exhausting and far more prolonged than it should have been - is a rousing success.


The code needs a lot of cleanup, and there's some downright hackery going on in a few places, but it works:
JIT Experimentation.png

This is the Release 12 Epoch compiler building a simple test benchmark and executing it in two modes: one in the "pure" VM mode, and one where some of the arithmetic is offloaded to the JIT compiler and runs as native code. As you can clearly see from the screenshot, the JIT version wins by a handy margin - and it's still far from optimal.

There's still a lot of room for improving the VM itself, of course, and the language has a few crufty edge cases that make it slower than it should be even when JIT compiled to native code. With a little bit of magic and trickery, I can probably get that margin substantially wider.


Last but not least, for the curious, here's the source code to the benchmark:

//
// JIT.EPOCH
//
// Just in time compilation test for Epoch
//


timeGetTime : -> integer ms = 0 [external("WinMM.dll", "timeGetTime")]


entrypoint :
{
integer four = 1 + 3
assert(four == 4)

vmbench(2, 3)
jitbench(2, 3)
}


vmbench : integer a, integer b
{
integer begintime = timeGetTime()
integer counter = 0
integer result = 0

while(counter < 100000)
{
result = vmmath(a, b, result)
counter++
}

integer duration = timeGetTime() - begintime
string durationstr = cast(string, duration)
print("VM benchmark lasted: " ; durationstr)
string resultstr = cast(string, result)
print("Result: " ; resultstr)
}


jitbench : integer a, integer b
{
integer begintime = timeGetTime()
integer counter = 0
integer result = 0

while(counter < 100000)
{
result = jitmath(a, b, result)
counter++
}

integer duration = timeGetTime() - begintime
string durationstr = cast(string, duration)
print("JIT benchmark lasted: " ; durationstr)
string resultstr = cast(string, result)
print("Result: " ; resultstr)
}


vmmath : integer a, integer b, integer accumulator -> integer ret = a * b
{
ret = ret + accumulator
}

jitmath : integer a, integer b, integer accumulator -> integer ret = a * b [native]
{
ret = ret + accumulator
}


I would have eliminated some of the code duplication using higher order functions, but indirect function calls would mean another set of JIT wizardry and I'm just too exhausted to care at the moment. That can come later.

If you study the code carefully, you'll notice that there's exactly one difference between the VM and JIT code paths: the [native] tag on the JIT version. This tag indicates to the VM that, when it loads the program, it should JIT compile the function body into native code, and henceforth execute it as such instead of through the VM instruction engine itself.

You may notice that the code is a bit contrived in a few places and could be shorter or more elegant in a few ways. This is mostly due to the fact that the R12 compiler is still a work in heavy progress, and a lot of permutations of syntax don't quite work yet. Thankfully, those are getting fewer and farther between, and it shouldn't be terribly long before the language is back up to par and supports the kind of concision and expressiveness that I've always had in mind.


Assuming, of course, I don't wander back into LLVM land and start fooling around with optimizations again...
0 likes 1 comments

Comments

rip-off
Very nice! I've been meaning to play around with LLVM for a while now.
April 06, 2012 07:45 AM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement