ddn.columnar.vector

The packed-bit vector kernels of ddn.df: dense core.simd loops that turn comparisons into bitmap words and arithmetic into raw value buffers, so kernels never pay per-element Nullable or per-element bitmap-append costs.

Every kernel computes every slot and leaves null handling to the caller's validity bitmaps (D14): the value and guard bits produced here are meaningful at valid slots only, and the packed bits are exactly the scalar semantics of the same op on the same operands (IEEE on floats, D's wrap-around on integers).

Comparisons pack one bit per element into ulong words, LSB-first, which is the layout Bitmap uses. Lanes wider than four bytes take the core.simd path (one vector compare per 32-byte block, mask lanes packed with shifts); narrower elements take the branchless scalar path, which is already bandwidth-bound at that width. Arithmetic writes raw physical elements with the same split: core.simd for `+`, `-`, `*` and floating `/`, the guarded scalar loop for the integer `/` and `%`, whose per-slot divisors must be inspected before dividing (no traps on null slots, D14; integer `/` is true division yielding FLOAT64).

Compiler and target matrix: the vector path requires the 32-byte * Implements ADR-2026-10-18-18 (amending ADR-2026-10-18-11's phase-1 "no core.simd" rule).

core.simd vector types to exist on the target, so baseline x86-64 builds of DMD and GDC (pre-AVX) compile every kernel onto the branchless scalar packing through simdCapable, LDC accepts the types at baseline and lowers them to SSE pairs, and -mcpu=avx/-mavx builds take the vector path wherever the compiler accepts the specific vector form: DMD rejects vector `==`/`!=` and the integer arithmetic forms, which vectorCompareOk and vectorArithOk route to the branchless scalar packing there (the floating arithmetic and ordered comparisons stay vectorised).

Functions 23

fnsize_t packedWords(size_t n) @safe pure nothrow @nogcThe number of packed words `n` elements need.
fnsize_t packCompare(T, string op)(const(T)[] a, const(T)[] b, ulong[] outWords) if (isNumeric!T)Packs `a[i] op b[i]` for every element into bitmap words, LSB-first. The `core.simd` path compares 32-byte blocks; the scalar tail and the narrow element types use the branchless loop. Unwritten ta...
fnsize_t packCompareScalar(T, string op)(const(T)[] a, T scalar, ulong[] outWords) if (isNumeric!T)Packs `a[i] op scalar` for every element into bitmap words, LSB-first. Unwritten tail bits of the last word are cleared.
fnsize_t packCompareString(string op)(const(string)[] a, const(string)[] b, ulong[] outWords)Packs `a[i] op b[i]` for STRING operands into bitmap words, LSB-first. Strings compare lexicographically as byte slices, like `string`'s ordering. Unwritten tail bits of the last word are cleared.
fnvoid arithInto(T, string op)(const(T)[] a, const(T)[] b, T[] outValues) if (isNumeric!T && isOp!op)Computes `outValues[i] = a[i] op b[i]` densely, with D's arithmetic semantics (`+`, `-`, `*` wrap on integers, IEEE on floats; `/` is floating division). Null slots hold arbitrary bits on both side...
fnvoid arithScalarInto(T, string op)(const(T)[] a, T scalar, bool scalarOnLeft, T[] outValues) if (isNumeric!T && isOp!op)Computes `outValues[i]` for `a[i] op scalar` (or `scalar op a[i]`), densely, with D's arithmetic semantics.
fnsize_t guardedDivInto(T, R, string op)(const(T)[] a, const(T)[] b, R[] outValues, ulong[] outGuards) if (isIntegral!T && (op == "/" || op == "%"))Computes the guarded integer division or modulo into `outValues`, writing a zero at guarded-out slots (the caller nulls those slots from the guard words). Every slot is inspected before dividing, s...
fnsize_t guardedDivScalarInto(T, R, string op)(const(T)[] a, T scalar, bool scalarOnLeft, R[] outValues, ulong[] outGuards) if (isIntegral!T && (op == "/" || op == "%"))The scalar-operand counterpart of `guardedDivInto`: `a[i] op scalar`, or `scalar op a[i]`, with the guard on the divisor of that operand order.
fnvoid negateInto(T)(const(T)[] a, T[] outValues) if (isNumeric!T)Computes `outValues[i] = -a[i]` densely (wrap-around on integers).
private fnR apply(T, R, string op)(T x, T y) @safe pure nothrowOne guarded application: true division for `/`, wrapping `%` otherwise.
fnvoid maskTail(ulong[] words, size_t n) @safe pure nothrow @nogcClears the packed bits past element `n` in the last word.
private fnvoid clearWords(ulong[] words, size_t from, size_t to) @safe pure nothrow @nogcZeroes the packed words `[from, to)`.
private fnauto splat(T)(T value) @trustedBuilds a `core.simd` vector with every lane set to `value`.
private fnauto loadVec(T)(const(T)[] src) @trusted pure nothrowLoads one `core.simd` vector from a possibly unaligned element position through an aligned staging buffer (a plain `cast(V*)` dereference promises the vector's natural alignment, which element offs...
private fnvoid storeVec(T)(T[] dst, VecOf!T v) @trusted pure nothrowStores one `core.simd` vector to a possibly unaligned element position through an aligned staging buffer.
private fnsize_t packCompareSimd(T, string op)(const(T)[] a, const(T)[] b, ulong[] outWords) @trustedCompares 32-byte blocks of two arrays with `core.simd`, packing one mask bit per element; the scalar tail is left to the caller.
private fnsize_t packCompareScalarSimd(T, string op)(const(T)[] a, T scalar, ulong[] outWords) @trustedCompares 32-byte blocks against a broadcast scalar with `core.simd`, packing one mask bit per element; the scalar tail is left to the caller.
private fnvoid packTail(T, string op)(const(T)[] a, const(T)[] b, ulong[] outWords, size_t bitBase)The branchless scalar packing of one run of comparisons, starting at bit `bitBase` of the destination.
private fnvoid packTailScalar(T, string op)(const(T)[] a, T scalar, ulong[] outWords, size_t bitBase)The branchless scalar packing of one run of scalar comparisons, starting at bit `bitBase` of the destination.
private fnvoid arithLoop(T, string op)(const(T)[] a, const(T)[] b, T[] outValues) @safe pure nothrowThe scalar fallback loop of `arithInto`: D's arithmetic semantics, element by element, into the destination. Used whole on targets whose `simdCapable` is false, and for the tail after the SIMD bloc...
private fnvoid arithScalarLoop(T, string op)(const(T)[] a, T scalar, bool scalarOnLeft, T[] outValues) @safe pure nothrowThe scalar fallback loop of `arithScalarInto`: D's arithmetic semantics against a broadcast scalar, element by element.
private fnsize_t arithIntoSimd(T, string op)(const(T)[] a, const(T)[] b, T[] outValues) @trustedApplies `op` to two arrays in 32-byte `core.simd` blocks; the scalar tail is left to the caller.
private fnsize_t arithScalarIntoSimd(T, string op)(const(T)[] a, T scalar, bool scalarOnLeft, T[] outValues) @trustedApplies `op` with a broadcast scalar in 32-byte `core.simd` blocks; the scalar tail is left to the caller.

Variables 2

enumvarPACK_BITS = 64

The number of bits one packed ulong word holds.

enumvarSIMD_ALIGN = 32

The alignment every core.simd staging buffer must carry.

Templates 9

tmplsimdCapable(T)

Whether the core.simd 32-byte vector path is compiled in for T: the vector type must exist on this target - core.simd guards its own aliases with the same is(Vector!(...)) idiom - and the lanes must be wide enough to pay off (narrow elements and every target without the vector types take the branchless scalar packing instead, which the probes measured at ~0.75 ms per million doubles against 14.7 ms for the per-element path, so the fallback stays fast).

Parameters

Tthe element type

Returns

true when the SIMD kernels instantiate for T.
tmplvectorArithOk(T, string op)

Whether the vector form of one comparison compiles for T on this compiler: DMD rejects `==`/`!=` between vectors (the ordered comparisons compile), so the two equality ops take the branchless scalar packing under DMD while every compiler that accepts them (LDC, GDC) keeps the vector path. Detected through __traits(compiles) rather than versioned, so a future DMD that accepts vector equality lights up on its own.

Parameters

Tthe element type
opthe comparison operator text

Returns

true when the SIMD compare kernel instantiates for T op.

Whether the vector form of one arithmetic operation compiles for T on this compiler: DMD accepts the floating vector arithmetic but rejects the integer forms, so integer `+`-`*` take the branchless scalar loop under DMD while LDC and GDC keep the vector path. Detected through __traits(compiles) so compilers that grow the missing forms light up on their own.

Params: T = the element type op = the arithmetic operator text

Returns: true when the SIMD arithmetic kernel instantiates.

tmplvectorCompareOk(T, string op)

Whether the vector form of one comparison compiles for T on this compiler: DMD rejects `==`/`!=` between vectors (the ordered comparisons compile), so the two equality ops take the branchless scalar packing under DMD while every compiler that accepts them (LDC, GDC) keeps the vector path. Detected through __traits(compiles) rather than versioned, so a future DMD that accepts vector equality lights up on its own.

Parameters

Tthe element type
opthe comparison operator text

Returns

true when the SIMD compare kernel instantiates for T op.
tmplisNumeric(T)

Whether T is one of the ten numeric physical element types.

Parameters

Tthe type to test

Returns

true for the integer and floating element types.
tmplisIntegral(T)

Whether T is one of the integral physical element types.

Parameters

Tthe type to test

Returns

true for the integer element types.
tmplisFloating(T)

Whether T is a floating physical element type.

Parameters

Tthe type to test

Returns

true for float and double.
tmplisOp(string op)

Whether op is one of the five arithmetic operators.

Parameters

opthe operator text

Returns

true for `"+"`, `"-"`, `"*"`, `"/"` and `"%"`.
tmplMaskT(T)

The unsigned lane type of a comparison mask vector at element size.

tmplVecOf(T)

One 32-byte core.simd vector of T.