DragonEgg - Using LLVM as a GCC backend

DragonEgg is a gcc plugin that replaces GCC's optimizers and code generators with those from the LLVM project. It works with gcc-4.5 or newer, can target the x86-32/x86-64 and ARM processor families, and has been successfully used on the Darwin, FreeBSD, KFreeBSD, Linux and OpenBSD platforms. It fully supports Ada, C, C++ and Fortran. It has partial support for Go, Java, Obj-C and Obj-C++.

Goals

Fully support all GCC languages

Current Status

Works best with gcc-4.6.

Fortran works very well. Ada, C and C++ also work well. Ada works poorly with gcc-4.7 and later.

It can compile a reasonable amount of Obj-C, Obj-C++ and Go.

It can compile simple Java programs, but they don't execute properly (this is a consequence of the java front-end not supporting GCC's LTO).

Debug info is poor.

Releases

DragonEgg-3.3 is the most recent DragonEgg release. It requires LLVM-3.3 and gcc 4.5 or newer. The 3.3 release has the following notable changes: Supports gcc-4.8 (requires gcc-4.8.1 or newer). Object files can be written directly using LLVM’s integrated assembler. Produces saner debug info. Bitfields can now contain arbitrary scalar types (useful for Ada).

DragonEgg-3.2 was the sixth DragonEgg release. It requires LLVM-3.2 and gcc-4.5, gcc-4.6 or gcc-4.7 (gcc-4.7 is only partially supported). The 3.2 release has the following notable changes: Able to load LLVM plugins such as Polly. Supports thread-local storage models. Passes knowledge of variable lifetimes to the LLVM optimizers. No longer requires GCC to be built with LTO support.

DragonEgg-3.1 was the fifth DragonEgg release. It requires LLVM-3.1 and gcc-4.5, gcc-4.6 or gcc-4.7 (gcc-4.7 is only partially supported). The 3.1 release has the following notable changes: Partial support for gcc-4.7. Ada support is poor, but other languages work fairly well. Support for ARM processors. Some essential gcc headers that are needed to build DragonEgg for ARM are not installed by gcc. To work around this, copy the missing headers from the gcc source tree. Better optimization for Fortran by exploiting the fact that Fortran scalar arguments have 'restrict' semantics. Better optimization for all languages by passing information about type aliasing and type ranges to the LLVM optimizers. A regression test-suite was added.

DragonEgg-3.0 was the fourth DragonEgg release. It requires LLVM-3.0 and gcc-4.5 or gcc-4.6. The 3.0 release has the following notable changes: GCC version 4.6 is now fully supported. Patching and building GCC is no longer required: the plugin should work with your system GCC (version 4.5 or 4.6; on Debian/Ubuntu systems the gcc-4.5-plugin-dev or gcc-4.6-plugin-dev package is also needed). The -fplugin-arg-dragonegg-enable-gcc-optzns option, which runs GCC's optimizers as well as LLVM's, now works much better. This is the option to use if you want ultimate performance! It is still experimental though: it may cause the plugin to crash. Setting the optimization level to -O4 when using this option will optimize even harder, though this usually doesn't result in any improvement over -O3 . The type and constant conversion logic has been almost entirely rewritten, fixing a multitude of obscure bugs. Known problems with the DragonEgg-3.0 release: The Makefile tries to use svnversion to get the LLVM revision. To fix this, replace this line REVISION:=$(shell svnversion -n $(TOP_DIR)) with REVISION:=3.0

DragonEgg-2.9 was the third DragonEgg release. It requires LLVM-2.9 and gcc-4.5. The 2.9 release has the following notable changes: The plugin is much more stable when compiling Fortran. Inline assembly where an asm output is tied to an input of a different size is now supported in many more cases. Basic support for the __float128 type was added. It is now possible to generate LLVM IR from programs using __float128 but code generation does not work yet. Compiling Java programs no longer systematically crashes the plugin. Common problems with building the DragonEgg-2.9 release: If you had to install the GMP, MPC or MPFR libraries locally in order to build gcc-4.5, then the dragonegg build may fail due to not finding header files from the libraries. You can tell the dragonegg build system where to find them by setting CPPFLAGS before calling make: CPPFLAGS="-I/path/to/header/files -I/another/header/path/" make The build fails if you are using a case insensitive file system, such as the default darwin filesystem HFS+ . To fix this, apply this patch.

DragonEgg-2.8 was the second DragonEgg release. It requires LLVM-2.8 and gcc-4.5. The 2.8 release had the following notable changes: The plugin loads faster due to exporting fewer symbols. Additional vector operations such as addps256 are now supported. Ada global variables with no initial value are no longer zero initialized, resulting in better optimization. The '-fplugin-arg-dragonegg-enable-gcc-optzns' flag now runs all gcc optimizers, rather than just a handful. Fortran programs using common variables now link correctly. GNU OMP constructs no longer crash the compiler. Known problems with the DragonEgg-2.8 release: Functions returning complex numbers are not handled in an ABI conformant way. This means for example that if code compiled with dragonegg calls a function in a system library that returns a complex number then you get a bogus result. The fix in subversion commit 117649 can be applied to the dragonegg-2.8 source to resolve the problem. Calling floor then converting the result to a long integer type can result in link failures due to an undefined reference to __builtin_lfloor . Likewise for ceil and variants like floorf . The fix in subversion commit 118499 can be applied to the dragonegg-2.8 source to resolve the problem. Some OpenMP programs fail to work when compiled without optimization. This has been fixed in the development version of LLVM. Compile at -O1 or better to workaround this. Programs that throw an uncaught exception when there are destructors to be run when unwinding would crash rather than terminating cleanly. The fix in subversion commit 120096 can be applied to the dragonegg-2.8 source to resolve the problem.

DragonEgg-2.7 was the first ever DragonEgg release. It works with LLVM-2.7 and gcc-4.5. Known problems with the DragonEgg-2.7 release: If gcc-4.5 was configured with a target triple of the form x86_64-linux-gnu or i386-linux-gnu then the build fails with "error: llvm-os.h: No such file or directory" . Use the four component style x86_64-unknown-linux-gnu or i386-unknown-linux-gnu instead. Fortran common variables may not be output when they should be, causing link failures. Programs using OpenMP directives crash the plugin. These problems have been fixed in the 2.8 release of DragonEgg.



DragonEgg in action

Here is the result of compiling a simple "hello world" program with gcc-4.5:

$ gcc hello.c -S -O1 -o - .file "hello.c" .section .rodata.str1.1,"aMS",@progbits,1 .LC0: .string "Hello world!" .text .globl main .type main, @function main: subq $8, %rsp movl $.LC0, %edi call puts movl $0, %eax addq $8, %rsp ret .size main, .-main .ident "GCC: (GNU) 4.5.0 20090928 (experimental)" .section .note.GNU-stack,"",@progbits

Adding -fplugin=path/dragonegg.so to the gcc command line causes the program to be optimized and codegened by LLVM instead:

$ gcc hello.c -S -O1 -o - -fplugin=./dragonegg.so .file "hello.c" # Start of file scope inline assembly .ident "GCC: (GNU) 4.5.0 20090928 (experimental) LLVM: 82450:82981" # End of file scope inline assembly .text .align 16 .globl main .type main,@function main: subq $8, %rsp movl $.L.str, %edi call puts xorl %eax, %eax addq $8, %rsp ret .size main, .-main .type .L.str,@object .section .rodata.str1.1,"aMS",@progbits,1 .L.str: .asciz "Hello world!" .size .L.str, 13 .section .note.GNU-stack,"",@progbits

Adding -fplugin-arg-dragonegg-emit-ir or -flto causes LLVM IR to be output (you need to request assembler output, -S, rather than object code output, -c, since otherwise gcc will pass the LLVM IR to the system assembler, which will doubtless fail to assemble it):

$ gcc hello.c -S -O1 -o - -fplugin=./dragonegg.so -fplugin-arg-dragonegg-emit-ir ; ModuleID = 'hello.c' target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" target triple = "x86_64-unknown-linux-gnu" module asm "\09.ident\09\22GCC: (GNU) 4.5.0 20090928 (experimental) LLVM: 82450:82981\22" @.str = private constant [13 x i8] c"Hello world!\00", align 1 ; <[13 x i8]*> [#uses=1] define i32 @main() nounwind { entry: %0 = tail call i32 @puts(i8* getelementptr inbounds ([13 x i8]* @.str, i64 0, i64 0)) nounwind ; <i32> [#uses=0] ret i32 0 } declare i32 @puts(i8* nocapture) nounwind

Get the DragonEgg-3.3 source code:

wget http://llvm.org/releases/3.3/dragonegg-3.3.src.tar.gz

Unpack it:

tar xzf dragonegg-3.3.src.tar.gz

Install version 3.3 of LLVM, for example by downloading and installing the LLVM-3.3 binaries (mysteriously referred to as clang binaries) for your platform.

Make sure you have gcc-4.5, gcc-4.6, gcc-4.7 or gcc-4.8 installed (you do not need to build your own copy); gcc-4.6 works best. On Debian and Ubuntu you need to install the corresponding plugin-dev package (gcc-4.5-plugin-dev, gcc-4.6-plugin-dev, etc).

Doing

GCC=gcc-4.6 make

(if using gcc-4.6; otherwise replace gcc-4.6 with your gcc version) in the dragonegg-3.3.src directory should then build dragonegg.so . If the LLVM binaries are not in your path then you can use

GCC=gcc-4.6 LLVM_CONFIG=directory_where_llvm_installed/bin/llvm-config make

If you only built LLVM and did not install it then you can still build dragonegg by setting LLVM_CONFIG to point to the copy of llvm-config in the build tree.

To use dragonegg.so , compile something with gcc-4.6, or whatever version of gcc you used, adding -fplugin=path_to_dragonegg/dragonegg.so to the command line. See the README file for more details and useful command line options.

Get the source code for the development version of DragonEgg:

svn co http://llvm.org/svn/llvm-project/dragonegg/trunk dragonegg

Get the source code for the development version of LLVM:

svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm

Build LLVM in the usual way.

Install gcc-4.5, gcc-4.6, gcc-4.7 or gcc-4.8 (you do not need to build your own copy). On Debian and Ubuntu you need to install the corresponding plugin-dev package (gcc-4.5-plugin-dev, gcc-4.6-plugin-dev, etc).

Doing

GCC=place_you_installed_gcc/bin/gcc make

in the dragonegg directory should then build dragonegg.so . See the README file for more details.

To use dragonegg.so , compile something with your just-installed version of gcc , adding -fplugin=path_to_dragonegg/dragonegg.so to the command line. See the README file for more details and useful command line options.

It doesn't work!

Sorry about that! Please report bugs and problems to the LLVM developers' mailing list, or using LLVM's bugzilla.

Suggestions for improvement are welcome. Patches are even more welcome!

More information

There was a talk "Reimplementing llvm-gcc as a gcc plugin" about DragonEgg at the 2009 llvm developers meeting . At that time, DragonEgg was known as "the gcc plugin".

[Slides]

[Video] (Computer)