这章主要讲解了表达式的匹配重写(pattern match rewrite),有两种方式:通过DRR在td文件中重写,或直接用C++写匹配重写函数。我们这里主要使用第二种方式。
给了一个例子,转置的转置可以直接写成原操作数:
transpose(transpose(x)) = x;
首先我们定义transpose简化类,继承自mlir的OpRewritePattern:
struct SimplifyRedundantTranspose : public mlir::OpRewritePattern<TransposeOp>
在类中定义rewrite方法:
llvm::LogicalResult
matchAndRewrite(TransposeOp op,
mlir::PatternRewriter &rewriter) const override {
// Look through the input of the current transpose.
mlir::Value transposeInput = op.getOperand(); //获取transposeOp的操作数
TransposeOp transposeInputOp = transposeInput.getDefiningOp<TransposeOp>();
//获取transpose操作数的操作Op,若为不为transpose,则直接返回failure
// Input defined by another transpose? If not, no match.
if (!transposeInputOp)
return failure();
// Otherwise, we have a redundant transpose. Use the rewriter.
rewriter.replaceOp(op, {transposeInputOp.getOperand()});//若是,则执行替换
return success();
}
另外,要在Ops.td里在transposeOp的定义里启用hasCanonicalizer选项,以便使用canonicalization框架,同时添加[NoSideEffect]参数,用来清除Operation中的副作用,如下:
你问我为什么要这么干?我也不知道。
def TransposeOp : Toy_Op<"transpose", [NoSideEffect]> {
// Enable registering canonicalization patterns with this operation.
let hasCanonicalizer = 1;
最后把我们编写的patterns注册成规范化pattern, 来让canonicalization framework pick up:
void TransposeOp::getCanonicalizationPatterns(RewritePatternSet &results,
MLIRContext *context) {
results.add<SimplifyRedundantTranspose>(context);
}
这样就实现了transpose嵌套的一个匹配重写优化。
接下来我们实现另一个优化,首先我在Ops.td里定义了两个Operation,selfaddone()和selfsubone(),也就是自增1和自减1,我们要实现的匹配重写是:
selfsubone(selfaddone(x)) = x;
因为首先匹配的是selfaddoneOp,所以记得在selfaddoneOp的定义里把“let hasCanonicalizer = 1”加上哦。
接着老套路,定义SimplifyRedundantAddSub 类继承自mlir::OpRewritePattern<SelfSubOneOp>:
struct SimplifyRedundantAddSub : public mlir::OpRewritePattern<SelfSubOneOp>
其中的匹配重写函数:
lvm::LogicalResult
matchAndRewrite(SelfSubOneOp op, mlir::PatternRewriter& rewriter) const override{
mlir::Value selfsubInput = op.getOperand();
SelfAddOneOp selfsubInputOp = selfsubInput.getDefiningOp<SelfAddOneOp>();
if(!selfsubInputOp)
return failure();
rewriter.replaceOp(op, {selfsubInputOp.getOperand()});
return success();
}
其中的逻辑我相信聪明的你一眼就懂了。
最后注册一下:
void SelfSubOneOp::getCanonicalizationPatterns(RewritePatternSet& results,
MLIRContext* context)
{
results.add<SimplifyRedundantAddSub>(context);
}
ok了,测试一下:很完美