Removing old JIT CodeEmitters for ARM and PPC

While the MCJIT doesn't cover all of the features the old JIT had, it has the huge advantage of actually producing working results on ARM and PPC64. The old JIT for non-x86 has bit-rotted a lot, to the point of crashing even for simple examples.

I'm proposing to remove the JIT code emitters for the ARM and PPC targets now so it's no longer holding back the development of the MC parts for those backends. The JITInfo parts can stay, they may be useful if someone wants to implement lazy compilation on top of MCJIT. It would become dead code though.

The MCJIT for PPC only supports PPC64 currently. However, PPC32 old JIT never worked for non-darwin platforms and seems to be broken even there at the moment.

Any objections? x86 will stay around for a while, it's reasonably well maintained and has many users.

- Ben

Thanks for your information. So, do you think it’s better working with MCJIT instead of JIT specially for ARM platforms? I’m going to work on .bc files of some benchmarks for ARM platform. And, I decided to work with the JIT. Now, you proposed working with MCJIT. Could I get all the benefits of JIT in MCJIT as well?

Regards
Negar

Thanks for your information. So, do you think it's better working with MCJIT instead of JIT specially for ARM platforms? I'm going to work on .bc files of some benchmarks for ARM platform. And, I decided to work with the JIT. Now, you proposed working with MCJIT. Could I get all the benefits of JIT in MCJIT as well?

The big missing feature from the MC JIT is lazy compilation, so it will compile all your code upfront instead of on a per-function basis. You still get all other benefits of the JIT. You can also use the old JIT for x86 and MCJIT on other targets with no big issues.

Did you try to use the old JIT on ARM yet? As far as I know it doesn't work at all, so MCJIT is a strict improvement.

- Ben

Thanks for your information. So, do you think it’s better working with MCJIT instead of JIT specially for ARM platforms? I’m going to work on .bc files of some benchmarks for ARM platform. And, I decided to work with the JIT. Now, you proposed working with MCJIT. Could I get all the benefits of JIT in MCJIT as well?

The big missing feature from the MC JIT is lazy compilation, so it will compile all your code upfront instead of on a per-function basis. You still get all other benefits of the JIT. You can also use the old JIT for x86 and MCJIT on other targets with no big issues.

Did you try to use the old JIT on ARM yet? As far as I know it doesn’t work at all, so MCJIT is a strict improvement.

Well, I just checked the lli command for a small and easy benchmark, and it seems that it works alright. But, I should do some analysis on my benchmark set first, which makes it more sophisticated working on a simulator and with an arm image. Working with JIT is my next step! Anyway, I’ll check both of them within the next two weeks and will tell you how’s everything on the old JIT or the MCJIT.

Regards
Negar

Sounds great to me, please remove the dead jit info code as well though - someone can pull them out of svn if useful in the future.

-Chris

Why is this holding back MCJIT development? If the old JIT with the x86
backend can coexist with MCJIT, why isn't this possible with the other
backends?

I have mixed feelings about this. I understand that you want to get rid
of cruft asap, but removing the old JIT or any significant part of it
seems premature at this point. MCJIT still has to prove itself. I've
really been looking forward to give MCJIT a try since it was first
announced, but if it still isn't a full replacement for the old JIT yet
then *that* is what needs to be worked on first IMHO.

Albert

I'm proposing to remove the JIT code emitters for the ARM and PPC targets now so it's no longer holding back the development of the MC parts for those backends.

Why is this holding back MCJIT development? If the old JIT with the x86
backend can coexist with MCJIT, why isn't this possible with the other
backends?

It's possible to coexist, but increases the maintenance burden. The old JIT basically contains a less maintained copy of the MC code emitter, which has to be updated if there are significant changes to the instruction definitions. New instructions often don't get added to the old JIT emitter, that's why AVX support in the old JIT on x86 is flaky at best. It also keeps people from restructuring parts of the backend, e.g. the ARM backend contains a number of hacks to keep the old JIT machine code emitter working.

I have mixed feelings about this. I understand that you want to get rid
of cruft asap, but removing the old JIT or any significant part of it
seems premature at this point. MCJIT still has to prove itself. I've
really been looking forward to give MCJIT a try since it was first
announced, but if it still isn't a full replacement for the old JIT yet
then *that* is what needs to be worked on first IMHO.

I can understand your concerns and I wouldn't have proposed this change if the old JIT for ARM and PPC actually worked. When running LLVM's regression tests on a ARM or PPC64 host most of the JIT tests simply fail. That's why the regression tests now run MCJIT by default on those platforms (and tests pass), which won't make the situation any better for the old JIT.

It's also important to know that the MCJIT is comparatively small compared to the old JIT in terms of specific code needed for it. Most of the target specific bits are shared with the static compiler now, which is extremely well tested and probably contains less bugs now than the old JIT machine code, which has matured over a long time.

I know that you rely on lazy compilation in your project and the old x86 JIT isn't going away until that is implemented in the MCJIT. However, it requires that someone makes the investment to port it over, not sure what exactly is needed for this.

- Ben

It's possible to coexist, but increases the maintenance burden.

Ok, I understand.

I can understand your concerns and I wouldn't have proposed this change if the old JIT for ARM and PPC actually worked. When running LLVM's regression tests on a ARM or PPC64 host most of the JIT tests simply fail. That's why the regression tests now run MCJIT by default on those platforms (and tests pass), which won't make the situation any better for the old JIT.

Indeed. Well, I've had reports that people got Pure to run on ARM at
some point, not sure how well it worked, though. :wink: I'm just beginning
to dabble with ARM myself as I'd like to port Pure to Android. Well, I
guess that we'll just continue to use older LLVM versions on ARM for the
time being, if I can get it to work at all with the old JIT. Who knows,
Pure is a rather special language which doesn't utilize all cpu
features, maybe the old JIT supports ARM well enough to run Pure code
even though it fails many of the tests.

I know that you rely on lazy compilation in your project and the old x86 JIT isn't going away until that is implemented in the MCJIT. However, it requires that someone makes the investment to port it over, not sure what exactly is needed for this.

Is anyone looking into this already? It seems that lazy compilation (or
any kind of incremental compilation; I don't really care as long as I
can swap out the bodies of single functions and the JIT is fast enough)
is the one critical feature that keeps us from using MCJIT for dynamic
language implementations. So it would be nice if someone who knows the
JIT code inside out could have a look at that. I know I'm asking too
much but I'd really like to give MCJIT a try rather sooner than later.
:wink: I'm afraid that I don't know enough about the lowlevel parts of the
JIT to have a go at it myself, but I could certainly help testing this
if someone else implements it.

Albert

I know the old JIT pretty well but have only used the MCJIT from the client side. Most of my experience is on the x86backend though.

Another critical feature missing from MCJIT is the JITEventListener. This is usually for supporting debuggers and profiling tools.

Ciao.

What makes you say it is missing?

Eli

Sorry for speaking too soon. It is missing from 3.2 which is the version I have been using. If it is already implemented than it is very good news.

Thanks.

Ops. I meant to say 3.1.

There have been quite a few changes in MCJIT since 3.1; if you're
using it, you should really check them out.

Eli

The current 3.2 code branch has events being broadcast from the MCJIT engine when a new object is emitted, but the profiling listeners do not do anything with the events (and I don't expect they will before the 3.2 release becomes official).

I have implemented some code in trunk since the 3.2 branch to traverse the emitted object and pick out named functions in the IntelJITEventsListener. An update that uses debug information to get source file and line numbers for the functions shouldn't be too far behind. Once that is working, it should be a very small task to port it over to the OProfile listener.

It's also worth noting that the MCJIT engine has support for registering JITed code with GDB for source-level debugging on platforms that use the ELF format. I believe this was in place in the 3.1 release. This is currently done inside the MCJIT engine but it definitely should be moved to a JIT event listener. FWIW, the legacy JIT only registered function names and unwind information (and I think even that may be gone now).

-Andy

Thanks Andrew for the update.

Does it support NotifyFunctionEmitted?

Cheers.

No. It adds a new event, 'NotifyObjectEmitted'. The Intel JIT listener that I mentioned then uses the emitted object to find the functions (which are all emitted together).

Because of the way that MCJIT is implemented, it isn't really feasible to reconstruct things like the EmittedFunctionDetails in the NotifyFunctionEmitted event.

-Andy

I see. If I am writing my own listener can I still get back the (llvm::Function, void* Code, size_t Size)?

Ciao.

You would have to jump through some hoops to get back to the llvm::Function object. I don't think it's possible with the current implementation. If you needed to have that, we could add the llvm::Module associated with the emitted object to the interface and you could iterate the llvm::Functions and use MCJIT::getPointerToFunction to make a mapping to the function addresses.

Obviously that's a hack. I'd be open to suggestions to improve the event interface.

Getting the address and size of the functions is simple.

-Andy

It's possible to coexist, but increases the maintenance burden.

Ok, I understand.

I can understand your concerns and I wouldn't have proposed this change if the old JIT for ARM and PPC actually worked. When running LLVM's regression tests on a ARM or PPC64 host most of the JIT tests simply fail. That's why the regression tests now run MCJIT by default on those platforms (and tests pass), which won't make the situation any better for the old JIT.

Indeed. Well, I've had reports that people got Pure to run on ARM at
some point, not sure how well it worked, though. :wink: I'm just beginning
to dabble with ARM myself as I'd like to port Pure to Android. Well, I
guess that we'll just continue to use older LLVM versions on ARM for the
time being, if I can get it to work at all with the old JIT. Who knows,
Pure is a rather special language which doesn't utilize all cpu
features, maybe the old JIT supports ARM well enough to run Pure code
even though it fails many of the tests.

I know that you rely on lazy compilation in your project and the old x86 JIT isn't going away until that is implemented in the MCJIT. However, it requires that someone makes the investment to port it over, not sure what exactly is needed for this.

Is anyone looking into this already? It seems that lazy compilation (or
any kind of incremental compilation; I don't really care as long as I
can swap out the bodies of single functions and the JIT is fast enough)
is the one critical feature that keeps us from using MCJIT for dynamic
language implementations. So it would be nice if someone who knows the
JIT code inside out could have a look at that. I know I'm asking too
much but I'd really like to give MCJIT a try rather sooner than later.
:wink: I'm afraid that I don't know enough about the lowlevel parts of the
JIT to have a go at it myself, but I could certainly help testing this
if someone else implements it.

The MCJIT will require a bit of change to the model clients use. Specifically, everything in the MCJIT is at the Module level of granularity, and that will include lazy compilation. So if you want to compile a function at a time, you'll need to create a separate Module for each function. Relatedly, a module is effectively immutable once it's been passed to the MCJIT. You can't keep adding new definitions to the module afterwards, for example.

The exact details of lazy compilation are a bit vague right now, but generally speaking, it'll work similarly to the old code, just with compilation being a module at a time.

-Jim