1363dd3f3SRob Suderman //===- ConvertSimQuant.cpp - Converts simulated quant ops------------------===// 2363dd3f3SRob Suderman // 3363dd3f3SRob Suderman // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4363dd3f3SRob Suderman // See https://llvm.org/LICENSE.txt for license information. 5363dd3f3SRob Suderman // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6363dd3f3SRob Suderman // 7363dd3f3SRob Suderman //===----------------------------------------------------------------------===// 8363dd3f3SRob Suderman 9363dd3f3SRob Suderman #include "mlir/Dialect/Quant/FakeQuantSupport.h" 10363dd3f3SRob Suderman #include "mlir/Dialect/Quant/Passes.h" 11363dd3f3SRob Suderman #include "mlir/Dialect/Quant/QuantOps.h" 12363dd3f3SRob Suderman #include "mlir/Dialect/Quant/UniformSupport.h" 13363dd3f3SRob Suderman #include "mlir/IR/Attributes.h" 14363dd3f3SRob Suderman #include "mlir/IR/PatternMatch.h" 15363dd3f3SRob Suderman #include "mlir/IR/StandardTypes.h" 16363dd3f3SRob Suderman #include "mlir/Pass/Pass.h" 17363dd3f3SRob Suderman 18363dd3f3SRob Suderman using namespace mlir; 19363dd3f3SRob Suderman using namespace mlir::quant; 20363dd3f3SRob Suderman 21363dd3f3SRob Suderman namespace { 22363dd3f3SRob Suderman 23363dd3f3SRob Suderman class ConvertSimulatedQuantPass 24363dd3f3SRob Suderman : public FunctionPass<ConvertSimulatedQuantPass> { 25363dd3f3SRob Suderman public: 26363dd3f3SRob Suderman void runOnFunction() override; 27363dd3f3SRob Suderman }; 28363dd3f3SRob Suderman 29363dd3f3SRob Suderman /// Base class rewrites ConstFakeQuant into a qbarrier/dbarrier pair. 30363dd3f3SRob Suderman template <typename ConcreteRewriteClass, typename FakeQuantOp> 31363dd3f3SRob Suderman class FakeQuantRewrite : public OpRewritePattern<FakeQuantOp> { 32363dd3f3SRob Suderman public: 33363dd3f3SRob Suderman using OpRewritePattern<FakeQuantOp>::OpRewritePattern; 34363dd3f3SRob Suderman 35363dd3f3SRob Suderman FakeQuantRewrite(MLIRContext *ctx, bool *hadFailure) 36363dd3f3SRob Suderman : OpRewritePattern<FakeQuantOp>(ctx), hadFailure(hadFailure) {} 37363dd3f3SRob Suderman 38*3145427dSRiver Riddle LogicalResult matchAndRewrite(FakeQuantOp op, 39363dd3f3SRob Suderman PatternRewriter &rewriter) const override { 40363dd3f3SRob Suderman // TODO: If this pattern comes up more frequently, consider adding core 41363dd3f3SRob Suderman // support for failable rewrites. 42363dd3f3SRob Suderman if (failableRewrite(op, rewriter)) { 43363dd3f3SRob Suderman *hadFailure = true; 44*3145427dSRiver Riddle return failure(); 45363dd3f3SRob Suderman } 46363dd3f3SRob Suderman 47*3145427dSRiver Riddle return success(); 48363dd3f3SRob Suderman } 49363dd3f3SRob Suderman 50363dd3f3SRob Suderman private: 51363dd3f3SRob Suderman bool *hadFailure; 52363dd3f3SRob Suderman 53363dd3f3SRob Suderman bool failableRewrite(FakeQuantOp op, PatternRewriter &rewriter) const { 54363dd3f3SRob Suderman auto converter = ExpressedToQuantizedConverter::forInputType(op.getType()); 55363dd3f3SRob Suderman if (!converter) { 56363dd3f3SRob Suderman return (op.emitError("unsupported quantized type conversion"), true); 57363dd3f3SRob Suderman } 58363dd3f3SRob Suderman 59363dd3f3SRob Suderman QuantizedType elementType = 60363dd3f3SRob Suderman static_cast<const ConcreteRewriteClass *>(this) 61363dd3f3SRob Suderman ->convertFakeQuantAttrsToType(op, converter.expressedType); 62363dd3f3SRob Suderman 63363dd3f3SRob Suderman if (!elementType) { 64363dd3f3SRob Suderman // Note that the fakeQuantAttrsToType will have emitted the error. 65363dd3f3SRob Suderman return true; 66363dd3f3SRob Suderman } 67363dd3f3SRob Suderman 68363dd3f3SRob Suderman Type quantizedType = converter.convert(elementType); 69363dd3f3SRob Suderman assert(quantizedType && 70363dd3f3SRob Suderman "Converter accepted a type that it did not convert"); 71363dd3f3SRob Suderman 72363dd3f3SRob Suderman // TODO: Map to a qbarrier with an attribute like [Forced] to signal that 73363dd3f3SRob Suderman // this is a forced/hard-coded constraint. 74363dd3f3SRob Suderman auto qbarrier = rewriter.create<QuantizeCastOp>(op.getLoc(), quantizedType, 75363dd3f3SRob Suderman op.inputs()); 76363dd3f3SRob Suderman rewriter.replaceOpWithNewOp<DequantizeCastOp>(op, converter.inputType, 77363dd3f3SRob Suderman qbarrier.getResult()); 78363dd3f3SRob Suderman 79363dd3f3SRob Suderman return false; 80363dd3f3SRob Suderman } 81363dd3f3SRob Suderman }; 82363dd3f3SRob Suderman 83363dd3f3SRob Suderman class ConstFakeQuantRewrite 84363dd3f3SRob Suderman : public FakeQuantRewrite<ConstFakeQuantRewrite, ConstFakeQuant> { 85363dd3f3SRob Suderman public: 86363dd3f3SRob Suderman using BaseRewrite = FakeQuantRewrite<ConstFakeQuantRewrite, ConstFakeQuant>; 87363dd3f3SRob Suderman 88363dd3f3SRob Suderman ConstFakeQuantRewrite(MLIRContext *ctx, bool *hadFailure) 89363dd3f3SRob Suderman : BaseRewrite(ctx, hadFailure) {} 90363dd3f3SRob Suderman 91363dd3f3SRob Suderman QuantizedType convertFakeQuantAttrsToType(ConstFakeQuant fqOp, 92363dd3f3SRob Suderman Type expressedType) const { 93363dd3f3SRob Suderman return fakeQuantAttrsToType( 94363dd3f3SRob Suderman fqOp.getLoc(), fqOp.num_bits().getSExtValue(), 95363dd3f3SRob Suderman fqOp.min().convertToFloat(), fqOp.max().convertToFloat(), 96363dd3f3SRob Suderman fqOp.narrow_range(), expressedType, fqOp.is_signed()); 97363dd3f3SRob Suderman } 98363dd3f3SRob Suderman }; 99363dd3f3SRob Suderman 100363dd3f3SRob Suderman class ConstFakeQuantPerAxisRewrite 101363dd3f3SRob Suderman : public FakeQuantRewrite<ConstFakeQuantPerAxisRewrite, 102363dd3f3SRob Suderman ConstFakeQuantPerAxis> { 103363dd3f3SRob Suderman public: 104363dd3f3SRob Suderman using BaseRewrite = 105363dd3f3SRob Suderman FakeQuantRewrite<ConstFakeQuantPerAxisRewrite, ConstFakeQuantPerAxis>; 106363dd3f3SRob Suderman 107363dd3f3SRob Suderman ConstFakeQuantPerAxisRewrite(MLIRContext *ctx, bool *hadFailure) 108363dd3f3SRob Suderman : BaseRewrite(ctx, hadFailure) {} 109363dd3f3SRob Suderman 110363dd3f3SRob Suderman QuantizedType convertFakeQuantAttrsToType(ConstFakeQuantPerAxis fqOp, 111363dd3f3SRob Suderman Type expressedType) const { 112363dd3f3SRob Suderman SmallVector<double, 4> min, max; 113363dd3f3SRob Suderman min.reserve(fqOp.min().size()); 114363dd3f3SRob Suderman max.reserve(fqOp.max().size()); 115363dd3f3SRob Suderman for (auto m : fqOp.min()) 116363dd3f3SRob Suderman min.push_back(m.cast<FloatAttr>().getValueAsDouble()); 117363dd3f3SRob Suderman for (auto m : fqOp.max()) 118363dd3f3SRob Suderman max.push_back(m.cast<FloatAttr>().getValueAsDouble()); 119363dd3f3SRob Suderman 120363dd3f3SRob Suderman return fakeQuantAttrsToType(fqOp.getLoc(), fqOp.num_bits().getSExtValue(), 121363dd3f3SRob Suderman fqOp.axis().getSExtValue(), min, max, 122363dd3f3SRob Suderman fqOp.narrow_range(), expressedType, 123363dd3f3SRob Suderman fqOp.is_signed()); 124363dd3f3SRob Suderman } 125363dd3f3SRob Suderman }; 126363dd3f3SRob Suderman 127363dd3f3SRob Suderman } // namespace 128363dd3f3SRob Suderman 129363dd3f3SRob Suderman void ConvertSimulatedQuantPass::runOnFunction() { 130363dd3f3SRob Suderman bool hadFailure = false; 131363dd3f3SRob Suderman OwningRewritePatternList patterns; 132363dd3f3SRob Suderman auto func = getFunction(); 133363dd3f3SRob Suderman auto ctx = func.getContext(); 134363dd3f3SRob Suderman patterns.insert<ConstFakeQuantRewrite, ConstFakeQuantPerAxisRewrite>( 135363dd3f3SRob Suderman ctx, &hadFailure); 136363dd3f3SRob Suderman applyPatternsGreedily(func, patterns); 137363dd3f3SRob Suderman if (hadFailure) 138363dd3f3SRob Suderman signalPassFailure(); 139363dd3f3SRob Suderman } 140363dd3f3SRob Suderman 141363dd3f3SRob Suderman std::unique_ptr<OpPassBase<FuncOp>> 142363dd3f3SRob Suderman mlir::quant::createConvertSimulatedQuantPass() { 143363dd3f3SRob Suderman return std::make_unique<ConvertSimulatedQuantPass>(); 144363dd3f3SRob Suderman } 145363dd3f3SRob Suderman 146363dd3f3SRob Suderman static PassRegistration<ConvertSimulatedQuantPass> 147363dd3f3SRob Suderman pass("quant-convert-simulated-quantization", 148363dd3f3SRob Suderman "Converts training-time simulated quantization ops to corresponding " 149363dd3f3SRob Suderman "quantize/dequantize casts."); 150