18#include "mlir/Dialect/Arith/IR/Arith.h"
19#include "mlir/Dialect/Math/IR/Math.h"
20#include "mlir/Dialect/SCF/IR/SCF.h"
21#include "mlir/Dialect/Tensor/IR/Tensor.h"
22#include "mlir/IR/DialectRegistry.h"
23#include "mlir/Support/LogicalResult.h"
26#include "mlir/IR/TypeSupport.h"
33struct ArithConstantOpBatchInterface
34 :
public BatchOpInterface::ExternalModel<ArithConstantOpBatchInterface,
37 mlir::LogicalResult createBatch(Operation *src, OpBuilder &builder,
39 ArrayRef<int64_t> batchSizes)
const {
41 SmallVector<Type> resultTypes(src->getResultTypes().begin(),
42 src->getResultTypes().end());
43 for (
auto &Ty : resultTypes) {
44 auto T = cast<TensorType>(Ty);
45 SmallVector<int64_t> shape(batchSizes.begin(), batchSizes.end());
46 shape.append(T.getShape().begin(), T.getShape().end());
49 mlir::NamedAttrList attrs;
50 for (
auto attr : src->getAttrs()) {
51 auto eattr = cast<DenseElementsAttr>(attr.getValue());
52 attr.setValue(eattr.resizeSplat(cast<ShapedType>(resultTypes[0])));
55 auto cop = mlir::Operation::create(
56 src->getLoc(), src->getName(), resultTypes, {}, std::move(attrs),
57 mlir::PropertyRef(), mlir::BlockRange(), 0);
59 mapper.map(src->getResult(0), cop->getResult(0));
64struct ArithAddFSimplifyMathInterface
65 :
public MathSimplifyInterface::ExternalModel<
66 ArithAddFSimplifyMathInterface, arith::AddFOp> {
67 mlir::LogicalResult simplifyMath(Operation *src,
68 PatternRewriter &rewriter)
const {
69 auto op = cast<arith::AddFOp>(src);
71 if (matchPattern(op.getLhs(), m_AnyZeroFloat())) {
72 rewriter.replaceOp(op, op.getRhs());
76 if (matchPattern(op.getRhs(), m_AnyZeroFloat())) {
77 rewriter.replaceOp(op, op.getLhs());
85struct ArithSubFSimplifyMathInterface
86 :
public MathSimplifyInterface::ExternalModel<
87 ArithSubFSimplifyMathInterface, arith::SubFOp> {
88 mlir::LogicalResult simplifyMath(Operation *src,
89 PatternRewriter &rewriter)
const {
90 auto op = cast<arith::SubFOp>(src);
92 if (matchPattern(op.getRhs(), m_AnyZeroFloat())) {
93 rewriter.replaceOp(op, op.getLhs());
97 if (matchPattern(op.getLhs(), m_AnyZeroFloat())) {
98 rewriter.replaceOpWithNewOp<arith::NegFOp>(op, op.getRhs(),
99 op.getFastmathAttr());
110static Value operandTangent(Value v, Operation *op, OpBuilder &builder,
114 auto iface = dyn_cast<AutoDiffTypeInterface>(
getShadowType(v.getType()));
115 if (iface && !iface.isMutable())
116 return iface.createNullValue(builder, op->getLoc());
118 <<
"constant mutable operand of an active select is passed through "
119 "as its own shadow pending runtime activity handling";
127struct SelectOpFwdInterface
128 :
public AutoDiffOpInterface::ExternalModel<SelectOpFwdInterface,
130 LogicalResult createForwardModeTangent(Operation *op, OpBuilder &builder,
132 auto selectOp = cast<arith::SelectOp>(op);
139 Value dTrue = operandTangent(selectOp.getTrueValue(), op, builder, gutils);
141 operandTangent(selectOp.getFalseValue(), op, builder, gutils);
143 arith::SelectOp::create(builder, op->getLoc(), cond, dTrue, dFalse);
144 gutils->
setDiffe(selectOp.getResult(), tangent, builder);
149struct SelectOpInterfaceReverse
150 :
public ReverseAutoDiffOpInterface::ExternalModel<SelectOpInterfaceReverse,
153 LogicalResult createReverseModeAdjoint(Operation *op, OpBuilder &builder,
155 SmallVector<Value> caches)
const {
156 auto selectOp = cast<arith::SelectOp>(op);
161 dyn_cast<AutoDiffTypeInterface>(selectOp.getResult().getType());
162 if (iface && iface.isMutable()) {
166 Value condition = gutils->
popCache(caches.front(), builder);
169 cast<AutoDiffTypeInterface>(
getShadowType(selectOp.getType()));
170 Value zero = siface.createNullValue(builder, selectOp.getLoc());
171 Value dret = gutils->
diffe(selectOp.getResult(), builder);
172 gutils->
zeroDiffe(selectOp.getResult(), builder);
174 Value trueSelect = arith::SelectOp::create(builder, selectOp.getLoc(),
175 condition, dret, zero);
177 gutils->
addToDiffe(selectOp.getTrueValue(), trueSelect, builder);
180 Value falseSelect = arith::SelectOp::create(builder, selectOp.getLoc(),
181 condition, zero, dret);
182 gutils->
addToDiffe(selectOp.getFalseValue(), falseSelect, builder);
188 SmallVector<Value> cacheValues(Operation *op,
190 auto selectOp = cast<arith::SelectOp>(op);
191 SmallVector<Value> caches;
195 dyn_cast<AutoDiffTypeInterface>(selectOp.getResult().getType());
196 if (iface && iface.isMutable()) {
205 LogicalResult createShadowValues(Operation *op, OpBuilder &builder,
207 auto selectOp = cast<arith::SelectOp>(op);
212 dyn_cast<AutoDiffTypeInterface>(selectOp.getResult().getType());
213 if (iface && iface.isMutable()) {
214 auto shadowOp = arith::SelectOp::create(
215 builder, selectOp.getLoc(),
225struct SelectActivityInterface
226 :
public ActivityOpInterface::ExternalModel<SelectActivityInterface,
228 bool isInactive(Operation *op)
const {
return false; }
229 bool isArgInactive(Operation *op,
size_t idx)
const {
236#include "Implementations/ArithDerivatives.inc"
240 DialectRegistry ®istry) {
241 registry.addExtension(+[](MLIRContext *context, arith::ArithDialect *) {
242 registerInterfaces(context);
243 arith::SelectOp::attachInterface<SelectActivityInterface>(*context);
244 arith::SelectOp::attachInterface<SelectOpFwdInterface>(*context);
245 arith::SelectOp::attachInterface<SelectOpInterfaceReverse>(*context);
246 arith::ConstantOp::attachInterface<ArithConstantOpBatchInterface>(*context);
247 arith::AddFOp::attachInterface<ArithAddFSimplifyMathInterface>(*context);
248 arith::SubFOp::attachInterface<ArithSubFSimplifyMathInterface>(*context);
253 DialectRegistry ®istry) {
254 registry.addExtension(+[](MLIRContext *context, tensor::TensorDialect *) {
255 registerInterfaces(context);
Type getShadowType(Type type, unsigned width)
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)
void eraseIfUnused(Operation *op, bool erase=true, bool check=true)
SmallVector< mlir::Value, 1 > getNewFromOriginal(ValueRange originst) const
bool isConstantInstruction(mlir::Operation *v) const
void setInvertedPointer(mlir::Value origv, mlir::Value newv)
bool isConstantValue(mlir::Value v) const
void registerArithDialectAutoDiffInterface(DialectRegistry ®istry)
void registerTensorDialectAutoDiffInterface(DialectRegistry ®istry)