|
| 1 | +# GCC as the intrinsic-spec reference — the three-layer drill-down |
| 2 | + |
| 3 | +> READ BY: anyone verifying what an intrinsic actually *does* before writing or |
| 4 | +> porting a SIMD kernel — `simd-savant`, `arm-neon-specialist`, and any session |
| 5 | +> touching `src/simd_*.rs`, the polyfill matryoshka, or a consumer-crate SIMD |
| 6 | +> swap. |
| 7 | +> |
| 8 | +> **Why this file exists:** the reference below was used across the NEON / |
| 9 | +> aarch64 / wasm planning work but was never written down. A 2026-07-27 sweep of |
| 10 | +> every URL host in every `.md` / `.rs` / `.toml` in this repo found no |
| 11 | +> intrinsic or ISA reference of any kind — the only spec-shaped citations were |
| 12 | +> four bare "Intel Intrinsics Guide" mentions with no link |
| 13 | +> (`vertical-simd-consumer-contract.md`) and one GCC file fetched off mutable |
| 14 | +> `master` (`agnostic-surface-cpu-matrix.md` §M). The link existed only in |
| 15 | +> session context. Recording it so it survives the session that knew it. |
| 16 | +
|
| 17 | +## The source |
| 18 | + |
| 19 | +**`github.com/gcc-mirror/gcc`** — mirror of `gcc.gnu.org`. Pin a commit; never |
| 20 | +cite `master` (a spec citation that moves under you is not a citation). |
| 21 | + |
| 22 | +Working pin used for the 2026-07-27 verification: |
| 23 | +`8f1698229d33a74cda7ec9f02575172df10b2774` |
| 24 | + |
| 25 | +``` |
| 26 | +https://raw.githubusercontent.com/gcc-mirror/gcc/<SHA>/<path> |
| 27 | +``` |
| 28 | + |
| 29 | +## The three layers — each answers a different question |
| 30 | + |
| 31 | +| layer | path | answers | |
| 32 | +|---|---|---| |
| 33 | +| **1. declarations** | `gcc/config/i386/*intrin.h`<br>`gcc/config/aarch64/arm_neon.h` | *What builtin does this intrinsic map to, and what are its exact C types?* | |
| 34 | +| **2. machine description** | `gcc/config/*/*.md` | *What instruction / RTL does that builtin lower to, and what are the bit encodings?* | |
| 35 | +| **3. conformance tests** | `gcc/testsuite/gcc.target/{i386,aarch64,arm,...}/` | *What does it compute?* — **where a runtime test exists**, an executable check with an **inline scalar reference implementation** | |
| 36 | + |
| 37 | +Layer 3 is the one people don't know about and is the most useful **when it |
| 38 | +applies** — but qualify the claim: `gcc.target` mixes runtime tests with |
| 39 | +compile-only, diagnostic, and codegen (`scan-assembler`) tests, and not every |
| 40 | +intrinsic has a runtime test with a scalar reference. The discriminator is the |
| 41 | +DejaGnu directive: `dg-do run` (executable) vs `dg-do compile` / `dg-do |
| 42 | +assemble` (no semantic validation). Where a `dg-do run` test with a scalar |
| 43 | +loop + `abort()`-style comparison exists, it is a per-intrinsic **oracle**, |
| 44 | +not prose — directly usable for the byte-parity discipline this workspace |
| 45 | +already applies elsewhere (tesseract-rs, stockfish-rs): port a kernel, then |
| 46 | +prove it against GCC's own definition of what the instruction computes rather |
| 47 | +than a hand-written reference. Where only a compile/scan test exists, layer 3 |
| 48 | +proves nothing about semantics — fall back to the ISA specification (Intel |
| 49 | +SDM / Arm ARM) as the authority, with layers 1-2 still pinning types and |
| 50 | +lowering. |
| 51 | + |
| 52 | +## Worked example — the question that motivated this file |
| 53 | + |
| 54 | +`_mm256_mul_epu32` vs `_mm256_mul_epi32`, needed for a `curve25519-dalek` |
| 55 | +SIMD swap onto `ndarray::simd`. |
| 56 | + |
| 57 | +**Layer 1** (`gcc/config/i386/avx2intrin.h`): |
| 58 | + |
| 59 | +```c |
| 60 | +_mm256_mul_epi32 (__m256i __X, __m256i __Y) |
| 61 | +{ return (__m256i) __builtin_ia32_pmuldq256 ((__v8si)__X, (__v8si)__Y); } |
| 62 | + |
| 63 | +_mm256_mul_epu32 (__m256i __A, __m256i __B) |
| 64 | +{ return (__m256i) __builtin_ia32_pmuludq256 ((__v8si)__A, (__v8si)__B); } |
| 65 | +``` |
| 66 | +
|
| 67 | +Both take `__v8si` and return `__m256i` — **identical C signatures**. The |
| 68 | +signed/unsigned distinction lives entirely in the instruction (VPMULDQ vs |
| 69 | +VPMULUDQ), not in the type. So the type system will not catch a mix-up here; |
| 70 | +only the semantics will. |
| 71 | +
|
| 72 | +**Layer 3** (`gcc/testsuite/gcc.target/i386/avx2-vpmuludq-2.c`) gives the |
| 73 | +semantics in one line: |
| 74 | +
|
| 75 | +```c |
| 76 | +for (i = 0; i < 4; i++) |
| 77 | + r[i] = s1[i * 2] * s2[i * 2]; /* unsigned int × unsigned int → unsigned long long */ |
| 78 | +``` |
| 79 | + |
| 80 | +i.e. **even 32-bit lanes only** (equivalently: the low 32 bits of each packed |
| 81 | +64-bit element), widening to 4 × u64. The odd lanes are ignored entirely. |
| 82 | +`avx2-vpmuldq-2.c` sits beside it as the signed twin — the pair is a ready-made |
| 83 | +differential oracle. |
| 84 | + |
| 85 | +## Honest limits |
| 86 | + |
| 87 | +- **Test filenames are not guessable.** `avx2-vpmuludq-2.c` and |
| 88 | + `avx2-vpermd-1.c` exist; `avx2-vpsrlvd-1.c` does not (that op is tested under |
| 89 | + a different name). Get a real directory listing rather than probing guesses. |
| 90 | +- **The GitHub *API* is scoped to session repos**, so `gcc-mirror/gcc` cannot be |
| 91 | + listed through it from here; `raw.githubusercontent.com` fetches work fine. |
| 92 | +- **GitHub *code search* excludes forks** — it silently returns 0 for files that |
| 93 | + demonstrably exist in this org's forked repos. Verified 2026-07-27: |
| 94 | + `filename:harvest_network.rs` returned 0 while the file exists at |
| 95 | + `AdaWorldAPI/ruff:crates/ruff_cpp_spo/examples/harvest_network.rs`. **Never |
| 96 | + treat a code-search miss on a fork as evidence of absence** — clone and grep. |
| 97 | +- Layer 3 covers what an intrinsic *computes*. It does not give latency or |
| 98 | + throughput; that is a separate question and a separate source. |
| 99 | + |
| 100 | +## Not harvested |
| 101 | + |
| 102 | +There is no baked/harvested copy of this spec set in the workspace. Checked |
| 103 | +2026-07-27 by local grep (not code search — see above): `ndarray` (tree + |
| 104 | +releases — it has none), `lance-graph` (tree + all 11 releases, which are model |
| 105 | +codebooks / corpus / topology data), `ruff` (5 harvest examples, all |
| 106 | +Tesseract/Leptonica C++), `curve25519-dalek`. The reference is consulted |
| 107 | +directly at a pinned SHA. |
| 108 | + |
| 109 | +Worth noting for anyone who wants one: `ruff_cpp_spo` already walks C++ headers |
| 110 | +via libclang and emits SPO manifests, and GCC's `*intrin.h` are plain C headers |
| 111 | +of exactly that shape — so a `harvest_intrinsics.rs` producing the full |
| 112 | +intrinsic → builtin → instruction table would be an extension of proven |
| 113 | +machinery rather than new machinery. Not built; recorded as an option. |
0 commit comments