Constexpr X86 Vector Element Operations in Clang
This post documents LLVM PR
#161302,
where I enabled constexpr evaluation for the x86 element
extract/insert builtins that back Intel's MMX, SSE, and AVX2 intrinsics. The work
continues the
previous patch
and completes the basic SIMD element operations needed for compile-time table
generation.
Goals
-
Bring parity between runtime and constexpr behavior for
__builtin_ia32_vec_ext_*and__builtin_ia32_vec_set_*. -
Preserve architectural quirks such as index masking
(
index & (NumElts - 1)) so constexpr execution matches hardware results. - Keep the AST evaluator and bytecode interpreter in sync, preventing divergence between the two constant-evaluation engines.
Design and Implementation
The targeted builtins span 64-bit MMX vectors through 256-bit AVX2 vectors, covering signed/unsigned integers and floats. Each builtin follows the same pattern:
- Normalize operands (vector value, element value, immediate index).
- Mask the index to the vector width.
- Either read or write the lane and return a new
APValue.
Clang's dual evaluator required two sets of changes:
-
ExprConstant.cpp: teachVectorExprEvaluatorto interpret the insert/extract builtins directly from the AST usingAPValuehelpers. -
InterpBuiltin.cpp: add bytecode handlers that operate on the constexpr VM's register model, with explicit type switching for integer and floating-point elements.
While prototyping I attempted to share logic via the TYPE_SWITCH
macro, but the macro expands to pointer types that lack toAPSInt().
The final implementation keeps the float case separate and uses
INT_TYPE_SWITCH_NO_BOOL for the integer matrix. I filed issue
#161685
to track a cleaner abstraction.
Testing
Support landed alongside updates to the existing x86 builtin tests:
clang/test/CodeGen/X86/mmx-builtins.cclang/test/CodeGen/X86/sse{2,41}-builtins.cclang/test/CodeGen/X86/avx2-builtins.c
Each file now exercises the relevant extract/set intrinsics under
TEST_CONSTEXPR, covering lane masking, type conversions, and boundary
conditions. Example:
TEST_CONSTEXPR(_mm_extract_epi16(vec16i, 5) == vec16i[5 & 0x3]);
TEST_CONSTEXPR(_mm256_insert_epi32(vec8i, value, 18) ==
replace_lane(vec8i, value, 18 & 0x7));
The tests ensure both evaluators agree and that regressions are caught by the standard Clang test suite.
Outcome
The patch resolves issue #159753 and unlocks constexpr usage for the remaining x86 element operations. Together with PR #158778, users can now construct and deconstruct SIMD data entirely at compile time, making it easier to build lookup tables and perform metaprogramming in header-only libraries.