The current status of Low Level Virtual Machine (LLVM) is in progress.
FPC with an LLVM code generator backend can be built from the https://svn.freepascal.org/svn/fpc/branches/debug_eh/ branch. It currently supports the following targets:
You can use a version included in an LLVM release available from the official LLVM site, or use a version that comes with Xcode (macOS) or your Linux distribution.
Note: while FPC can generate LLVM code that can be compiled with LLVM 3.4 till 8.0, older versions of LLVM may contain bugs that break your program. It is recommended to use at least LLVM/Clang 7.0 or Xcode 9.3.
Build FPC with LLVM support
First build the compiler with LLVM support (using FPC 3.0.4 as a starting compiler)
- go into the compiler subdirectory
- build the compiler using the LLVM code generator backend with
- move the resulting compiler binary (ppcx64 on x86-64) to a safe location (e.g. $HOME/bin/ppcxllvm)
- go back to the top level FPC directory
- now uild FPC as usual, but add FPC=/<path>/<to>/ppcxllvm LLVM=1 to the make command line, and
- Specify the LLVM/Clang version you are using by adding the appropriate -CLv command line parameter to OPT. E.g. OPT="-CLv7.0" (Clang 7.0) or OPT="-CLvXcode-9.3 (the Clang that ships with Xcode 9.3). The latest supported versions currently are Clang 8.0 and Xcode 10.1, but it is quite possible that the generated code will be compatible with later versions. If it compiles, it should work fine.
- If you use a custom installed LLVM version, specify the path to its Clang binary using the BINUTILSPREFIX= make option. The compiler will also use this path to find the LTO library if needed (see later).
- In this case, also add the path to the custom clang binary to your .fpc.cfg file (so it will be found when you compile code with the compiler after the "make" command has finished), e.g. like this:
#ifdef CPULLVM -FD/Users/Me/clang+llvm-8.0.0-x86_64-apple-darwin/bin #endif
- On Linux, also add the path to libgcc_s to the compilation options. E.g. on Ubuntu 16.04: OPT="-Fl/usr/lib/gcc/x86_64-linux-gnu/5 -CLvX.Y". Also add this '-Fl' parameter to your .fpc.cfg, similar to the above.
Using Link-Time Optimisation (LTO)
Link-time optimisation means that potentially the entire program and all units that it uses are all optimised together.
To compile units with LTO support, or to compile a program or library with LTO, you have to add -CLflto on the compiler command line. If you add this to OPT when building FPC, all standard units and the compiler itself will also be built with LTO.
- If you compile a unit with LTO, it will also be compiled normally. This means you can use it both for LTO and for normal (static or smart) linking afterwards.
- The linker (ld) included with least Xcode 9 until and including 10.1 contain various bugs that cause errors when the system unit is included in the LTO. You can work around this by also specifying the -CLfltonosystem command line option.
- On Linux, unless you are using your distribution's default LLVM version, you will also have to build the LLVMgold.so linker plugin and place it in the "lib" directory of your custom LLVM installation (it is not shipped as part of the official LLVM installers, because it needs to be built for the binutils you have on your system). See http://llvm.org/docs/GoldPlugin.html for more information.
- Only a few platforms are supported right now, but more can be added. Windows will be harder (and not something I plan on working any time soon), because I have not yet added support for generating LLVM-based exception handling code that is needed for SEH-based exception handling. Other 64 bit platforms should be "reasonably" easy (the parameter handling needs to be generalised more though).
- LLVM has no support for the i386 "register" calling convention, so support for the i386 target using LLVM will probably always miss this feature (unless someone adds it to LLVM).
- add support for generating debug info
- add support for generating more meta-information for optimizations (e.g. range information about subrange types and enums)
- pass on more FPC-related code generation options to LLVM (currently, mainly -CfXXX and -Ox get passed on)
- add support for TLS-based threadvars
- directly generate bitcode (.bc) instead of bitcode assembly (.ll) files. The reason is that the LLVM project attempts to ensure backward compatibility for bitcode files, but not bitcode assembly. The reason FPC currently generates bitcode assembly files anyway, is that they're much easier to create and debug (in the sense of debugging the compiler's LLVM code generator).
Frequently Asked Questions
- 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, using 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
- Is it at all likely that an LLVM compiler would produce significantly better/faster optimizations than FPC as it stand currently?
- 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, don't expect much change.
- Example 1: the compiler itself on x86-64 is about 10% faster when compiled with LLVM on an Intel Haswell processor, or 18% if you also enable link-time optimization.
- Example 2: A Viprinet benchmark compiled for ARMv7, running on an APM Mustang X-Gene board: 18% faster.