My First LLVM Patch: AVX/AVX512 Subvector Insert Intrinsics in constexpr
In LLVM PR
#158778
I enabled constexpr support for AVX and AVX512 subvector insert
intrinsics, allowing code that uses helpers such as _mm256_insertf128_ps
to fold at compile time. The change removes a long-standing gap between the
runtime behavior of these intrinsics and the guarantees developers expect inside
constexpr functions.
Summary
-
Extended both of Clang's constant-evaluation engines
(
ExprConstant.cppandInterpBuiltin.cpp) so they understand the x86 insert builtins. - Added validation around vector sizes, subvector widths, and insertion offsets to match hardware semantics.
-
Landed over 40 new
TEST_CONSTEXPRcases in theclang/test/CodeGen/X86suite to lock in support across AVX and AVX512 variants.
Implementation Notes
Constant evaluation in Clang runs through two independent paths: AST evaluation during semantic analysis and the bytecode interpreter used by the experimental constexpr VM. Each path needed the same primitive:
- Fetch the base vector and the subvector operands.
- Verify element counts and derive the target lane from the immediate operand.
- Copy the subvector elements into the base vector while preserving
APValuemetadata.
The AST path lives in ExprConstant.cpp and manipulates
APValue directly, while the interpreter path adds bytecode handlers
in InterpBuiltin.cpp. Keeping the logic in sync required building
small helpers shared across both implementations.
Builtins and Headers
The Clang frontend maps intrinsics through BuiltinsX86.td into header
wrappers in clang/include/clang/Headers. Once the constant evaluator
gained support for the builtins listed there, existing user code (and the standard
Intel headers) immediately benefited without further changes. This also meant no
additional masking logic was necessary: the headers expand mask variations into
separate builtins, so the evaluator only needs to honor the immediate lane argument.
Testing
Reviewers asked for the new behavior to be exercised in the same files that cover
the rest of the x86 builtin matrix. I replaced an ad-hoc test with additions to
clang/test/CodeGen/X86/avx{,2}-builtins.cpp and related files, all
using TEST_CONSTEXPR to guarantee compile-time execution. A
representative case:
TEST_CONSTEXPR(match_v16si(
_mm512_mask_inserti32x4(base, 0x00F0, base, sub, 1),
2, 3, 4, 5, 20, 30, 40, 50, 10, 11, 12, 13, 14, 15, 16, 17));
These tests cover lane boundaries, mask interactions, and error paths to ensure both evaluators agree on the result.
Result
After two review rounds focused on naming consistency and LLVM formatting rules, the change was approved and merged. Issue #157709 is now closed, and constexpr users can rely on these intrinsics in table-generation and other compile-time SIMD workflows.