OK, so it's green, we're taking on faith for it's working.
All right, I think we're starting.
OK, and I have working mouse, excellent.
And I will stay behind the desk.
OK, so I'm a compiler dev over at AMD.
And I want to float a slightly weird idea,
as a bunch of friendly compiler engineers,
and falls down to quite friendly,
and some of you are probably compiler engineers.
So I hope that's going to work out.
Just for those brief scientists check for me,
just at your hand of the air,
if you've committed something to LOM or GC.
OK, that's really good news.
This is a short block of time.
So I can't start with a nice discussion
of what a compiler front end is.
So we're going to go straight for,
I think the compiler back end
is more specialized to the task that it needs to be.
But we would have a happier time as compiler engineers,
and as users of the compiler,
if we gradually threw away the back end,
by stretching the middle end further and further back,
until it actually hits instruction, the mission.
And that is not a widely popular view.
But it's not completely unfounded.
So the spirit of establishing some form of credibility,
I'm going to try to talk about a couple of very strongly
back end specific things, which I mentioned in the back end,
which I didn't, and it was fine.
There.
It's a little bit GPU-specific, but not horrendously so.
I think complete ignorance of GPU architectures will be fine.
So that, notwithstanding, first example is memory allocation,
specific to GPU.
Oh, over this context.
Excellent.
Yes, please talk to me while I'm speaking,
or after I'm speaking, or using these computer things,
if you must, questions are welcome anywhere in this.
If none of you ask any questions,
there's going to be a lot of time at the end,
so I probably don't have 20 minutes of content for you all.
So it's been called ODS.
This is a small block, our very fast memory,
which it's important to use if you want your GPU code to run quickly.
There's a GPU is structured as a kind of...
Emure was a number of completely independent programs,
which can talk to each other a bit,
backed by slightly jibis terminology.
The best way to describe this is as a register allocation problem.
The premises, one part of your paid,
has a number on it for how many bytes of its magic memory do you want,
and you have to ask for a small number,
it doesn't start.
But you can say, I want 16 kilobytes,
and you have that, and that's fine.
And then other parts of your code,
want to use variables, which are somewhere in the single,
integer's block, and they need to find them.
So the original game here,
is if you want to reference ODS from a different function,
to one which allocates a debt, you can't,
just like tough, doesn't compile.
So you can say,
who has 16 kilobytes,
and a few calls bar,
and bar wants to reference a variable number ODS,
air can't.
That was unpopular, because people write functions,
and if he functions,
cannot be fully in line into the caller,
you get a compile error, and it's sad.
So what I want to do here is take
the block memory allocates in one function,
and scribble out enough metadata that it can be found from other functions.
And the task here amounts to,
x is a double, y is a float.
They both need an address in your single block memory,
about 10 and 16 or whatever you want.
Such that it can be located elsewhere.
And,
for the compile engine, there's some buildings,
but it's really obviously register allocation.
We used to think it registers as you have 16 distinct values,
and we all have our own special name.
But it's clearly a single block of memory of length 16 times which we've registered.
And the goal is assigning offsets in this block of memory to the magic names,
so that you can find stuff in these variables from somewhere else.
And the reason you do register allocation in the back end,
which is you want to do it relatively late.
And the reason we did ODS allocation in the back end,
is because that's where we did register allocation.
So yeah, there's a small common theme here.
There's a thing called global ISO.
I love the underside of the selection-day based back end
was ugly and could be improved,
and adopted a more as safe and alternative IR.
I want to say 10 years ago.
I remember it being announced and being very excited.
And I don't believe we've moved over to it yet.
But if you write code for the NDGP back end,
you end up implementing for SDG and for global ISO,
and the code path is different and it's,
I don't want to write all of test cases twice.
So instead,
there's an IR pass,
which does all the red,
like sort of things you'd expect to see.
It proves for call graph going,
who can reach this variable,
do this variable as ALS,
where shall we allocate these variables?
And the IR pass,
and it's a table investigator as IR.
It's a constant array of integers.
And that's tested in IR.
It has lists of optimizations,
which try to do a better job of laying out memory.
Or to an IR.
And because it's written as a single pass,
the SDG and global ISO parts are tiny.
In fact, it's mostly implemented in the assembler,
which had to be taught what a constant number was for ALDS.
And it was fine.
I got some pushback from colleagues,
because I was writing it in my wrong place.
But it worked.
It's since been modified by people.
People have now mostly stopped tagging me and reviews for it.
So it means that code is coherent enough
for other people to change it without dragging me into a loop, which is great.
And even though it's been done in the wrong place,
it's fine.
It's kind of a simple instance of red sugar allocation.
But if we can do some forms of red sugar allocation in IR,
we can't do other forms of red sugar allocation in IR.
We're like brief side note that some other compilers do
in fact do red sugar allocation on S-saform.
And it's okay.
It works out all right.
Here's your example.
I've got cooler and is very back end.
It's very architecture-specific.
There's lots of scribbling stuff in specific registers.
And carefully managing the stack.
I'm lucky that previous talk had pictures of the stack,
manipulation code around function calls,
because I don't have any code.
And very edit functions are crafty awkward things,
where you have to scribble state into particular parts of the stack
and go forth and find it later.
And people want,
strictly speaking people want to print F on the GPU.
The only very edit function anyone ever cares about is print F.
Yeah, it's cyber.
It seems to be the case.
And in fact, print F is currently implemented in,
I think, four different ways on AMD,
four different languages.
Like, hip and open-open, open-open,
or have their own one.
Oh, and lib C has its own one as well.
And all of that one is a dreadful.
So I was looking at,
implementing their edit functions for lib C mostly.
And the similar theme turned up.
I don't want to do this twice.
Ah, I have fixed that typo under review,
and then failed to update the slides.
Never mind.
And I don't want to write the test code for,
are we lowering their edit calls correctly?
Because I've done that for a simple architecture.
It was dreadful.
It was for a huge comment or a problem.
And you have to do it for a stack and the global ISO.
And it's just very edit functions.
No one cares about much about them.
So really, who's got the patience?
Also, that's kind of common theme.
People don't care about their edit functions.
The standard thing which you get when you're bringing up
a new architecture is to do,
or like, fatal error, unimplemented.
Or maybe if name is print F, do this otherwise fatal error.
And there's nothing that magic about varied functions,
inherently.
You can kill these things off in IR.
What a varied function amongst you is,
take all of the arguments,
and stick them in contingent memory,
and pass a pointer to that contingent memory.
That's all we're doing.
That's all ARCH does.
It's all X86 does.
They have different weird ideas about pointer.
Shout out to WebAssembly for actually just
doing a really obvious simple thing.
A WebAssembly just sticks them all in struct,
and passes a void start of a struct.
That's it.
And that works for everything.
Right?
So AMD GPU and the APTX,
they can totally take all the arguments
and put them in a struct,
and pass a pointer to a struct.
And then you don't have to do a bunch of stuff in back end.
But that would have been even worse,
because this was partly for lib C.
I'd have had to do this for
S-Dite and Global ISO for AMD GPU and for MDPTX,
and I really don't want to write test cases for MDPTX.
So just not having it.
So I do this as an ARCH bus.
This actually works out really pretty,
because all the horrible target specific craft,
which was very scary,
and made people want to do this in the back end.
Both of you actually had to send the ARCH 64 API docs
are crazy in having described
but you have to lower the stuff.
But all the architecture dependent stuff
is kind of hidden behind the fearless destroyer,
which is basically a pointer
that you can walk forwards.
So you can take a very early function
as we're presented in IR,
and you can build a struct,
an alica,
and you can copy the ARCH into it.
And then you can kill the dot dot dots at the end of a function,
and pass a VA list instead.
And now you're a very early function's gone,
although the no longer really knows
if it used to be a very early function,
it thinks you're just passing a pointer to an alica.
And that means stuff like inlining, now works again.
And for AMD and MDPTX,
that's just how it works.
Veredic functions are free.
Instead of this crafty aggravesing thing,
they're just weird syntactic shooter
for passing a struct to a function.
For a web assembly,
I actually have this conference.
I need to find someone in WebAssembly
and get them to review a change
because I implemented a thing for WebAssembly
and couldn't get them sign off on it.
So Veredic should be free on WebAssembly too.
And we'll be, once I find one of them.
Strictly speaking, I haven't bothered to do this.
I've implemented this website to six and eight out of six to four.
And when I went to check,
May and it turns out I haven't pushed it.
So they will be free on those scenes,
but currently they're not.
Yeah.
So I like testing code in IR,
because you write for code you've got
and you write for your code you expect.
And then you argue with file checks,
red-exengine for a while.
And then you're done.
And relative to testing in MIR.
It's great.
Relative to testing clan.
It's great.
You have an IR pass.
You can print bits of IR,
or the objects you've got.
You can dump.
That is so easy.
And the backend does not always like that.
So this is sort of a question I want to post to you guys.
The compiler backend is very specialized to machine code.
So specialized to specific targets machine code.
You drop out of a safe form,
as soon as you do register allocation.
So that actually necessary.
We've got here in a sensible half dependent kind of fashion.
But I live from does red-alip on a safe form.
And it's fine.
You had an infinite set of SSA variables.
And you marked some of them as this one needs to be in Rax.
So this one.
And you're fine.
It's the same as red-alip always is.
I sell.
My favorite is not GPA.
My favorite is the crackpot ASIC, which is no longer with us.
But that featured a kind of MIPS style instruction set,
which is very friendly to work with.
And we just did, I just did an intrinsic for every instruction.
Every instruction you could write an assembly had an intrinsic,
with a name very like the assembly instruction.
So if you didn't want to do instruction selection in the compiler,
and you didn't want to write assembly,
you could just write the sequence of intrinsic.
You wanted.
And you got out exactly about sequence of assembly,
position intrinsic turned into one assembly instruction.
And scheduling's even easier.
We can reorder instructions in SSA for almost not problem.
And this DAQ and BIND thing.
I really like S DAQ and BIND.
That's very pretty.
You write your little transform and see this passing turn into a simple thing.
It's lovely.
But it's combined as the same thing, with a better DSL.
And MIR rewrite passes looks an awful lot like an IR rewrite pass.
It's the same premise, right? Just with more awkward notation.
So yeah.
I kind of it we shouldn't do this.
I'm running our sign and no one's asking any questions.
Which is dreadful.
So I'm going to try to prompt you to ask something here,
because I've just told you wildly contentious things, right?
We've got a compiler back end, it has its own special structures.
I'm saying we didn't have to do that.
No one wants to call me on that.
Wonderful, we have to take.
You're the one.
Go, you're first.
Well, I think you're working your business here.
I have to like this.
I have to refer to this idea of being an estimator.
So you work on a formula that I've always scaled up.
I'm trying to realize that I'm a bit in the end.
But on the end, do you mean you're, what the heck it does?
And in terms of the director, so we're dealing with a lot of things.
So that is tomorrow's talk.
The question here is paraphrasing slightly.
Isn't the AMD GB, isn't the AMD back end?
Crazy complicated.
Which is yes.
It would be an awful lot simpler if we kept it in IR.
But the AMD GB back end, slowly, solely under my prodding,
trying to move stuff out of the back end into IR,
because the back end confuses the hell out of me.
And every time I touch it it breaks in really weird ways.
So I don't think we should throw the back end away in really right fashion.
Though I need to find some MLIR people to see if they're a bit more game for that.
I think we should just bear in mind that when you're writing something in the back end,
wouldn't to be easier in IR.
There's madly slow optimization you're writing in MIR.
Wouldn't to be much nicer to write it in IR instead.
How much structured do you need to add to the IR,
so you can write the optimization in IR instead,
as still get the code out.
And if we can slowly drift things like, I don't say,
all the type mungent nonsense around lowering,
but you've got an I-66, because I love the info that was a good idea,
and your target doesn't know what that is.
So you do the type legalising and all the re-rising.
Totally divasin IR.
And that's for this huge block of really complicated stuff in IR stack,
which we could just gently migrate up into IR,
and factor out of IR and out of global IRs,
and release in two places when you add it in one place,
and you test them more easily,
and you just have two slightly simpler back ends.
And everything is better, except for compile time.
But it's, but it's, it's something that everything is better.
I'm not sure I've got any more slides.
Oh yeah, we should do more of this.
And we've had one question.
Did you have another one?
Oh yes, one person speaks, two more speak.
Yeah.
So I understand, I, once I'm communicating about where you draw the line,
meet with middle end and back end, because in my act,
well, I'm not very much involved with either 360 or LLVM.
I, but my knife interpretation is something like the middle end
is something architecture independent stuff,
and the back end is where the architecture independent stuff happens.
Excellent.
It is one way of cutting it.
But I get the impression you use a different way of cutting it
with a sign.
So you would say, middle end is where you are in IR,
which is a mostly machine independent representation.
And then we have MIR with, if I gather correctly,
means something like machine dependent IR in LLVM.
And you are mostly talking about doing stuff
on IR instead of MIR.
But the stuff may still be targeted dependent,
because you introduce more target specific.
The target specific in 26 into IR.
So if I get the point of your talk correctly,
you don't say do everything platform independent,
because there are really things that are platform dependent.
But you are more questioning.
I think this is a very good question,
and we should consider it.
Do we need some different kinds of IR for the back end
and for the middle end?
And I think you just show that most likely
we don't need to kinds of IR.
Excellent.
The main point.
OK, I must try to repeat that.
So the first of it is where you draw the line
between the middle end and the back end.
It's different between different people.
And the general premise of this talk is roughly
that we're drawing it in the wrong place.
One belief is that I love the IR.
It's target independent.
I think the target independent work in the middle end
on IR.
I love the IR.
It's not target independent.
Also, that was a nice idea which we lost 20 years ago.
They're in tracks really badly.
We're like, see.
So you can't have that.
Currently, we try to keep the very back end specific stuff.
Way down in MIR.
But by the time it was work out,
we increasingly drift information back up towards the middle end.
Because if you don't spend things like that,
there are vectorizer optimization in middle end.
You don't want to write about for every target.
I know what registers you've got.
What's not going to work.
So I think we have some slightly historic ideas
about where we should do work in the compiler.
And it should be recognised as such.
There's not so much of a right place to do the transform.
It's where do we currently do similar transforms?
And there's some inertia to moving stuff.
But you can absolutely write the entirety of X86 as a safe form.
And you can do the same with MDGPA.
And you should not do it with SIMT.
You should do it with vector types.
I'm a fat gentleman.
But if you can describe machine code,
literally verbatim in a safe form.
And we do most of our optimizations in a safe form.
Why are we accidentally, well,
are we sure that it's important to change
to this much more awkward representation
to shuffle stuff around for a bit?
Because it feels like our testing would be best
if we didn't.
Ah, I've run out of time.
Thank you.
Your question was wonderful.
It was a summary of the entire talk.
Thank you.