The Clang bytecode interpreter, an experimental constant expression evaluator, has received over 640 new commits in the past year. The primary changes include support for virtual bases, improved dynamic_cast handling, tail-call optimization similar to Python, and more x86 SIMD intrinsic support. To address memory inefficiencies, dummy pointers were replaced with opaque pointers that store only a base and pointer path without full allocation. String pointers were introduced to directly reference AST nodes for string literals, saving memory and correctly disambiguating multiple evaluations of the same literal. Additionally, integers larger than or equal to 16 bits now require 24 bytes to carry a kind field and offset, enabling proper handling of pointer-to-integer casts in constant expressions.
Context
The Clang bytecode interpreter is an experimental feature in the Clang compiler that evaluates constant expressions at compile time. This post updates on recent developments, including new pointer types and integer representation changes.
Approach / What changed
Replaced dummy pointers with opaque pointers that store only a base and pointer path without memory allocation; added string pointers that reference AST nodes directly and use an ID field to disambiguate evaluations; increased integer representation to 24 bytes for integers >= 16 bits to support pointer-to-integer casts and address label differences.
Takeaways
1
Opaque pointers reduce compile-time memory usage by avoiding allocation for variables that are only referenced but not read or written in constant expressions.
2
String pointers use an ID field to disambiguate multiple evaluations of the same string literal, enabling correct pointer comparison in constant expressions.
3
To support pointer-to-integer casts, integers 16 bits or larger now occupy 24 bytes to store a kind field, offset, and optionally two pointers for address label differences.
FAQ
What are opaque pointers and why were they introduced?
Opaque pointers store only a base declaration or expression and an optional pointer path, without allocating memory for the variable. They replace dummy pointers to reduce compile-time memory usage and enable features like __builtin_object_size.
How does the bytecode interpreter handle string literal comparisons from different evaluations?
String pointers include an ID field that distinguishes multiple evaluations of the same string literal. This allows the interpreter to correctly reject comparisons of pointers that refer to different instances of the same literal, as required by C++.
Why did integers increase to 24 bytes in the bytecode interpreter?
To properly handle pointer-to-integer casts, integers now store a kind field and offset. For address label differences, two pointers are also stored, requiring 24 bytes for integers 16 bits or larger.
A bytecode interpreter is a compiler's output plus a loop that runs it. This explainer maps its five parts — bytecode, dispatch loop, runtime state, and the host boundary — and why the shape repeats.
Keep reading
Related reading
The Good Stuff
Paid picks we use ourselves. Links carry a referral code — a subscription through one earns us a commission at no extra cost to you.