Enzyme main
Loading...
Searching...
No Matches
GradientUtilsReverse.cpp
Go to the documentation of this file.
1//===- GradientUtilsReverse.cpp - Utilities for gradient interfaces
2//--------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
11#include "Dialect/Ops.h"
14#include "mlir/IR/Matchers.h"
15#include "mlir/IR/SymbolTable.h"
16#include "mlir/Interfaces/FunctionInterfaces.h"
17
18// TODO: this shouldn't depend on specific dialects except Enzyme.
19#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
20
21#include "CloneFunction.h"
22#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
23#include "mlir/Dialect/Func/IR/FuncOps.h"
24#include "mlir/IR/Dominance.h"
25#include "llvm/ADT/BreadthFirstIterator.h"
26
27using namespace mlir;
28using namespace mlir::enzyme;
29
31 MEnzymeLogic &Logic, FunctionOpInterface newFunc_,
32 FunctionOpInterface oldFunc_, MTypeAnalysis &TA_,
33 IRMapping invertedPointers_, const llvm::ArrayRef<bool> returnPrimals,
34 const llvm::ArrayRef<bool> returnShadows,
35 const SmallPtrSetImpl<mlir::Value> &constantvalues_,
36 const SmallPtrSetImpl<mlir::Value> &activevals_,
37 ArrayRef<DIFFE_TYPE> ReturnActivity, ArrayRef<DIFFE_TYPE> ArgDiffeTypes_,
38 IRMapping &originalToNewFn_,
39 std::map<Operation *, Operation *> &originalToNewFnOps_,
40 DerivativeMode mode_, unsigned width, bool omp, StringRef postpasses,
41 bool verifyPostPasses, bool strongZero)
42 : MDiffeGradientUtils(Logic, newFunc_, oldFunc_, TA_, /*MTypeResults*/ {},
43 invertedPointers_, returnPrimals, returnShadows,
44 constantvalues_, activevals_, ReturnActivity,
45 ArgDiffeTypes_, originalToNewFn_, originalToNewFnOps_,
46 mode_, width, omp, postpasses, verifyPostPasses,
47 strongZero) {}
48
50 Type indexType = getIndexType();
51 return getCacheType(indexType);
52}
53
55 return mlir::IntegerType::get(initializationBlock->begin()->getContext(), 32);
56}
57
59 OpBuilder builder(initializationBlock, initializationBlock->begin());
60 // The block is where the init goes, not where a location comes from: asking
61 // its last operation for one reads off the end of an empty block, and the
62 // first cache anything asks for is the one that finds it empty.
63 Location loc = initializationBlock->empty()
64 ? builder.getUnknownLoc()
65 : initializationBlock->rbegin()->getLoc();
66 return enzyme::InitOp::create(builder, loc, t);
67}
68
69// Cache
71 // Likewise the context, which is the type's own and does not need looking up
72 // in the block.
73 Type cacheType = CacheType::get(t.getContext(), t);
74 return cacheType;
75}
76
78 std::function<std::pair<Value, Value>(Type)> hook) {
79 if (hook != nullptr) {
80 cacheCreatorHook.push_back(hook);
81 }
82}
83
85 std::function<std::pair<Value, Value>(Type)> hook) {
86 if (hook != nullptr) {
87 cacheCreatorHook.pop_back();
88 }
89}
90
91std::pair<Value, Value> MGradientUtilsReverse::getNewCache(Type t) {
92 if (cacheCreatorHook.empty()) {
93 Value cache = insertInit(t);
94 return {cache, cache};
95 }
96 return cacheCreatorHook.back()(t);
97}
98
99// We assume that caches will only be written to at one location. The returned
100// cache is (might be) "pop only"
101Value MGradientUtilsReverse::initAndPushCache(Value v, OpBuilder &builder) {
102 auto ct = getCacheType(v.getType());
103 auto [pushCache, popCache] = getNewCache(ct);
104 enzyme::PushOp::create(builder, v.getLoc(), pushCache, v);
105 return popCache;
106}
107
108Value MGradientUtilsReverse::popCache(Value cache, OpBuilder &builder) {
109 return enzyme::PopOp::create(
110 builder, cache.getLoc(),
111 cast<enzyme::CacheType>(cache.getType()).getType(), cache);
112}
113
114Operation *
116 Operation *op) {
117 IRMapping map;
118 for (auto operand : op->getOperands())
119 map.map(operand, getNewFromOriginal(operand));
120 return B.clone(*op, map);
121}
122
124 Value addedGradient,
125 OpBuilder &builder) {
126 assert(!isConstantValue(oldGradient));
127 Value operandGradient = diffe(oldGradient, builder);
128 auto iface = cast<AutoDiffTypeInterface>(addedGradient.getType());
129 auto added = iface.createAddOp(builder, oldGradient.getLoc(), operandGradient,
130 addedGradient);
131 setDiffe(oldGradient, added, builder);
132}
133
135 Region &newFunc) {
136 for (auto it = oldFunc.getBlocks().rbegin(); it != oldFunc.getBlocks().rend();
137 ++it) {
138 Block *block = &*it;
139 Block *reverseBlock = new Block();
140 newFunc.getBlocks().insert(newFunc.end(), reverseBlock);
141 mapReverseModeBlocks.map(block, reverseBlock);
142 }
143}
144
146 MEnzymeLogic &Logic, DerivativeMode mode_, unsigned width,
147 FunctionOpInterface todiff, MTypeAnalysis &TA, MFnTypeInfo &oldTypeInfo,
148 const ArrayRef<bool> returnPrimals, const ArrayRef<bool> returnShadows,
149 ArrayRef<DIFFE_TYPE> retType, ArrayRef<DIFFE_TYPE> constant_args,
150 mlir::Type additionalArg, bool omp, llvm::StringRef postpasses,
151 bool verifyPostPasses, bool strongZero) {
152 std::string prefix;
153
154 switch (mode_) {
158 assert(false);
159 break;
162 prefix = "diffe";
163 break;
165 llvm_unreachable("invalid DerivativeMode: ReverseModePrimal\n");
166 }
167
168 if (width > 1)
169 prefix += std::to_string(width);
170
171 IRMapping originalToNew;
172 std::map<Operation *, Operation *> originalToNewOps;
173
174 SmallPtrSet<mlir::Value, 1> returnvals;
175 SmallPtrSet<mlir::Value, 1> constant_values;
176 SmallPtrSet<mlir::Value, 1> nonconstant_values;
177 IRMapping invertedPointers;
178 FunctionOpInterface newFunc = CloneFunctionWithReturns(
179 mode_, width, todiff, invertedPointers, constant_args, constant_values,
180 nonconstant_values, returnvals, returnPrimals, returnShadows, retType,
181 prefix + todiff.getName(), originalToNew, originalToNewOps,
182 additionalArg);
183
184 return new MGradientUtilsReverse(
186 returnShadows, constant_values, nonconstant_values, retType,
187 constant_args, originalToNew, originalToNewOps, mode_, width, omp,
189}
FunctionOpInterface CloneFunctionWithReturns(DerivativeMode mode, unsigned width, FunctionOpInterface F, IRMapping &ptrInputs, ArrayRef< DIFFE_TYPE > ArgActivity, SmallPtrSetImpl< mlir::Value > &constants, SmallPtrSetImpl< mlir::Value > &nonconstants, SmallPtrSetImpl< mlir::Value > &returnvals, const std::vector< bool > &returnPrimals, const std::vector< bool > &returnShadows, ArrayRef< DIFFE_TYPE > RetActivity, Twine name, IRMapping &VMap, std::map< Operation *, Operation * > &OpMap, mlir::Type additionalArg)
DerivativeMode
Definition Utils.h:524
Value popCache(Value cache, OpBuilder &builder)
SmallVector< std::function< std::pair< Value, Value >(Type)> > cacheCreatorHook
Value initAndPushCache(Value v, OpBuilder &builder)
MGradientUtilsReverse(MEnzymeLogic &Logic, FunctionOpInterface newFunc_, FunctionOpInterface oldFunc_, MTypeAnalysis &TA_, IRMapping invertedPointers_, const llvm::ArrayRef< bool > returnPrimals, const llvm::ArrayRef< bool > returnShadows, const SmallPtrSetImpl< mlir::Value > &constantvalues_, const SmallPtrSetImpl< mlir::Value > &activevals_, ArrayRef< DIFFE_TYPE > ReturnActivity, ArrayRef< DIFFE_TYPE > ArgDiffeTypes_, IRMapping &originalToNewFn_, std::map< Operation *, Operation * > &originalToNewFnOps_, DerivativeMode mode_, unsigned width, bool omp, llvm::StringRef postpasses, bool verifyPostPasses, bool strongZero)
void createReverseModeBlocks(Region &oldFunc, Region &newFunc)
void deregisterCacheCreatorHook(std::function< std::pair< Value, Value >(Type)> hook)
void registerCacheCreatorHook(std::function< std::pair< Value, Value >(Type)> hook)
void addToDiffe(mlir::Value oldGradient, mlir::Value addedGradient, OpBuilder &builder)
static MGradientUtilsReverse * CreateFromClone(MEnzymeLogic &Logic, DerivativeMode mode_, unsigned width, FunctionOpInterface todiff, MTypeAnalysis &TA, MFnTypeInfo &oldTypeInfo, const ArrayRef< bool > returnPrimals, const ArrayRef< bool > returnShadows, llvm::ArrayRef< DIFFE_TYPE > retType, llvm::ArrayRef< DIFFE_TYPE > constant_args, mlir::Type additionalArg, bool omp, llvm::StringRef postpasses, bool verifyPostPasses, bool strongZero)
std::pair< Value, Value > getNewCache(Type t)
Operation * cloneWithNewOperands(OpBuilder &B, Operation *op)
const llvm::ArrayRef< bool > returnShadows
const llvm::ArrayRef< bool > returnPrimals
FunctionOpInterface oldFunc
FunctionOpInterface newFunc
static LoopCacheType getCacheType(Operation *op)