Posts
clang-format and single-line statements
The Google C++ Style is widely adopted by projects. It contains a brace omission guideline in Looping and branching statements:
…For historical reasons, we allow one exception to the above rules: the curly braces for the controlled statement or the line breaks inside the curly braces may be omitted if as a result the entire statement appears on either a single line (in which case there is a space between the closing parenthesis and the controlled statement) or on two lines (in which case there is a line break after the closing parenthesis and there are no braces).
Removing global state from LLD
LLD, the LLVM linker, is a mature and fast linker supporting multiple binary formats (ELF, Mach-O, PE/COFF, WebAssembly). Designed as a standalone program, the code base relies heavily on global state, making it less than ideal for library integration. As outlined in RFC: Revisiting LLD-as-a-library design, two main hurdles exist:
- Fatal errors: they exit the process without returning control to the caller. This was actually addressed for most scenarios in 2020 by utilizing
llvm::sys::Process::Exit(val, /*NoCleanup=*/true)andCrashRecoveryContext(longjmpunder the hood). - Global variable conflicts: shared global variables do not allow two concurrent invocation.
I understand that calling a linker API could be convenient, especially when you want to avoid shipping another executable (which can be large when you link against LLVM statically). However, I believe that invoking LLD as a separate process remains the recommended approach. There are several advantages:
- Build system control: Build systems gain greater control over scheduling and resource allocation for LLD. In an edit-compile-link cycle, the link could need more resources and threading is more useful.
- Better parallelism management
- Global state isolation: LLVM's global state (primarily
cl::optandManagedStatic) is isolated.
Keeping pace with LLVM: compatibility strategies
LLVM's C++ API doesn't offer a stability guarantee. This means function signatures can change or be removed between versions, forcing projects to adapt.
On the other hand, LLVM has an extensive API surface. When a library like llvm/lib/Y relies functionality from another library, the API is often exported in header files under llvm/include/llvm/X/, even if it is not intended to be user-facing.
To be compatible with multiple LLVM versions, many projects rely on #if directives based on the LLVM_VERSION_MAJOR macro.
This post explores the specific techniques used by ccls to ensure compatibility with LLVM versions 7 to 19.
For the latest release (ccls 0.20241108), support for LLVM versions 7 to 9 has been discontinued.
Given the tight coupling between LLVM and Clang, the LLVM_VERSION_MAJOR macro can be used for both version detection. There's no need to check CLANG_VERSION_MAJOR.
Tinkering with Neovim
After migrating from Vim to Emacs as my primary C++ editor in 2015, I switched from Vim to Neovim for miscellaneous non-C++ tasks as it is more convenient in a terminal. Customizing the editor with a language you are comfortable with is important. I found myself increasingly drawn to Neovim's terminal-based simplicity for various tasks. Recently, I've refined my Neovim setup to the point where I can confidently migrate my entire C++ workflow away from Emacs.
This post explores the key improvements I've made to achieve this transition. My focus is on code navigation.
…My involvement with LLVM 19
LLVM 19.1 will soon be released. This post provides a summary of my contributions in this release cycle to record my learning progress.
…lld 19 ELF changes
LLVM 19 will be released. As usual, I maintain lld/ELF and have added some notes to https://github.com/llvm/llvm-project/blob/release/19.x/lld/docs/ReleaseNotes.rst. I've meticulously reviewed nearly all the patches that are not authored by me. I'll delve into some of the key changes.
…Mapping symbols: rethinking for efficiency
In object files, certain code patterns embed data within instructions or transitions occur between instruction sets. This can create hurdles for disassemblers, which might misinterpret data as code, resulting in inaccurate output. Furthermore, code written for one instruction set could be incorrectly disassembled as another. To address these issues, some architectures (Arm, C-SKY, NDS32, RISC-V, etc) define mapping symbols to explicitly denote state transition. Let's explore this concept using an AArch32 code example:
…Linker compatibility and the "User-Agent" problem
The output of ld.lld -v includes a message "compatible with GNU linkers" to address detection mechanism used by GNU Libtool.
This problem is described by Software compatibility and our own "User-Agent" problem.
The latest m4/libtool.m4 continues to rely on a GNU check.
Integrated assembler improvements in LLVM 19
Within the LLVM project, MC is a library responsible for handling assembly, disassembly, and object file formats. Intro to the LLVM MC Project, which was written back in 2010, remains a good source to understand the high-level structures.
In the latest release cycle, substantial effort has been dedicated to refining MC's internal representation for improved performance and readability. These changes have decreased compile time significantly. This blog post will delve into the details, providing insights into the specific changes.
…