clang
Who pays for Clang
Clang's funders have changed since 2010: Apple and Google, which wrote most of it until the mid-2010s, now write a small share, and GPU and accelerator vendors, Red Hat, and new sponsors of C++ conformance work write more. This post counts commits, pull-request approvals, and the kind of code each employer touches. The method is unscientific: commit counts are a crude proxy for work, and the attribution is my best guess, so read the numbers as rough trends, not an authoritative record. It grew out of ClangIR and the cost of MLIR, which needed it to explain who wanted an MLIR-based Clang.
…ClangIR and the cost of MLIR
ClangIR (CIR) is an MLIR dialect between the AST and LLVM IR, and in October 2026 the clang area team accepted building it by default. CIR is built on MLIR because each step along the way was locally reasonable, and together the steps locked MLIR in. The costs (build time, binary size, MLIR API churn) land largely on Clang contributors who neither chose MLIR nor use CIR.
This post traces how CIR came to depend on MLIR, collects what the dependency costs, and uses an MLIR-free CIR as a thought experiment to separate the costs inherent to MLIR from those that can be reduced.
…Fighting Hyrum's Law in LLVM
With a sufficient number of users of an API, it does not matter what you promise in the contract: all observable behaviors of your system will be depended on by somebody. — Hyrum's Law
In a compiler, the most common form of Hyrum's Law is dependence on unspecified behavior — hash bucket order, the order of equal elements after std::sort, padding offsets.
The same framing covers a few cases that are technically undefined behavior (use of an invalidated iterator) or plain incidental properties (ABI struct layout, ELF section offsets).
When the compiler itself harbors such a dependency, the symptom is usually output that varies build-to-build: an unstable sort that lands differently after the standard library changes, a hash map whose iteration order shifts when the hash function does.
Occasionally the variation is run-to-run within a single build — DenseMap<void *, X> keys with an ASLR-derived seed reorder buckets each invocation.
Either way, reproducible builds, bisection, and bug reports all assume same input → same output, and a stealth Hyrum dependency breaks that.
This post surveys some mechanisms that perturb the contract's blind spots so dependencies cannot quietly form.
…Bit-field layout
The C and C++ standards leave nearly every detail to the implementation. C23 §6.7.3.2:
An implementation may allocate any addressable storage unit large enough to hold a bit-field. If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified
C++ is also terse — [class.bit]p1:
…Allocation of bit-fields within a class object is implementation-defined. Alignment of bit-fields is implementation-defined. Bit-fields are packed into some addressable allocation unit.
Compiling C++ with the Clang API
This post describes how to compile a single C++ source file to an object file with the Clang API.
Here is the code. It behaves like a simplified clang executable that handles -c and -S.
Understanding and improving Clang -ftime-report
Clang provides a few options to generate timing report. Among them, -ftime-report and -ftime-trace can be used to analyze the performance of Clang's internal passes.
-fproc-stat-reportrecords time and memory on spawned processes (ld, and gas if-fno-integrated-as).-ftime-trace, introduced in 2019, generates Clang timing information in the Chrome Trace Event format (JSON). The format supports nested events, providing a rich view of the front end.-ftime-report: The option name is borrowed from GCC.
This post focuses on the traditional -ftime-report, which uses a line-based textual format.
Understanding -ftime-report output
The output consists of information about multiple timer groups. The last group spans the largest interval and encompasses timing data from other groups.
Up to Clang 19, the last group is called "Clang front-end time report". You would see something like the following.
…Clang's -O0 output: branch displacement and size increase
tl;dr Clang 19 will remove the -mrelax-all default at -O0, significantly decreasing the text section size for x86.
Span-dependent instructions
In assembly languages, some instructions with an immediate operand can be encoded in two (or more) forms with different sizes. On x86-64, a direct JMP/JCC can be encoded either in 2 bytes with a 8-bit relative offset or 6 bytes with a 32-bit relative offset. A short jump is preferred because it takes less space. However, when the target of the jump is too far away (out of range for a 8-bit relative offset), a near jump must be used.
ja foo # jump short if above, 77 <rel8>
ja foo # jump near if above, 0f 87 <rel32>
.nops 126
foo: ret
A 1978 paper by Thomas G. Szymanski ("Assembling Code for Machines with Span-Dependent Instructions") used the term "span-dependent instructions" to refer to such instructions with short and long forms. Assemblers grapple with the challenge of choosing the optimal size for these instructions, often referred to as the "branch displacement problem" since branches are the most common type. A good resource for understanding Szymanski's work is Assembling Span-Dependent Instructions.
…A deep dive into Clang's source file compilation
Clang is a C/C++ compiler that generates LLVM IR and utilizes LLVM to generate relocatable object files. Using the classic three-stage compiler structure, the stages can be described as follows:
C/C++ =(front end)=> LLVM IR =(middle end)=> LLVM IR (optimized) =(back end)=> relocatable object file
If we follow the internal representations of instructions, a more detailed diagram looks like this:
C/C++ =(front end)=> LLVM IR =(middle end)=> LLVM IR (optimized) =(instruction selector)=> MachineInstr =(AsmPrinter)=> MCInst =(assembler)=> relocatable object file
LLVM and Clang are designed as a collection of libraries. This post describes how different libraries work together to create the final relocatable object file. I will focus on how a function goes through the multiple compilation stages.
…Clang -Wunused-command-line-argument
clangDriver is the library implementing the compiler driver for Clang. It utilitizes LLVMOption to process command line options. As options are processed when required, as opposed to use a large switch, Clang gets the ability to detect unused options straightforwardly.
…Precompiled headers
C/C++ projects can benefit from using precompiled headers to improve compile time. GCC added support for precompiled headers in 2003 (version 3.4), and the current documentation can be found at https://gcc.gnu.org/onlinedocs/gcc/Precompiled-Headers.html.
Even with the emergence of C++ modules, precompiled headers remain relevant for several reasons:
- Precompiled headers share implementation aspects with modules (e.g., AST serialization in Clang).
- Many C++ projects rely on the traditional compilation model and are not converted to C++ modules.
- Modules may possibly use some preamble-like technology to accelerate IDE-centric operations.
- C doesn't have C++ modules.
This article focuses on Clang precompiled headers (PCH). Let's begin with an example.
…Compiler output files
For a GCC or Clang command, there is typically one primary output file, specified by -o or the default (a.out or a.exe).
There can also be temporary files and auxiliary files.
Layering check with Clang
Updated in 2023-07.
This article describes some Clang header modules features that apply to #include.
These features enforce a more explicit dependency graph, which provide documentation purposes and makes refactoring convenient.
The benefits of clean header inclusions are well described in Include What You Use as well, so I won't repeat them here.
When using C++20 modules, these features apply to #include in a global module fragment (module;) but have no effect for import declarations.
Layering check
-fmodules-decluse
For a #include directive, this option emits an error if the following conditions are satisfied (see clang/lib/Lex/ModuleMap.cpp diagnoseHeaderInclusion):
- The main file is within a module (called "source module", say,
A). - The main file or an included file from the source module includes a file from another module
B. Adoes not have a use-declaration ofB(nouse B).
For the first condition, -fmodule-map-file= is needed to load the source module map and -fmodule-name=A is needed to indicate that the source file is logically part of module A.
For the second condition, the module map defining B must be loaded by specifying -fimplicit-module-maps (implied by -fmodules and -fcxx-modules) or a -fmodule-map-file=.
-march=, -mcpu=, and -mtune=
Updated in 2025-05.
In GCC and Clang, there are three major options specifying the architecture and microarchitecture the generated code can run on. The general semantics are described below, but each target machine may assign different semantics.
-march=X: (execution domain) Generate code that can use instructions available in the architecture X-mtune=X: (optimization domain) Optimize for the microarchitecture X, but does not change the ABI or make assumptions about available instructions-mcpu=X: Specify both-march=and-mtune=but can be overridden by the two options. The supported values are generally the same as-mtune=. The architecture name is inferred fromX
When can glibc be built with Clang?
Updated in 2026: glibc 2.43 added experimental support for building with Clang.
In September 2021, I wrote "So, dear glibc, will you be happy with my sending Clang patches?" in Build glibc with LLD 13. We have come to a turning point.
In Linux Plumbers Conference 2021, at the glibc Birds of a Feather session, I asked the Clang buildability question to the glibc stewards. (Interlude: I did not realize that I should attend the conference (it was a great opportunity from an outlier to meet some glibc folks). In Tuesday, Wei Wu (lazyparser) kindly gave me his account: "想去参加LPC么?我会议太多了今天参加不过来". I happily accepted it and typed the question during the glibc session.)
So I got positive responses. "Carlos: Yes, we could be happy with clang buildability." "Joseph: Patches should be split into logical changes." This is really great news! My unnesting patch had sat there for a while and I was unsure about the Clang buildability interest.
…