Enzyme main
Loading...
Searching...
No Matches
GradientUtils.h
Go to the documentation of this file.
1//===- GradientUtils.h - Utilities for gradient interfaces -------* C++ -*-===//
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#pragma once
9
12
14#include "mlir/IR/IRMapping.h"
15#include "mlir/Interfaces/FunctionInterfaces.h"
16
17namespace mlir {
18namespace enzyme {
19
21public:
22 // From CacheUtility
23 FunctionOpInterface newFunc;
24
28 FunctionOpInterface oldFunc;
30 IRMapping originalToNewFn;
31 std::map<Operation *, Operation *> originalToNewFnOps;
32
33 SmallPtrSet<Block *, 4> blocksNotForAnalysis;
34 DenseMap<Operation *, bool> readOnlyCache;
35 std::unique_ptr<enzyme::ActivityAnalyzer> activityAnalyzer;
36 // The solver the annotations below were run in. One per function being
37 // differentiated: a DataFlowSolver keeps every lattice it has ever made, and
38 // these analyses are not interprocedural, so one shared across a module's
39 // worth of functions only makes each of them join against all the ones
40 // before. Declared ahead of the analyzer, which refers to it.
41 std::unique_ptr<DataFlowSolver> dataflowSolver;
42 std::unique_ptr<enzyme::DataFlowActivityAnalyzer> dataflowActivityAnalyzer;
43
46 bool omp;
48 llvm::StringRef postpasses;
50 const llvm::ArrayRef<bool> returnPrimals;
51 const llvm::ArrayRef<bool> returnShadows;
52
53 unsigned width;
54 ArrayRef<DIFFE_TYPE> ArgDiffeTypes;
55 ArrayRef<DIFFE_TYPE> RetDiffeTypes;
56
57 SmallVector<mlir::Value, 1> getNewFromOriginal(ValueRange originst) const;
58 mlir::Value getNewFromOriginal(const mlir::Value originst) const;
59 mlir::Block *getNewFromOriginal(mlir::Block *originst) const;
60 Operation *getNewFromOriginal(Operation *originst) const;
61
62 MGradientUtils(MEnzymeLogic &Logic, FunctionOpInterface newFunc_,
63 FunctionOpInterface oldFunc_, MTypeAnalysis &TA_,
64 MTypeResults TR_, IRMapping &invertedPointers_,
65 const llvm::ArrayRef<bool> returnPrimals,
66 const llvm::ArrayRef<bool> returnShadows,
67 const SmallPtrSetImpl<mlir::Value> &constantvalues_,
68 const SmallPtrSetImpl<mlir::Value> &activevals_,
69 ArrayRef<DIFFE_TYPE> ReturnActivities,
70 ArrayRef<DIFFE_TYPE> ArgDiffeTypes_,
71 IRMapping &originalToNewFn_,
72 std::map<Operation *, Operation *> &originalToNewFnOps_,
73 DerivativeMode mode, unsigned width, bool omp,
74 llvm::StringRef postpasses, bool verifyPostPasses,
75 bool strongZero);
76 void erase(Operation *op) { op->erase(); }
77 void replaceOrigOpWith(Operation *op, ValueRange vals) {
78 for (auto &&[res, rep] : llvm::zip(op->getResults(), vals)) {
79 originalToNewFn.map(res, rep);
80 }
81 auto newOp = getNewFromOriginal(op);
82 newOp->replaceAllUsesWith(vals);
83 originalToNewFnOps.erase(op);
84 }
85 void eraseIfUnused(Operation *op, bool erase = true, bool check = true) {
86 // TODO
87 }
88 bool isConstantInstruction(mlir::Operation *v) const;
89 bool isConstantValue(mlir::Value v) const;
90
91 /// The base allocation a pointer-like value views: view-like ops and LLVM
92 /// geps and casts peeled away, the way LLVM's getUnderlyingObject does.
93 static mlir::Value getBaseObject(mlir::Value v);
95 /// The activity the caller declared for the memory this pointer views:
96 /// the base's entry in ArgDiffeTypes when the base is an argument of the
97 /// function being differentiated, DUP_ARG otherwise.
98 DIFFE_TYPE getDiffeTypeOfBase(mlir::Value ptr);
99
100 /// True when a primal store through this pointer may be omitted:
101 /// declaring the base enzyme_dupnoneed is the caller saying nothing --
102 /// itself included -- needs the primal contents of that memory.
103 bool primalStoreElidable(mlir::Value ptr) {
105 }
106 mlir::Value invertPointerM(mlir::Value v, OpBuilder &Builder2);
108
109 Operation *cloneWithNewOperands(OpBuilder &B, Operation *op);
110
111 LogicalResult visitChild(Operation *op);
112
113 void setDiffe(mlir::Value origv, mlir::Value newv, mlir::OpBuilder &builder);
114 void setInvertedPointer(mlir::Value origv, mlir::Value newv);
116 mlir::Type getShadowType(mlir::Type T) {
117 auto iface = cast<AutoDiffTypeInterface>(T);
118 return iface.getShadowType(width);
119 }
121 static llvm::SmallVector<mlir::Value, 1>
122 reindex_arguments(llvm::ArrayRef<mlir::Value> vals,
123 mlir::OperandRange range) {
124 llvm::SmallVector<mlir::Value, 1> results;
125 for (size_t i = 0; i < range.size(); i++) {
126 results.push_back(vals[range.getBeginOperandIndex() + i]);
127 }
128 return results;
129 }
133protected:
134 IRMapping differentials;
135
137 SmallVector<std::function<Value(Location, Type)>> gradientCreatorHook;
138
139public:
140 void registerGradientCreatorHook(std::function<Value(Location, Type)> hook);
141 void deregisterGradientCreatorHook(std::function<Value(Location, Type)> hook);
142 Value getNewGradient(Location loc, Type t);
144 mlir::Value getDifferential(mlir::Value origv);
146 void setDiffe(mlir::Value origv, mlir::Value newv, mlir::OpBuilder &builder);
148 void zeroDiffe(mlir::Value origv, mlir::OpBuilder &builder);
149
150 mlir::Value diffe(mlir::Value origv, mlir::OpBuilder &builder);
151
152 MDiffeGradientUtils(MEnzymeLogic &Logic, FunctionOpInterface newFunc_,
153 FunctionOpInterface oldFunc_, MTypeAnalysis &TA,
154 MTypeResults TR, IRMapping &invertedPointers_,
155 const llvm::ArrayRef<bool> returnPrimals,
156 const llvm::ArrayRef<bool> returnShadows,
157 const SmallPtrSetImpl<mlir::Value> &constantvalues_,
158 const SmallPtrSetImpl<mlir::Value> &activevals_,
159 ArrayRef<DIFFE_TYPE> RetActivity,
160 ArrayRef<DIFFE_TYPE> ArgActivity, IRMapping &origToNew_,
161 std::map<Operation *, Operation *> &origToNewOps_,
162 DerivativeMode mode, unsigned width, bool omp,
163 llvm::StringRef postpasses, bool verifyPostPasses,
165 : MGradientUtils(Logic, newFunc_, oldFunc_, TA, TR, invertedPointers_,
166 returnPrimals, returnShadows, constantvalues_,
167 activevals_, RetActivity, ArgActivity, origToNew_,
168 origToNewOps_, mode, width, omp, postpasses,
170 initializationBlock(&*(newFunc.getFunctionBody().begin())) {}
171
172 // Technically diffe constructor
175 FunctionOpInterface todiff, MTypeAnalysis &TA, MFnTypeInfo &oldTypeInfo,
176 const llvm::ArrayRef<bool> returnPrimals,
177 const llvm::ArrayRef<bool> returnShadows,
178 ArrayRef<DIFFE_TYPE> RetActivity, ArrayRef<DIFFE_TYPE> ArgActivity,
179 mlir::Type additionalArg, bool omp, llvm::StringRef postpasses,
180 bool verifyPostPasses, bool strongZero) {
181 std::string prefix;
183 switch (mode) {
187 prefix = "fwddiffe";
188 break;
191 prefix = "diffe";
192 break;
194 llvm_unreachable("invalid DerivativeMode: ReverseModePrimal\n");
196
197 if (width > 1)
198 prefix += std::to_string(width);
199
200 IRMapping originalToNew;
201 std::map<Operation *, Operation *> originalToNewOps;
202
203 SmallPtrSet<mlir::Value, 1> returnvals;
204 SmallPtrSet<mlir::Value, 1> constant_values;
205 SmallPtrSet<mlir::Value, 1> nonconstant_values;
206 IRMapping invertedPointers;
207 FunctionOpInterface newFunc = CloneFunctionWithReturns(
208 mode, width, todiff, invertedPointers, ArgActivity, constant_values,
209 nonconstant_values, returnvals, returnPrimals, returnShadows,
210 RetActivity, prefix + todiff.getName(), originalToNew, originalToNewOps,
211 additionalArg);
213 return new MDiffeGradientUtils(
215 returnShadows, constant_values, nonconstant_values, RetActivity,
216 ArgActivity, originalToNew, originalToNewOps, mode, width, omp,
218 }
219};
220
221}; // namespace enzyme
222}; // namespace mlir
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)
DIFFE_TYPE
Potential differentiable argument classifications.
DerivativeMode
Definition Utils.h:524
SmallVector< std::function< Value(Location, Type)> > gradientCreatorHook
void registerGradientCreatorHook(std::function< Value(Location, Type)> hook)
mlir::Value getDifferential(mlir::Value origv)
void setDiffe(mlir::Value origv, mlir::Value newv, mlir::OpBuilder &builder)
void deregisterGradientCreatorHook(std::function< Value(Location, Type)> hook)
static MDiffeGradientUtils * CreateFromClone(MEnzymeLogic &Logic, DerivativeMode mode, unsigned width, FunctionOpInterface todiff, MTypeAnalysis &TA, MFnTypeInfo &oldTypeInfo, const llvm::ArrayRef< bool > returnPrimals, const llvm::ArrayRef< bool > returnShadows, ArrayRef< DIFFE_TYPE > RetActivity, ArrayRef< DIFFE_TYPE > ArgActivity, mlir::Type additionalArg, bool omp, llvm::StringRef postpasses, bool verifyPostPasses, bool strongZero)
Value getNewGradient(Location loc, Type t)
mlir::Value diffe(mlir::Value origv, mlir::OpBuilder &builder)
void zeroDiffe(mlir::Value origv, mlir::OpBuilder &builder)
MDiffeGradientUtils(MEnzymeLogic &Logic, FunctionOpInterface newFunc_, FunctionOpInterface oldFunc_, MTypeAnalysis &TA, MTypeResults TR, 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 > RetActivity, ArrayRef< DIFFE_TYPE > ArgActivity, IRMapping &origToNew_, std::map< Operation *, Operation * > &origToNewOps_, DerivativeMode mode, unsigned width, bool omp, llvm::StringRef postpasses, bool verifyPostPasses, bool strongZero)
bool primalStoreElidable(mlir::Value ptr)
True when a primal store through this pointer may be omitted: declaring the base enzyme_dupnoneed is ...
Operation * cloneWithNewOperands(OpBuilder &B, Operation *op)
ArrayRef< DIFFE_TYPE > RetDiffeTypes
static llvm::SmallVector< mlir::Value, 1 > reindex_arguments(llvm::ArrayRef< mlir::Value > vals, mlir::OperandRange range)
std::unique_ptr< DataFlowSolver > dataflowSolver
const llvm::ArrayRef< bool > returnShadows
mlir::Type getShadowType(mlir::Type T)
const llvm::ArrayRef< bool > returnPrimals
FunctionOpInterface oldFunc
void replaceOrigOpWith(Operation *op, ValueRange vals)
std::map< Operation *, Operation * > originalToNewFnOps
DenseMap< Operation *, bool > readOnlyCache
ArrayRef< DIFFE_TYPE > ArgDiffeTypes
LogicalResult visitChild(Operation *op)
void erase(Operation *op)
DIFFE_TYPE getDiffeTypeOfBase(mlir::Value ptr)
The activity the caller declared for the memory this pointer views: the base's entry in ArgDiffeTypes...
void setDiffe(mlir::Value origv, mlir::Value newv, mlir::OpBuilder &builder)
mlir::Value invertPointerM(mlir::Value v, OpBuilder &Builder2)
void eraseIfUnused(Operation *op, bool erase=true, bool check=true)
SmallVector< mlir::Value, 1 > getNewFromOriginal(ValueRange originst) const
std::unique_ptr< enzyme::DataFlowActivityAnalyzer > dataflowActivityAnalyzer
MGradientUtils(MEnzymeLogic &Logic, FunctionOpInterface newFunc_, FunctionOpInterface oldFunc_, MTypeAnalysis &TA_, MTypeResults TR_, 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 > ReturnActivities, ArrayRef< DIFFE_TYPE > ArgDiffeTypes_, IRMapping &originalToNewFn_, std::map< Operation *, Operation * > &originalToNewFnOps_, DerivativeMode mode, unsigned width, bool omp, llvm::StringRef postpasses, bool verifyPostPasses, bool strongZero)
std::unique_ptr< enzyme::ActivityAnalyzer > activityAnalyzer
FunctionOpInterface newFunc
bool isConstantInstruction(mlir::Operation *v) const
void setInvertedPointer(mlir::Value origv, mlir::Value newv)
bool isConstantValue(mlir::Value v) const
SmallPtrSet< Block *, 4 > blocksNotForAnalysis
static mlir::Value getBaseObject(mlir::Value v)
The base allocation a pointer-like value views: view-like ops and LLVM geps and casts peeled away,...