Okay, and here we have, we have one last talk for the day, I hope we will be back next
year, or in other venues of course, okay up next and that's not what you would consider
a standard new tools package, but it has new in it and it's compiler tools related to
new lighting, so there we go, you will tell us some details about that, Paul Kirkke, about
new lighting, cross-platform, just in-time compilation, and the bucket, yeah, hello, I hope everybody
can hear me right, my name is Paul Kirkke, I'm going to talk about a small library I've
been using for the last 10 years already, it's called new lighting, if you close the official
website of new lighting, or if you go to the Wikipedia page, you will read this sentence,
new lighting is a library that generates assembly language at one time, it's, I kind of disagree
with that, I would say it doesn't generate assembly language, it does generate machine code
at one time, and what is it exactly, well if you consider, if you imagine a jet engine,
lighting would be only the code generation part, it does provide you with what you could imagine
as a virtual CPU with virtual registers, virtual obcodes, I think the thing that is most
interesting about new lighting is it's cross-platform and by cross-platform, I mean, if there's
somebody that has another guy in the room, it's the only person that can say, it's not learning
on my CPU, but that everybody else should be covered, right, and it does work, you know, on all
the common ones, I'm sorry to beat 64 beats, little and young, big and young, it's LGPL versions
really is written in C, it has more dependencies, I think the only saying you could consider
a dependency and that's, I mean, you can even work around that is all the memory mapping,
functions, and map, and protects, stuff like that. It was painted in 2000, so it's 25 years old,
by Paolo Bonzimu, and it's been developed and used for new small talk,
C-lisp, in 2008, it moved to Gipz, and the maintainer is Paolo Caesar, Pereira, the Andrade,
and it's at 2.2.3 right now, and personally, I'm not the also, I just contributed a few
optimizations, and I wrote the effect for back end. A little bit about my involvement in that project,
while I'm working on my own Gipz engine, that uses lightning, it's a Gipz engine for PlayStation
1 emulator, and if you're interested in that, you should go see my talk about it tomorrow.
So, why would you use lightning? Well, people could tell me, we own the GCC Devon. People
would tell me, yeah, why don't you just use lip GCC GIT? They're actually different tools for different purposes.
LLVM, GCC GIT, they were designed mostly for languages, so they, they manipulate concepts
that when you want to do binary translation, or say like that, you just don't have, you don't have
the concept of variable, for instance, or the concept of functional blocks. So, they're very
long-watch focused, and as such, they also have very long-watch focused optimizations.
They were also designed mostly for a head-of-time compiling, which means they have very,
very powerful optimizations, and they generally generate very, very fast code,
but they do it slowly, and in my case, in my emulator, I need to recompile 10,000 piece of code
per second, and then if I use LLVM, or GCC GIT, it just takes minutes when I only have 16
nelesicles. And lightning helps here, because lightning is very good at generating bad codes,
but it does, it very, very fast. A little bit about the API, so it gives you a minimum of six
general purpose registers, and six floating pond registers. The way you use them is basically,
it's not macros, so you have from GIT or zero to GIT or two plus, if you have more,
than three colors of color saved registers. GIT or V2 plus, if colleagues saved registers,
and six floating points, GIT and zero to GCC F5 plus. You have a simple register,
locator using the functions GIT, GIT and GIT reg. But the thing is, this register locator is
just going to return one of the three registers that is listed above. If you are not going,
if you don't need to dynamically allocate a register, you don't need that, and you can also
implement your own register locator, just manipulating the register that you already have.
In the API, so you have V2 locators, they are basically macros that allow you to generate
a specific instruction, and you have these V2 locators for all kinds of things, binary operations,
or arithmetic, etc. Each instruction is basically the name of the occult rule or sub,
most time there is a register or immediate flag, which allows you to specify the type of the last
parameter, if it's a register or if it's an immediate value, and if applicable, the type of
suffix. So, for instance, you have the format on the top, so the format of macros you would call
the GIT underscore, the name of the occult or i, then the type and the parameters, and according to,
that's just one small sample of all the occults that you have, but a little bit about branching
to create a forward branch, you would add branching occult in this code, this is the
be a twice or branch, if equal, so if the register or zero is equal equals to zero,
that is going to branch, and then a bit further in your program, you can just patch the node,
so you just say, yeah, I want this previous branch to jump to these address. For backwards,
branch is a bit similar, but different, you just declare a label first, and then in your branch
occult, you're going to get the address of the branch occult, and using GIT patch,
as you can patch the branch back to the label. To generate the function polar function
epilogue, you have GIT polar GIT epilogue, it's not that average is obvious, and for
regeneration, you just call the GIT, and it function, it returns point out to the function that
you just created. Finally, for seeing, there is assembly of the code that you created,
you can just call GIT disassemble. So on top, you have an example, for instance, of
a macro that I call with three parameters, it's just a dumb A plus B equals C, or sorry,
C, well, you understand, I hope, and this is what, you know, it generates on four different
architectures, on x86, 64 bits going to use the LEA instruction, on x64 is going to use the
LEA instruction, on power pc is going to use the add instructions on fh4, so the hsh4
has 16 bits instructions, and then it doesn't support three parameters to the instruction, so
it's first going to move one register to the result, in this case, I think it's moving R2 to R0,
and then just add R1 to R0. And basically, every old code that are supported by a new Lightning
can add a result in one instruction, if the architecture supports it in one instruction,
otherwise it's going to, you know, find a way to generate the code that that
reproduces the behavior. The wise mind once said, one's unfortunately the one can be told
what new Lightning is, you have to see it for yourself, so I'm going to show you a small demo.
To understand the demo, you have to energy in yourself, you have to imagine
a scripting on which I am going to call my blog. My blog works with memory array of 32k
cells. Each cell is assigned 32 bit value, and you have eight seven different
odd codes. The shovels allow you to switch the current cell, the plus minus allows you to
increment the value of the cell, and the bracket allows you to repeat the content of the cell
until the value of the current cell, sorry, repeat the code between the brackets, until the value
of the current cell is zero. Finally, the dot allows you to print a character in the current cell.
So let's see if I can switch. Yeah, so I'm just going to show you how we can write a
jit engine for that right now in five minutes. That's okay. So it's called mb.c.
Yeah, so that's my function. All the code of my jit engine is 92 lines.
So here we have my cells all right. My cells all right. We first initialize lightning
calling energy. We pass the pass to the binary just because jit has a lightning has a
built in this assembler. So it helps it disassemble. Then we're going to create a new
compilation state with jit new state. We want to create a function so we're going to call the jit
product for creating the product of the function. Then we're going to use two registers. The first
one will be jit v1, which is our cell pointer. We'll just pass it the cell pointer. The second one is
the value of the current cell. And what we're going to do is in the four loop for each character
that we read on the input, stand out input. We're going to see if it's a plus, then we just
generate an incrementation of the current value. If it's minus, then we just generate a
decolonation of the current value. If it's a shovel, then we store the current value to the current
pointer. We increment the cell pointer, and we just load the new value of the current cell.
And similarly, if it's a shiver on facing left, then we store the old value. We
decrement the pointer, then load the new value. If we have an opening bracket, then we're going to
check the value of the cell counter. If it's zero, that means we don't have to enter the loop,
then we can just exit. And I'm going to talk about it later. Otherwise, we have a label, which will
allow the closing bracket to jump back to that point. And in the closing bracket, we just check
if the current value of the current cell is zero, then we want to launch back to the
beginning. So we have the gpatch at, which we launch back to the label. Otherwise, we want this
label to this bounce function to jump here after the loop, so we just patch it there.
Finally, if we find a dot, we're just going to call gppatch test the lightning that we're
going to call a function. Pouching arguments as a char, sign char, which is the current value of
the current cell. And we call the put char function. And that's it. We just emit the function.
We're going to print the design. Call the function, so we get the output and clean up.
So I have my program here that everybody can obviously tell what it does.
And I have my BC. I have my program compiled for the exact same code that I showed. I didn't
modify it. Compile for x86, MIPS and SH4, so I can read it for x86. That's the program output.
All the details on the code. Then mbc, MIPS, you have the xx4, the compile form MIPS,
I pass the same program, then you see all the MIPS code. And the same one for SH4.
And then you go.
Yes, the question is, why use a jit compiler in an emulator? It's much faster. Like 10 times faster or
more. If you just consider the CPU in relation part, there's no comparison. It's the latest faster.
We're going to use a function. How do you handle the exact exception for example?
You can help with the exact exception in your emulator because you can compile everything.
Each of you, you don't know, like you get control, but only when you use the basic code.
So you have an exception in the middle of the basic code.
Yeah. How do you handle that?
So the question is, how do I handle exceptions in the middle of generating a block?
Is that right?
Well, when you write that code is important, then you'll execute it, and you'll skip the whole
piece of code that's on. So you have to see the talk tomorrow.
Okay. Because I'm talking about code generator, the question, I'm going to answer it tomorrow
in the talk is about more like a jit engine. That's like a jit engine scene.
TLDR, all the blocks are connected between each other, the jump to each other.
Actually, no, they don't. In my diner like they don't.
They jump back to a specific function that I call dispatcher, and the dispatcher is going to
check the stages of exceptions and the stages of the cycle selects.
And exit if the time is up or if there is an exception.
So if I have like a block of compiled code and I get an exception in the middle, I'm going to
handle it or report the exception only at the end. That works good enough.
Yes.
So I don't know if the question is talk today or tomorrow.
So basically, jit confires, they do average some transit part.
I'll just try to trace the execution and try to compile more walks at the same time.
He compares his approach for instance to a lot of QM was doing.
And why would you opt for this enough work?
This is the time.
So the question is how do I compare what Lightning is doing to what and being is doing?
Well, QM uses them all for instance.
Yeah.
Why don't you explain the use of them on this time of writing all of this?
That's a good question.
I was funny how to do it from scratch, I guess.
Yeah.
And so QM using mode.
I don't know if you can just plug it into a PlayStation emulator that easily.
It's especially using mode.
It's mostly, yeah, okay.
I mean, you're missing the point.
The point there, what it was turned right, you know.
Oh, depth?
Libertary, that's compilation.
I'm talking about Libertjit.
Pipi also?
Yep.
The bi from Pipi.
One day, told me that you was doing exactly what you said.
Yep.
But you generate the very clear code.
Because it was passed.
And then the compiler is small enough.
Yep.
And the compiler just they deliver first.
Right in the pool, but anyway, so I have to...
Yeah.
So I was thinking, do you know if this is something different approach?
We've been in a relationship by Pi and is this library?
So we have to, we have to go for it.
We have to go.
We can talk after if you want.
Yeah.