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).