Enzyme main
Loading...
Searching...
No Matches
ActivityAnalysis.h
Go to the documentation of this file.
1#ifndef ENZYME_MLIR_ANALYSIS_ACTIVITYANALYSIS_H
2#define ENZYME_MLIR_ANALYSIS_ACTIVITYANALYSIS_H
3
4#include "../../Utils.h"
6#include "mlir/IR/Block.h"
7#include "mlir/Interfaces/FunctionInterfaces.h"
8
9namespace mlir {
10
11class CallOpInterface;
12class FunctionOpInterface;
13
14namespace enzyme {
15
16// class TypeResults {};
17
18class MTypeResults;
19
21public:
22 DataFlowActivityAnalyzer(DataFlowSolver &solver, FunctionOpInterface funcOp,
23 ArrayRef<DIFFE_TYPE> argActivity,
24 ArrayRef<DIFFE_TYPE> returnActivity);
25
26 bool isInactiveOperation(Operation *op);
27 bool isInactiveValue(Value value);
28
29private:
30 // The answers are fixed once the analysis is constructed, and the queries
31 // walk points-to closures: differentiation asks about every value, often
32 // repeatedly, so cache.
33 DenseMap<Value, bool> inactiveValueCache;
34 DenseMap<Operation *, bool> inactiveOpCache;
35
36 FunctionOpInterface funcOp;
37 DataFlowSolver &solver;
38 enzyme::PointsToSets p2sets;
39 enzyme::ForwardOriginsMap forwardOriginsMap;
40 enzyme::BackwardOriginsMap backwardOriginsMap;
41
42 const ArrayRef<DIFFE_TYPE> argActivity;
43 const ArrayRef<DIFFE_TYPE> returnActivity;
44
45 bool isOriginActive(OriginAttr origin);
46 void joinActiveDataState(Value v, ForwardOriginsLattice &sources,
47 BackwardOriginsLattice &sinks);
48 void joinActivePointerState(const AliasClassSet &aliasClasses,
49 ForwardOriginsLattice &sources,
50 BackwardOriginsLattice &sinks);
51 void joinActiveValueState(Value v, ForwardOriginsLattice &sources,
52 BackwardOriginsLattice &sinks);
53};
54
55/// Helper class to analyze the differential activity
57 // PreProcessCache &PPC;
58
59 // TODO: MLIR aliasing Information
60 // llvm::AAResults &AA;
61
62 // Blocks not to be analyzed
63 const llvm::SmallPtrSetImpl<Block *> &notForAnalysis;
64
65 // Blocks not to be analyzed
66 llvm::DenseMap<Operation *, bool> &readOnlyCache;
68 /// Library Information
69 // llvm::TargetLibraryInfo &TLI;
70
71public:
72 /// Whether the returns of the function being analyzed are active
73 const llvm::ArrayRef<DIFFE_TYPE> ActiveReturns;
74
75private:
76 /// Direction of current analysis
77 const uint8_t directions;
78 /// Analyze up based off of operands
79 static constexpr uint8_t UP = 1;
80 /// Analyze down based off uses
81 static constexpr uint8_t DOWN = 2;
82
83 /// Operations that don't propagate adjoints
84 /// These operations could return an active pointer, but
85 /// do not propagate adjoints themselves
86 llvm::SmallPtrSet<Operation *, 4> ConstantOperations;
87
88 /// Operations that could propagate adjoints
89 llvm::SmallPtrSet<Operation *, 20> ActiveOperations;
90
91 /// Values that do not contain derivative information, either
92 /// directly or as a pointer to
93 llvm::SmallPtrSet<Value, 4> ConstantValues;
94
95 /// Values that may contain derivative information
96 llvm::SmallPtrSet<Value, 2> ActiveValues;
97
98 /// Intermediate pointers which are created by inactive instructions
99 /// but are marked as active values to inductively determine their
100 /// activity.
101 llvm::SmallPtrSet<Value, 1> DeducingPointers;
102
103public:
104 /// Construct the analyzer from the a previous set of constant and active
105 /// values and whether returns are active. The all arguments of the functions
106 /// being analyzed must be in the set of constant and active values, lest an
107 /// error occur during analysis
109 // PreProcessCache &PPC, llvm::AAResults &AA_,
110 const llvm::SmallPtrSetImpl<Block *> &notForAnalysis_,
111 llvm::DenseMap<Operation *, bool> &readOnlyCache_,
112 // llvm::TargetLibraryInfo &TLI_,
113 const llvm::SmallPtrSetImpl<Value> &ConstantValues,
114 const llvm::SmallPtrSetImpl<Value> &ActiveValues,
115 llvm::ArrayRef<DIFFE_TYPE> ActiveReturns)
116 : notForAnalysis(notForAnalysis_), readOnlyCache(readOnlyCache_),
117 ActiveReturns(ActiveReturns), directions(UP | DOWN),
118 ConstantValues(ConstantValues.begin(), ConstantValues.end()),
119 ActiveValues(ActiveValues.begin(), ActiveValues.end()) {}
120
121 /// Return whether this operation is known not to propagate adjoints
122 /// Note that operations could return an active pointer, but
123 /// do not propagate adjoints themselves
124 bool isConstantOperation(MTypeResults const &TR, Operation *op);
125
126 /// Return whether this values is known not to contain derivative
127 /// information, either directly or as a pointer to
128 bool isConstantValue(MTypeResults const &TR, Value val);
129
130 bool isReadOnly(Operation *val);
131
132private:
133 DenseMap<Operation *, llvm::SmallPtrSet<Value, 4>>
134 ReEvaluateValueIfInactiveOp;
135 DenseMap<Value, llvm::SmallPtrSet<Value, 4>> ReEvaluateValueIfInactiveValue;
136 DenseMap<Value, llvm::SmallPtrSet<Operation *, 4>>
137 ReEvaluateOpIfInactiveValue;
138
139 void InsertConstantOperation(MTypeResults const &TR, Operation *op);
140 void InsertConstantValue(MTypeResults const &TR, Value V);
141
142 /// Create a new analyzer starting from an existing Analyzer
143 /// This is used to perform inductive assumptions
144 ActivityAnalyzer(ActivityAnalyzer &Other, uint8_t directions)
145 : notForAnalysis(Other.notForAnalysis),
146 readOnlyCache(Other.readOnlyCache), ActiveReturns(Other.ActiveReturns),
147 directions(directions), ConstantOperations(Other.ConstantOperations),
148 ActiveOperations(Other.ActiveOperations),
149 ConstantValues(Other.ConstantValues), ActiveValues(Other.ActiveValues) {
150 // DeducingPointers(Other.DeducingPointers) {
151 assert(directions != 0);
152 assert((directions & Other.directions) == directions);
153 assert((directions & Other.directions) != 0);
154 }
155
156 /// Import known constants from an existing analyzer
157 void insertConstantsFrom(MTypeResults const &TR,
158 ActivityAnalyzer &Hypothesis) {
159 for (auto I : Hypothesis.ConstantOperations) {
160 InsertConstantOperation(TR, I);
161 }
162 for (auto V : Hypothesis.ConstantValues) {
163 InsertConstantValue(TR, V);
164 }
165 }
166
167 /// Import known data from an existing analyzer
168 void insertAllFrom(MTypeResults const &TR, ActivityAnalyzer &Hypothesis,
169 Value Orig) {
170 insertConstantsFrom(TR, Hypothesis);
171 for (auto I : Hypothesis.ActiveOperations) {
172 bool inserted = ActiveOperations.insert(I).second;
173 if (inserted && directions == 3) {
174 ReEvaluateOpIfInactiveValue[Orig].insert(I);
175 }
176 }
177 for (auto V : Hypothesis.ActiveValues) {
178 bool inserted = ActiveValues.insert(V).second;
179 if (inserted && directions == 3) {
180 ReEvaluateValueIfInactiveValue[Orig].insert(V);
181 }
182 }
183 }
184
185 /// Is the use of value val as an argument of call CI known to be inactive
186 bool isFunctionArgumentConstant(mlir::CallOpInterface CI, Value val);
187
188 /// Is the value guaranteed to be inactive because of how it's produced.
189 /// If active and inactArg is non-null, store any values which may allow this
190 /// to succeed in the future
191 bool isValueInactiveFromOrigin(
192 MTypeResults const &TR, Value val,
193 llvm::SmallPtrSetImpl<mlir::Value> *inactArg = nullptr);
194
195 /// Is the operation guaranteed to be inactive because of how its operands are
196 /// produced.
197 bool isOperationInactiveFromOrigin(
198 MTypeResults const &TR, Operation *op,
199 std::optional<unsigned> resultNo = std::nullopt,
200 llvm::SmallPtrSetImpl<mlir::Value> *inactArg = nullptr);
201
202public:
203 enum class UseActivity {
204 // No Additional use activity info
205 None = 0,
206
207 // Only consider loads of memory
208 OnlyLoads = 1,
209
210 // Only consider active stores into
211 OnlyStores = 2,
212
213 // Only consider active stores and pointer-style loads
215
216 // Only consider any (active or not) stores into
217 AllStores = 4
218 };
219 /// Is the value free of any active uses
220 bool isValueInactiveFromUsers(MTypeResults const &TR, Value val,
221 UseActivity UA,
222 Operation **FoundInst = nullptr);
223
224 /// Is the value potentially actively returned or stored
225 bool isValueActivelyStoredOrReturned(MTypeResults const &TR, Value val,
226 bool outside = false);
227
228private:
229 /// StoredOrReturnedCache acts as an inductive cache of results for
230 /// isValueActivelyStoredOrReturned
231 std::map<std::pair<bool, Value>, bool> StoredOrReturnedCache;
232};
234} // namespace enzyme
235
236inline bool operator<(const Value &lhs, const Value &rhs) {
237 return lhs.getAsOpaquePointer() < rhs.getAsOpaquePointer();
238}
239} // namespace mlir
240
241#endif // ENZYME_MLIR_ANALYSIS_ACTIVITYANALYSIS_H
Helper class to analyze the differential activity.
Helper class to analyze the differential activity.
bool isConstantOperation(MTypeResults const &TR, Operation *op)
Return whether this operation is known not to propagate adjoints Note that operations could return an...
const llvm::ArrayRef< DIFFE_TYPE > ActiveReturns
Library Information.
ActivityAnalyzer(const llvm::SmallPtrSetImpl< Block * > &notForAnalysis_, llvm::DenseMap< Operation *, bool > &readOnlyCache_, const llvm::SmallPtrSetImpl< Value > &ConstantValues, const llvm::SmallPtrSetImpl< Value > &ActiveValues, llvm::ArrayRef< DIFFE_TYPE > ActiveReturns)
Construct the analyzer from the a previous set of constant and active values and whether returns are ...
bool isValueInactiveFromUsers(MTypeResults const &TR, Value val, UseActivity UA, Operation **FoundInst=nullptr)
Is the value free of any active uses.
bool isValueActivelyStoredOrReturned(MTypeResults const &TR, Value val, bool outside=false)
Is the value potentially actively returned or stored.
bool isConstantValue(MTypeResults const &TR, Value val)
Return whether this values is known not to contain derivative information, either directly or as a po...
DataFlowActivityAnalyzer(DataFlowSolver &solver, FunctionOpInterface funcOp, ArrayRef< DIFFE_TYPE > argActivity, ArrayRef< DIFFE_TYPE > returnActivity)
SetLattice< DistinctAttr > AliasClassSet
A set of alias class identifiers to be treated as a single union.
bool operator<(const Value &lhs, const Value &rhs)