From 95bb4ea1ab475bd703f8027b8a961bb857487d64 Mon Sep 17 00:00:00 2001 From: Basil Fierz Date: Sat, 17 Oct 2026 15:14:38 +0200 Subject: [PATCH] Add a README, and move agent guidance into a tool-neutral AGENTS.md The README covers what FloatWeaver is, supported backends, how to build and test it, the docs, and where the library came from (the SIMD module of VCL). The project guidance for coding agents lives in AGENTS.md so any agent can use it; CLAUDE.md just imports it. --- AGENTS.md | 60 +++++++++++++++++++++++++++++++ CLAUDE.md | 3 ++ README.md | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100644 AGENTS.md create mode 100644 CLAUDE.md create mode 100644 README.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..14ff06c --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,60 @@ +# AGENTS.md + +This file provides guidance to AI coding agents working with code in this repository. + +## Project background + +FloatWeaver is a header-mostly C++17 library for writing CUDA-style SIMD code that runs on the CPU: you write scalar-looking code against `VectorScalar` types and it compiles down to SSE/AVX/AVX512/NEON instructions (or a portable scalar fallback), with Eigen integration so `Eigen::Matrix` etc. work out of the box. + +**Status**: the core SIMD types (bool/float/int × 4/8/16, ref/SSE/AVX/AVX512/NEON backends) and the Eigen adapter are implemented and have baseline Catch2 tests. Not yet done: examples, broader test coverage, user-facing documentation, and benchmarks — treat these as open work, not as things that don't belong here. There is also an open, undecided question about whether some standalone high-speed SVD tooling should live in this repo or a separate one under the same org — don't assume either answer without asking. + +## Build & test commands + +Dependencies (Eigen3, Catch2) are managed via Conan 2; do a full from-scratch build with: + +```bash +conan install --build=missing -of build . +cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=build/build/Release/generators/conan_toolchain.cmake +cmake --build build --config Release +``` + +(On Windows/multi-config generators the generators dir is `build/build/generators` instead — see `.github/workflows/build.yml` for the exact matrix.) + +Run the whole test suite: + +```bash +ctest --test-dir build --build-config Release +``` + +Run a single test / tag with Catch2 directly (faster than going through ctest), e.g. only float tests, or one named test case: + +```bash +build/weaver_tests "[float]" +build/weaver_tests "Sqrt FloatN" +``` + +The vectorization backend used for the build is a CMake cache variable, not autodetected: + +```bash +cmake -S . -B build -DWEAVER_VECTORIZE="AVX 2" # one of: Generic, SSE 4.2, AVX, AVX 2, AVX 512, NEON +``` + +This sets `WEAVER_VECTORIZE_*` compile definitions (see `cmake/config.cmake`) which in turn drive which per-ISA headers get pulled in (see Architecture below). When adding a new SIMD feature, it needs to be exercised under more than one backend to be considered validated — CI (`.github/workflows/build.yml`) builds gcc/clang/MSVC/emscripten across the matrix, but locally only one backend is active per configure. + +## Architecture + +**File naming = one axis per file.** Each SIMD type is split as `{category}{width}_{isa}.h`, e.g. `float8_avx.h`, `bool16_avx512.h`, `int4_neon.h`, plus a `*_ref.h` scalar-fallback variant for every width. There's no single "generic float vector" header — instead `include/weaver/eigen.h` (and equally `vector_types.h`'s consumers) `#if`-chains on `WEAVER_VECTORIZE_AVX512` / `_AVX` / `_SSE` / `_NEON` to pick exactly one full set of backend headers, falling back to `*_ref.h` for Generic builds. When adding a new op, it must be implemented consistently across all five backends (ref/SSE/AVX/AVX512/NEON) for a given width — a partial implementation will only surface as a build failure on the backends you didn't touch. + +**Two-layer register model** (`include/weaver/vector_types.h`): +- `SimdRegister` is the thin, per-ISA-and-scalar-type wrapper around the actual intrinsic type (`__m128`, `float32x4_t`, `__mmask16`, ...). It only knows how to `set`/`get` lanes. +- `VectorScalarBase` stacks `NrRegs = Width / NrValuesPerReg` of those registers to build wider logical vectors from narrower physical registers (e.g. a `float16` on SSE hardware is 4 `__m128` registers). `VectorScalar` (defined per-ISA in the `{type}{width}_{isa}.h` files) is the public-facing type built on top of this. + +**Operator codegen via macros**, not templates, because SIMD intrinsics for +, -, cmp, reductions etc. don't share a signature: `common.h` defines `WEAVER_SIMD_UNARY_OP` / `_BINARY_OP` / `_ASSIGN_OP` / `_COMP_OP` / `_QUERY_OP` / `_UNARY_REDUCTION_OP` / `_BINARY_REDUCTION_OP`, each expanding through `WEAVER_SIMD_P1_N` / `WEAVER_SIMD_P2_N` helper macros that unroll across the `NrRegs` registers for a given width `N` (4/8/16). Each per-width-per-ISA header instantiates these macros with the intrinsic function name for that op. `WEAVER_SIMD_VECTORSCALAR_SETUP(ISA)` wires up the constructors and type aliases (`Self`, `Bool`, `RegType`) each `VectorScalar` specialization needs. + +**Free functions vs. members**: elementwise math (`sqrt`, `exp`, `log`, `min`, `max`, `select`, `equal`, `sgn`, ...) is exposed as free functions in `namespace weaver` (`vector_types.h`, bottom) that mostly just forward to a member of the same name — this mirrors ``/Eigen calling conventions and is what makes generic code (templated on `Scalar`/`Width`) work uniformly across scalar and vector types. + +**Eigen integration** (`include/weaver/eigen.h`): specializes `Eigen::NumTraits` and the relevant `Eigen::numext` functions so `weaver::floatN`/`int N`/`boolN` can be used as the `Scalar` of an `Eigen::Matrix`. `select`/`cswap`/`cnswap` (`conditional.h`) are the masked-branchless primitives this whole model relies on instead of real control flow — any "CUDA-style" branch in user code should compile down to one of these rather than an `if`. + +**`intrinsics_*.h`/`.cpp`** wrap raw platform intrinsics not otherwise exposed cleanly (lane extraction, mathfun-derived transcendentals in `src/detail/*_mathfun.h`, sourced from Julien Pommier / Giovanni Garberoglio / JishinMaster implementations). **`memory_*.h`** covers load/store/gather/scatter/interleave, which is why those get their own test files (`load.cpp`, `store.cpp`, `gather.cpp`, `scatter.cpp`, `interleave.cpp`) rather than living inside `float.cpp`/`int.cpp`. + +**Tests** (`src/tests/`) use Catch2 v3. `src/tests/common.h` provides `WEAVER_SIMD_FLOATS` / `_INTS` / `_BOOLS` macros that inject a standard set of ascending/descending fixture vectors (`f4_asc`, `f8_desc`, ...) at all three widths into a test case — reuse these instead of hand-rolling fixtures. Tag tests with `[float]`/`[int]`/`[bool]`/`[operation]` etc. matching the existing convention so `-t "[tag]"` filtering keeps working. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..f6aa6c0 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,3 @@ +# CLAUDE.md + +@AGENTS.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..de215c3 --- /dev/null +++ b/README.md @@ -0,0 +1,105 @@ +# FloatWeaver + +FloatWeaver is a C++17 library for writing CUDA-style SIMD code that runs on the CPU. You write ordinary, scalar-looking code against vector types such as `weaver::float8`, and it compiles down to SSE, AVX, AVX-512 or NEON instructions, or to a portable scalar fallback. + +The vector types also work as the scalar type of an Eigen matrix, so `Eigen::Matrix` is eight 3D vectors processed in lockstep. + +```cpp +#include + +weaver::float8 x{ 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f }; +weaver::float8 y{ 8.0f, 7.0f, 6.0f, 5.0f, 4.0f, 3.0f, 2.0f, 1.0f }; + +weaver::float8 z = x + y; // one vector add per lane group +``` + +```cpp +#include +#include + +Eigen::Matrix a{ weaver::float8{1.0f}, weaver::float8{2.0f}, weaver::float8{3.0f} }; +Eigen::Matrix b{ weaver::float8{4.0f}, weaver::float8{5.0f}, weaver::float8{6.0f} }; + +Eigen::Matrix c = a.cross(b); // eight cross products at once +``` + +Branches are expressed with masked, branchless primitives (`select`, `cswap`, `cnswap`) instead of `if`, the same way divergent code is handled on a GPU. + +## Features + +- `float`, `int` and `bool` vectors at widths 4, 8 and 16 (`float4`, `int8`, `bool16`, ...). +- Arithmetic, comparison and reduction operators, plus ``-style free functions (`sqrt`, `exp`, `log`, `min`, `max`, `sgn`, ...). +- Load, store, gather, scatter and interleave helpers. +- Eigen integration via `NumTraits` and `numext` specializations. +- Vectors wider than the hardware register are split across several registers automatically, so `float16` works on SSE and `float8` works on NEON. + +## Supported backends + +The instruction set is chosen at configure time with the `WEAVER_VECTORIZE` CMake cache variable. It is not autodetected. + +| `WEAVER_VECTORIZE` | Target | +| --- | --- | +| `Generic` | Portable scalar fallback | +| `SSE 4.2` (default) | x86 / x86-64 | +| `AVX`, `AVX 2` | x86-64 | +| `AVX 512` | x86-64 | +| `NEON` | ARM / AArch64 | + +CI builds and tests the library with GCC, Clang and MSVC on x86-64 and ARM64, and with Emscripten. + +## Building + +You need CMake 3.21 or newer and a C++17 compiler. The dependencies are [Eigen](https://eigen.tuxfamily.org) 3.4 and, for the tests, [Catch2](https://github.com/catchorg/Catch2) 3. + +**With Conan 2:** + +```bash +conan install --build=missing -of build . +cmake -S . -B build -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_TOOLCHAIN_FILE=build/build/Release/generators/conan_toolchain.cmake \ + -DWEAVER_VECTORIZE="AVX 2" +cmake --build build --config Release +``` + +On multi-config generators (for example Visual Studio), the toolchain file is in `build/build/generators` instead. + +**Without Conan:** if Eigen or Catch2 aren't found as packages, CMake falls back to the git submodules under `external/`: + +```bash +git submodule update --init +cmake -S . -B build -DCMAKE_BUILD_TYPE=Release +cmake --build build --config Release +``` + +**Running the tests:** + +```bash +ctest --test-dir build --build-config Release +``` + +Tests are only built when FloatWeaver is the top-level project. To use it from another CMake project, add it with `add_subdirectory` and link against the `weaver` target. + +## Documentation + +The documentation is built with Doxygen, Breathe and Sphinx. It includes how-to guides that show the assembly each example compiles to. Build it locally with: + +```bash +cmake -S . -B build -DWEAVER_BUILD_DOCS=ON # plus the options above +cmake --build build --target docs +``` + +The code examples in the docs live in [`doc/snippets`](doc/snippets) and are compiled and run as part of the test suite, so they stay in sync with the API. + +## Origin + +FloatWeaver started as the SIMD module of the [Visual Computing Library (VCL)](https://github.com/bfierz/vcl). Basil Fierz began VCL in 2014 to collect the algorithms and data structures from a PhD on visual simulation. + +VCL grew into a large library covering many topics, but its SIMD types are useful on their own. FloatWeaver reimplements that module from scratch, along with parts of the math built on it, as a small standalone library. It targets C++17 instead of VCL's C++14 and uses a CMake build with Conan-managed dependencies. The core vector types and the Eigen adapter are complete. Examples, benchmarks and broader test coverage are still being brought over. + +## Acknowledgements + +The trigonometric, logarithm and power functions build on existing SIMD math libraries. The SSE and NEON versions come from [Julien Pommier's sse_mathfun](http://gruntthepeon.free.fr/ssemath/), the AVX version is by Giovanni Garberoglio, and the AVX-512 version comes from [JishinMaster's simd_utils](https://github.com/JishinMaster/simd_utils). + +## License + +FloatWeaver is released under the [MIT License](LICENSE).