Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More Code Cleanup, Licensing, and Readme #57

Merged
merged 2 commits into from
Sep 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 22 additions & 21 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
# The Enzyme Automatic differentiator
# <img src="https://enzyme.mit.edu/logo.svg" width="75" align=left> The Enzyme High-Performance Automatic Differentiator of LLVM

To build Enzyme run the following steps:
```bash
cd enzyme && mkdir build && cd build
cmake ..
make
```

This will pick up your default installation of LLVM, to specify a specific LLVM installation add the LLVM_DIR flag to cmake as follows:
Enzyme is a plugin that performs automatic differentiation (AD) of statically analyzable LLVM. It is highly-efficient and its ability perform AD on optimized code allows Enzyme to meet or exceed the performance of state-of-the-art AD tools.

```bash
cmake .. -DLLVM_DIR=/path/to/llvm/lib/cmake/llvm
```
Enzyme can be used by calling `__enzyme_autodiff_` on a function to be differentiated as shown below:
```c
double foo(double);

To run Enzyme tests use the following:
```bash
make check-enzyme
double grad_foo(double x) {
return __enzyme_autodiff(foo, x);
}
```

If you run the above and get an error like `/bin/sh: 1: ../../: Permission denied` or ` ../../ not found`, it's likely that cmake wasn't able to find your version of llvm-lit, LLVM's unit tester. This often happens if you use the default Ubuntu install of LLVM as they stopped including it in their packaging. To remedy, find lit.py or lit or llvm-lit on your system and add the following flag to cmake:
```bash
cmake .. -DLLVM_EXTERNAL_LIT=/path/to/lit/lit.py
```
Running the Enzyme transformation pass then replaces the call to `__enzyme_autodiff` with the gradient of its first argument.

To run C++ integration tests (which require boost/eigen and take quite a while) use the following:
```bash
make check-enzyme-integration
Information on installing and using Enzyme can be found on our website: [https://enzyme.mit.edu](https://enzyme.mit.edu).

To get involved or if you have questions, please join our [mailing list](https://groups.google.com/d/forum/enzyme-dev).

If using this code in an academic setting, please cite the following:
```
@misc{enzymeGithub,
author = {William S. Moses and Valentin Churavy},
title = {Enzyme: High Performance Automatic Differentiation of LLVM},
year = {2020},
howpublished = {\url{https://github.com/wsmoses/Enzyme}},
note = {commit xxxxxxx}
}
```
44 changes: 30 additions & 14 deletions enzyme/Enzyme/ActiveVariable.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
/*
* ActiveVariable.cpp - Active Varaible Detection Utilities
*
* Copyright (C) 2020 William S. Moses (enzyme@wsmoses.com) - All Rights
* Reserved
*
* For commercial use of this code please contact the author(s) above.
*/

//===- ActiveVariable.cpp - Implementation of Activity Analysis -----------===//
//
// Enzyme Project
//
// Part of the Enzyme Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// If using this code in an academic setting, please cite the following:
// @misc{enzymeGithub,
// author = {William S. Moses and Valentin Churavy},
// title = {Enzyme: High Performance Automatic Differentiation of LLVM},
// year = {2020},
// howpublished = {\url{https://github.com/wsmoses/Enzyme}},
// note = {commit xxxxxxx}
// }
//
//===----------------------------------------------------------------------===//
//
// This file contains the implementation of Activity Analysis -- an AD-specific
// analysis that deduces if a given instruction or value can impact the
// calculation of a derivative. This file consists of two mutually recurive
// functions that compute this for values and instructions, respectively.
//
//===----------------------------------------------------------------------===//
#include <cstdint>
#include <deque>

Expand Down Expand Up @@ -166,17 +182,17 @@ bool isFunctionArgumentConstant(TypeResults &TR, CallInst *CI, Value *val,
for (auto &arg : F->args()) {
nextTypeInfo.first.insert(std::pair<Argument *, TypeTree>(
&arg, TR.query(CI->getArgOperand(argnum))));
argnum++;
++argnum;
}
nextTypeInfo.second = TR.query(CI);
TypeResults TR2 = TR.analysis.analyzeFunction(nextTypeInfo);

for (unsigned i = 0; i < CI->getNumArgOperands(); i++) {
for (unsigned i = 0; i < CI->getNumArgOperands(); ++i) {
if (CI->getArgOperand(i) == val) {
arg_findifactive.insert(a);
idx_findifactive.insert(i);
newnonconstant.insert(a);
a++;
++a;
continue;
}

Expand All @@ -188,7 +204,7 @@ bool isFunctionArgumentConstant(TypeResults &TR, CallInst *CI, Value *val,
} else {
newnonconstant.insert(a);
}
a++;
++a;
}

bool constret;
Expand Down Expand Up @@ -455,7 +471,7 @@ bool isconstantM(TypeResults &TR, Instruction *inst,
bool allIntegral = true;
bool anIntegral = false;
auto q = TR.query(storeinst->getPointerOperand()).Data0();
for (int i = -1; i < (int)storeSize; i++) {
for (int i = -1; i < (int)storeSize; ++i) {
auto dt = q[{i}];
if (dt.isIntegral() || dt.typeEnum == BaseType::Anything) {
anIntegral = true;
Expand Down
33 changes: 25 additions & 8 deletions enzyme/Enzyme/ActiveVariable.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
/*
* ActiveVariable.h - Active Varaible Detection Utilities
*
* Copyright (C) 2020 William S. Moses (enzyme@wsmoses.com) - All Rights
* Reserved
*
* For commercial use of this code please contact the author(s) above.
*/
//===- ActiveVariable.h - Declaration of Activity Analysis -----------===//
//
// Enzyme Project
//
// Part of the Enzyme Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// If using this code in an academic setting, please cite the following:
// @misc{enzymeGithub,
// author = {William S. Moses and Valentin Churavy},
// title = {Enzyme: High Performance Automatic Differentiation of LLVM},
// year = {2020},
// howpublished = {\url{https://github.com/wsmoses/Enzyme}},
// note = {commit xxxxxxx}
// }
//
//===----------------------------------------------------------------------===//
//
// This file contains the declaration of Activity Analysis -- an AD-specific
// analysis that deduces if a given instruction or value can impact the
// calculation of a derivative. This file consists of two mutually recurive
// functions that compute this for values and instructions, respectively.
//
//===----------------------------------------------------------------------===//
#ifndef ENZYME_ACTIVE_VAR_H
#define ENZYME_ACTIVE_VAR_H 1

Expand Down
56 changes: 40 additions & 16 deletions enzyme/Enzyme/AdjointGenerator.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,27 @@
//===- AdjointGenerator.h - Implementation of Adjoint's of instructions --===//
//
// Enzyme Project
//
// Part of the Enzyme Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// If using this code in an academic setting, please cite the following:
// @misc{enzymeGithub,
// author = {William S. Moses and Valentin Churavy},
// title = {Enzyme: High Performance Automatic Differentiation of LLVM},
// year = {2020},
// howpublished = {\url{https://github.com/wsmoses/Enzyme}},
// note = {commit xxxxxxx}
// }
//
//===----------------------------------------------------------------------===//
//
// This file contains an instruction visitor DerivativeMaker that generates
// the corresponding augmented forward pass code, and adjoints for all
// LLVM instructions.
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/Value.h"
Expand Down Expand Up @@ -101,7 +125,7 @@ class DerivativeMaker
if (erased.count(inst_orig))
continue;
auto inst = gutils->getNewFromOriginal(inst_orig);
for (unsigned i = 0; i < inst->getNumOperands(); i++) {
for (unsigned i = 0; i < inst->getNumOperands(); ++i) {
if (inst->getOperand(i) == iload) {
inst->setOperand(i, pn);
}
Expand Down Expand Up @@ -574,7 +598,7 @@ class DerivativeMaker
->addToDiffeIndexed(SVI.getOperand(opnum),
Builder2.CreateExtractElement(loaded, instidx),
sv, Builder2);
instidx++;
++instidx;
}
setDiffe(&SVI, Constant::getNullValue(SVI.getType()), Builder2);
}
Expand Down Expand Up @@ -617,7 +641,7 @@ class DerivativeMaker

auto st = cast<StructType>(IVI.getType());
bool hasNonPointer = false;
for (unsigned i = 0; i < st->getNumElements(); i++) {
for (unsigned i = 0; i < st->getNumElements(); ++i) {
if (!st->getElementType(i)->isPointerTy()) {
hasNonPointer = true;
}
Expand Down Expand Up @@ -1104,7 +1128,7 @@ class DerivativeMaker
unsigned nextStart = size;

auto dt = vd[{-1}];
for (size_t i = start; i < size; i++) {
for (size_t i = start; i < size; ++i) {
bool legal = true;
dt.legalMergeIn(vd[{(int)i}], /*pointerIntSame*/ true, legal);
if (!legal) {
Expand Down Expand Up @@ -1168,7 +1192,7 @@ class DerivativeMaker
eraseIfUnused(II);
Value *orig_ops[II.getNumOperands()];

for (unsigned i = 0; i < II.getNumOperands(); i++) {
for (unsigned i = 0; i < II.getNumOperands(); ++i) {
orig_ops[i] = II.getOperand(i);
}

Expand Down Expand Up @@ -1799,7 +1823,7 @@ class DerivativeMaker
std::vector<Instruction *> postCreate;
std::vector<Instruction *> userReplace;

for (unsigned i = 0; i < orig->getNumArgOperands(); i++) {
for (unsigned i = 0; i < orig->getNumArgOperands(); ++i) {

auto argi = gutils->getNewFromOriginal(orig->getArgOperand(i));

Expand Down Expand Up @@ -1894,7 +1918,7 @@ class DerivativeMaker
std::pair<Argument *, std::set<int64_t>>(
&arg, TR.knownIntegralValues(orig->getArgOperand(argnum))));

argnum++;
++argnum;
}
nextTypeInfo.second = TR.query(orig);
}
Expand Down Expand Up @@ -2016,7 +2040,7 @@ class DerivativeMaker
llvm::errs() << " trying to call " << *newcalled << " " << *FT
<< "\n";

for (unsigned i = 0; i < pre_args.size(); i++) {
for (unsigned i = 0; i < pre_args.size(); ++i) {
assert(pre_args[i]);
assert(pre_args[i]->getType());
llvm::errs() << "args[" << i << "] = " << *pre_args[i]
Expand All @@ -2029,7 +2053,7 @@ class DerivativeMaker
if (pre_args.size() != FT->getNumParams())
goto badaugmentedfn;

for (unsigned i = 0; i < pre_args.size(); i++) {
for (unsigned i = 0; i < pre_args.size(); ++i) {
if (pre_args[i]->getType() != FT->getParamType(i))
goto badaugmentedfn;
}
Expand Down Expand Up @@ -2308,7 +2332,7 @@ class DerivativeMaker
else
llvm::errs() << " trying to call " << *newcalled << " " << *FT << "\n";

for (unsigned i = 0; i < args.size(); i++) {
for (unsigned i = 0; i < args.size(); ++i) {
assert(args[i]);
assert(args[i]->getType());
llvm::errs() << "args[" << i << "] = " << *args[i]
Expand All @@ -2321,7 +2345,7 @@ class DerivativeMaker
if (args.size() != FT->getNumParams())
goto badfn;

for (unsigned i = 0; i < args.size(); i++) {
for (unsigned i = 0; i < args.size(); ++i) {
if (args[i]->getType() != FT->getParamType(i))
goto badfn;
}
Expand All @@ -2332,12 +2356,12 @@ class DerivativeMaker

unsigned structidx = retUsed ? 1 : 0;
if (subdretptr)
structidx++;
++structidx;

for (unsigned i = 0; i < orig->getNumArgOperands(); i++) {
for (unsigned i = 0; i < orig->getNumArgOperands(); ++i) {
if (argsInverted[i] == DIFFE_TYPE::OUT_DIFF) {
Value *diffeadd = Builder2.CreateExtractValue(diffes, {structidx});
structidx++;
++structidx;
addToDiffe(orig->getArgOperand(i), diffeadd, Builder2,
TR.intType(orig->getArgOperand(i), false).isFloat());
}
Expand Down Expand Up @@ -2405,7 +2429,7 @@ class DerivativeMaker
bool fromStore = false;
for (auto &pair : *replacedReturns) {
if (pair.second == a) {
for (unsigned i = 0; i < a->getNumOperands(); i++) {
for (unsigned i = 0; i < a->getNumOperands(); ++i) {
a->setOperand(i, gutils->unwrapM(a->getOperand(i), Builder2, mapp,
UnwrapMode::LegalFullUnwrap));
}
Expand All @@ -2420,7 +2444,7 @@ class DerivativeMaker

auto orig_a = gutils->isOriginal(a);
if (orig_a) {
for (unsigned i = 0; i < a->getNumOperands(); i++) {
for (unsigned i = 0; i < a->getNumOperands(); ++i) {
a->setOperand(i,
gutils->unwrapM(
gutils->getNewFromOriginal(orig_a->getOperand(i)),
Expand Down
24 changes: 24 additions & 0 deletions enzyme/Enzyme/DifferentialUseAnalysis.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,27 @@
//===- DifferentialUseAnalysis.h - Determine values needed in reverse pass-===//
//
// Enzyme Project
//
// Part of the Enzyme Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// If using this code in an academic setting, please cite the following:
// @misc{enzymeGithub,
// author = {William S. Moses and Valentin Churavy},
// title = {Enzyme: High Performance Automatic Differentiation of LLVM},
// year = {2020},
// howpublished = {\url{https://github.com/wsmoses/Enzyme}},
// note = {commit xxxxxxx}
// }
//
//===----------------------------------------------------------------------===//
//
// This file contains the declaration of Differential USe Analysis -- an
// AD-specific analysis that deduces if a given value is needed in the reverse
// pass.
//
//===----------------------------------------------------------------------===//
#include "GradientUtils.h"

// Determine if a value is needed in the reverse pass. We only use this logic in
Expand Down
Loading