Source profileQuality 95/100

dotnet/skills/plugins/dotnet-experimental/skills/exp-simd-vectorization/SKILL.md

exp-simd-vectorization

Optimizes hot-path scalar loops in .NET 8+ with cross-platform Vector128/Vector256/Vector512 SIMD intrinsics, or replaces manual math loops with single TensorPrimitives API calls. Covers byte-range validation, character counting, bulk bitwise ops, cross-type conversion, fused multi-array computations, and float/double math operations.

Source repository stars
5,248
Declared platforms
0
Static risk flags
0
Last source update
2026-08-26
Source checked
2026-08-26

Decision brief

What it does: where it fits

Optimizes hot-path scalar loops in . NET 8+ with cross-platform Vector128/Vector256/Vector512 SIMD intrinsics, or replaces manual math loops with single TensorPrimitives API calls.

Best for

    Not for

    • Tasks that require unconfirmed production actions or broad system permissions.
    • Environments where the pinned source and install steps cannot be inspected.

    Compatibility matrix

    Platform support, with evidence labels

    PlatformStatusEvidenceWhat to check
    CodexNot declaredNo explicit evidencePortability before use
    Claude CodeNot declaredNo explicit evidencePortability before use
    CursorNot declaredNo explicit evidencePortability before use
    Gemini CLINot declaredNo explicit evidencePortability before use
    Open the compatibility checker

    Installation

    Inspect first. Install second.

    The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

    Source-detected install commandSource
    npx skills add https://github.com/dotnet/skills --skill "plugins/dotnet-experimental/skills/exp-simd-vectorization"
    Safe inspection promptEditorial

    Inspect the Agent Skill "exp-simd-vectorization" from https://github.com/dotnet/skills/blob/1b896e91feb0f613cb54a914f1efd2897810ae02/plugins/dotnet-experimental/skills/exp-simd-vectorization/SKILL.md at commit 1b896e91feb0f613cb54a914f1efd2897810ae02. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

    Workflow

    What the source asks the agent to do

    1. 01

      Decision Gate

      1. Check Span and MemoryExtensions first. If the operation can be expressed using built-in Span methods (e.g., Contains, IndexOf, CopyTo, SequenceEqual) or MemoryExtensions, use them — no additional dependency is needed and the runtime already vectorizes many of these internally…

      Check Span and MemoryExtensions first. If the operation can be expressed using built-in Span methods (e.g., Contains, IndexOf, CopyTo, SequenceEqual) or MemoryExtensions, use them — no additional dependency is needed an…Check for TensorPrimitives next. If one or more TensorPrimitives methods cover the operation → use them. If the .csproj does NOT already reference System.Numerics.Tensors, add the package, for example: (or use the versi…Scalar loop over contiguous array/span of byte, sbyte, short, ushort, int, uint, long, ulong, nint, nuint, float, double (and char via reinterpretation as ushort)? → Implement with explicit Vector128 / Vector256 / Vecto…
    2. 02

      TensorPrimitives API Reference

      TensorPrimitives APIs are generic and work for any primitive type that satisfies the method's generic constraints — not just float/double. For example, Sum requires IAdditionOperators + IAdditiveIdentity and works for all primitive numeric types, while CosineSimilarity requires…

      TensorPrimitives APIs are generic and work for any primitive type that satisfies the method's generic constraints — not just float/double. For example, Sum requires IAdditionOperators + IAdditiveIdentity and works for a…AddMultiply and MultiplyAdd are distinct — they optimize differently depending on whether the dependency chain flows from the addend or the multiplier. FusedMultiplyAdd is the IEEE 754 fused form of (xy)+z with a single…
    3. 03

      Reductions (span → scalar)

      Review the “Reductions (span → scalar)” section in the pinned source before continuing.

      Review and apply the “Reductions (span → scalar)” source section.
    4. 04

      Element-wise transforms (span → span)

      Review the “Element-wise transforms (span → span)” section in the pinned source before continuing.

      Review and apply the “Element-wise transforms (span → span)” source section.
    5. 05

      Two-span operations (a, b → dst)

      Review the “Two-span operations (a, b → dst)” section in the pinned source before continuing.

      Review and apply the “Two-span operations (a, b → dst)” source section.

    Permission review

    Static risk signals and limitations

    No configured static risk pattern was detected

    This is not proof of safety. Runtime behavior, indirect dependencies, and hidden external systems are outside the static scan.

    Evidence record

    Why each signal appears

    EvidenceSourceComputedTestedEditorial
    SignalValueEvidence typeMeaning
    Quality score95/100ComputedDocumentation, specificity, maintenance, and trust rules
    Repository stars5,248SourceRepository attention, not individual Skill quality
    Compatibility0 platformsSourceDeclared in the catalog source record
    Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

    Pinned source

    Provenance and original SKILL.md

    Repository
    dotnet/skills
    Skill path
    plugins/dotnet-experimental/skills/exp-simd-vectorization/SKILL.md
    Commit
    1b896e91feb0f613cb54a914f1efd2897810ae02
    License
    MIT
    Collected
    2026-08-26
    Default branch
    main
    View the original SKILL.md

    SIMD Vectorization

    Decision Gate

    1. Check Span<T> and MemoryExtensions first. If the operation can be expressed using built-in Span<T> methods (e.g., Contains, IndexOf, CopyTo, SequenceEqual) or MemoryExtensions, use them — no additional dependency is needed and the runtime already vectorizes many of these internally.
    2. Check for TensorPrimitives next. If one or more TensorPrimitives methods cover the operation → use them. If the .csproj does NOT already reference System.Numerics.Tensors, add the package, for example: <PackageReference Include="System.Numerics.Tensors" /> (or use the versioning approach already used by your solution). Then replace the scalar loop with TP calls and stop. See the full API table below. Compose multiple TP calls when needed (e.g., finding both min and max → TensorPrimitives.Min(span) + TensorPrimitives.Max(span) as two calls). Do NOT write manual Vector128 code for operations TP already handles.
    3. Scalar loop over contiguous array/span of byte, sbyte, short, ushort, int, uint, long, ulong, nint, nuint, float, double (and char via reinterpretation as ushort)? → Implement with explicit Vector128<T> / Vector256<T> / Vector512<T> intrinsics using the patterns below.
    4. No contiguous numeric arrays to process (dictionary lookups, tree traversals, linked lists, state machines, string formatting, small collections, enum comparisons, recursive algorithms, decimal arithmetic)? → Report [NO SIMD OPPORTUNITY] and write a full paragraph explaining WHY, referencing the specific code characteristics that prevent vectorization (e.g., "State machines require sequential branching on enum values — there are no contiguous numeric arrays to process in parallel, and each transition depends on the previous state"). This explanation is graded.

    TensorPrimitives API Reference

    TensorPrimitives APIs are generic and work for any primitive type that satisfies the method's generic constraints — not just float/double. For example, Sum requires IAdditionOperators<T,T,T> + IAdditiveIdentity<T,T> and works for all primitive numeric types, while CosineSimilarity requires IRootFunctions<T> and only works for float/double. If the project doesn't already reference System.Numerics.Tensors, add it to the .csproj. Replace the entire manual loop with one or more TensorPrimitives calls as needed (prefer a single call when possible):

    Reductions (span → scalar)

    OperationAPI
    SumTensorPrimitives.Sum(span)
    Sum of squaresTensorPrimitives.SumOfSquares(span)
    Sum of magnitudes (L1 norm)TensorPrimitives.SumOfMagnitudes(span)
    L2 normTensorPrimitives.Norm(span)
    Product of all elementsTensorPrimitives.Product(span)
    Min valueTensorPrimitives.Min(span)
    Max valueTensorPrimitives.Max(span)
    Index of maxTensorPrimitives.IndexOfMax(span)
    Index of minTensorPrimitives.IndexOfMin(span)
    Dot productTensorPrimitives.Dot(a, b)
    Cosine similarityTensorPrimitives.CosineSimilarity(a, b)
    Euclidean distanceTensorPrimitives.Distance(a, b)

    Element-wise transforms (span → span)

    OperationAPI
    NegateTensorPrimitives.Negate(src, dst)
    AbsTensorPrimitives.Abs(src, dst)
    SqrtTensorPrimitives.Sqrt(src, dst)
    ExpTensorPrimitives.Exp(src, dst)
    LogTensorPrimitives.Log(src, dst)
    Log2TensorPrimitives.Log2(src, dst)
    TanhTensorPrimitives.Tanh(src, dst)
    SigmoidTensorPrimitives.Sigmoid(src, dst)
    SoftMaxTensorPrimitives.SoftMax(src, dst)
    SinhTensorPrimitives.Sinh(src, dst)
    CoshTensorPrimitives.Cosh(src, dst)
    RoundTensorPrimitives.Round(src, dst)
    FloorTensorPrimitives.Floor(src, dst)
    CeilingTensorPrimitives.Ceiling(src, dst)
    CopySignTensorPrimitives.CopySign(src, sign, dst)
    PowTensorPrimitives.Pow(bases, exponents, dst)

    Two-span operations (a, b → dst)

    OperationAPI
    AddTensorPrimitives.Add(a, b, dst)
    SubtractTensorPrimitives.Subtract(a, b, dst)
    MultiplyTensorPrimitives.Multiply(a, b, dst)
    DivideTensorPrimitives.Divide(a, b, dst)
    Element-wise MinTensorPrimitives.Min(a, b, dst)
    Element-wise MaxTensorPrimitives.Max(a, b, dst)

    Three-span fused operations

    OperationAPI
    (x+y)*zTensorPrimitives.AddMultiply(x, y, z, dst)
    x*y+zTensorPrimitives.MultiplyAdd(x, y, z, dst)
    fma(x,y,z)TensorPrimitives.FusedMultiplyAdd(x, y, z, dst)

    AddMultiply and MultiplyAdd are distinct — they optimize differently depending on whether the dependency chain flows from the addend or the multiplier. FusedMultiplyAdd is the IEEE 754 fused form of (x*y)+z with a single rounding step.

    Manual SIMD with Vector128/Vector256/Vector512

    Use this when TensorPrimitives doesn't have a single API for the operation. This is required for byte-level operations, character class counting, range validation, bitwise bulk ops, cross-type conversions, and custom patterns.

    Required imports

    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Runtime.Intrinsics;
    

    Prefer cross-platform APIs (System.Runtime.Intrinsics). Only use platform-specific intrinsics (System.Runtime.Intrinsics.X86, .Arm) when there is a significant performance advantage that justifies the increased code complexity of maintaining separate code paths.

    Three-tier dispatch pattern

    Always include all three tiers. Use if/else if so that small inputs hit only one branch before reaching the scalar fallback — a fallthrough pattern (sequential ifs) pessimizes the scalar case by requiring up to three not-taken branches that may mispredict. The IsHardwareAccelerated checks are JIT-time constants, so dead paths are eliminated at compile time:

    ref var src = ref MemoryMarshal.GetReference(span);
    uint i = 0;
    uint length = (uint)span.Length;
    
    if (Vector512.IsHardwareAccelerated && Vector512<T>.IsSupported)
    {
        uint vec512Count = (uint)Vector512<T>.Count;
        while (i + vec512Count <= length)
        {
            var vec = Vector512.LoadUnsafe(ref src, i);
            // ... process vec ...
            i += vec512Count;
        }
    }
    else if (Vector256.IsHardwareAccelerated && Vector256<T>.IsSupported)
    {
        uint vec256Count = (uint)Vector256<T>.Count;
        while (i + vec256Count <= length)
        {
            var vec = Vector256.LoadUnsafe(ref src, i);
            // ... process vec ...
            i += vec256Count;
        }
    }
    else if (Vector128.IsHardwareAccelerated && Vector128<T>.IsSupported)
    {
        uint vec128Count = (uint)Vector128<T>.Count;
        while (i + vec128Count <= length)
        {
            var vec = Vector128.LoadUnsafe(ref src, i);
            // ... process vec ...
            i += vec128Count;
        }
    }
    // Scalar fallback for remaining elements (and the only loop hit for small inputs)
    for (; i < length; i++)
    {
        // ... scalar processing ...
    }
    

    Core SIMD operations

    • Load/Store: Vector128.LoadUnsafe(ref src, offset) / .StoreUnsafe(ref dst, offset)
    • Arithmetic: +, -, *, / operators on vector types
    • Multiply-add (approximate): Vector128.MultiplyAddEstimate(a, b, c) — performs a multiply-add with implementation-defined approximation; not guaranteed to be a strict IEEE fused multiply-add. For precise fused semantics, use Vector128.FusedMultiplyAdd(a, b, c).
    • Comparison: Vector128.Equals, .LessThan, .GreaterThan — returns mask vector
    • Mask ops: Vector128.All(mask), .Any(mask), .None(mask), .Count(mask), .CountWhereAllBitsSet(mask)
    • Horizontal: Vector128.Sum(vec) for reduction; .Min(a,b), .Max(a,b) element-wise
    • Broadcast: Vector128.Create(scalarValue) — fill all lanes with one value
    • Bitwise: &, |, ^, ~ operators; Vector128.ShiftLeft, .ShiftRightLogical
    • Widening: Vector128.WidenLower(v) / .WidenUpper(v) for byte→short, short→int
    • Narrowing: Vector128.Narrow(lower, upper) for int→short, short→byte
    • Type convert: Vector128.ConvertToSingle(intVec), .ConvertToInt32(floatVec)
    • Shuffle: Vector128.Shuffle(vec, indices) — lookup table / permutation
    • Conditional: Vector128.ConditionalSelect(mask, trueVec, falseVec)

    Pattern: Unsigned range check (byte-range validation)

    For checking if all bytes are in range [lo, hi]:

    var vLo = Vector128.Create((byte)lo);
    var vRange = Vector128.Create((byte)(hi - lo));
    // (b - lo) > range means out-of-range (unsigned wraparound catches b < lo)
    var shifted = Vector128.Subtract(vec, vLo);
    var inRange = Vector128.LessThanOrEqual(shifted, vRange);
    if (!Vector128.All(inRange.AsByte())) return false; // for validation
    // or: count += Vector128.CountWhereAllBitsSet(inRange); // for counting
    

    Pattern: Nibble-lookup counting (character classes, popcount, etc.)

    For counting bytes matching a sparse set of values (vowels, digits, punctuation, bit counts) — build two 16-byte lookup tables indexed by low/high nibble:

    var lo_lut = Vector128.Create(/* 16 bytes: bit pattern for low nibble match */);
    var hi_lut = Vector128.Create(/* 16 bytes: bit pattern for high nibble match */);
    var nibbleMask = Vector128.Create((byte)0x0F);
    
    var lo_nibble = vec & nibbleMask;
    var hi_nibble = Vector128.ShiftRightLogical(vec.AsUInt16(), 4).AsByte() & nibbleMask;
    var lo_match = Vector128.Shuffle(lo_lut, lo_nibble);
    var hi_match = Vector128.Shuffle(hi_lut, hi_nibble);
    var match = lo_match & hi_match;
    count += Vector128.CountWhereAllBitsSet(~Vector128.Equals(match, Vector128<byte>.Zero));
    

    This same technique works for popcount (LUT = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4}). For simpler cases (single byte value, adjacent range), use Equals + Count or range check instead.

    Pattern: Cross-type conversion (widening chains)

    When the source and destination types differ (e.g., byte→float for dequantization, short→byte for narrowing):

    // Widen: byte → short → int → float
    var bytes = Vector128.LoadUnsafe(ref src, offset);
    var (lo16, hi16) = Vector128.Widen(bytes);
    var (lo32a, lo32b) = Vector128.Widen(lo16);
    var f0 = Vector128.ConvertToSingle(lo32a.AsInt32());
    
    // Narrow: int → short → byte (with saturation via Min/Max clamping)
    var clamped = Vector128.Min(Vector128.Max(vec, Vector128<short>.Zero), Vector128.Create((short)255));
    var narrowed = Vector128.Narrow(clamped.AsUInt16(), nextVec.AsUInt16());
    

    Trailing elements

    • Idempotent ops (validation, search): overlap last vector — re-processing is safe
    • Aggregations (sum, count, min/max): scalar loop for remainder to avoid double-counting
    • Store ops (transform in-place): use ConditionalSelect to merge with last stored vector

    Key Rules

    • Preserve original method signature — drop-in replacement
    • Keep scalar code as fallback — never delete it
    • Use Vector128<T> / Vector256<T> / Vector512<T> explicitly — never Vector<T>
    • Prefer portable Vector128<T>/Vector256<T>/Vector512<T> APIs over platform-specific intrinsics (Avx2, Sse42, AdvSimd, Fma) unless there is a significant performance advantage
    • Testing: use dotnet run (NOT dotnet test) — xunit.v3 is an in-process runner

    Frequently asked questions

    What to verify before installation and use

    What does the exp-simd-vectorization source document cover?

    Optimizes hot-path scalar loops in . NET 8+ with cross-platform Vector128/Vector256/Vector512 SIMD intrinsics, or replaces manual math loops with single TensorPrimitives API calls.

    How do I install exp-simd-vectorization?

    The source record exposes this install command: npx skills add https://github.com/dotnet/skills --skill "plugins/dotnet-experimental/skills/exp-simd-vectorization". Inspect the command and pinned source before running it.

    Alternatives

    Compare before choosing

    Computed 10029,095

    garrytan/gbrain

    bulk-ingestion

    End-to-end discipline for turning any large data source (audio libraries, email takeouts, document corpora, chat exports, API dumps) into brain pages at scale. The lifecycle spine: SCHEMA → ACCESS → TRIAL → EVALUATE → IMPROVE → CODIFY → TEST → SKILLIFY → BULK → MONITOR. State is tracked in a durable JSON manifest (see MANIFEST-PATTERN.md) so any crash, session boundary, or subagent fan-out resumes from ground truth instead of memory.

    Computed 10024,975

    alirezarezvani/claude-skills

    app-store-optimization

    App Store Optimization (ASO) toolkit for researching keywords, analyzing competitor rankings, generating metadata suggestions, and improving app visibility on Apple App Store and Google Play Store. Use when the user asks about ASO, app store rankings, app metadata, app titles and descriptions, app store listings, app visibility, or mobile app marketing on iOS or Android. Supports keyword research and scoring, competitor keyword analysis, metadata optimization, A/B test planning, launch checklist

    Computed 1005,248

    dotnet/skills

    migrate-vstest-to-mtp

    Migrates .NET test projects from VSTest to Microsoft.Testing.Platform (MTP). Use when user asks to "migrate to MTP", "switch from VSTest", "enable Microsoft.Testing.Platform", "use MTP runner", set OutputType=Exe only for test projects in Directory.Build.props, or mentions EnableMSTestRunner, EnableNUnitRunner, or UseMicrosoftTestingPlatformRunner. USE FOR: MTP behavioral differences vs VSTest (exit code 8, zero tests discovered, --ignore-exit-code, TESTINGPLATFORM_EXITCODE_IGNORE); centralizing

    Computed 100146

    oaustegard/claude-skills

    featuring

    Generate hierarchical _FEATURES.md files that describe what a codebase DOES from a user/consumer perspective, anchored to source symbols via tree-sitting. Supports large complex codebases through feature-driven decomposition into sub-feature files. Uses a multi-pass synthesis: orientation → detail → overview rewrite. Use when someone says "what does this do", "document features", "feature inventory", "_FEATURES.md", or needs to understand a codebase's purpose before modifying it. Complements tre