By Jake Edge
April 25, 2012
The LLVM compiler, and its Clang C-family front-end, are getting
increasing
attention as they mature. At last year's Linux Foundation Collaboration
Summit (LFCS), Bryce Lelbach talked about building the
kernel with Clang. This year, Mark Charlebois of the Qualcomm
Innovation Center (QuIC) picked up where Lelbach
left off and, along with his Qualcomm colleague David
Kipping, gave a talk at this year's LFCS about LLVM, what its attractions are,
and where things stand in building the Linux kernel with Clang.
An introduction to LLVM
Kipping started off with a brief introduction to LLVM, which came from an
experiment in compiler construction that Chris Lattner started as part of
his PhD. work in 2000. It
is a framework for building compilers, rather than a compiler itself. The
idea is that components can be assembled into a compiler, and that those
components can be reused by other tools. For example, he said,
debuggers can use the same parser that the compiler does. But one of the basic
premises that underlies LLVM is that no one component is able to serve all
of the possible use-cases, so there is no "one true register allocator", no
single
scheduler, nor a required optimization order in LLVM, he said.
A secondary mission of the LLVM project was to build compilers using the
components. "LLVM" is an overloaded term these days, and many use
it when they really mean "Clang", Kipping said. LLVM is actually an
"umbrella project" with multiple sub-projects.
Clang is the best known of these sub-projects, and is a front-end that
supports C, C++, and Objective-C. Clang is known as a fast-to-run compiler, but
it is getting slower as more features, optimizations in particular, are
added. But it is still a fast compiler, he said. It is designed for
conformance with standards and, at least to some extent, compatibility with
GCC.
Clang is a strict compiler that is known for the quality of its error
messages. It will complain about things that GCC does not, which is part
of what led Google to become a "large supporter of LLVM". Google does
simultaneous builds of its internal code, using GCC for the code generation
and Clang for its static analysis and error/warning messages. By reworking
some of
the code that Clang was complaining about, Google actually found some
"potential problems" in its source code, he said.
Another project under the umbrella is DragonEgg, which is a plug-in that
implements a back-end for GCC. That can either provide more GCC
compatibility for LLVM code generation or allow one to use GCC language
front-ends, like Fortran, that there is no LLVM compiler for. The LLVM
debugger (LLDB) is still probably two years away from being ready for
production but, because of LLVM's component model, it provides some
opportunities for better debugger integration. "Polly" is another area of
work for the project. It implements polyhedral optimization, which is an
"immature technology" that shows promise for improving the amount of
parallelization and vectorization in generated code.
Clang architecture
Clang has a fairly common architecture, with front, middle, and back-ends.
It has a "fairly clean" architecture-independent intermediate
representation called "Bitcode", though it does have some architecture
dependencies, which can cause problems for some back-ends. But, Bitcode
can be separated by "space, time, and architecture", so it can be used for
code generation at a later time or on a different machine or architecture.
That separability means that Clang can not only be used as a static compiler, but also
as JIT compiler. For example, in using Renderscript for Android, developers
can package up the
Bitcode into the .apk file and the actual code generation is
done for the proper target when the app is run for the first time. For
example, scalar code
would be generated for an ARMv7, but vectorized code would be generated for
a Neon core.
LLVM development is "accelerating", Kipping said, with a lot of activity
taking place in the last few years. The Android adoption of LLVM for
Renderscript in its Honeycomb (3.0) and Qualcomm's contribution of VLIW
(very long instruction word) support for LLVM in just the last year or so
are some examples he gave of this acceleration. In addition, LLVM is being
adopted widely for graphics (e.g. Renderscript, LLVMpipe), parallel
programming (e.g. OpenCL), and for things like the Chrome Portable Native
Client (PNaCl).
LLVM is also becoming more important in academia. Kipping noted that
Lattner gave a keynote speech at the 2012 International Symposium on
Code Generation and Optimization, which is one of the most important
technical
conferences for compiler technology. This year's Proceedings has 103
references to LLVM, which is up from 34 the previous year, he said.
The performance of LLVM's generated code is improving as well. Comparing it
to that of GCC,
which
is the "gold standard today", shows that the LLVM tip is within 1-3% of GCC
4.6 performance for ARM, and within about 4% for x86. The tests need to be
re-run
for GCC 4.7, he said.
Qualcomm is interested in LLVM because of the "exceedingly complex" nature of
ARM system-on-chips (SoCs), with multiple processor cores and multiple
graphics pipelines. Code may run on a DSP in one configuration, or on the CPU
or GPU in another. The decision on where to run the code may be made based
on power saving scenarios. Having a common toolchain that generates code
for any of those situations is helpful. In addition, any optimizations
that are done in LLVM will be available for multiple code generators,
he said.
LLVM is "not there yet" to do complete Linux system builds, Kipping said,
which would be a good
way to reduce build complexity while getting the advantages of bug fixes
and optimizations that have been going into LLVM. Linux is a great source of
code that can be used to test and improve LLVM as well. LLVM has a "great
community" that is open for participation in various ways including LLVM.org, developer meetings, and conferences.
With that, he
turned the floor over to Charlebois to talk about LLVM and Linux.
Compiling Linux with Clang
Charlebois began with an explanation of the reasons to build the kernel
using Clang. One reason is to get to the point where Clang can be the
compiler for the whole system, as Kipping described, and the kernel is a
core part of that system. The better diagnostics produced by Clang, which
show the actual code where the problem is, are useful, he said. In
addition, the kernel uses lots of GCC extensions, which Clang helps find.
The "fix-it" hints that are produced by Clang are very helpful as well
because they not only show the problem that produced the warning or error,
but also
often show how to fix the code. Another area where Clang shines is that it
fully expands macros in the diagnostics, which makes it easier to spot
problems with macros. Clang has a "still maturing" static analyzer that
can show code flow paths. Bringing these kinds of diagnostics to the
kernel "will be great", he said.
MINIX has switched to Clang as its default compiler and FreeBSD is working on
building its system using Clang. FreeBSD is also using LLVM and KLEE for automatic test generation. LLVM
is also being used in graphics applications, like Renderscript for Android
and LLVMpipe for Gallium3D. In addition, he noted Sylvestre
Ledru's efforts to build Debian with Clang, which LWN also looked at in March.
Most of Charlebois's work on building Linux with Clang focused on
cross-compiling for ARM. One of the difficulties he encountered was in
finding the right parameters for cross-compilation. The Clang mailing list
is very helpful with suggestions, but it is an unsupported configuration
and getting all of the flags (e.g. the "triplet") just right can be difficult.
Most of the conversations on the mailing list centered on solving this
configuration problem "the right way", which involves a "universal driver"
for Clang. That driver would have access to all of the information on the
location for the compilers and other tools needed, and users would just
point it at a configuration file that specified the target. It's a great
idea, he said, but he hasn't seen much movement on it yet.
Another project that he mentioned is ELLCC
(Embedded LLVM Compiler Collection),
which is a single cross-compiler code base that is based on Clang and
LLVM and targets many different
architectures (ARM,
x86, MIPS, PowerPC, ...). The project has a live web page where you can
submit source code, choose a target, and examine the generated code. He
said he is
"quite impressed" with ELLCC.
Challenges
There are, of course, some challenges building with Clang.
Cross-compilation is not a supported configuration, and it is dependent on
a GNU cross-toolchain for its assembler and linker. There are lots of
warnings produced by Clang which slows down compilation, for example all of
the functions that are called (e.g. memcpy()) where the return
value is ignored. There are also some bugs in Clang and LLVM for ARM, he said,
which he has reported and QuIC has worked on fixing some of them.
The kernel expects to be able to use some GCC behavior that is not
supported by Clang. The scripts/Kbuild.include files are
GCC-specific, for example. Clang does not have a way to check which
options are supported, while GCC does. Clang warns for unused
options, but not unsupported ones. In addition, GCC returns false when it
it gives an error that
there is an unsupported flag, while Clang returns true when it warns about
unused flags. There are also "a bunch" of unsupported GCC flags, he said.
There is a master LLVM
bug for building the kernel with Clang. The blockers are mostly
x86-specific and there are 8-11 of them currently. That bug is a good way
to keep
track of the status, he said.
The problem with variable-length arrays in structures that Lelbach reported
persists. Charlebois
patched the kernel to avoid those constructs. It is a non-standard feature
of C that is a "GCC-ism", he said. It may come from the fact that GCC
supports Ada, so it was probably easy to throw that into C as well.
Explicit register variables are also not supported by Clang, so things like
putting the stack pointer into a named variable do not work. In fact,
Clang sets the value to null, which doesn't make for a very good stack
pointer. Nested functions are also not supported, but they are only
present in the Thinkpad driver; since he has been focusing on ARM, he
hasn't looked into that.
There are thousands of instances where return values are unused in the
kernel, which causes a huge number of warnings when using -Wunused
in Clang. It's not desirable to turn off that warning, he said, so he
patched around the problem in the kernel. The semantics of the
inline keyword for functions is different between GCC's gnu89 and
Clang's C99 behavior. There is a gnu89 compatibility flag for Clang, but
he has not used it because he wanted to get the kernel to build with
Clang's semantics. In addition, EXPORT_SYMBOL() for inline
functions makes
Clang crash, he said.
There are also missing features or bugs in Clang/LLVM for ARM that he has
had to work around. The -mabi-linux flag is not fully supported
for Linux. GCC uses four bytes for all enums, while Clang has
variable-length enums, which creates incorrect structure offsets,
so he doesn't use -mabi-linux in Clang.
64-bit parameter passing requires paired registers in ARM, which is broken
in LLVM. There are also problems accessing the upper 32 bits of 64-bit
atomic types, which use GCC-specific features to do so in Linux. QuIC has
submitted a patch
for the first 64-bit problem and is developing one for the second, he said;
once they are merged, he can uncomment the affected code in the kernel he
is building.
The Clang integrated assembler (IA) is not the default for ARM, because it
is still not finished. Finding the right "triplet" for the kernel vs. the
one for user-space programs is a problem as "arm-none-linux-gnueabi", for
example, works
fine for user space, but not for the kernel. Using just "arm" or "armv7"
works for the kernel, but gives warnings about not having EABI support.
There is also difference in the definition of __kernel_size_t
(which is an unsigned long) and size_t (which is defined
by Clang to be an unsigned int) which required him to patch the
kernel definition to avoid warnings for different argument types for
various library
functions.
Building
A project has been set up at llvm.linuxfoundation.org that
has an automated build framework. It will download the latest LLVM, Clang,
QEMU, and
the kernel,
then patch and build the kernel, and run it in QEMU. It supports the ARM
Versatile Express board and Qualcomm's MSM processor, though there is no
QEMU target for the MSM, so you can only build for that platform. The
Versatile Express boots a 3.3 kernel and runs a toybox user space.
The project site also has Git trees with the patches that he made to the
kernel for some of the problems he mentioned earlier. No patches are
applied to Clang or LLVM, he said. It is easy to add
new architectures to the build framework, and he would love to see people
add things like x86, MIPS, and other targets. There is a set of Python
tools available to help manage any patches required.
There are still lots of things left to do, of course, and Charlebois
wrapped up with his list. First up was to check the status of the problems
that Lelbach had reported a year ago. The status of the ARM IA for Clang is
also something he needs to look into, as are some of the bugs and problems
he mentioned earlier in the talk (inline differences, segment linkage
differences, etc.). He would like to build the Linux Test Project
with Clang onto a virtual SD card filesystem to use with QEMU and do some
regression testing using that. The last item on his list was to set up a
test suite for known LLVM bugs so that fixes for those bugs can be detected
in newer releases.
It is "pretty exciting" that he can build and run Linux using Clang for one
of the ARM architectures, he said. None of the changes that he has made to
the kernel stop it from building with GCC, they "just make the kernel less
dependent on GCC". He has not tried to merge any of his work upstream,
yet, but he hopes that at some point there is interest in making Clang an
officially supported compiler for building the kernel. If that happens, he
is hopeful that his patches will be helpful in that endeavor.
(
Log in to post comments)