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.
Comments (30 posted)
By Jonathan Corbet
April 21, 2012
Concurrency tends to make programming hard. Kernel development obviously
involves dealing with a lot of concurrency, but there is also a lot of
multi-threaded user-space development that suffers from the same issues.
It would be nice if the computer could help developers avoid race
conditions and other problems that arise in concurrent environments. Some
developers at Google have been working on just such a project for some
time, but they have just relocated the project from GCC to the LLVM Clang
compiler, saying that GCC is not suited to the work they want to do. The
result has been a sort of wake-up call for GCC developers. Is the GCC
compiler suite not well suited to the creation of static analysis tools?
Like kernel programming, multi-threaded user-space programming involves
creating and using locks to prevent concurrent access to shared data. In a
properly designed and implemented locking scheme, code will never see
inconsistent views of shared data, and that data will not change when the
code is not expecting changes. Getting to that point is hard, though, and the
bugs that result from locking mistakes can be hard to reproduce and hard to
diagnose. There are few things more frustrating than a highly intermittent
bug that seemingly makes no sense and defies efforts to track it down.
In 2008, Google developer Le-Chun Wu announced a
project to add support for "thread safety annotations" in C and C++
programs to the
GCC compiler. Since then, work has progressed to the point that the
developers have a useful system that is employed by a number of internal
projects. The ideas are relatively
straightforward. Shared data requiring a lock is annotated with something
like:
Mutex data_mutex;
struct shared_data Data GUARDED_BY(data_mutex);
Functions that manipulate locks are annotated with:
class some_class {
Mutex mutex;
void get_lock() EXCLUSIVE_LOCK_FUNCTION(mutex) { ... }
void put_lock() UNLOCK_FUNCTION(mutex) { ... }
/* ... */
};
There are also annotations for shared locks and "trylock" functions that
may not succeed. If a function expects a given lock to be held when it is
called, it can be annotated with EXCLUSIVE_LOCKS_REQUIRED(); there
is also a LOCKS_EXCLUDED() annotation for functions that will
acquire non-nesting locks themselves. Finally, this construction can be
used for lock ordering constraints:
class some_class {
Mutex m1;
Mutex m2 ACQUIRED_AFTER(m1);
/* ... */
};
Some other annotations exist; they can be seen in this slide
deck [PDF], which is where your editor stole the above examples from.
The GCC implementation sets itself up as an early optimization pass. It
builds a representation of the code from the GIMPLE internal
representation, tracking which locks are held at each point through the
function. When problems or inconsistencies are found, the compiler raises the
alarm, hopefully causing the problem to be fixed before it gets into
production code and bites somebody.
This code is available in a branch in the GCC repository and appears to be
useful, so it came as a bit of a surprise when, on April 19,
Google developer Diego Novillo announced
that the project had been terminated, and that the group was now working to
implement the same functionality in the LLVM Clang compiler instead. When
asked why the group was making this change, developer Delesley Hutchins responded:
The gcc version has been difficult to support and maintain, due
mainly to the fact that the GIMPLE intermediate language was never
designed for static analysis. The abstract syntax tree provided by
Clang is an easier data structure to work with for front-end
analyses of this kind.
The response added that the GCC implementation has "some
issues" that would make it hard to merge into the GCC mainline,
while the Clang implementation has been in the trunk all along.
The GCC developers, naturally, would like to understand what it is about
their compiler that made this project hard. The Google team was hesitant
to respond, seemingly unwilling to criticize GCC or to cause a compiler
flame war. Eventually, though, Delesley posted a more detailed description of the kinds of
difficulties they had run into. There is a lot of information there, but
it seems to come down to two crucial points:
- The GIMPLE representation loses information about the structure
of the original program that the static analysis pass really
needs to
have. LLVM, instead, builds an abstract syntax tree that much more
closely matches the original C/C++ syntax; additional structures are
then based on that tree. LLVM's tree is evidently well suited to the
task of static analysis.
- The GIMPLE representation changes significantly from one compiler
release to the next, causing a lot of things to break. That adds a
maintenance cost that the Google developers are unwilling to pay -
especially if basing on LLVM instead makes that cost go away.
There were other things that were better for their purposes in GCC, but, in
the balance, the developers concluded that LLVM is the better platform for
their work. They seem determined to make the shift and feel that attempts
to fix the problems they encountered in GCC would create difficulties
elsewhere in the compiler. So this move appears to be a done deal.
In one sense, this decision lacks serious implications for the free
software community. LLVM, too, is free software and the static analysis
code will be part of it. That said, it is worrisome if GCC's internal
structure truly turns out to be poorly suited to static analysis tasks.
There is a lot of interesting work being done in the static analysis area;
it offers the prospect of finding large numbers of bugs early in the
development process. Static analysis tools will almost certainly be an
increasingly important part of many developers' tool boxes. If those tools
cannot easily be implemented with GCC, that compiler's future may not be as
bright as it otherwise should be.
That said, it is dangerous to extrapolate from one project to the whole
field of static analysis tools. The GCC plugin mechanism is just beginning
to mature; it really has not had the time to turn into a platform that
complex tools can be built on top of. So, while this episode is a warning
that the GCC developers should hear (and evidently have heard quite well),
it should not be seen as evidence of fatal design flaws. Likely as not, it
is just an indication of a problem in need of solution - something the GCC
community is good at.
Comments (76 posted)
By Jonathan Corbet
April 25, 2012
Once upon a time, Unix was the up-and-coming operating system that was the
future of computing. But something happened on the way to world
domination, and, while Unix was certainly a commercial success for many
years, it has mostly been supplanted by other things - including Linux. It
has often been said that Linux cannot suffer the same fate that brought
down Unix, but it is worth thinking about whether that is really true.
Unix had been growing in popularity for many years before its commercial
explosion, but the key to its
commercial success was a new wave of low-cost workstations that quickly
pushed aside centralized minicomputers. These
workstations ran an operating system that was, in many cases, nearly
identical to the one found on the larger systems, but they were smaller and
cheaper, to the point that they could be deployed on the desktops of
individual employees. Several vendors jumped into that market and the
related market for storage and compute servers.
The problem is that each of those vendors had its own variety of Unix. All
of the Unix variants may have had some sort of common heritage, but, by the time
they showed up on deployed systems, they were quite different.
Heterogeneous networks of Unix-like systems posed challenges for system
administrators, developers, and users alike; each new system type brought
its own set of quirks, bugs, and misfeatures to deal with. As the various
Unix implementations diverged, they became increasingly obnoxious to deal
with. As a result, many groups tried to standardize on a single vendor,
hoping that they had chosen the right one.
Either that, or they moved to those cheap new PC systems which, at that
time, did not run Unix in any convincing way. But they did run DOS
(and, eventually, Windows), and, once you got them running, they were all
the same. Packaged software became readily available, and, by the mid
1990's, it became increasingly clear that the desktop systems of the future
were not going to run Unix. Discouragingly, almost all of the Unix
workstation vendors were making deals with Microsoft and announcing that
future workstations (and servers) would run NT instead. It was a dark time.
It is fair to say that Linux saved the world from an all-Windows future
that was rapidly approaching. Almost since the beginning, though, critics
started to say that Linux would fragment just as badly as Unix did; indeed,
they predicted that the situation would be even worse. How could things
stay coherent, after all, without a benevolent corporate overlord to keep
fragmentation from happening?
But that fragmentation did not happen. Lots of distributions exist, but
they have all followed roughly the same course and, for the most part, do
not differ by all that much. Efforts like the Linux Standard Base and
Filesystem Hierarchy Standard have helped in this area. Arguably, a strong
focus on avoiding proprietary drivers and basing every distribution on
something close to a mainline kernel has helped even more. Moving from one
Linux distribution to another can be mildly disorienting for a brief
period, but the administration skills are mostly the same, the software
still mostly works, and one comes up to speed relatively quickly. Linux has
not suffered the fate of proprietary Unix, or even the fragmentation seen
in the current free Unix distributions.
But that situation may be changing. An obvious example is Android which,
while being based on a Linux kernel, is hardly recognizable as Linux
otherwise. Other mobile distributions—MeeGo, Tizen, webOS, etc.—may differ
less from "standard" Linux, but they still don't look much like the desktop
on which this article is being written. Enterprise distributions
increasingly emphasize their own special features - see Oracle's addition
of features like Ksplice and Dtrace, for example.
Most recently, we have seen Ubuntu seemingly determined to diverge from
other Linux distributions. In particular, the recent announcement that
Ubuntu would not move to systemd has led to some charges
that they are fragmenting the Linux ecosystem. Such charges do not ring
fully true: remember that upstart was there first and was in use by a number of
distributions before those distributions (not Ubuntu) switched to something
newer and
shinier. But, with developments like Unity, Ubuntu does show signs of
wanting to be its own world, increasingly removed from the rest of Linux.
It is becoming harder for a user of another distribution to sit down at a
Ubuntu system and quickly feel at home.
So one could argue that we are heading into a repeat of the Unix wars.
It is noteworthy that the word "Linux" does not appear on the ubuntu.com front page; its absence from
android.com, instead, has lost its
ability to surprise. Distributions were once promoted as a superior form
of Linux; now they are given an identity as a separate operating system
altogether. Linux, one could say, is just a set of components that a
company grabs to build its own special operating system.
That said, there are a couple of things to keep in mind, starting with the
fact that the amount of shared code is still high and likely to remain that
way. The notable exception, of course, is Android, but that may well be
the exception that proves the rule: only a company with the financial
resources of Google can hope to take on responsibility for that much code
and hope to maintain it over the long term. For most other companies, the
cost of going it alone will simply be too high; economics will tend to
place an upper limit on how much divergence we will see. That divergence
may grow as projects try to do things that Unix-like systems have never
done before, but it can also be expected to shrink as the best solutions
win and are adopted by others.
The other relevant point is that the computing environment as a whole is
becoming far more diverse. A world that was once made up of "desktops" and
"servers" now has a far wider variety of computers, most of which are not
marketed as such. It seems natural that the Linux that runs on a
traditional desktop will be quite different from the Linux that lives on a
phone handset, a television, or a logic analyzer. We are not
necessarily seeing destructive fragmentation; instead, we're seeing the
flexibility of Linux as it easily adapts to a wide range of uses.
In summary: it is probably too soon to declare that the Unix wars have come
to Linux. Every Unix was different because vendors felt the need to
differentiate their offerings and lock the customer in. Linux vendors, too,
are trying to differentiate, but they are doing so (mostly) with free
software, which limits how effective such a strategy can be. If Unity
truly ends up taking the world by storm, other distributions can ship it
overnight. As long as the software remains free, Linux, as a whole, will
be as unified as it needs to be.
Comments (38 posted)
We put out a call for applicants for a job as an LWN editor in January, and
were quite surprised by all of the excellent responses we received. It
took us a while to narrow the list down, but we eventually got there and we
are excited to announce that longtime LWN guest author Nathan Willis has
accepted our offer to join the staff.
Not surprisingly, based on the great
work he has done for us over the last few years, Nate had the right mix of
skills and experience for the job. We look forward to him building on those
to help LWN expand its coverage and reach over the coming years. Readers
undoubtedly already know about his writing, but we asked him to give us a
little biographical background; here's what he had to say:
Nate has been using Linux full-time since 1998, and writing about it since
2004. At some point in the intervening stretch he worked as a photographer
and got hooked on free software tools for creative graphics. For the past
few years he has lent a hand with the Texas Linux Fest regional community
conference at night while writing during the day. He also works on open
font development in between, at dusk and shortly before dawn. He lives in
western-north-central Texas, right where the Monarch butterfly migrations and
tornadoes cross paths.
Nate will be starting on April 27 and will quickly be tossed into the fire
with trips to two conferences shortly after he starts. Please join us in
welcoming Nate to LWN.
We'd also like to thank all of the folks who took the time and effort to
apply for the job. There was a long series of hard decisions, which is
part of what took us so long. But the result was a good one, and Nate's help will be important in our efforts to make LWN better.
Comments (14 posted)
Page editor: Jonathan Corbet
Inside this week's LWN.net Weekly Edition
- Security: Quantum random numbers; New vulnerabilities in dropbear, kernel, Mozilla products, wicd, ...
- Kernel: O_HOT and O_COLD; Toward a safer fput(); A library for seccomp filters.
- Distributions: Mageia nears its second release; Fedora architecture promotion requirements adopted, Red Hat, Scientific Linux, Swift Linux, ...
- Development: The first Calligra release; dwz, gitolite, openssh, symphony, ...
- Announcements: Linus Torvalds a finalist for MTP, LAC 2012 proceedings, LPI "Linux Essentials", Peru's OLPC Implementation, ...
Next page:
Security>>