BLAS: add rules for cblas_?dotc_sub and cblas_?dotu_sub

Add derivative rules for the complex dot products in their cblas `_sub`
form (e.g. cblas_zdotc_sub64_), whose result is written through a
pointer passed as the last argument instead of being returned.

  dotc: res = sum(conj(x_i) * y_i)   REV: dx += conj(dres)*y, dy += dres*x
  dotu: res = sum(x_i * y_i)         REV: dx += dres*y,       dy += dres*x
  FWD (both): dres = dot(dx, y) + dot(x, dy)

To express this in the BLAS tblgen:
* new `fpret` argument type for a scalar result returned through a
  pointer; its shadow provides DiffeRet in reverse mode (and is reset,
  since the primal overwrote the result) and receives the dual in
  forward mode. BlasCalls to `*_sub` functions get a result alloca
  appended and their result loaded back, like the cublas v2 path.
* new `BConj` op for the complex conjugate of an fp scalar.
* per-pattern `supportsComplex` bit, so the blanket "complex inputs not
  supported in reverse mode" error only applies to patterns that have
  not been checked for complex inputs.
* complex scalars under the cblas ABI are passed by pointer, so
  byRefFloat now accounts for that (shared helper for all generators).

The result pointer is attributed nocapture but not writeonly: with
writeonly, the unused-value analysis drops a local result buffer
(e.g. a julia Ref) while keeping the primal call writing to it.
nocapture is also no longer applied to non-pointer (integer) vector
arguments, which is invalid IR.

Assisted-by: Claude Code (Fable 5.1)
14 files changed
tree: 45d9acaebbefde3faa002b56cdd784037ff0d7b5
  1. .devcontainer/
  2. .github/
  3. .packaging/
  4. enzyme/
  5. integration/
  6. .gitattributes
  7. .gitignore
  8. CITATION.bib
  9. CONTRIBUTING.md
  10. fpm.toml
  11. LICENSE
  12. Readme.md
Readme.md

The Enzyme High-Performance Automatic Differentiator of LLVM and MLIR

Enzyme is a plugin that performs automatic differentiation (AD) of statically analyzable LLVM and MLIR.

Enzyme can be used by calling __enzyme_autodiff on a function to be differentiated as shown below. Running the Enzyme transformation pass then replaces the call to __enzyme_autodiff with the gradient of its first argument.

double foo(double);

double grad_foo(double x) {
    return __enzyme_autodiff(foo, x);
}

Enzyme is highly-efficient and its ability to perform AD on optimized code allows Enzyme to meet or exceed the performance of state-of-the-art AD tools.

Detailed information on installing and using Enzyme can be found on our website: https://enzyme.mit.edu.

A short example of how to install Enzyme is below:

cd /path/to/Enzyme/enzyme
mkdir build && cd build
cmake -G Ninja .. -DLLVM_DIR=/path/to/llvm/lib/cmake/llvm -DLLVM_EXTERNAL_LIT=/path/to/lit/lit.py
ninja

Or, install Enzyme using a package manager:

Homebrew

brew install enzyme

Spack

spack install enzyme

Nix

nix-shell -p enzyme

To get involved or if you have questions, please join our mailing list.

If using this code in an academic setting, please cite the following three papers (first for Enzyme as a whole, second for GPU+optimizations, and third for AD of all other parallel programs (OpenMP, MPI, Julia Tasks, etc.)):

@inproceedings{NEURIPS2020_9332c513,
 author = {Moses, William and Churavy, Valentin},
 booktitle = {Advances in Neural Information Processing Systems},
 editor = {H. Larochelle and M. Ranzato and R. Hadsell and M. F. Balcan and H. Lin},
 pages = {12472--12485},
 publisher = {Curran Associates, Inc.},
 title = {Instead of Rewriting Foreign Code for Machine Learning, Automatically Synthesize Fast Gradients},
 url = {https://proceedings.neurips.cc/paper/2020/file/9332c513ef44b682e9347822c2e457ac-Paper.pdf},
 volume = {33},
 year = {2020}
}
@inproceedings{10.1145/3458817.3476165,
author = {Moses, William S. and Churavy, Valentin and Paehler, Ludger and H\"{u}ckelheim, Jan and Narayanan, Sri Hari Krishna and Schanen, Michel and Doerfert, Johannes},
title = {Reverse-Mode Automatic Differentiation and Optimization of GPU Kernels via Enzyme},
year = {2021},
isbn = {9781450384421},
publisher = {Association for Computing Machinery},
address = {New York, NY, USA},
url = {https://doi.org/10.1145/3458817.3476165},
doi = {10.1145/3458817.3476165},
booktitle = {Proceedings of the International Conference for High Performance Computing, Networking, Storage and Analysis},
articleno = {61},
numpages = {16},
keywords = {CUDA, LLVM, ROCm, HPC, AD, GPU, automatic differentiation},
location = {St. Louis, Missouri},
series = {SC '21}
}
@inproceedings{10.5555/3571885.3571964,
author = {Moses, William S. and Narayanan, Sri Hari Krishna and Paehler, Ludger and Churavy, Valentin and Schanen, Michel and H\"{u}ckelheim, Jan and Doerfert, Johannes and Hovland, Paul},
title = {Scalable Automatic Differentiation of Multiple Parallel Paradigms through Compiler Augmentation},
year = {2022},
isbn = {9784665454445},
publisher = {IEEE Press},
booktitle = {Proceedings of the International Conference on High Performance Computing, Networking, Storage and Analysis},
articleno = {60},
numpages = {18},
keywords = {automatic differentiation, tasks, OpenMP, compiler, Julia, parallel, Enzyme, C++, RAJA, hybrid parallelization, MPI, distributed, LLVM},
location = {Dallas, Texas},
series = {SC '22}
}

Julia bindings, Rust bindings, and Fortran bindings are available for Enzyme.