Hello,
What is the current status of the LLVM backend support?
Best regards

Mailing lists / fpc-pascal / 2016-08
22 messages · 9 people · –
Reply by email Subscribe to this list Your subscription
Read-only archive. Use j and k to move between messages.
Hello,
What is the current status of the LLVM backend support?
Best regards
African Wild Dog wroteWhat is the current status of the LLVM backend support?
"make cycle" works on my machine for Darwin/x86-64, and most test suite failures (apart from exception handling tests if the optimisation level is increased, see point 2 below) are related to LLVM limitations rather than to bugs in the FPC code generator to LLVM. I have not yet committed everything, because some changes still need to be implemented in a cleaner way.
The main missing features before the result is usable for real world code are
1) support for inline assembler blocks in Pascal routines (they are currently silently discarded). On the other hand, pure assembler routines are already handled correctly (routines with only an "asm ... end" block and no "begin ... end")
2) LLVM has support for explicit setjmp/longjmp (which we use on most platforms for exception handling), but I still have to mark all accesses to local variables in exception blocks as "volatile" because otherwise they are not guaranteed to keep their value (similar to how we disable register variables in code that may trigger an exception). A future, better, way may be to use LLVM's built-in primitives for exception handling.
3) possibly support for debug information generation
There are also a few LLVM limitations over which I have no influence: a) LLVM has no support for arbitrary instructions throwing exceptions. I.e., segmentation faults, alignment exceptions, bus errors, floating point exceptions etc are not supported in any way by LLVM. If it can prove at compile time that a non-floating point exception will happen (e.g., you store nil in a pointer and immediately dereference it), it will simply interpret the exception-causing instruction as having "undefined behaviour", which generally results in pretty much all code depending on the result of that instruction getting "optimised" away. In case of floating point exceptions, LLVM will replace the result of the instruction with Inf/Nan at compile time. They are aware of this limitation
(http://llvm.org/devmtg/2015-10/slides/KlecknerMajnemer-ExceptionHandling.pdf ), but there is no one actively working on it right now (https://groups.google.com/forum/#!topic/llvm-dev/7yLycHmeydo ) b) LLVM has no support for the i386 "register" calling convention, so I will probably never add support for the i386 target using LLVM
As alluded to above, LLVM support needs to be added/tested/maintained separately for each supported architecture and to a lesser extent for each supported OS. Right now, I only have plans for x86-64 and AArch64 (and maybe PowerPC64), on Darwin and Linux. Personally, I won't add support for Windows since I don't use that platform. Support for 32 bit platforms in general will be a bit tricky due to the way our compiler is structured.
Jonas
Why is it that 32-bit targets would be a bit tricky to implement?
Regards,
Sven
I believe because of this:
There are also a few LLVM limitations over which I have no influence: <snip>
b) LLVM has no support for the i386 "register" calling convention, so I will probably never add support for the i386 target using LLVM
Why is it that 32-bit targets would be a bit tricky to implement? Sven
Sven Barth wroteWhy is it that 32-bit targets would be a bit tricky to implement?
It's because our code generators don't have full generic support for 32 bit architectures with 64 bit integer "registers". It's possible to implement support for something like that (the JVM code generator does it), but then you have to take care of it in various code generator units. We have separate defines for cpuXXbitalu and cpuXXbitaddr, but they don't handle everything everywhere in the generic code yet.
Jonas
Jonas Maebe wrote on Fri, 19 Aug 2016:
Another, more important, issue is that the LLVM-based compiler also includes the regular code generator for the targeted architecture (to generate entry and exit code for pure assembler routines). This means you have both a 64 bit ALU and a 32 bit ALU code generator in the same binary, which may need different constant values (e.g. OS_INT should be OS_32 for one and OS_64 for the other -- so that may have change from a global constant into a class field).
Jonas
bit architectures with 64 bit integer "registers". It's possible to implement support for something like that (the JVM code generator does it), but then you have to take care of it in various code generator units. We have separate defines for cpuXXbitalu and cpuXXbitaddr, but they don't handle everything everywhere in the generic code yet.
Another, more important, issue is that the LLVM-based compiler also
includes the regular code generator for the targeted architecture (to generate entry and exit code for pure assembler routines). This means you have both a 64 bit ALU and a 32 bit ALU code generator in the same binary, which may need different constant values (e.g. OS_INT should be OS_32 for one and OS_64 for the other -- so that may have change from a global constant into a class field).
Ah, okay, thanks for clearing up.
Regards,
Sven
I believe because of this: There are also a few LLVM limitations over which I have no…
is
Jonas wrote about the structure of the compiler. "register" support is not about the structure, it's merely an additional calling convention.
Regards,
Sven
Jonas Maebe wrote on Fri, 19 Aug 2016: Another, more important, issue is that the…
In our previous episode, Jonas Maebe said:
Another, more important, issue is that the LLVM-based compiler also includes the regular code generator for the targeted architecture (to generate entry and exit code for pure assembler routines).
FYI, I've been creating some SSE image conversion routines in Delphi/FPC (FPC for avx) the last few days, and I noticed that Delphi allows something like that too for 64-bit. (That being generating entry and exit code for asm code)
It has pseudo directives to push registers on entry, allowing it to create a stack frame (aligned, with SEH record).
There are four functions:
.noframe - omit stackframe (our nostackframe)
.pushnv - save general purpose non-volatile register (pushes) .savenv - save sse2/3 non-volatile (saves to stack) .params <x> - reserves enoughs stackspace to call a procedure with <x> regs params the (<x> time 8, addressable as an byte array using @param[])
marcov wrote on Fri, 19 Aug 2016:
[snip]
That's a bit different. I was talking about the entry and exit code for a pure assembler routine based on e.g. declared local variables and types of the parameters, which was done already even by Turbo Pascal. That has to be done even when using an LLVM code generator, since pure assembler routines are not touched by the LLVM-to-native passes that come after.
The directives you mention are extra features to influence the kind of entry/exit code to generate for assembler routines (which we indeed don't have yet).
Jonas
"make cycle" works on my machine for Darwin/x86-64, and most test suite failures (apart…
2016-08-19 4:55 GMT-03:00 Jonas Maebe :
Thanks for the detailed explanation. I asked about it because apparently it is a good idea to adopt the LLVM as the backend for FPC compiler. This would free the FPC's core developers from the task of maintain the backend portion of the compiler, which is not a trivial task, considering the dozens of architectures and operating systems which is currently supported, and other details such as the code optimizer.
Will the FPC team, somewhere in the future, adopt the LLVM as the backend on all platforms ?
Best regards
it is a good idea to adopt the LLVM as the backend for FPC compiler.
This would free the FPC's core developers from the task of maintain the
backend portion of the compiler, which is not a trivial task, considering the dozens of architectures and operating systems which is currently supported, and other details such as the code optimizer.
Will the FPC team, somewhere in the future, adopt the LLVM as the backend
on all platforms ?
The LLVM backend will never completely take over, not only because LLVM doesn't support all targets that we do (M68k for example), but some portions still need our backend anyway (inline assembly for example) and also Florian *prefers* to work in the backends.
Regards,
Sven
2016-08-19 4:55 GMT-03:00 Jonas Maebe : Thanks for the detailed explanation. I asked…
The code optimizers, yes. The rest, not so much.
Will the FPC team, somewhere in the future, adopt the LLVM as the backend on all platforms ?
No, for various reasons:
* LLVM will almost certainly never support all targets that we support (Gameboy Advance, OS/2, WinCE, ...), or at some point drop support for targets that we still support (as already happened with Mac OS X for PowerPC/PowerPC64).
* the native FPC code generators require very little maintenance once written, as they are quite well insulated via abstractions from the rest of the compiler
* you still need some of the hardest parts of the FPC native code generators anyway for LLVM (entry/exit code handling, parameter manager), to be able to deal with assembler routines and because LLVM does not fully abstract parameter passing
* a hardware architecture seldom changes in backward-compatibility breaking ways once released, while LLVM makes no such promises. They do seem to have finally settled more or less on the binary bitcode format (even there are no guarantees, but maybe I'll add support for that after all)
* LLVM changes a lot, all the time. That means a high chance of introducing regressions. I don't know how likely it would be that FPC-with-LLVM would one day be admissible to be run as part of LLVM's buildbots and automatic regression tests, but if not then it's possible that maintaining the LLVM backend may become more work than the regular code generators and optimizers combined (at least if we want to keep up with the latest LLVM versions, and not stick with a particular version for long times like most out-of-tree "consumers" of LLVM do)
* most OS-specific support is in the run time library, not in the compiler. As a result, LLVM will not save much time there
* our native code generators are much faster than LLVM's (even if you would neglect the overhead of FPC generating bitcode and the LLVM tool chain reading it back in), so especially while developing it may be more interesting to use our code generators
Jonas
I'm not too familiar with LLVM so I'll ask, is it at all likely that an LLVM compiler would produce significantly better/faster optimizations than FPC as it stand currently? What range would be talking about 100% faster? Less? More?
Anthony Walter wroteI'm not too familiar with LLVM so I'll ask, is it at all likely that an LLVM compiler would produce significantly better/faster optimizations than FPC as it stand currently? What range would be talking about 100% faster? Less? More?
It depends on the kind of code. The more pure maths (floating point or integer, especially in tight loops), the more likely it will be faster. Artificial benchmarks will also be much faster.
For a typical database program, I don't expect much change.
I can't give any figures.
Jonas
The code optimizers, yes. The rest, not so much. No, for various reasons: * LLVM will…
Em quarta-feira, 31 de agosto de 2016, Jonas Maebe <
Again,thanks for the detailed explanation. As this is a recurrent topic,maybe it would be a good ideia to create a wiki page with all these points.
And about GCC? It supports a wide variety of processors and OS.
Regards
I'm not too familiar with LLVM so I'll ask, is it at all likely that an LLVM compiler…
Hi,
Anthony Walter wroteI'm not too familiar with LLVM so I'll ask, is it at all likely that an LLVM compiler would produce significantly better/faster optimizations than FPC as it stand currently? What range would be talking about 100% faster? Less? More?
We just had a C vs. Rust vs. FPC showdown with a
wrote a small tight loop example with float maths, we ported it to three languages, and we looked at the results.
C (clang/llvm) came first, Rust was closely behind, FPC was about 2x as slow as Rust (which is llvm based as well). But it turned out, that if I did some hand optimization by moving unchanging parts of some expressions outside the innermost loop, plus enabled SSE42 for floating pointinstead of x87, the speed matched the Rust implementation (which is again, LLVM based). And no, no inline assembly was involved.
The big tricks in compilers are still Common Subexpression Elimination and Single Static Assignment. Especially the later. Only if we could have a good one of that...
But again, as Jonas said, this was an artificial benchmark of an abusive, badly written tight loop, and with thousands of iterations, we're talking about the ms range for results, on modern CPUs.
Charlie
Em quarta-feira, 31 de agosto de 2016, Jonas Maebe < Again,thanks for the detailed…
Hi,
90% of the same as for the LLVM backend applies. Also, it doesn't support all the systems we do, not in mainline, or in current versions anyway. Granted, these are usually smaller, less significant, or legacy systems, but still...
I know these are the days of going Easy instead of staying Simple, but for a lot of us the fact that FPC doesn't depend on any kind of other monster-framework and backend of a competing product and language is pretty much *the* killer feature...
But anyway, if someone wants to see a GCC-backend in FPC, he is welcomed to work on it. But as a team-policy to migrate to it - no thanks.
Charlie
Em quarta-feira, 31 de agosto de 2016, Jonas Maebe < Again,thanks for the detailed…
African Wild Dog wroteAgain,thanks for the detailed explanation. As this is a recurrent topic,maybe it would be a good ideia to create a wiki page with all these points.
http://wiki.freepascal.org/LLVM
thanks,
Dmitry
Em quarta-feira, 31 de agosto de 2016, Jonas Maebe < Again,thanks for the detailed…
"African Wild Dog" wroteAnd about GCC? It supports a wide variety of processors and OS.
Why would we want to depend on the behemoth that is GCC as a dependency when FPC currently only needs an assembler and a linker and on some systems not even that? That thought can also be applied to LLVM by the way...
Regards,
Sven
Em quarta-feira, 31 de agosto de 2016, Jonas Maebe < Again,thanks for the detailed…
African Wild Dog wroteAnd about GCC? It supports a wide variety of processors and OS.
Apart from what others mentioned, GCC doesn't have a (even semi-)stable interface that can be used by external tools. Someone once started on something like that (https://gcc.gnu.org/wiki/GimpleFrontEnd ), but it isn't finished.
Jonas
90% of the same as for the LLVM backend applies. Also, it doesn't support all the systems…
Karoly Balogh wrote90% of the same as for the LLVM backend applies.
I suppose inline ASM should be no problem with the GNU compile infrastructure. With the typical "embedded" cross compiling, all high language code is compiled to their ASM dialect and converted to binary by AS.
Inline ASM just bypasses the high language to ASM step (i.e. replaces it by a very simple "compiler" that handles labels like "1:" (accesses by a notation like "1f" or "1b") and some % - notation for accessing registers.
Of course th GNU inline assembler syntax is completely different (and very versatile and rather hard to understand in detail -> in/out parameters, "clobbers", memory barriers...) than the ASM inline syntax used in fpc.
-Michael