Skip to content

ansi-c: declare ARM/AArch64 NEON builtins#9039

Draft
tautschnig wants to merge 7 commits into
diffblue:developfrom
tautschnig:neon_builtins
Draft

ansi-c: declare ARM/AArch64 NEON builtins#9039
tautschnig wants to merge 7 commits into
diffblue:developfrom
tautschnig:neon_builtins

Conversation

@tautschnig

@tautschnig tautschnig commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

Depends-on: #9041

Add gcc_builtin_headers_aarch64.h (Clang _builtin_neon* declarations, generated by clang_builtins.py from clang-tblgen -gen-arm-neon-sema) and wire it into the front-end like the other per-target builtin headers: extern + string constant in ansi_c_internal_additions, a find_pattern() lookup in the ARM branch of builtin_factory, and the .inc generation rules in the Makefile and CMakeLists. The NEON builtins are polymorphic (arm_neon.h casts operands to the representative lane type and passes a NeonTypeFlags code), so each has a single concrete __gcc_v* signature.

  • Each commit message has a non-empty body, explaining why the change was made.
  • Methods or procedures I have added are documented, following the guidelines provided in CODING_STANDARD.md.
  • The feature or user visible behaviour I have added or modified has been documented in the User Guide in doc/cprover-manual/
  • Regression or unit tests are included, or existing tests cover the modified code (in this case I have detailed which ones those are in the commit message).
  • My commit message includes data points confirming performance improvements (if claimed).
  • My PR is restricted to a single feature or bugfix.
  • White-space or formatting changes outside the feature-related changed lines are in commits of their own.

@tautschnig tautschnig self-assigned this Jun 15, 2026
Copilot AI review requested due to automatic review settings June 15, 2026 18:39

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds support for parsing/declaring AArch64 NEON (__builtin_neon_*) builtins by introducing a new per-target GCC builtin header and wiring it into the ANSI-C front-end builtin lookup.

Changes:

  • Add a generated gcc_builtin_headers_aarch64.h and its corresponding .inc integration.
  • Extend builtin lookup to consult the AArch64 builtin header in the ARM-related path.
  • Update Makefile/CMake to generate/ship the new .inc file.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/ansi-c/compiler_headers/gcc_builtin_headers_aarch64.h New generated declarations for AArch64 NEON builtins
src/ansi-c/builtin_factory.cpp Consult AArch64 builtin header during builtin resolution
src/ansi-c/ansi_c_internal_additions.h Declare new builtin-header string symbol for AArch64
src/ansi-c/ansi_c_internal_additions.cpp Define builtin-header string for AArch64 and include generated .inc
src/ansi-c/Makefile Add AArch64 .inc file to builtin generation list
src/ansi-c/CMakeLists.txt Add AArch64 .inc generation and dependencies

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

float __builtin_neon_vabds_f32(float, float);
__gcc_v8qi __builtin_neon_vabs_f16(__gcc_v8qi, int);
__gcc_v8qi __builtin_neon_vabs_v(__gcc_v8qi, int);
int64_t int64_t __builtin_neon_vabsd_s64(void);
Comment on lines +23 to +33
int64_t int64_t int64_t __builtin_neon_vaddd_s64(void);
unsigned int64_t unsigned int64_t unsigned int64_t __builtin_neon_vaddd_u64(void);
__gcc_v8qi __builtin_neon_vaddhn_v(__gcc_v16qi, __gcc_v16qi, int);
int __builtin_neon_vaddlv_s16(__gcc_v4hi);
int64_t __gcc_v2si __builtin_neon_vaddlv_s32(void);
short __builtin_neon_vaddlv_s8(__gcc_v8qi);
int __builtin_neon_vaddlvq_s16(__gcc_v8hi);
int64_t __gcc_v4si __builtin_neon_vaddlvq_s32(void);
short __builtin_neon_vaddlvq_s8(__gcc_v16qi);
unsigned int __builtin_neon_vaddlvq_u16(__gcc_v8uhi);
unsigned int64_t __gcc_v4usi __builtin_neon_vaddlvq_u32(void);
Comment on lines +241 to +244
double __builtin_neon_vcvtd_n_f64_s64(int64_t int);
double __builtin_neon_vcvtd_n_f64_u64(unsigned int64_t int);
int64_t double __builtin_neon_vcvtd_n_s64_f64(int);
unsigned int64_t double __builtin_neon_vcvtd_n_u64_f64(int);
Comment on lines +733 to +734
int __builtin_neon_vqrshrnd_n_s64(int64_t int);
unsigned int __builtin_neon_vqrshrnd_n_u64(unsigned int64_t int);
__gcc_v16qi __builtin_neon_vldap1q_lane_p64(const void *, __gcc_v16qi, int, int);
__gcc_v16qi __builtin_neon_vldap1q_lane_s64(const void *, __gcc_v16qi, int, int);
__gcc_v16qi __builtin_neon_vldap1q_lane_u64(const void *, __gcc_v16qi, int, int);
const unsigned __int128_t void * __builtin_neon_vldrq_p128(void);
Comment on lines 206 to 212
{
if(find_pattern(pattern, gcc_builtin_headers_arm, s))
return convert(identifier, s, symbol_table, mh);

if(find_pattern(pattern, gcc_builtin_headers_aarch64, s))
return convert(identifier, s, symbol_table, mh);
}
@codecov

codecov Bot commented Jun 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.68%. Comparing base (0139d01) to head (ad215fc).

Files with missing lines Patch % Lines
src/ansi-c/builtin_factory.cpp 0.00% 2 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##           develop    #9039   +/-   ##
========================================
  Coverage    80.68%   80.68%           
========================================
  Files         1713     1713           
  Lines       189499   189501    +2     
  Branches        73       73           
========================================
+ Hits        152890   152894    +4     
+ Misses       36609    36607    -2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

tautschnig and others added 7 commits June 16, 2026 15:05
As of LLVM 20 the per-target builtin databases were migrated from the X-macro
".def" files to TableGen ".td", and NEON/SVE builtins are emitted by clang-tblgen
into a "..._BUILTIN_INFOS" form using the classic compact type encoding. Rewrite
clang_builtins.py to parse the TableGen .td databases directly, and add a
--inc PREFIX:PATH mode that parses clang-tblgen-generated .inc files (e.g. NEON
from -gen-arm-neon-sema), prepending PREFIX to each spelling.

Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
The compact-encoding decoder treated the width-modified integer types Wi
(64-bit), Zi (32-bit) and LLLi (128-bit) as non-terminating prefixes mapped to
int64_t/int32_t/__int128_t. As a result a following type was merged into the
same one (e.g. WiWi -> "int64_t int64_t" rather than a 64-bit return plus a
64-bit argument), and the unsigned forms produced invalid C ("unsigned
int64_t"). These show up in the ARM NEON scalar builtins (vabsd_s64,
vaddlvq_u32, vcvtd_n_u64_f64, vqrshrnd_n_u64, vaddq_p128, vmull_p64, ...).

Treat Wi/Zi/LLLi as complete types ("long long"/"int"/"__int128") that
terminate the prefix, with U/S applying as the sign, and alias the resulting
"long long" element to the existing vector typedef key so int64 vectors still
resolve. uint64x1 vectors remain skipped as CBMC has no __gcc_v1udi typedef.

Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
The TableGen .td walker and the compact-encoding decoder are the pieces most
likely to break silently when LLVM changes its emitters, and nothing in CI
exercises this maintainer script. Add a --self-test flag that round-trips a
one-line X86Builtin def through process_td, checks a handful of
decode_encoding cases (including the Wi/Zi/LLLi width-modified integer types
and a half-float scalar), guards that a vector without a lane count is
reported as unmappable rather than crashing, and runs process_inc on a
one-entry BUILTIN_INFOS snippet.

Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
Embed builtin headers as a C character-array initialiser ({ 'a', 'b', ..., 0 })
rather than a string literal. String literals are limited to 65536 characters
after concatenation -- a limit clang enforces under -pedantic -- which forced
large headers (e.g. the ia32 ones) to be split across several files; a
character array has no such limit. The #line directive that the use sites used
to prepend as a separate string literal is now baked into the array by
file_converter, so each use site is just `const char x[] = #include "x.inc";`.

This unblocks embedding arbitrarily large generated headers and lets the
artificially split headers be recombined (done separately).

Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
The ia32 GCC builtin declarations were split across nine headers
(gcc_builtin_headers_ia32.h plus -2..-9) solely to keep each embedded string
literal under the 65536-character limit. Now that file_converter emits a
character-array initialiser with no such limit, fold them back into a single
gcc_builtin_headers_ia32.h and drop the now-redundant per-file symbols,
find_pattern lookups, and build rules.

Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
Add gcc_builtin_headers_aarch64.h (Clang __builtin_neon_* declarations,
generated by clang_builtins.py from clang-tblgen -gen-arm-neon-sema) and wire
it into the front-end like the other per-target builtin headers: extern + string
constant in ansi_c_internal_additions, a find_pattern() lookup in the ARM branch
of builtin_factory, and the .inc generation rules in the Makefile and
CMakeLists. The NEON builtins are polymorphic (arm_neon.h casts operands to the
representative lane type and passes a NeonTypeFlags code), so each has a single
concrete __gcc_v* signature.

Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
Regenerate gcc_builtin_headers_aarch64.h with the corrected clang_builtins.py
decoder: the width-modified integer encodings Wi/Zi/LLLi are now rendered as
complete C types, fixing the malformed prototypes Copilot flagged (e.g.
"int64_t int64_t __builtin_neon_vabsd_s64(void)" becomes "long long
__builtin_neon_vabsd_s64(long long)"). The set otherwise tracks the LLVM
version of the arm_neon.td used to regenerate it.

Give arm64 (AArch64) its own arch branch in builtin_factory that searches only
the AArch64 header: AArch64 has no 32-bit-only builtins, and searching the
32-bit ARM header first could let an ARM signature win for a NEON name shared
by both architectures.

Drop the "#line" string-literal prefix from the AArch64 header embedding: now
that file_converter emits a character-array initialiser, the directive is baked
into the array and a string-literal prefix can no longer be concatenated to it.

Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants