1*34810e1bSTres Popp //===-- MathToLibm.cpp - conversion from Math to libm calls ---------------===// 2*34810e1bSTres Popp // 3*34810e1bSTres Popp // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*34810e1bSTres Popp // See https://llvm.org/LICENSE.txt for license information. 5*34810e1bSTres Popp // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*34810e1bSTres Popp // 7*34810e1bSTres Popp //===----------------------------------------------------------------------===// 8*34810e1bSTres Popp 9*34810e1bSTres Popp #include "mlir/Conversion/MathToLibm/MathToLibm.h" 10*34810e1bSTres Popp 11*34810e1bSTres Popp #include "../PassDetail.h" 12*34810e1bSTres Popp #include "mlir/Dialect/Math/IR/Math.h" 13*34810e1bSTres Popp #include "mlir/Dialect/StandardOps/IR/Ops.h" 14*34810e1bSTres Popp #include "mlir/Dialect/Vector/VectorOps.h" 15*34810e1bSTres Popp #include "mlir/IR/BuiltinDialect.h" 16*34810e1bSTres Popp #include "mlir/IR/PatternMatch.h" 17*34810e1bSTres Popp 18*34810e1bSTres Popp using namespace mlir; 19*34810e1bSTres Popp 20*34810e1bSTres Popp namespace { 21*34810e1bSTres Popp // Pattern to convert vector operations to scalar operations. This is needed as 22*34810e1bSTres Popp // libm calls require scalars. 23*34810e1bSTres Popp template <typename Op> 24*34810e1bSTres Popp struct VecOpToScalarOp : public OpRewritePattern<Op> { 25*34810e1bSTres Popp public: 26*34810e1bSTres Popp using OpRewritePattern<Op>::OpRewritePattern; 27*34810e1bSTres Popp 28*34810e1bSTres Popp LogicalResult matchAndRewrite(Op op, PatternRewriter &rewriter) const final; 29*34810e1bSTres Popp }; 30*34810e1bSTres Popp // Pattern to convert scalar math operations to calls to libm functions. 31*34810e1bSTres Popp // Additionally the libm function signatures are declared. 32*34810e1bSTres Popp template <typename Op> 33*34810e1bSTres Popp struct ScalarOpToLibmCall : public OpRewritePattern<Op> { 34*34810e1bSTres Popp public: 35*34810e1bSTres Popp using OpRewritePattern<Op>::OpRewritePattern; 36*34810e1bSTres Popp ScalarOpToLibmCall<Op>(MLIRContext *context, StringRef floatFunc, 37*34810e1bSTres Popp StringRef doubleFunc, PatternBenefit benefit) 38*34810e1bSTres Popp : OpRewritePattern<Op>(context, benefit), floatFunc(floatFunc), 39*34810e1bSTres Popp doubleFunc(doubleFunc){}; 40*34810e1bSTres Popp 41*34810e1bSTres Popp LogicalResult matchAndRewrite(Op op, PatternRewriter &rewriter) const final; 42*34810e1bSTres Popp 43*34810e1bSTres Popp private: 44*34810e1bSTres Popp std::string floatFunc, doubleFunc; 45*34810e1bSTres Popp }; 46*34810e1bSTres Popp } // namespace 47*34810e1bSTres Popp 48*34810e1bSTres Popp template <typename Op> 49*34810e1bSTres Popp LogicalResult 50*34810e1bSTres Popp VecOpToScalarOp<Op>::matchAndRewrite(Op op, PatternRewriter &rewriter) const { 51*34810e1bSTres Popp auto opType = op.getType(); 52*34810e1bSTres Popp auto loc = op.getLoc(); 53*34810e1bSTres Popp auto vecType = opType.template dyn_cast<VectorType>(); 54*34810e1bSTres Popp 55*34810e1bSTres Popp if (!vecType) 56*34810e1bSTres Popp return failure(); 57*34810e1bSTres Popp if (!vecType.hasRank()) 58*34810e1bSTres Popp return failure(); 59*34810e1bSTres Popp auto shape = vecType.getShape(); 60*34810e1bSTres Popp // TODO: support multidimensional vectors 61*34810e1bSTres Popp if (shape.size() != 1) 62*34810e1bSTres Popp return failure(); 63*34810e1bSTres Popp 64*34810e1bSTres Popp Value result = rewriter.create<ConstantOp>( 65*34810e1bSTres Popp loc, DenseElementsAttr::get( 66*34810e1bSTres Popp vecType, FloatAttr::get(vecType.getElementType(), 0.0))); 67*34810e1bSTres Popp for (auto i = 0; i < shape.front(); ++i) { 68*34810e1bSTres Popp SmallVector<Value> operands; 69*34810e1bSTres Popp for (auto input : op->getOperands()) 70*34810e1bSTres Popp operands.push_back( 71*34810e1bSTres Popp rewriter.create<vector::ExtractElementOp>(loc, input, i)); 72*34810e1bSTres Popp Value scalarOp = 73*34810e1bSTres Popp rewriter.create<Op>(loc, vecType.getElementType(), operands); 74*34810e1bSTres Popp result = rewriter.create<vector::InsertElementOp>(loc, scalarOp, result, i); 75*34810e1bSTres Popp } 76*34810e1bSTres Popp rewriter.replaceOp(op, {result}); 77*34810e1bSTres Popp return success(); 78*34810e1bSTres Popp } 79*34810e1bSTres Popp 80*34810e1bSTres Popp template <typename Op> 81*34810e1bSTres Popp LogicalResult 82*34810e1bSTres Popp ScalarOpToLibmCall<Op>::matchAndRewrite(Op op, 83*34810e1bSTres Popp PatternRewriter &rewriter) const { 84*34810e1bSTres Popp auto module = op->template getParentOfType<ModuleOp>(); 85*34810e1bSTres Popp auto type = op.getType(); 86*34810e1bSTres Popp // TODO: Support Float16 by upcasting to Float32 87*34810e1bSTres Popp if (!type.template isa<Float32Type, Float64Type>()) 88*34810e1bSTres Popp return failure(); 89*34810e1bSTres Popp 90*34810e1bSTres Popp auto name = type.getIntOrFloatBitWidth() == 64 ? doubleFunc : floatFunc; 91*34810e1bSTres Popp auto opFunc = module.template lookupSymbol<FuncOp>(name); 92*34810e1bSTres Popp // Forward declare function if it hasn't already been 93*34810e1bSTres Popp if (!opFunc) { 94*34810e1bSTres Popp OpBuilder::InsertionGuard guard(rewriter); 95*34810e1bSTres Popp rewriter.setInsertionPointToStart(module.getBody()); 96*34810e1bSTres Popp auto opFunctionTy = FunctionType::get( 97*34810e1bSTres Popp rewriter.getContext(), op->getOperandTypes(), op->getResultTypes()); 98*34810e1bSTres Popp opFunc = 99*34810e1bSTres Popp rewriter.create<FuncOp>(rewriter.getUnknownLoc(), name, opFunctionTy); 100*34810e1bSTres Popp opFunc.setPrivate(); 101*34810e1bSTres Popp } 102*34810e1bSTres Popp assert(opFunc.getType().template cast<FunctionType>().getResults() == 103*34810e1bSTres Popp op->getResultTypes()); 104*34810e1bSTres Popp assert(opFunc.getType().template cast<FunctionType>().getInputs() == 105*34810e1bSTres Popp op->getOperandTypes()); 106*34810e1bSTres Popp 107*34810e1bSTres Popp rewriter.replaceOpWithNewOp<CallOp>(op, opFunc, op->getOperands()); 108*34810e1bSTres Popp 109*34810e1bSTres Popp return success(); 110*34810e1bSTres Popp } 111*34810e1bSTres Popp 112*34810e1bSTres Popp void mlir::populateMathToLibmConversionPatterns(RewritePatternSet &patterns, 113*34810e1bSTres Popp PatternBenefit benefit) { 114*34810e1bSTres Popp patterns.add<VecOpToScalarOp<math::Atan2Op>, VecOpToScalarOp<math::ExpM1Op>, 115*34810e1bSTres Popp VecOpToScalarOp<math::TanhOp>>(patterns.getContext(), benefit); 116*34810e1bSTres Popp patterns.add<ScalarOpToLibmCall<math::Atan2Op>>(patterns.getContext(), 117*34810e1bSTres Popp "atan2f", "atan2", benefit); 118*34810e1bSTres Popp patterns.add<ScalarOpToLibmCall<math::ExpM1Op>>(patterns.getContext(), 119*34810e1bSTres Popp "expm1f", "expm1", benefit); 120*34810e1bSTres Popp patterns.add<ScalarOpToLibmCall<math::TanhOp>>(patterns.getContext(), "tanhf", 121*34810e1bSTres Popp "tanh", benefit); 122*34810e1bSTres Popp } 123*34810e1bSTres Popp 124*34810e1bSTres Popp namespace { 125*34810e1bSTres Popp struct ConvertMathToLibmPass 126*34810e1bSTres Popp : public ConvertMathToLibmBase<ConvertMathToLibmPass> { 127*34810e1bSTres Popp void runOnOperation() override; 128*34810e1bSTres Popp }; 129*34810e1bSTres Popp } // namespace 130*34810e1bSTres Popp 131*34810e1bSTres Popp void ConvertMathToLibmPass::runOnOperation() { 132*34810e1bSTres Popp auto module = getOperation(); 133*34810e1bSTres Popp 134*34810e1bSTres Popp RewritePatternSet patterns(&getContext()); 135*34810e1bSTres Popp populateMathToLibmConversionPatterns(patterns, /*benefit=*/1); 136*34810e1bSTres Popp 137*34810e1bSTres Popp ConversionTarget target(getContext()); 138*34810e1bSTres Popp target.addLegalDialect<BuiltinDialect, StandardOpsDialect, 139*34810e1bSTres Popp vector::VectorDialect>(); 140*34810e1bSTres Popp target.addIllegalDialect<math::MathDialect>(); 141*34810e1bSTres Popp if (failed(applyPartialConversion(module, target, std::move(patterns)))) 142*34810e1bSTres Popp signalPassFailure(); 143*34810e1bSTres Popp } 144*34810e1bSTres Popp 145*34810e1bSTres Popp std::unique_ptr<OperationPass<ModuleOp>> mlir::createConvertMathToLibmPass() { 146*34810e1bSTres Popp return std::make_unique<ConvertMathToLibmPass>(); 147*34810e1bSTres Popp } 148