18#include "mlir/IR/DialectRegistry.h"
19#include "mlir/Support/LogicalResult.h"
23#include "mlir/Dialect/Affine/IR/AffineOps.h"
24#include "mlir/IR/TypeSupport.h"
30#include "Implementations/EnzymeDerivatives.inc"
41struct AffineAtomicRMWOpInterfaceReverse
42 :
public ReverseAutoDiffOpInterface::ExternalModel<
43 AffineAtomicRMWOpInterfaceReverse, enzyme::AffineAtomicRMWOp> {
44 LogicalResult createReverseModeAdjoint(Operation *op, OpBuilder &builder,
46 SmallVector<Value> caches)
const {
47 auto rmwOp = cast<enzyme::AffineAtomicRMWOp>(op);
48 Value memref = rmwOp.getMemref();
49 Value val = rmwOp.getValue();
55 gutils->
zeroDiffe(rmwOp.getResult(), builder);
59 if (rmwOp.getKind() != arith::AtomicRMWKind::addf)
60 return op->emitError()
61 <<
"could not compute the adjoint of a non-add atomic rmw " << *op;
63 auto iface = dyn_cast<AutoDiffTypeInterface>(val.getType());
65 return op->emitError()
66 <<
"could not compute the adjoint of an atomic rmw on a type "
67 "without autodiff semantics "
70 Value memrefGradient = gutils->
popCache(caches.front(), builder);
71 SmallVector<Value> retrievedArguments;
72 for (Value cache : ValueRange(caches).drop_front(1))
73 retrievedArguments.push_back(gutils->
popCache(cache, builder));
75 auto alignAttr = rmwOp.getAlignmentAttr();
77 auto loadedGradient = affine::AffineLoadOp::create(
78 builder, rmwOp.getLoc(), memrefGradient, rmwOp.getMap(),
79 ArrayRef<Value>(retrievedArguments));
81 loadedGradient->setAttr(
"alignment", alignAttr);
82 gutils->
addToDiffe(val, loadedGradient, builder);
86 Value gradient = gutils->
diffe(rmwOp.getResult(), builder);
87 gutils->
zeroDiffe(rmwOp.getResult(), builder);
91 builder, rmwOp.getLoc(), gradient.getType(),
92 arith::AtomicRMWKind::addf, rmwOp.getOrdering(), gradient,
93 memrefGradient, retrievedArguments, rmwOp.getMap(), alignAttr));
99 SmallVector<Value> cacheValues(Operation *op,
101 auto rmwOp = cast<enzyme::AffineAtomicRMWOp>(op);
105 SmallVector<Value> caches;
107 gutils->
invertPointerM(rmwOp.getMemref(), cacheBuilder), cacheBuilder));
108 for (Value v : rmwOp.getIndices())
114 LogicalResult createShadowValues(Operation *op, OpBuilder &builder,
125struct AffineAtomicRMWOpForwardInterface
126 :
public AutoDiffOpInterface::ExternalModel<
127 AffineAtomicRMWOpForwardInterface, enzyme::AffineAtomicRMWOp> {
128 LogicalResult createForwardModeTangent(Operation *op, OpBuilder &builder,
130 auto rmwOp = cast<enzyme::AffineAtomicRMWOp>(op);
131 auto iface = dyn_cast<AutoDiffTypeInterface>(rmwOp.getValue().getType());
133 return op->emitError()
134 <<
"could not compute the tangent of an atomic rmw on a type "
135 "without autodiff semantics "
143 iface.createNullValue(builder, op->getLoc()), builder);
147 if (rmwOp.getKind() != arith::AtomicRMWKind::addf)
148 return op->emitError()
149 <<
"could not compute the tangent of a non-add atomic rmw " << *op;
151 Value shadowMemref = gutils->
invertPointerM(rmwOp.getMemref(), builder);
153 ? iface.createNullValue(builder, op->getLoc())
157 SmallVector<Value> shadowIndices;
158 for (Value v : newOp.getIndices())
159 shadowIndices.push_back(v);
160 auto shadowOp = enzyme::AffineAtomicRMWOp::create(
161 builder, rmwOp.getLoc(), shadowVal.getType(),
162 arith::AtomicRMWKind::addf, rmwOp.getOrdering(), shadowVal,
163 shadowMemref, shadowIndices, rmwOp.getMap(), rmwOp.getAlignmentAttr());
164 shadowOp->setAttr(
"fastmath", newOp.getFastmathAttr());
166 gutils->
setDiffe(rmwOp.getResult(), shadowOp.getResult(), builder);
174 DialectRegistry ®istry) {
175 registry.addExtension(+[](MLIRContext *context, enzyme::EnzymeDialect *) {
176 registerInterfaces(context);
178 context->getOrLoadDialect<affine::AffineDialect>();
179 enzyme::AffineAtomicRMWOp::attachInterface<
180 AffineAtomicRMWOpInterfaceReverse>(*context);
181 enzyme::AffineAtomicRMWOp::attachInterface<
182 AffineAtomicRMWOpForwardInterface>(*context);
mlir::Value diffe(mlir::Value origv, mlir::OpBuilder &builder)
void zeroDiffe(mlir::Value origv, mlir::OpBuilder &builder)
Value popCache(Value cache, OpBuilder &builder)
Value initAndPushCache(Value v, OpBuilder &builder)
void addToDiffe(mlir::Value oldGradient, mlir::Value addedGradient, OpBuilder &builder)
void setDiffe(mlir::Value origv, mlir::Value newv, mlir::OpBuilder &builder)
mlir::Value invertPointerM(mlir::Value v, OpBuilder &Builder2)
SmallVector< mlir::Value, 1 > getNewFromOriginal(ValueRange originst) const
bool isConstantValue(mlir::Value v) const
void registerEnzymeDialectAutoDiffInterface(DialectRegistry ®istry)
void setDerivativeFastMath(Operation *op)
Give an operation built for a derivative the fast-math flags the LLVM path gives everything it builds...