diff --git a/interfaces/Crafter.Math-VectorF32.cppm b/interfaces/Crafter.Math-VectorF32.cppm index ecb91a1..6ffccc6 100755 --- a/interfaces/Crafter.Math-VectorF32.cppm +++ b/interfaces/Crafter.Math-VectorF32.cppm @@ -2136,6 +2136,28 @@ namespace Crafter { return sq; } + // Batched dot product over BatchSize (a, b) pairs: Dot(a0, b0, a1, b1, + // ...) returns one lane per pair. MatrixRowMajor relies on it, so + // without it this fallback (every target that has no intrinsic + // backend above) does not compile. Only the first Len lanes of each + // input are summed, as in the other backends. + template + requires((std::is_same_v> && ...) && + (1 + sizeof...(Rest) == 2 * VectorBase::BatchSize)) + constexpr static auto Dot(VectorF32 first, Rest... rest) { + constexpr std::uint8_t N = VectorBase::BatchSize; + VectorF32<1, static_cast(Packing * N)> r; + std::array, 2 * N> args{ first, rest... }; + for (std::uint8_t i = 0; i < N; ++i) + for (std::uint8_t p = 0; p < Packing; ++p) { + float acc = 0.0f; + for (std::uint8_t k = 0; k < Len; ++k) + acc += args[2 * i].v[p * Len + k] * args[2 * i + 1].v[p * Len + k]; + r.v[i * Packing + p] = acc; + } + return r; + } + template requires((std::is_same_v> && ...) && (1 + sizeof...(Rest) == VectorBase::BatchSize))