NEON backend for VectorF32 on AArch64: one float32x4_t per vector (Len * Packing <= 4), with a vectorised sin/cos port of the SSE helpers. VectorF16 gets a native float16x8_t path when the target has ARMv8.2-FP16 arithmetic. Without it VectorF16 aliases VectorF32, which converts fp16 <-> fp32 on Load/Store. The scalar fallback gains the batched Dot that MatrixRowMajor relies on. Test tiers added for armv8-a and armv8.2-a+fp16. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
68 lines
2.6 KiB
C++
68 lines
2.6 KiB
C++
//SPDX-License-Identifier: LGPL-3.0-only
|
|
//SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
|
|
|
|
import std;
|
|
import Crafter.Build;
|
|
namespace fs = std::filesystem;
|
|
using namespace Crafter;
|
|
|
|
extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> args) {
|
|
std::array<fs::path, 8> mathInterfaces = {
|
|
"interfaces/Crafter.Math-Basic",
|
|
"interfaces/Crafter.Math",
|
|
"interfaces/Crafter.Math-Common",
|
|
"interfaces/Crafter.Math-Vector",
|
|
"interfaces/Crafter.Math-Intersection",
|
|
"interfaces/Crafter.Math-MatrixRowMajor",
|
|
"interfaces/Crafter.Math-VectorF16",
|
|
"interfaces/Crafter.Math-VectorF32",
|
|
};
|
|
|
|
Configuration cfg;
|
|
cfg.path = "./";
|
|
cfg.name = "Crafter.Math";
|
|
cfg.outputName = "Crafter.Math";
|
|
cfg.type = ConfigurationType::LibraryStatic;
|
|
ApplyStandardArgs(cfg, args);
|
|
{
|
|
std::array<fs::path, 0> impls = {};
|
|
cfg.GetInterfacesAndImplementations(mathInterfaces, impls);
|
|
}
|
|
|
|
// SIMD tier matrix: each tier rebuilds the math interfaces with its own
|
|
// -march so codegen actually varies. Per-arch gating is just an `if`
|
|
// around the AddMarchVariants call.
|
|
std::array<MarchTier, 3> x86Tiers = {{
|
|
{"sapphirerapids", "native"},
|
|
{"x86-64-v4", "generic"},
|
|
{"x86-64-v3", "generic"},
|
|
}};
|
|
// RISC-V tiers mirror the x86 selector: register width is picked from
|
|
// the guaranteed VLEN encoded in the march's Zvl* suffix. rv64gcv →
|
|
// ZVL128B (matches the RVA23 baseline).
|
|
std::array<MarchTier, 3> riscvTiers = {{
|
|
{"rv64gcv_zvl512b", "generic"},
|
|
{"rv64gcv_zvl256b", "generic"},
|
|
{"rv64gcv", "generic"},
|
|
}};
|
|
|
|
// AArch64 has a single NEON register width (128-bit), so the tiers
|
|
// differ in VectorF16 only: ARMv8.2-FP16 gives it a native half-precision
|
|
// path, the baseline aliases it to VectorF32.
|
|
std::array<MarchTier, 2> armTiers = {{
|
|
{"armv8.2-a+fp16", "generic"},
|
|
{"armv8-a", "generic"},
|
|
}};
|
|
|
|
const std::string_view target = cfg.target;
|
|
const bool isX86 = target.starts_with("x86_64") || target.starts_with("i686");
|
|
const bool isRiscv = target.starts_with("riscv");
|
|
const bool isArm = target.starts_with("aarch64");
|
|
for (std::string_view name : { "Vector", "Intersection", "Matrix" }) {
|
|
if (isX86) cfg.AddMarchVariants(name, mathInterfaces, x86Tiers);
|
|
if (isRiscv) cfg.AddMarchVariants(name, mathInterfaces, riscvTiers);
|
|
if (isArm) cfg.AddMarchVariants(name, mathInterfaces, armTiers);
|
|
}
|
|
|
|
return cfg;
|
|
}
|