From ed188f207ba45014265e5a1fa4f868441fed153b Mon Sep 17 00:00:00 2001 From: Jorijn van der Graaf Date: Tue, 6 Oct 2026 16:52:24 +0200 Subject: [PATCH] fix(vector): batched Dot in the scalar VectorF32 fallback MatrixRowMajor calls VectorF32::Dot(a0, b0, a1, b1, ...) for its matrix-vector products and for LookAt. The x86, wasm and RISC-V backends each define it; the scalar fallback, which every other target gets, did not. Anything that imports Crafter.Math on such a target failed to compile with "no member named 'Dot' in VectorF32", aarch64 included: cross-building Crafter.Graphics for a phone stopped there. The fallback gains the same batched Dot, written like the RISC-V one: one lane per (a, b) pair, summing only the first Len lanes of each input. No test exercises it: the suite builds the x86 and RISC-V tiers only. Checked by cross-building Crafter.Graphics for aarch64-alpine-linux-musl and running its UI on the device. Co-Authored-By: Claude Fable 5.1 --- interfaces/Crafter.Math-VectorF32.cppm | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) 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)) -- 2.47.3