/simd-intrinsics
SIMD intrinsics skill for x86 (SSE/AVX) and ARM (NEON) vectorization. Use when reading auto-vectorization reports, writing SSE2/AVX2/NEON intrinsics, checking CPU feature flags at runtime, choosing between compiler builtins and raw intrinsics, or diagnosing why
$ npx -y skills add mohitmishra786/low-level-dev-skills --skill simd-intrinsics --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/simd-intrinsics
Context preview
The summary Claude sees to decide when to auto-load this skill.
SIMD intrinsics skill for x86 (SSE/AVX) and ARM (NEON) vectorization. Use when reading auto-vectorization reports, writing SSE2/AVX2/NEON intrinsics, checking CPU feature flags at runtime, choosing between compiler builtins and raw intrinsics, or diagnosing why
SKILL.md
simd-intrinsics.SKILL.mdname: simd-intrinsics
description: SIMD intrinsics skill for x86 (SSE/AVX) and ARM (NEON) vectorization. Use when reading auto-vectorization reports, writing SSE2/AVX2/NEON intrinsics, checking CPU feature flags at runtime, choosing between compiler builtins and raw intrinsics, or diagnosing why auto-vectorization failed. Activates on queries about SIMD, SSE2, AVX2, NEON, intrinsics, -fopt-info-vec, auto-vectorization, or vectorization failures.
SIMD Intrinsics
Purpose
Guide agents through SIMD: reading auto-vectorization output, writing SSE2/AVX2/NEON intrinsics, runtime CPU feature detection, and choosing between compiler auto-vectorization and manual intrinsics.
Triggers
- "How do I check if my loop is being auto-vectorized?"
- "How do I write SSE2/AVX2 intrinsics?"
- "Auto-vectorization failed — how do I fix it?"
- "How do I check for CPU features at runtime?"
- "Should I use intrinsics or let the compiler vectorize?"
- "How do I write NEON intrinsics for ARM?"
Workflow
1. Check auto-vectorization
# GCC: show vectorization info
gcc -O2 -march=native -fopt-info-vec src/hot.c -o hot
# Verbose: show missed + successful
gcc -O2 -march=native -fopt-info-vec-missed -fopt-info-vec-optimized src/hot.c
# Clang: vectorization remarks
clang -O2 -march=native \
-Rpass=loop-vectorize \
-Rpass-missed=loop-vectorize \
-Rpass-analysis=loop-vectorize \
src/hot.c -o hot
# Example missed message:
# hot.c:15:5: remark: loop not vectorized: value that could not be identified as
# reduction is used outside the loop [-Rpass-missed=loop-vectorize]Common auto-vectorization blockers:
| Blocker | Fix | |---------|-----| | Loop-carried dependency | Restructure to remove dependency | | Data-dependent exit (early return) | Move exit after loop | | Non-contiguous memory | Use gather/scatter or restructure | | Aliasing (pointer may alias) | Add `__restrict__` or `restrict` | | Unknown trip count | Add `__builtin_expect` or hint | | Function call in loop body | Inline the function |
// Help the compiler by adding restrict
void add_arrays(float * __restrict__ dst,
const float * __restrict__ a,
const float * __restrict__ b,
size_t n) {
for (size_t i = 0; i < n; i++)
dst[i] = a[i] + b[i]; // Now vectorizable
}2. Runtime CPU feature detection
// Linux: use __builtin_cpu_supports (GCC/Clang)
if (__builtin_cpu_supports("avx2")) {
process_avx2(data, len);
} else if (__builtin_cpu_supports("sse4.2")) {
process_sse42(data, len);
} else {
process_scalar(data, len);
}
// Check specific features:
__builtin_cpu_supports("sse2")
__builtin_cpu_supports("sse4.1")
__builtin_cpu_supports("sse4.2")
__builtin_cpu_supports("avx")
__builtin_cpu_supports("avx2")
__builtin_cpu_supports("avx512f")
__builtin_cpu_supports("bmi")
__builtin_cpu_supports("bmi2")
__builtin_cpu_supports("fma")// Portable: use CPUID directly
#include <cpuid.h>
static int has_avx2(void) {
unsigned int eax, ebx, ecx, edx;
// CPUID leaf 7, subleaf 0
__cpuid_count(7, 0, eax, ebx, ecx, edx);
return (ebx >> 5) & 1; // bit 5 = AVX2
}3. SSE2 / SSE4.2 intrinsics (x86)
#include <immintrin.h> // All x86 intrinsics
// SSE2: 128-bit vectors
// __m128 = 4 floats
// __m128d = 2 doubles
// __m128i = integers (8x16, 4x32, 2x64, 16x8)
void sum_floats_sse2(float *dst, const float *a, const float *b, int n) {
int i = 0;
for (; i <= n - 4; i += 4) {
__m128 va = _mm_loadu_ps(a + i); // unaligned load
__m128 vb = _mm_loadu_ps(b + i);
__m128 vc = _mm_add_ps(va, vb);
_mm_storeu_ps(dst + i, vc); // unaligned store
}
// Handle remainder
for (; i < n; i++) dst[i] = a[i] + b[i];
}4. AVX2 intrinsics (x86)
#ifdef __AVX2__
#include <immintrin.h>
// __m256 = 8 floats, __m256d = 4 doubles, __m256i = integers
void sum_floats_avx2(float *dst, const float *a, const float *b, int n) {
int i = 0;
for (; i <= n - 8; i += 8) {
__m256 va = _mm256_loadu_ps(a + i);
__m256 vb = _mm256_loadu_ps(b + i);
__m256 vc = _mm256_add_ps(va, vb);
_mm256_storeu_ps(dst + i, vc);
}
// SSE2 tail (4 elements)
for (; i <= n - 4; i += 4) {
__m128 va = _mm_loadu_ps(a + i);
__m128 vb = _mm_loadu_ps(b + i);
_mm_storeu_ps(dst + i, _mm_add_ps(va, vb));
}
// Scalar tail
for (; i < n; i++) dst[i] = a[i] + b[i];
}
// Fused multiply-add (FMA) — 1 instruction for a*b+c
void fma_avx2(float *dst, const float *a, const float *b, const float *c, int n) {
for (int i = 0; i <= n - 8; i += 8) {
__m256 va = _mm256_loadu_ps(a + i);
__m256 vb = _mm256_loadu_ps(b + i);
__m256 vc = _mm256_loadu_ps(c + i);
_mm256_storeu_ps(dst + i, _mm256_fmadd_ps(va, vb, vc)); // dst = a*b + c
}
}
#endifCompile with: `gcc -O2 -mavx2 -mfma src/simd.c`
5. NEON intrinsics (ARM/AArch64)
#include <arm_neon.h>
// float32x4_t = 4 floats (128-bit)
// float32x8_t = 8 floats (ARM SVE — scalable)
// uint8x16_t = 16 bytes
// int32x4_t = 4 int32
void sum_floats_neon(float *dst, const float *a, const float *b, int n) {
int i = 0;
for (; i <= n - 4; i += 4) {
float32x4_t va = vld1q_f32(a + i); // load 4 floats
float32x4_t vb = vld1q_f32(b + i);
float32x4_t vc = vaddq_f32(va, vb); // add
vst1q_f32(dst + i, vc); // store 4 floats
}
for (; i < n; i++) dst[i] = a[i] + b[i];
}
// AArch64 FMA
void fma_neon(float *dst, const float *a, const float *b, const float *c, int n) {
for (int i = 0; i <= n - 4; i += 4) {
float32x4_t va = vld1q_f32(a + i);
float32x4_t vb = vld1q_f32(b + i);
float32x4_t vc = vld1q_f32(c + i);
vst1q_f32(dst + i, vfmaq_f32(vc, va, vb)); // vc + va*vb
}
}Compile with: `gcc -O2 -march=armv8-a+simd src/simd.c`
6. Choose aut
Read more
name: simd-intrinsics description: SIMD intrinsics skill for x86 (SSE/AVX) and ARM (NEON) vectorization. Use when reading auto-vectorization reports, writing SSE2/AVX2/NEON intrinsics, checking CPU feature flags at runtime, choosing between compiler builtins and raw intrinsics, or diagnosing why auto-vectorization failed. Activates on queries about SIMD, SSE2, AVX2, NEON, intrinsics, -fopt-info-vec, auto-vectorization, or vectorization failures.
SIMD Intrinsics
Purpose
Guide agents through SIMD: reading auto-vectorization output, writing SSE2/AVX2/NEON intrinsics, runtime CPU feature detection, and choosing between compiler auto-vectorization and manual intrinsics.
Triggers
- "How do I check if my loop is being auto-vectorized?"
- "How do I write SSE2/AVX2 intrinsics?"
- "Auto-vectorization failed — how do I fix it?"
- "How do I check for CPU features at runtime?"
- "Should I use intrinsics or let the compiler vectorize?"
- "How do I write NEON intrinsics for ARM?"
Workflow
1. Check auto-vectorization
# GCC: show vectorization info
gcc -O2 -march=native -fopt-info-vec src/hot.c -o hot
# Verbose: show missed + successful
gcc -O2 -march=native -fopt-info-vec-missed -fopt-info-vec-optimized src/hot.c
# Clang: vectorization remarks
clang -O2 -march=native \
-Rpass=loop-vectorize \
-Rpass-missed=loop-vectorize \
-Rpass-analysis=loop-vectorize \
src/hot.c -o hot
# Example missed message:
# hot.c:15:5: remark: loop not vectorized: value that could not be identified as
# reduction is used outside the loop [-Rpass-missed=loop-vectorize]Common auto-vectorization blockers:
| Blocker | Fix | |---------|-----| | Loop-carried dependency | Restructure to remove dependency | | Data-dependent exit (early return) | Move exit after loop | | Non-contiguous memory | Use gather/scatter or restructure | | Aliasing (pointer may alias) | Add `__restrict__` or `restrict` | | Unknown trip count | Add `__builtin_expect` or hint | | Function call in loop body | Inline the function |
// Help the compiler by adding restrict
void add_arrays(float * __restrict__ dst,
const float * __restrict__ a,
const float * __restrict__ b,
size_t n) {
for (size_t i = 0; i < n; i++)
dst[i] = a[i] + b[i]; // Now vectorizable
}2. Runtime CPU feature detection
// Linux: use __builtin_cpu_supports (GCC/Clang)
if (__builtin_cpu_supports("avx2")) {
process_avx2(data, len);
} else if (__builtin_cpu_supports("sse4.2")) {
process_sse42(data, len);
} else {
process_scalar(data, len);
}
// Check specific features:
__builtin_cpu_supports("sse2")
__builtin_cpu_supports("sse4.1")
__builtin_cpu_supports("sse4.2")
__builtin_cpu_supports("avx")
__builtin_cpu_supports("avx2")
__builtin_cpu_supports("avx512f")
__builtin_cpu_supports("bmi")
__builtin_cpu_supports("bmi2")
__builtin_cpu_supports("fma")// Portable: use CPUID directly
#include <cpuid.h>
static int has_avx2(void) {
unsigned int eax, ebx, ecx, edx;
// CPUID leaf 7, subleaf 0
__cpuid_count(7, 0, eax, ebx, ecx, edx);
return (ebx >> 5) & 1; // bit 5 = AVX2
}3. SSE2 / SSE4.2 intrinsics (x86)
#include <immintrin.h> // All x86 intrinsics
// SSE2: 128-bit vectors
// __m128 = 4 floats
// __m128d = 2 doubles
// __m128i = integers (8x16, 4x32, 2x64, 16x8)
void sum_floats_sse2(float *dst, const float *a, const float *b, int n) {
int i = 0;
for (; i <= n - 4; i += 4) {
__m128 va = _mm_loadu_ps(a + i); // unaligned load
__m128 vb = _mm_loadu_ps(b + i);
__m128 vc = _mm_add_ps(va, vb);
_mm_storeu_ps(dst + i, vc); // unaligned store
}
// Handle remainder
for (; i < n; i++) dst[i] = a[i] + b[i];
}4. AVX2 intrinsics (x86)
#ifdef __AVX2__
#include <immintrin.h>
// __m256 = 8 floats, __m256d = 4 doubles, __m256i = integers
void sum_floats_avx2(float *dst, const float *a, const float *b, int n) {
int i = 0;
for (; i <= n - 8; i += 8) {
__m256 va = _mm256_loadu_ps(a + i);
__m256 vb = _mm256_loadu_ps(b + i);
__m256 vc = _mm256_add_ps(va, vb);
_mm256_storeu_ps(dst + i, vc);
}
// SSE2 tail (4 elements)
for (; i <= n - 4; i += 4) {
__m128 va = _mm_loadu_ps(a + i);
__m128 vb = _mm_loadu_ps(b + i);
_mm_storeu_ps(dst + i, _mm_add_ps(va, vb));
}
// Scalar tail
for (; i < n; i++) dst[i] = a[i] + b[i];
}
// Fused multiply-add (FMA) — 1 instruction for a*b+c
void fma_avx2(float *dst, const float *a, const float *b, const float *c, int n) {
for (int i = 0; i <= n - 8; i += 8) {
__m256 va = _mm256_loadu_ps(a + i);
__m256 vb = _mm256_loadu_ps(b + i);
__m256 vc = _mm256_loadu_ps(c + i);
_mm256_storeu_ps(dst + i, _mm256_fmadd_ps(va, vb, vc)); // dst = a*b + c
}
}
#endifCompile with: `gcc -O2 -mavx2 -mfma src/simd.c`
5. NEON intrinsics (ARM/AArch64)
#include <arm_neon.h>
// float32x4_t = 4 floats (128-bit)
// float32x8_t = 8 floats (ARM SVE — scalable)
// uint8x16_t = 16 bytes
// int32x4_t = 4 int32
void sum_floats_neon(float *dst, const float *a, const float *b, int n) {
int i = 0;
for (; i <= n - 4; i += 4) {
float32x4_t va = vld1q_f32(a + i); // load 4 floats
float32x4_t vb = vld1q_f32(b + i);
float32x4_t vc = vaddq_f32(va, vb); // add
vst1q_f32(dst + i, vc); // store 4 floats
}
for (; i < n; i++) dst[i] = a[i] + b[i];
}
// AArch64 FMA
void fma_neon(float *dst, const float *a, const float *b, const float *c, int n) {
for (int i = 0; i <= n - 4; i += 4) {
float32x4_t va = vld1q_f32(a + i);
float32x4_t vb = vld1q_f32(b + i);
float32x4_t vc = vld1q_f32(c + i);
vst1q_f32(dst + i, vfmaq_f32(vc, va, vb)); // vc + va*vb
}
}Compile with: `gcc -O2 -march=armv8-a+simd src/simd.c`
6. Choose aut
A curated suite of AI agent skills for systems and low-level programming — C/C++, Rust, Zig, GPU, bare-metal firmware, Linux kernel/driver development, computer architecture, compiler internals, HPC, and more.
Repo: mohitmishra786/low-level-dev-skills
Other skills on low-level-dev-skills.
- /custom-allocators
Custom allocator skill for memory allocation strategies. Use when implementing pool/slab/arena allocators, tuning jemalloc/mimalloc, writing Rust GlobalAlloc, or benchmarking allocator performance. Activates on queries about jemalloc, mimalloc, tcmalloc, arena allocator,
Open skill - /numa-programming
NUMA programming skill for multi-socket memory locality. Use when detecting NUMA topology, binding processes with numactl, using libnuma API, building NUMA-aware data structures, or measuring remote access penalties. Activates on queries about numactl, libnuma, NUMA topology,
Open skill - /af-xdp
AF_XDP skill for high-performance XDP sockets. Use when creating AF_XDP sockets, configuring UMEM and XSK rings, XDP_REDIRECT programs, copy vs zero-copy mode, or comparing with DPDK. Activates on queries about AF_XDP, xsk_umem, XDP_REDIRECT, libbpf xsk, or zero-copy XDP.
Open skill - /dpdk
DPDK skill for userspace packet I/O. Use when initializing EAL, configuring PMD drivers, using mbuf pools and rte_ring, setting up huge pages, RSS, or testpmd validation. Activates on queries about DPDK, EAL, rte_eth_rx_burst, hugepages, PMD, or testpmd.
Open skill - /io-uring
io_uring skill for Linux async I/O. Use when building high-performance servers with liburing, multi-shot operations, provided buffers, fixed files, zero-copy send, or tokio-uring. Activates on queries about io_uring, SQE/CQE, liburing, IORING_OP_PROVIDE_BUFFERS, or io_uring vs
Open skill - /adc-dac-baremetal
Bare-metal ADC and DAC skill. Use when configuring analog sampling, DMA-driven ADC, calibration, or DAC output on MCUs. Activates on queries about ADC bare-metal, sampling time, DMA ADC, or DAC channel setup.
Open skill

