# MaskRay

Published articles for MaskRay.

This is one page of public article previews, not the complete archive. Follow Next page to continue. Summaries are not the original full articles.

## lld 23 ELF changes

DevFeed: [lld 23 ELF changes](<https://devfeed.tech/articles/lld-23-elf-changes-31132.md>)

Original publisher: [Read original article](<https://maskray.me/blog/lld-23-elf-changes>)

Published: 2026-09-12T07:00:00Z

Content type: release

Language: en

Sources: [MaskRay](<https://devfeed.tech/sources/maskray.md>)

Topics: [LLVM](<https://devfeed.tech/topics/llvm.md>), [Git](<https://devfeed.tech/topics/git.md>), [Claude Code](<https://devfeed.tech/topics/claude-code.md>)

Tags: [2026](<https://devfeed.tech/tags/2026.md>), [compression](<https://devfeed.tech/tags/compression.md>), [linker](<https://devfeed.tech/tags/linker.md>), [llvm](<https://devfeed.tech/tags/llvm.md>), [performance](<https://devfeed.tech/tags/performance.md>), [release](<https://devfeed.tech/tags/release.md>)

### AI overview

This release article summarizes changes in lld/ELF for LLVM 23.1. It reports 141 commits during the development cycle, with substantial performance work including parallelized input-file loading and mark processing, along with linker behavior and compatibility updates.

### Source excerpt

LLVM 23.1 has been released. As usual, I maintain lld/ELF and as volunteer work have added some notes to https://github.com/llvm/llvm-project/blob/release/23.x/lld/docs/ReleaseNotes.rst. Like last time, I used Claude Code to summarize git log llvmorg-23-init..origin/release/23.x -- lld/ELF, excluding changes cherry-picked into 22.x (git rev-list llvmorg-23-init..llvmorg-22.1.8 -- lld), and then edited the draft. This was a busy cycle: 141 commits landed in lld/ELF between the branch point (2026-01-13) and 23.1.0-rc1 (2026-07-16), compared with 72 in the 22 cycle. Much of the increase is performance work, which I described in Recent lld/ELF performance improvements. lld 23 is the first release that ships all of it.

## Block frequency

DevFeed: [Block frequency](<https://devfeed.tech/articles/block-frequency-31125.md>)

Original publisher: [Read original article](<https://maskray.me/blog/block-frequency>)

Published: 2026-08-23T07:00:00Z

Content type: article

Language: en

Sources: [MaskRay](<https://devfeed.tech/sources/maskray.md>)

Topics: [LLVM](<https://devfeed.tech/topics/llvm.md>)

Tags: [algorithm](<https://devfeed.tech/tags/algorithm.md>), [graph](<https://devfeed.tech/tags/graph.md>), [llvm](<https://devfeed.tech/tags/llvm.md>)

### AI overview

This article explains how LLVM turns branch probabilities into per-block frequencies through linear-time propagation over loop-structured regions. It also notes that irreducible control flow reduces accuracy.

### Source excerpt

Estimating branch probabilities says how one branch splits. BlockFrequencyInfo turns those local numbers into per-block frequencies, which nearly every profitability decision in LLVM ends up reading. The core is a linear-time propagation over loop-packaged regions. Where no such structure exists -- irreducible control flow -- the accuracy goes with it.

## Estimating branch probabilities

DevFeed: [Estimating branch probabilities](<https://devfeed.tech/articles/estimating-branch-probabilities-31127.md>)

Original publisher: [Read original article](<https://maskray.me/blog/estimating-branch-probabilities>)

Published: 2026-08-09T07:00:00Z

Content type: article

Language: en

Sources: [MaskRay](<https://devfeed.tech/sources/maskray.md>)

Topics: [LLVM](<https://devfeed.tech/topics/llvm.md>)

Tags: [algorithm](<https://devfeed.tech/tags/algorithm.md>), [analysis](<https://devfeed.tech/tags/analysis.md>), [functions](<https://devfeed.tech/tags/functions.md>), [graph](<https://devfeed.tech/tags/graph.md>), [llvm](<https://devfeed.tech/tags/llvm.md>), [structure](<https://devfeed.tech/tags/structure.md>)

### AI overview

This post explains how LLVM estimates branch probabilities when profile data is unavailable. It examines the heuristic that classifies control-flow blocks and successor paths using unreachable, cold, unwinding, and loop information, and presents a standalone reimplementation.

### Source excerpt

LLVM's BranchProbabilityInfo assigns every multi-successor terminator a probability distribution over its successors. This post describes the estimation used when no profile is available and reimplements it as a standalone program.

## Irreducible loops

DevFeed: [Irreducible loops](<https://devfeed.tech/articles/irreducible-loops-31129.md>)

Original publisher: [Read original article](<https://maskray.me/blog/irreducible-loops>)

Published: 2026-07-12T07:00:00Z

Content type: tutorial

Language: en

Sources: [MaskRay](<https://devfeed.tech/sources/maskray.md>)

Topics: [Graphs](<https://devfeed.tech/topics/graphs.md>), [Algorithms](<https://devfeed.tech/topics/algorithms.md>), [Code](<https://devfeed.tech/topics/code.md>), [LLVM](<https://devfeed.tech/topics/llvm.md>)

Tags: [algorithm](<https://devfeed.tech/tags/algorithm.md>), [analysis](<https://devfeed.tech/tags/analysis.md>), [code](<https://devfeed.tech/tags/code.md>), [entries](<https://devfeed.tech/tags/entries.md>), [flow](<https://devfeed.tech/tags/flow.md>), [graph](<https://devfeed.tech/tags/graph.md>), [graphs](<https://devfeed.tech/tags/graphs.md>), [llvm](<https://devfeed.tech/tags/llvm.md>), [loops](<https://devfeed.tech/tags/loops.md>), [static](<https://devfeed.tech/tags/static.md>), [structure](<https://devfeed.tech/tags/structure.md>)

### AI overview

This technical post explains why dominator-based natural-loop detection fails for irreducible control-flow graphs, which can have multiple entries. It describes reducibility, the irreducible three-node pattern, and a DFS-based loop-nesting forest using Havlak's convention.

### Source excerpt

The dominator tree lets us identify natural loops: a back edge T->H whose head H dominates its tail T defines a loop with the single entry H. This works only for reducible control flow graphs. Optimized machine code and decompiler output routinely contain irreducible loops, which have more than one entry and thus no dominating header, so the dominator-based method cannot see them. This post builds a loop-nesting forest for an arbitrary CFG with the single-pass depth-first search of 韦韬、毛剑、邹维、陈宇(Tao Wei, Jian Mao, Wei Zou & Yu Chen) A New Algorithm for Identifying Loops in Decompilation, SAS 2007 (The 14th International Static Analysis Symposium).

## Optimizing LLVM's bump allocator

DevFeed: [Optimizing LLVM's bump allocator](<https://devfeed.tech/articles/optimizing-llvm-s-bump-allocator-31134.md>)

Original publisher: [Read original article](<https://maskray.me/blog/optimizing-llvm-bump-allocator>)

Published: 2026-06-28T07:00:00Z

Content type: article

Language: en

Sources: [MaskRay](<https://devfeed.tech/sources/maskray.md>)

Topics: [LLVM](<https://devfeed.tech/topics/llvm.md>), [clang](<https://devfeed.tech/topics/clang.md>)

Tags: [changes](<https://devfeed.tech/tags/changes.md>), [clang](<https://devfeed.tech/tags/clang.md>), [codegen](<https://devfeed.tech/tags/codegen.md>), [debug](<https://devfeed.tech/tags/debug.md>), [llvm](<https://devfeed.tech/tags/llvm.md>), [memory](<https://devfeed.tech/tags/memory.md>), [optimizing](<https://devfeed.tech/tags/optimizing.md>), [performance](<https://devfeed.tech/tags/performance.md>)

### AI overview

This article explains three recent changes that optimize LLVM's BumpPtrAllocator: avoiding unnecessary realignment, using a sentinel to eliminate a null check, and removing per-allocation accounting from the hot path. It also discusses alignment, typed allocation, incomplete types, and ABI considerations.

### Source excerpt

BumpPtrAllocator is LLVM's bump allocator (arena allocator): each allocation bumps a pointer within a slab, and everything is freed at once when the allocator dies. It backs Clang's ASTContext, lld's make<T> object pools, TableGen records, and many other arenas. Here is the fast path before three recent changes: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 __attribute__((returns_nonnull)) void *Allocate(size_t Size, Align Alignment) { BytesAllocated += Size; // (3) accounting RMW uintptr_t AlignedPtr = alignAddr(CurPtr, Alignment); // (1) always realign size_t SizeToAllocate = Size; #if LLVM_ADDRESS_SANITIZER_BUILD SizeToAllocate += RedZoneSize; #endif uintptr_t AllocEndPtr = AlignedPtr + SizeToAllocate; if (LLVM_LIKELY(AllocEndPtr <= uintptr_t(End) && CurPtr != nullptr)) { // (2) bound + null check CurPtr = reinterpret_cast<char *>(AllocEndPtr); ... return reinterpret_cast<char *>(AlignedPtr); } return AllocateSlow(Size, SizeToAllocate, Alignment); }

## A deep dive into SmallVector::push\_back

DevFeed: [A deep dive into SmallVector::push\_back](<https://devfeed.tech/articles/a-deep-dive-into-smallvector-push-back-31123.md>)

Original publisher: [Read original article](<https://maskray.me/blog/a-deep-dive-into-smallvector-push-back>)

Published: 2026-06-27T07:00:00Z

Content type: article

Language: en

Sources: [MaskRay](<https://devfeed.tech/sources/maskray.md>)

Topics: [LLVM](<https://devfeed.tech/topics/llvm.md>), [Optimization](<https://devfeed.tech/topics/optimization.md>), [Compiler](<https://devfeed.tech/topics/compiler.md>), [clang](<https://devfeed.tech/topics/clang.md>), [Assembly](<https://devfeed.tech/topics/assembly.md>), [gcc](<https://devfeed.tech/topics/gcc.md>)

Tags: [assembly](<https://devfeed.tech/tags/assembly.md>), [clang](<https://devfeed.tech/tags/clang.md>), [codegen](<https://devfeed.tech/tags/codegen.md>), [compiler](<https://devfeed.tech/tags/compiler.md>), [gcc](<https://devfeed.tech/tags/gcc.md>), [llvm](<https://devfeed.tech/tags/llvm.md>), [optimization](<https://devfeed.tech/tags/optimization.md>), [performance](<https://devfeed.tech/tags/performance.md>)

### AI overview

This article examines an LLVM SmallVector::push_back optimization for approximately trivially copyable element types. It explains how tail-calling the slow growth path reduces the fast path from 14 to 7 instructions and avoids callee-saved registers, while noting tradeoffs for out-of-line calls and overall build size.

### Source excerpt

tl;dr This blog post describes a recent SmallVector::push_back optimization for approximately trivially copyable element types. SmallVector is LLVM's most-used container, and push_back its hot operation. For the trivially-copyable specialization the fast path should be fast. 1 2 3 #include <llvm/ADT/SmallVector.h> void f(llvm::SmallVectorImpl<int> &v, int x) { v.push_back(x); } clang -S --target=x86_64 -O2 -DNDEBUG a.cc generates: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 push rbp # callee-saved spills + a stack realignment, push rbx # all on the fast path push rax mov eax, [rdi + 8] # size cmp eax, [rdi + 12] # vs capacity jae .Lgrow .Lstore: # reached from the fast path AND from .Lgrow mov rcx, [rdi] mov [rcx + rax*4], esi inc dword ptr [rdi + 8] add rsp, 8 pop rbx pop rbp ret .Lgrow: mov rbx, rdi # keep `this`/`x` alive across the call mov ebp, esi call SmallVectorBase<unsigned>::grow_pod ... jmp .Lstore

## Recent LLVM hash table improvements

DevFeed: [Recent LLVM hash table improvements](<https://devfeed.tech/articles/recent-llvm-hash-table-improvements-31122.md>)

Original publisher: [Read original article](<https://maskray.me/blog/2026-06-07-recent-llvm-hash-table-improvements>)

Published: 2026-06-07T07:00:00Z

Content type: article

Language: en

Sources: [MaskRay](<https://devfeed.tech/sources/maskray.md>)

Topics: [LLVM](<https://devfeed.tech/topics/llvm.md>), [hash](<https://devfeed.tech/topics/hash.md>), [Algorithms](<https://devfeed.tech/topics/algorithms.md>), [benchmarking](<https://devfeed.tech/topics/benchmarking.md>)

Tags: [algorithm](<https://devfeed.tech/tags/algorithm.md>), [compiler](<https://devfeed.tech/tags/compiler.md>), [data-structures](<https://devfeed.tech/tags/data-structures.md>), [hash](<https://devfeed.tech/tags/hash.md>), [improvements](<https://devfeed.tech/tags/improvements.md>), [llvm](<https://devfeed.tech/tags/llvm.md>), [performance](<https://devfeed.tech/tags/performance.md>)

### AI overview

The article reviews recent improvements to LLVM hash tables, including replacing quadratic probing and tombstone or empty-key sentinels with linear probing, Algorithm R deletion, and bit-array occupancy. It also discusses pointer and iterator invalidation behavior and reports performance improvements in DenseMap.

### Source excerpt

LLVM has several hash tables. They used quadratic probing with in-band sentinel keys (empty, tombstone); recent work has been replacing that with linear probing with tombstone key removed. DenseMap (replacement for std::unordered_map): DenseMapInfo::getEmptyKey() / getTombstoneKey(). DenseSet: implemented using DenseMap compiler-rt/lib/sanitizer_common/sanitizer_dense_map.h ports the implementation for sanitizers. SmallPtrSet (replacement for std::unordered_set<T *>): hard-coded -1 (empty) and -2 (tombstone). StringMap (replacement for std::unordered_map<std::string, V>) StringSet: implemented using StringMap FoldingSet (uniquing/hash-consing container, not a general map) For the open-addressed DenseMap and SmallPtrSet, pointers, references, and iterators are invalidated by insert. StringMap is different: each entry lives in a heap-allocated StringMapEntry<V> node, so entry pointers survive grow. std::unordered_map, being node-based, keeps surviving-element pointers valid across both insert and erase and only invalidates the erased element's own iterator. LLVM code rarely needs that stronger contract -- callers do not hold long-lived references into the container across mutation -- and that gap is what gives pass to relocating erase and bit-array occupancy. Recently, Tombstones have been removed from DenseMap and SmallPtrSet. erase() also invalidates pointers. DenseMap has also retired its empty-key sentinel, leading to significant performance improvements. DenseMap with integer keys (int/unsigned/size_t) had -1/-2 reserved -- a footgun, now fixed. StringMap got Algorithm R deletion too. Its entries are separately heap-allocated, so erase keeps entry pointers valid but invalidates iterators; erase-while-iterating moved to remove_if. FoldingSet dropped chaining for linear probing plus Algorithm R; the intrusive next-in-bucket pointer became a cached 32-bit hash.

## Fighting Hyrum's Law in LLVM

DevFeed: [Fighting Hyrum's Law in LLVM](<https://devfeed.tech/articles/fighting-hyrum-s-law-in-llvm-31128.md>)

Original publisher: [Read original article](<https://maskray.me/blog/fighting-hyrums-law-in-llvm>)

Published: 2026-05-10T07:00:00Z

Content type: article

Language: en

Sources: [MaskRay](<https://devfeed.tech/sources/maskray.md>)

Topics: [LLVM](<https://devfeed.tech/topics/llvm.md>), [Compiler](<https://devfeed.tech/topics/compiler.md>), [reproducible builds](<https://devfeed.tech/topics/reproducible-builds.md>), [hash](<https://devfeed.tech/topics/hash.md>)

Tags: [clang](<https://devfeed.tech/tags/clang.md>), [compiler](<https://devfeed.tech/tags/compiler.md>), [hash](<https://devfeed.tech/tags/hash.md>), [lld](<https://devfeed.tech/tags/lld.md>), [llvm](<https://devfeed.tech/tags/llvm.md>), [reproducible-builds](<https://devfeed.tech/tags/reproducible-builds.md>), [test](<https://devfeed.tech/tags/test.md>)

### AI overview

This article examines how LLVM can develop dependencies on unspecified or incidental behavior under Hyrum's Law, causing output variation that harms reproducible builds, bisection, and bug reports. It describes hash-seed perturbation, reverse container iteration, and iterator invalidation checks as mechanisms for exposing such dependencies.

### Source excerpt

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.

## Recent lld/ELF performance improvements

DevFeed: [Recent lld/ELF performance improvements](<https://devfeed.tech/articles/recent-lld-elf-performance-improvements-31121.md>)

Original publisher: [Read original article](<https://maskray.me/blog/2026-04-12-recent-lld-elf-performance-improvements>)

Published: 2026-04-12T07:00:00Z

Content type: article

Language: en

Sources: [MaskRay](<https://devfeed.tech/sources/maskray.md>)

Topics: [LLVM](<https://devfeed.tech/topics/llvm.md>), [Benchmark](<https://devfeed.tech/topics/benchmark.md>), [benchmarking](<https://devfeed.tech/topics/benchmarking.md>), [clang](<https://devfeed.tech/topics/clang.md>), [Chromium](<https://devfeed.tech/topics/chromium.md>)

Tags: [2026](<https://devfeed.tech/tags/2026.md>), [benchmark](<https://devfeed.tech/tags/benchmark.md>), [chromium](<https://devfeed.tech/tags/chromium.md>), [clang](<https://devfeed.tech/tags/clang.md>), [gc](<https://devfeed.tech/tags/gc.md>), [gdb](<https://devfeed.tech/tags/gdb.md>), [improvements](<https://devfeed.tech/tags/improvements.md>), [linker](<https://devfeed.tech/tags/linker.md>), [lld](<https://devfeed.tech/tags/lld.md>), [llvm](<https://devfeed.tech/tags/llvm.md>), [macos](<https://devfeed.tech/tags/macos.md>), [overhead](<https://devfeed.tech/tags/overhead.md>), [patches](<https://devfeed.tech/tags/patches.md>), [performance](<https://devfeed.tech/tags/performance.md>)

### AI overview

This article reports LLVM lld/ELF linker performance improvements from parallelizing link phases and reducing task-runtime overhead. Benchmarks show a 1.34x speedup over lld 22.1 for a Release+Asserts clang link and a 1.09x speedup for a Chromium debug link, while mold and wild remain faster in the comparisons described.

### Source excerpt

Updated in 2026-05. Since the LLVM 22 branch was cut, I've landed patches that parallelize more link phases and cut task-runtime overhead. This post compares current main against lld 22.1, mold, and wild. Headline: a Release+Asserts clang --gc-sections link is 1.34x as fast as lld 22.1; Chromium debug with --gdb-index is 1.09x as fast. mold and wild are still ahead -- the last section explains why.

## Bit-field layout

DevFeed: [Bit-field layout](<https://devfeed.tech/articles/bit-field-layout-31124.md>)

Original publisher: [Read original article](<https://maskray.me/blog/bit-field-layout>)

Published: 2026-02-22T08:00:00Z

Content type: tutorial

Language: en

Sources: [MaskRay](<https://devfeed.tech/sources/maskray.md>)

Topics: [implementation](<https://devfeed.tech/topics/implementation.md>), [C](<https://devfeed.tech/topics/c.md>), [C++](<https://devfeed.tech/topics/c-plus-plus.md>), [Compiler](<https://devfeed.tech/topics/compiler.md>), [clang](<https://devfeed.tech/topics/clang.md>), [gcc](<https://devfeed.tech/topics/gcc.md>), [LLVM](<https://devfeed.tech/topics/llvm.md>), [MSVC](<https://devfeed.tech/topics/msvc.md>)

Tags: [c](<https://devfeed.tech/tags/c.md>), [c-plus-plus](<https://devfeed.tech/tags/c-plus-plus.md>), [clang](<https://devfeed.tech/tags/clang.md>), [codegen](<https://devfeed.tech/tags/codegen.md>), [compiler](<https://devfeed.tech/tags/compiler.md>), [compiler-optimization](<https://devfeed.tech/tags/compiler-optimization.md>), [gcc](<https://devfeed.tech/tags/gcc.md>), [implementation](<https://devfeed.tech/tags/implementation.md>), [llvm](<https://devfeed.tech/tags/llvm.md>), [msvc](<https://devfeed.tech/tags/msvc.md>)

### AI overview

This article explains how C and C++ bit-field layout is implementation-defined and governed primarily by platform ABIs. It distinguishes ABI-defined storage layout from compiler code generation, focusing on the Itanium ABI and describing differences in the Microsoft ABI.

### Source excerpt

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.

## Call relocation types

DevFeed: [Call relocation types](<https://devfeed.tech/articles/call-relocation-types-31126.md>)

Original publisher: [Read original article](<https://maskray.me/blog/call-relocation-types>)

Published: 2026-02-16T08:00:00Z

Content type: article

Language: en

Sources: [MaskRay](<https://devfeed.tech/sources/maskray.md>)

Topics: [x86](<https://devfeed.tech/topics/x86.md>), [Assembly](<https://devfeed.tech/topics/assembly.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [architectures](<https://devfeed.tech/tags/architectures.md>), [binutils](<https://devfeed.tech/tags/binutils.md>), [function](<https://devfeed.tech/tags/function.md>), [linker](<https://devfeed.tech/tags/linker.md>), [static-linking](<https://devfeed.tech/tags/static-linking.md>), [symbols](<https://devfeed.tech/tags/symbols.md>), [x86](<https://devfeed.tech/tags/x86.md>), [x86-64](<https://devfeed.tech/tags/x86-64.md>)

### AI overview

This technical post explains why some architectures use separate ELF relocation types for direct function calls and tail calls. It contrasts static linking, where a PC-relative relocation can often be reused, with dynamic linking, where calls may use PLT indirection and therefore require relocation types that encode call semantics.

### Source excerpt

Most architectures encode direct branch/call instructions with a PC-relative displacement. This post discusses a specific category of branch relocations: those used for direct function calls and tail calls. Some architectures use two ELF relocation types for a call instruction: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # i386, x86-64 call foo # R_386_PC32, R_X86_64_PC32 call foo@plt # R_386_PLT32, R_X86_64_PLT32 # m68k bsr.l foo # R_68K_PC32 bsr.l foo@plt # R_68K_PLT32 # s390/s390x brasl %r14, foo # R_390_PC32DBL brasl %r14, foo@plt # R_390_PLT32DBL # sparc call foo, 0 # not PIC: R_SPARC_WDISP30 call foo, 0 # gas -KPIC: R_SPARC_WPLT30

## lld 22 ELF changes

DevFeed: [lld 22 ELF changes](<https://devfeed.tech/articles/lld-22-elf-changes-31131.md>)

Original publisher: [Read original article](<https://maskray.me/blog/lld-22-elf-changes>)

Published: 2026-02-01T08:00:00Z

Content type: release

Language: en

Sources: [MaskRay](<https://devfeed.tech/sources/maskray.md>)

Topics: [LLVM](<https://devfeed.tech/topics/llvm.md>), [releases](<https://devfeed.tech/topics/releases.md>), [Release notes](<https://devfeed.tech/topics/release-notes.md>), [Claude Code](<https://devfeed.tech/topics/claude-code.md>), [Large Language Model](<https://devfeed.tech/topics/llm.md>)

Tags: [claude-code](<https://devfeed.tech/tags/claude-code.md>), [compiler](<https://devfeed.tech/tags/compiler.md>), [git](<https://devfeed.tech/tags/git.md>), [linker](<https://devfeed.tech/tags/linker.md>), [lld](<https://devfeed.tech/tags/lld.md>), [llm](<https://devfeed.tech/tags/llm.md>), [llvm](<https://devfeed.tech/tags/llvm.md>), [release](<https://devfeed.tech/tags/release.md>), [release-notes](<https://devfeed.tech/tags/release-notes.md>), [releases](<https://devfeed.tech/tags/releases.md>)

### AI overview

An LLVM lld/ELF maintainer summarizes changes planned for LLVM 22.1, including linker behavior updates, parsing improvements, relocation support, partitioning changes, and architecture-specific fixes. The author also describes using Claude Code to review commits and draft release notes.

### Source excerpt

For those unfamiliar, lld is the LLVM linker, supporting PE/COFF, ELF, Mach-O, and WebAssembly ports. These object file formats differ significantly, and each port must follow the conventions of the platform's system linker. As a result, the ports share limited code (diagnostics, memory allocation, etc) and have largely separate reviewer groups. With LLVM 22.1 releasing soon, I've added some notes to the https://github.com/llvm/llvm-project/blob/release/22.x/lld/docs/ReleaseNotes.rst as an lld/ELF maintainer. As usual, I've reviewed almost all the patches not authored by me. For the first time, I used an LLM agent (Claude Code) to help look through commits (git log release/21.x..release/22.x -- lld/ELF) and draft the release notes. Despite my request to only read lld/ELF changes, Claude Code also crafted notes for other ports, which I retained since their release notes had been quite sparse for several releases. Changes back ported to the 21.x release are removed (git log --oneline llvmorg-22-init..llvmorg-21.1.8 -- lld). I'll delve into some of the key changes.

## Long branches in compilers, assemblers, and linkers

DevFeed: [Long branches in compilers, assemblers, and linkers](<https://devfeed.tech/articles/long-branches-in-compilers-assemblers-and-linkers-31133.md>)

Original publisher: [Read original article](<https://maskray.me/blog/long-branches-in-compilers-assemblers-and-linkers>)

Published: 2026-01-25T08:00:00Z

Content type: article

Language: en

Sources: [MaskRay](<https://devfeed.tech/sources/maskray.md>)

Topics: [toolchain](<https://devfeed.tech/topics/toolchain.md>), [Compiler](<https://devfeed.tech/topics/compiler.md>), [Assembly](<https://devfeed.tech/topics/assembly.md>)

Tags: [architectures](<https://devfeed.tech/tags/architectures.md>), [article](<https://devfeed.tech/tags/article.md>), [assembler](<https://devfeed.tech/tags/assembler.md>), [binutils](<https://devfeed.tech/tags/binutils.md>), [compilers](<https://devfeed.tech/tags/compilers.md>), [implementation](<https://devfeed.tech/tags/implementation.md>), [linker](<https://devfeed.tech/tags/linker.md>), [llvm](<https://devfeed.tech/tags/llvm.md>), [toolchain](<https://devfeed.tech/tags/toolchain.md>)

### AI overview

This article explains how compilers, assemblers, and linkers handle branch instructions whose PC-relative targets exceed the supported range. It describes the division of responsibility across toolchain stages and compares branch-range limitations across architectures, including AArch32, AArch64, and LoongArch.

### Source excerpt

Branch instructions on most architectures use PC-relative addressing with a limited range. When the target is too far away, the branch becomes "out of range" and requires special handling. Consider a large binary where main() at address 0x10000 calls foo() at address 0x8010000-over 128MiB away. On AArch64, the bl instruction can only reach ±128MiB, so this call cannot be encoded directly. Without proper handling, the linker would fail with an error like "relocation out of range." The toolchain must handle this transparently to produce correct executables. This article explores how compilers, assemblers, and linkers work together to solve the long branch problem. Compiler (IR to assembly): Handles branches within a function that exceed the range of conditional branch instructions Assembler (assembly to relocatable file): Handles branches within a section where the distance is known at assembly time Linker: Handles cross-section and cross-object branches discovered during final layout

## Maintaining shadow branches for GitHub PRs

DevFeed: [Maintaining shadow branches for GitHub PRs](<https://devfeed.tech/articles/maintaining-shadow-branches-for-github-prs-31120.md>)

Original publisher: [Read original article](<https://maskray.me/blog/2026-01-22-maintaining-shadow-branches-for-github-prs>)

Published: 2026-01-22T08:00:00Z

Content type: article

Language: en

Sources: [MaskRay](<https://devfeed.tech/sources/maskray.md>)

Topics: [GitHub](<https://devfeed.tech/topics/github.md>), [Pull Request](<https://devfeed.tech/topics/pull-request.md>), [Vibe coding](<https://devfeed.tech/topics/vibe-coding.md>), [Tool](<https://devfeed.tech/topics/tool.md>), [LLVM](<https://devfeed.tech/topics/llvm.md>)

Tags: [git](<https://devfeed.tech/tags/git.md>), [github](<https://devfeed.tech/tags/github.md>), [pull-request](<https://devfeed.tech/tags/pull-request.md>), [text](<https://devfeed.tech/tags/text.md>), [tool](<https://devfeed.tech/tags/tool.md>), [vibe-coding](<https://devfeed.tech/tags/vibe-coding.md>), [workflow](<https://devfeed.tech/tags/workflow.md>)

### AI overview

The author describes pr-shadow, a tool created with vibe coding that maintains a fast-forward-only shadow branch for GitHub pull requests. Developers can rebase, amend, or squash locally while reviewers see stable diffs and the workflow avoids force-pushing problems.

### Source excerpt

I've created pr-shadow with vibe coding, a tool that maintains a shadow branch for GitHub pull requests (PR) that never requires force-pushing. This addresses pain points I described in Reflections on LLVM's switch to GitHub pull requests#Patch evolution.

## 2025年总结

DevFeed: [2025年总结](<https://devfeed.tech/articles/2025-31119.md>)

Original publisher: [Read original article](<https://maskray.me/blog/2025-12-31-summary>)

Published: 2025-12-31T08:00:00Z

Content type: article

Language: zh

Sources: [MaskRay](<https://devfeed.tech/sources/maskray.md>)

Topics: [toolchain](<https://devfeed.tech/topics/toolchain.md>), [LLVM](<https://devfeed.tech/topics/llvm.md>), [patches](<https://devfeed.tech/topics/patches.md>), [Linux](<https://devfeed.tech/topics/linux.md>)

Tags: [assembler](<https://devfeed.tech/tags/assembler.md>), [blogging](<https://devfeed.tech/tags/blogging.md>), [bugs](<https://devfeed.tech/tags/bugs.md>), [https-maskray-me-blog-tags-assembler](<https://devfeed.tech/tags/https-maskray-me-blog-tags-assembler.md>), [linux](<https://devfeed.tech/tags/linux.md>), [llvm](<https://devfeed.tech/tags/llvm.md>), [patches](<https://devfeed.tech/tags/patches.md>), [summary](<https://devfeed.tech/tags/summary.md>)

### AI overview

A 2025 personal summary covering reduced open-source involvement, 18 blog posts, work on LLVM's integrated assembler and ELF specifications, Linux kernel contributions, ccls, binutils reports, and travel.

### Source excerpt

TODO 一如既往，主要在工具链领域耕耘。但由于工作忙碌在open source社区投入的时间减少了。 Blogging 不包括这篇总结，一共写了18篇文章。

## Weak AVL Tree

DevFeed: [Weak AVL Tree](<https://devfeed.tech/articles/weak-avl-tree-31118.md>)

Original publisher: [Read original article](<https://maskray.me/blog/2025-12-14-weak-avl-tree>)

Published: 2025-12-14T08:00:00Z

Content type: tutorial

Language: en

Sources: [MaskRay](<https://devfeed.tech/sources/maskray.md>)

Topics: [Data structures](<https://devfeed.tech/topics/data-structures.md>), [implementation](<https://devfeed.tech/topics/implementation.md>)

Tags: [algorithm](<https://devfeed.tech/tags/algorithm.md>), [data-structure](<https://devfeed.tech/tags/data-structure.md>), [implementation](<https://devfeed.tech/tags/implementation.md>), [root](<https://devfeed.tech/tags/root.md>), [rotation](<https://devfeed.tech/tags/rotation.md>), [rules](<https://devfeed.tech/tags/rules.md>)

### AI overview

This article introduces weak AVL trees as a rank-based balanced binary search tree and compares their balancing behavior with AVL and red-black trees. It describes rank differences, insertion cases, rotation bounds, and an implementation detail for encoding ranks, while noting that deletion is not yet described.

### Source excerpt

tl;dr: Weak AVL trees are replacements for AVL trees and red-black trees. The 2014 paper

## Stack walking: space and time trade-offs

DevFeed: [Stack walking: space and time trade-offs](<https://devfeed.tech/articles/stack-walking-space-and-time-trade-offs-31136.md>)

Original publisher: [Read original article](<https://maskray.me/blog/stack-walking-space-and-time-trade-offs>)

Published: 2025-10-26T07:00:00Z

Content type: article

Language: en

Sources: [MaskRay](<https://devfeed.tech/sources/maskray.md>)

Topics: [LLVM](<https://devfeed.tech/topics/llvm.md>), [Linux](<https://devfeed.tech/topics/linux.md>), [C++](<https://devfeed.tech/topics/c-plus-plus.md>)

Tags: [article](<https://devfeed.tech/tags/article.md>), [gcc](<https://devfeed.tech/tags/gcc.md>), [linux](<https://devfeed.tech/tags/linux.md>), [llvm](<https://devfeed.tech/tags/llvm.md>), [performance-analysis](<https://devfeed.tech/tags/performance-analysis.md>), [platforms](<https://devfeed.tech/tags/platforms.md>), [required](<https://devfeed.tech/tags/required.md>), [sframe](<https://devfeed.tech/tags/sframe.md>), [update](<https://devfeed.tech/tags/update.md>)

### AI overview

This article examines space and time trade-offs among stack-walking mechanisms on Linux, including DWARF, frame pointers, SFrame, LLVM's Compact Unwinding Format, Last Branch Record, and CET Shadow Stack. It analyzes the size overhead of enabling non-DWARF mechanisms when building LLVM executables; runtime performance analysis is deferred to a future update.

### Source excerpt

On most Linux platforms (except AArch32, which uses .ARM.exidx), DWARF .eh_frame is required for C++ exception handling and stack unwinding to restore callee-saved registers. While .eh_frame can be used for call trace recording, it is often criticized for its runtime overhead. As an alternative, developers can enable frame pointers, or adopt SFrame, a newer format designed specifically for profiling. This article examines the size overhead of enabling non-DWARF stack walking mechanisms when building several LLVM executables. Runtime performance analysis will be added in a future update.

## Remarks on SFrame

DevFeed: [Remarks on SFrame](<https://devfeed.tech/articles/remarks-on-sframe-31135.md>)

Original publisher: [Read original article](<https://maskray.me/blog/remarks-on-sframe>)

Published: 2025-09-28T07:00:00Z

Content type: article

Language: en

Sources: [MaskRay](<https://devfeed.tech/sources/maskray.md>)

Topics: [Linux](<https://devfeed.tech/topics/linux.md>), [Compiler](<https://devfeed.tech/topics/compiler.md>), [Optimization](<https://devfeed.tech/topics/optimization.md>), [x86](<https://devfeed.tech/topics/x86.md>)

Tags: [compiler](<https://devfeed.tech/tags/compiler.md>), [linker](<https://devfeed.tech/tags/linker.md>), [linux](<https://devfeed.tech/tags/linux.md>), [llvm](<https://devfeed.tech/tags/llvm.md>), [optimization](<https://devfeed.tech/tags/optimization.md>), [profiling](<https://devfeed.tech/tags/profiling.md>), [sframe](<https://devfeed.tech/tags/sframe.md>), [x86-64](<https://devfeed.tech/tags/x86-64.md>)

### AI overview

An analysis of SFrame, a stack-walking format for userspace profiling inspired by Linux's ORC unwind format. It examines SFrame's trade-offs against .eh_frame and Windows ARM64 unwind codes, its section layout, versioning, and opportunities to reduce data-structure overhead.

### Source excerpt

SFrame is a new stack walking format for userspace profiling, inspired by Linux's in-kernel ORC unwind format. While SFrame eliminates some .eh_frame CIE/FDE overhead, it sacrifices functionality (e.g., personality, LSDA, callee-saved registers) and flexibility, and its stack offsets are less compact than .eh_frame's bytecode-style CFI instructions. In llvm-project executables I've tested on x86-64, .sframe section is 20% larger than .eh_frame. It also remains significantly larger than highly compact schemes like Windows ARM64 unwind codes. SFrame describes three elements for each function: Canonical Frame Address (CFA): The base address for stack frame calculations Return address Frame pointer An .sframe section follows a straightforward layout: Header: Contains metadata and offset information Auxiliary header (optional): Reserved for future extensions Function Descriptor Entries (FDEs): Array describing each function Frame Row Entries (FREs): Arrays of unwinding information per function

## lld 21 ELF changes

DevFeed: [lld 21 ELF changes](<https://devfeed.tech/articles/lld-21-elf-changes-31130.md>)

Original publisher: [Read original article](<https://maskray.me/blog/lld-21-elf-changes>)

Published: 2025-09-07T07:00:00Z

Content type: release

Language: en

Sources: [MaskRay](<https://devfeed.tech/sources/maskray.md>)

Topics: [LLVM](<https://devfeed.tech/topics/llvm.md>), [patches](<https://devfeed.tech/topics/patches.md>), [toolchain](<https://devfeed.tech/topics/toolchain.md>), [Arm](<https://devfeed.tech/topics/arm.md>), [RISC-V](<https://devfeed.tech/topics/riscv.md>), [TLS (Transport Layer Security)](<https://devfeed.tech/topics/tls.md>)

Tags: [architecture](<https://devfeed.tech/tags/architecture.md>), [arm](<https://devfeed.tech/tags/arm.md>), [linker](<https://devfeed.tech/tags/linker.md>), [llvm](<https://devfeed.tech/tags/llvm.md>), [optimization](<https://devfeed.tech/tags/optimization.md>), [patches](<https://devfeed.tech/tags/patches.md>), [release](<https://devfeed.tech/tags/release.md>), [riscv](<https://devfeed.tech/tags/riscv.md>), [tls](<https://devfeed.tech/tags/tls.md>)

### AI overview

An overview of selected changes in the ELF linker lld included with LLVM 21.1, covering symbol handling, garbage-collection diagnostics, ThinLTO, linker scripts, architecture-specific features, branch relaxation, TLS optimizations, and bug fixes.

### Source excerpt

LLVM 21.1 have been released. As usual, I maintain lld/ELF and have added some notes to https://github.com/llvm/llvm-project/blob/release/21.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.