Enzyme main
Loading...
Searching...
No Matches
EnzymeWrapPass.cpp
Go to the documentation of this file.
1//===- EnzymeWrapPass.cpp - Replace calls with their derivatives ------------ //
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements a pass to create wrapper functions which differentiate
10// ops.
11//===----------------------------------------------------------------------===//
12
14#include "Dialect/Ops.h"
17#include "PassDetails.h"
18#include "Passes/Passes.h"
19#include "mlir/IR/Builders.h"
20#include "mlir/IR/IRMapping.h"
21#include "mlir/Interfaces/ControlFlowInterfaces.h"
22#include "mlir/Interfaces/FunctionInterfaces.h"
23
24#include "mlir/Dialect/Func/IR/FuncOps.h"
25#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
26#include "mlir/Dialect/Math/IR/Math.h"
27#include "mlir/Dialect/Tensor/IR/Tensor.h"
28
29#define DEBUG_TYPE "enzyme"
30
31namespace mlir {
32namespace enzyme {
33#define GEN_PASS_DEF_DIFFERENTIATEWRAPPERPASS
34#include "Passes/Passes.h.inc"
35} // namespace enzyme
36} // namespace mlir
37
38using namespace mlir;
39using namespace mlir::enzyme;
40using namespace enzyme;
41
42std::vector<DIFFE_TYPE> parseActivityString(StringRef inp) {
43 if (inp.size() == 0)
44 return {};
45 std::vector<DIFFE_TYPE> ArgActivity;
46 SmallVector<StringRef, 1> split;
47 StringRef(inp.data(), inp.size()).split(split, ',');
48 for (auto &str : split) {
49 if (str == "enzyme_dup")
50 ArgActivity.push_back(DIFFE_TYPE::DUP_ARG);
51 else if (str == "enzyme_const")
52 ArgActivity.push_back(DIFFE_TYPE::CONSTANT);
53 else if (str == "enzyme_dupnoneed")
54 ArgActivity.push_back(DIFFE_TYPE::DUP_NONEED);
55 else if (str == "enzyme_active")
56 ArgActivity.push_back(DIFFE_TYPE::OUT_DIFF);
57 else {
58 llvm::errs() << "unknown activity to parse, found: '" << str << "'\n";
59 assert(0 && " unknown constant");
60 }
61 }
62 return ArgActivity;
63}
64
65namespace {
66struct DifferentiateWrapperPass
67 : public enzyme::impl::DifferentiateWrapperPassBase<
68 DifferentiateWrapperPass> {
69 using DifferentiateWrapperPassBase::DifferentiateWrapperPassBase;
70
71 void runOnOperation() override {
72 MEnzymeLogic Logic(dataflowActivity);
73 SymbolTableCollection symbolTable;
74 symbolTable.getSymbolTable(getOperation());
75
76 Operation *symbolOp = nullptr;
77 if (infn != "")
78 symbolOp = symbolTable.lookupSymbolIn<Operation *>(
79 getOperation(), StringAttr::get(getOperation()->getContext(), infn));
80 else {
81 for (auto &op : getOperation()->getRegion(0).front()) {
82 auto fn = dyn_cast<FunctionOpInterface>(symbolOp);
83 if (!fn)
84 continue;
85 assert(symbolOp == nullptr);
86 symbolOp = &op;
87 }
88 }
89 if (!symbolOp) {
90 llvm::errs() << " Could not find function '" << infn
91 << "' to differentiate\n";
92 signalPassFailure();
93 return;
94 }
95 auto fn = cast<FunctionOpInterface>(symbolOp);
96 bool omp = false;
97 std::string postpasses = "";
98 bool verifyPostPasses = true;
99
100 std::vector<DIFFE_TYPE> ArgActivity =
101 parseActivityString(argTys.getValue());
102
103 if (ArgActivity.size() != fn.getNumArguments()) {
104 fn->emitError()
105 << "Incorrect number of arg activity states for function, found "
106 << ArgActivity.size() << " expected "
107 << fn.getFunctionBody().front().getNumArguments();
108 return;
109 }
110
111 std::vector<DIFFE_TYPE> RetActivity =
112 parseActivityString(retTys.getValue());
113 if (RetActivity.size() != fn.getNumResults()) {
114 fn->emitError()
115 << "Incorrect number of ret activity states for function, found "
116 << RetActivity.size() << " expected " << fn.getNumResults();
117 return;
118 }
119 std::vector<bool> returnPrimal;
120 std::vector<bool> returnShadow;
121 for (auto act : RetActivity) {
122 returnPrimal.push_back(act == DIFFE_TYPE::DUP_ARG);
123 returnShadow.push_back(false);
124 }
125
126 MTypeAnalysis TA;
127 auto type_args = TA.getAnalyzedTypeInfo(fn);
128
129 bool freeMemory = true;
130 size_t width = 1;
131
132 std::vector<bool> overwritten_args;
133 for (auto &a : fn.getFunctionBody().getArguments()) {
134 (void)a;
135 overwritten_args.push_back(
137 }
138
139 FunctionOpInterface newFunc;
140 if (mode == DerivativeMode::ForwardMode) {
141 newFunc = Logic.CreateForwardDiff(
142 fn, RetActivity, ArgActivity, TA, returnPrimal, mode, freeMemory,
143 width,
144 /*addedType*/ nullptr, type_args, overwritten_args,
145 /*augmented*/ nullptr, omp, postpasses, verifyPostPasses, strongZero);
146 if (!newFunc)
147 return signalPassFailure();
148 } else {
149 newFunc = Logic.CreateReverseDiff(
150 fn, RetActivity, ArgActivity, TA, returnPrimal, returnShadow, mode,
151 freeMemory, atomicAdd, width,
152 /*addedType*/ nullptr, type_args, overwritten_args,
153 /*augmented*/ nullptr, omp, postpasses, verifyPostPasses, strongZero,
154 markReadonly);
155 }
156 if (!newFunc) {
157 signalPassFailure();
158 return;
159 }
160 if (outfn == "") {
161 fn->erase();
162 SymbolTable::setSymbolVisibility(newFunc,
163 SymbolTable::Visibility::Public);
164 SymbolTable::setSymbolName(cast<FunctionOpInterface>(newFunc),
165 (std::string)infn);
166 } else {
167 SymbolTable::setSymbolName(cast<FunctionOpInterface>(newFunc),
168 (std::string)outfn);
169 }
170
171 getOperation()->walk([&](FunctionOpInterface op) { removeSummaries(op); });
172 }
173};
174
175} // end anonymous namespace
std::vector< DIFFE_TYPE > parseActivityString(StringRef inp)
static std::string str(AugmentedStruct c)
Definition EnzymeLogic.h:62
MFnTypeInfo getAnalyzedTypeInfo(FunctionOpInterface op) const
Definition EnzymeLogic.h:25
void removeSummaries(Operation *op)