Enzyme is a high-performance automatic differentiation (AD) plugin for LLVM and MLIR. It performs AD of statically analyzable LLVM IR and MLIR code through compiler transformations, achieving state-of-the-art performance by working on optimized code.
enzyme/ ├── Enzyme/ # Core AD transformation logic │ ├── ActivityAnalysis.cpp/h # Determines active/inactive values │ ├── TypeAnalysis/ # Type tracking and propagation │ ├── EnzymeLogic.cpp/h # Main AD transformation logic │ ├── GradientUtils.cpp/h # Gradient computation utilities │ ├── AdjointGenerator.h # Reverse-mode AD code generation │ ├── CacheUtility.cpp/h # Caching mechanism for AD │ ├── FunctionUtils.cpp/h # Function manipulation utilities │ ├── MLIR/ # MLIR dialect and passes │ └── Clang/ # Clang plugin integration ├── BCLoad/ # Bitcode loader for runtime library support ├── test/ # Test suite using LLVM lit │ ├── Enzyme/ # Core Enzyme tests │ ├── ActivityAnalysis/ # Activity analysis tests │ ├── TypeAnalysis/ # Type analysis tests │ ├── Integration/ # Integration tests (ReverseMode, ForwardMode, etc.) │ └── MLIR/ # MLIR-specific tests ├── tools/ # Additional tools │ └── enzyme-tblgen/ # TableGen tool for derivative rules └── cmake/ # CMake configuration files
.github/workflows/enzyme-ci.yml for supported versions)cd enzyme mkdir build && cd build cmake -G Ninja .. \ -DCMAKE_BUILD_TYPE=Release \ -DLLVM_DIR=/path/to/llvm/lib/cmake/llvm \ -DLLVM_EXTERNAL_LIT=$(which lit) ninja
Release: Optimized build (default)Debug: Debug symbols, no optimizationRelWithDebInfo: Optimized with debug symbolsENZYME_ENABLE_PLUGINS: Enable Clang/LLD/Opt plugins (default: ON)ENZYME_BC_LOADER: Enable bitcode loader (default: ON)ENZYME_CLANG: Build enzyme clang plugin (default: ON)ENZYME_MLIR: Build enzyme MLIR plugin (default: OFF)ENZYME_STATIC_LIB: Build static library (default: OFF)Enzyme uses LLVM's lit test framework. Tests are written as LLVM IR (.ll), C/C++ (.c, .cpp), MLIR (.mlir), or Fortran (.f90) files with RUN directives.
cd build make check-enzyme # Run all Enzyme tests make check-typeanalysis # Run Type Analysis tests make check-activityanalysis # Run Activity Analysis tests
Tests use lit directives:
; RUN: %opt < %s %loadEnzyme -enzyme -S | FileCheck %s
Tests should verify both correctness and performance properties where applicable.
clang-format with LLVM style (configured in enzyme/Enzyme/.clang-format)-fno-rtti is required)# Format changed files in last commit git clang-format HEAD~1 # Format specific file clang-format -i path/to/file.cpp
#ifndef HEADER_NAME_H formatCallDerivatives.cpp and BlasDerivatives.td for examplesNew transformation passes should use AnalysisInfoMixin pattern (even though they modify IR):
class MyPass final : public AnalysisInfoMixin<MyPass> { friend struct AnalysisInfoMixin<MyPass>; private: static AnalysisKey Key; public: using Result = PreservedAnalyses; Result run(Function &F, FunctionAnalysisManager &AM); static bool isRequired() { return true; } };
TypeTree for tracking type informationisConstantValue and isConstantInstruction carefullySmallVector, DenseMap)EmitFailure over compile-time crashes when possible for better error diagnostics:EmitFailure("RemarkName", Loc, CodeRegion, "Error message: ", value);
CustomErrorHandler to provide user-customizable error handling (especially useful for language bindings)CustomErrorHandler is a global variable set by tools that use Enzyme as a libraryEmitNoDerivativeError, EmitNoTypeError implement this pattern: they first check if CustomErrorHandler is set and call it, otherwise fall back to EmitFailurellvm::errs(), dbgs(), assertionsllvm_unreachable() for impossible casesThe easiest way to explore and debug Enzyme: https://enzyme.mit.edu/explorer
Build with CMAKE_BUILD_TYPE=Debug for better debugging:
opt -load-pass-plugin=path/to/LLVMEnzyme-<version>.so \ -enzyme -enzyme-print -debug -debug-only=enzyme \ input.ll -S -o output.ll
llvm::errs() << "Debug message: " << value << "\n"; dbgs() << "Debug-only message\n"; // Only with -debug flag
LLVM_DIR points to the correct LLVM installationpip install lit and set LLVM_EXTERNAL_LITEnzyme can be integrated with any language that compiles to LLVM IR:
When adding language-specific features, ensure they work correctly with the core AD transformation.
#0) from CHECK lines for function calls and definitions. Attribute numbering is unstable.{ in function definition CHECK lines.FileCheck variable captures (e.g., [[VAR:%.+]]) instead of hardcoded SSA values. IMPORTANT: Remember to include the % prefix when using the captured variable (e.g., %[[VAR]]), as the capture usually only matches the numeric ID.CHECK-NEXT: for empty lines. Resume matching with CHECK: for the next basic block or instruction sequence.[ %[[VAR:[0-9]+]], ... ]) and verify it in the subsequent definition (%[[VAR]] = ...).test/Integration/ReverseMode/blas.cpp).ninja check-enzyme or llvm-lit on modified tests before submitting to ensure they pass.