28 if (oBB->getNumSuccessors() == 0) {
29 Operation *returnStatement = newBB->getTerminator();
30 gutils->
erase(returnStatement);
32 OpBuilder forwardToBackwardBuilder(newBB, newBB->end());
34 Operation *newBranchOp = cf::BranchOp::create(
35 forwardToBackwardBuilder, oBB->getTerminator()->getLoc(), reverseBB);
56 if ((op->getBlock()->getTerminator() != op) &&
isFullyInactive(op, gutils)) {
59 if (
auto ifaceOp = dyn_cast<ReverseAutoDiffOpInterface>(op)) {
60 SmallVector<Value> caches = ifaceOp.cacheValues(gutils);
62 if (failed(ifaceOp.createShadowValues(augmentBuilder, gutils)))
64 return ifaceOp.createReverseModeAdjoint(builder, gutils, caches);
66 op->emitError() <<
"could not compute the adjoint for this operation " << *op;
87 llvm::function_ref<buildReturnFunction> buildReturnOp) {
88 OpBuilder revBuilder(reverseBB, reverseBB->end());
89 if (oBB->hasNoPredecessors()) {
90 buildReturnOp(revBuilder, oBB);
92 Location loc = oBB->rbegin()->getLoc();
98 enzyme::PopOp::create(revBuilder, loc, gutils->
getIndexType(), cache);
100 Block *defaultBlock =
nullptr;
102 SmallVector<Block *> blocks;
103 SmallVector<APInt> indices;
105 OpBuilder newBuilder(newBB, newBB->begin());
107 SmallVector<Value, 1> diffes;
108 for (
auto arg : oBB->getArguments()) {
110 !cast<AutoDiffTypeInterface>(arg.getType()).isMutable()) {
111 diffes.push_back(gutils->
diffe(arg, revBuilder));
115 diffes.push_back(
nullptr);
118 for (
auto [idx, pred] : llvm::enumerate(oBB->getPredecessors())) {
123 OpBuilder predecessorBuilder(newPred->getTerminator());
126 arith::ConstantIntOp::create(predecessorBuilder, loc, idx - 1, 32);
127 enzyme::PushOp::create(predecessorBuilder, loc, cache, pred_idx_c);
130 defaultBlock = reversePred;
133 indices.push_back(APInt(32, idx - 1));
134 blocks.push_back(reversePred);
137 auto term = pred->getTerminator();
138 if (
auto iface = dyn_cast<BranchOpInterface>(term)) {
139 for (
auto &op : term->getOpOperands())
141 iface.getSuccessorBlockArgument(op.getOperandNumber()))
143 (*blk_idx).getOwner() == oBB) {
144 auto idx = (*blk_idx).getArgNumber();
148 arith::ConstantIntOp::create(revBuilder, loc, idx - 1, 32);
150 auto to_prop = arith::SelectOp::create(
152 arith::CmpIOp::create(revBuilder, loc,
153 arith::CmpIPredicate::eq, flag,
156 cast<AutoDiffTypeInterface>(diffes[idx].getType())
157 .createNullValue(revBuilder, loc));
159 gutils->
addToDiffe(op.get(), to_prop, revBuilder);
163 assert(0 &&
"predecessor did not implement branch op interface");
167 cf::SwitchOp::create(revBuilder, loc, flag, defaultBlock, ArrayRef<Value>(),
168 ArrayRef<APInt>(indices), ArrayRef<Block *>(blocks),
169 SmallVector<ValueRange>(indices.size(), ValueRange()));
175 llvm::function_ref<buildReturnFunction> buildFuncReturnOp,
176 std::function<std::pair<Value, Value>(Type)> cacheCreator) {
182 for (
auto &oBB : oldRegion) {
191 return success(valid);
195 FunctionOpInterface fn, std::vector<DIFFE_TYPE> retType,
197 std::vector<bool> returnPrimals, std::vector<bool> returnShadows,
198 DerivativeMode mode,
bool freeMemory,
bool atomicAdd,
size_t width,
200 std::vector<bool> overwritten_args,
void *augmented,
bool omp,
201 llvm::StringRef postpasses,
bool verifyPostPasses,
bool strongZero,
204 if (fn.getFunctionBody().empty()) {
205 fn.emitError() <<
"cannot differentiate a function without a body: "
206 << fn.getNameAttr() <<
"\n";
218 static_cast<unsigned>(width),
227 return cachedFn->second;
230 SmallVector<bool> returnPrimalsP(returnPrimals.begin(), returnPrimals.end());
231 SmallVector<bool> returnShadowsP(returnShadows.begin(), returnShadows.end());
234 *
this, mode, width, fn, TA, type_args, returnPrimalsP, returnShadowsP,
235 retType, constants, addedType, omp, postpasses, verifyPostPasses,
239 gutils->getNewFromOriginal(origOp)->setAttr(
240 "enzyme.readonly", UnitAttr::get(origOp->getContext()));
247 Region &oldRegion = gutils->
oldFunc.getFunctionBody();
248 Region &newRegion = gutils->
newFunc.getFunctionBody();
250 auto buildFuncReturnOp = [&](OpBuilder &builder, Block *oBB) {
251 SmallVector<mlir::Value> retargs;
252 for (
auto [arg, returnPrimal] :
253 llvm::zip(oBB->getTerminator()->getOperands(), returnPrimals)) {
258 for (
auto [arg, cv] : llvm::zip(oBB->getArguments(), constants)) {
260 retargs.push_back(gutils->
diffe(arg, builder));
264 Location loc = oBB->rbegin()->getLoc();
265 if (
auto iface = dyn_cast<enzyme::AutoDiffFunctionInterface>(*fn))
266 iface.createReturn(builder, loc, retargs);
268 fn->emitError() <<
"this function operation does not implement "
269 "AutoDiffFunctionInterface";
276 differentiate(gutils, oldRegion, newRegion, buildFuncReturnOp,
nullptr);
282 if (!res.succeeded())
285 if (postpasses !=
"") {
286 mlir::PassManager pm(nf->getContext());
287 pm.enableVerifier(verifyPostPasses);
288 std::string error_message;
290 mlir::LogicalResult result = mlir::parsePassPipeline(postpasses, pm);
291 if (mlir::failed(result)) {
295 if (!mlir::succeeded(pm.run(nf))) {
FunctionOpInterface CreateReverseDiff(FunctionOpInterface fn, std::vector< DIFFE_TYPE > retType, std::vector< DIFFE_TYPE > constants, MTypeAnalysis &TA, std::vector< bool > returnPrimals, std::vector< bool > returnShadows, DerivativeMode mode, bool freeMemory, bool atomicAdd, size_t width, mlir::Type addedType, MFnTypeInfo type_args, std::vector< bool > overwritten_args, void *augmented, bool omp, llvm::StringRef postpasses, bool verifyPostPasses, bool strongZero, bool markReadonly)
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)