MLIR 24.0.0git
MathToLibm.cpp
Go to the documentation of this file.
1//===-- MathToLibm.cpp - conversion from Math to libm calls ---------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10
20#include "llvm/ADT/SmallVectorExtras.h"
21
22namespace mlir {
23#define GEN_PASS_DEF_CONVERTMATHTOLIBMPASS
24#include "mlir/Conversion/Passes.h.inc"
25} // namespace mlir
26
27using namespace mlir;
28
29namespace {
30// Pattern to convert vector operations to scalar operations. This is needed as
31// libm calls require scalars.
32template <typename Op>
33struct VecOpToScalarOp : public OpRewritePattern<Op> {
34public:
35 using OpRewritePattern<Op>::OpRewritePattern;
36
37 LogicalResult matchAndRewrite(Op op, PatternRewriter &rewriter) const final;
38};
39// Pattern to promote an op of a smaller floating point type to F32.
40template <typename Op>
41struct PromoteOpToF32 : public OpRewritePattern<Op> {
42public:
43 using OpRewritePattern<Op>::OpRewritePattern;
44
45 LogicalResult matchAndRewrite(Op op, PatternRewriter &rewriter) const final;
46};
47// Pattern to convert scalar math operations to calls to libm functions.
48// Additionally the libm function signatures are declared.
49template <typename Op>
50struct ScalarOpToLibmCall : public OpRewritePattern<Op> {
51public:
52 using OpRewritePattern<Op>::OpRewritePattern;
53 ScalarOpToLibmCall(MLIRContext *context, PatternBenefit benefit,
54 StringRef floatFunc, StringRef doubleFunc)
55 : OpRewritePattern<Op>(context, benefit), floatFunc(floatFunc),
56 doubleFunc(doubleFunc) {};
57
58 LogicalResult matchAndRewrite(Op op, PatternRewriter &rewriter) const final;
59
60private:
61 std::string floatFunc, doubleFunc;
62};
63
64template <typename OpTy>
65void populatePatternsForOp(RewritePatternSet &patterns, PatternBenefit benefit,
66 MLIRContext *ctx, StringRef floatFunc,
67 StringRef doubleFunc) {
68 patterns.add<VecOpToScalarOp<OpTy>, PromoteOpToF32<OpTy>>(ctx, benefit);
69 patterns.add<ScalarOpToLibmCall<OpTy>>(ctx, benefit, floatFunc, doubleFunc);
70}
71
72} // namespace
73
74template <typename Op>
75LogicalResult
76VecOpToScalarOp<Op>::matchAndRewrite(Op op, PatternRewriter &rewriter) const {
77 auto opType = op.getType();
78 auto loc = op.getLoc();
79 auto vecType = dyn_cast<VectorType>(opType);
80
81 if (!vecType)
82 return failure();
83 if (!vecType.hasRank())
84 return failure();
85 auto shape = vecType.getShape();
86 int64_t numElements = vecType.getNumElements();
87
88 Value result = arith::ConstantOp::create(
89 rewriter, loc,
91 FloatAttr::get(vecType.getElementType(), 0.0)));
93 for (auto linearIndex = 0; linearIndex < numElements; ++linearIndex) {
94 SmallVector<int64_t> positions = delinearize(linearIndex, strides);
95 SmallVector<Value> operands;
96 for (auto input : op->getOperands())
97 operands.push_back(
98 vector::ExtractOp::create(rewriter, loc, input, positions));
99 Value scalarOp = Op::create(
100 rewriter, loc, TypeRange{vecType.getElementType()}, operands,
101 op.getProperties(), op->getDiscardableAttrDictionary().getValue());
102 result =
103 vector::InsertOp::create(rewriter, loc, scalarOp, result, positions);
104 }
105 rewriter.replaceOp(op, {result});
106 return success();
107}
108
109template <typename Op>
110LogicalResult
111PromoteOpToF32<Op>::matchAndRewrite(Op op, PatternRewriter &rewriter) const {
112 auto opType = op.getType();
113 if (!isa<Float16Type, BFloat16Type>(opType))
114 return failure();
115
116 auto loc = op.getLoc();
117 auto f32 = rewriter.getF32Type();
118 auto extendedOperands =
119 llvm::map_to_vector(op->getOperands(), [&](Value operand) -> Value {
120 return arith::ExtFOp::create(rewriter, loc, TypeRange{f32},
121 ValueRange{operand},
122 arith::ExtFOp::Properties{});
123 });
124 auto newOp = Op::create(rewriter, loc, TypeRange{f32}, extendedOperands,
125 op.getProperties(),
126 op->getDiscardableAttrDictionary().getValue());
127 rewriter.replaceOpWithNewOp<arith::TruncFOp>(op, opType, newOp);
128 return success();
129}
130
131template <typename Op>
132LogicalResult
133ScalarOpToLibmCall<Op>::matchAndRewrite(Op op,
134 PatternRewriter &rewriter) const {
135 auto module = SymbolTable::getNearestSymbolTable(op);
136 auto type = op.getType();
137 if (!isa<Float32Type, Float64Type>(type))
138 return failure();
139
140 auto name = type.getIntOrFloatBitWidth() == 64 ? doubleFunc : floatFunc;
141 auto opFunc = dyn_cast_or_null<SymbolOpInterface>(
142 SymbolTable::lookupSymbolIn(module, name));
143 // Forward declare function if it hasn't already been
144 if (!opFunc) {
145 OpBuilder::InsertionGuard guard(rewriter);
146 rewriter.setInsertionPointToStart(&module->getRegion(0).front());
147 auto opFunctionTy = FunctionType::get(
148 rewriter.getContext(), op->getOperandTypes(), op->getResultTypes());
149 opFunc = func::FuncOp::create(rewriter, rewriter.getUnknownLoc(), name,
150 opFunctionTy);
151 opFunc.setPrivate();
152
153 // By definition Math dialect operations imply LLVM's "readnone"
154 // function attribute, so we can set it here to provide more
155 // optimization opportunities (e.g. LICM) for backends targeting LLVM IR.
156 // This will have to be changed, when strict FP behavior is supported
157 // by Math dialect.
158 opFunc->setDiscardableAttr(LLVM::LLVMDialect::getReadnoneAttrName(),
159 UnitAttr::get(rewriter.getContext()));
160 }
161 assert(isa<FunctionOpInterface>(SymbolTable::lookupSymbolIn(module, name)));
162
163 rewriter.replaceOpWithNewOp<func::CallOp>(op, name, op.getType(),
164 op->getOperands());
165
166 return success();
167}
168
170 PatternBenefit benefit) {
171 MLIRContext *ctx = patterns.getContext();
172
173 populatePatternsForOp<math::AbsFOp>(patterns, benefit, ctx, "fabsf", "fabs");
174 populatePatternsForOp<math::AcosOp>(patterns, benefit, ctx, "acosf", "acos");
175 populatePatternsForOp<math::AcoshOp>(patterns, benefit, ctx, "acoshf",
176 "acosh");
177 populatePatternsForOp<math::AsinOp>(patterns, benefit, ctx, "asinf", "asin");
178 populatePatternsForOp<math::AsinhOp>(patterns, benefit, ctx, "asinhf",
179 "asinh");
180 populatePatternsForOp<math::Atan2Op>(patterns, benefit, ctx, "atan2f",
181 "atan2");
182 populatePatternsForOp<math::AtanOp>(patterns, benefit, ctx, "atanf", "atan");
183 populatePatternsForOp<math::AtanhOp>(patterns, benefit, ctx, "atanhf",
184 "atanh");
185 populatePatternsForOp<math::CbrtOp>(patterns, benefit, ctx, "cbrtf", "cbrt");
186 populatePatternsForOp<math::CeilOp>(patterns, benefit, ctx, "ceilf", "ceil");
187 populatePatternsForOp<math::CosOp>(patterns, benefit, ctx, "cosf", "cos");
188 populatePatternsForOp<math::CoshOp>(patterns, benefit, ctx, "coshf", "cosh");
189 populatePatternsForOp<math::ErfOp>(patterns, benefit, ctx, "erff", "erf");
190 populatePatternsForOp<math::ErfcOp>(patterns, benefit, ctx, "erfcf", "erfc");
191 populatePatternsForOp<math::ExpOp>(patterns, benefit, ctx, "expf", "exp");
192 populatePatternsForOp<math::Exp2Op>(patterns, benefit, ctx, "exp2f", "exp2");
193 populatePatternsForOp<math::ExpM1Op>(patterns, benefit, ctx, "expm1f",
194 "expm1");
195 populatePatternsForOp<math::FloorOp>(patterns, benefit, ctx, "floorf",
196 "floor");
197 populatePatternsForOp<math::FmaOp>(patterns, benefit, ctx, "fmaf", "fma");
198 populatePatternsForOp<math::LogOp>(patterns, benefit, ctx, "logf", "log");
199 populatePatternsForOp<math::Log2Op>(patterns, benefit, ctx, "log2f", "log2");
200 populatePatternsForOp<math::Log10Op>(patterns, benefit, ctx, "log10f",
201 "log10");
202 populatePatternsForOp<math::Log1pOp>(patterns, benefit, ctx, "log1pf",
203 "log1p");
204 populatePatternsForOp<math::PowFOp>(patterns, benefit, ctx, "powf", "pow");
205 populatePatternsForOp<math::RoundEvenOp>(patterns, benefit, ctx, "roundevenf",
206 "roundeven");
207 populatePatternsForOp<math::RoundOp>(patterns, benefit, ctx, "roundf",
208 "round");
209 populatePatternsForOp<math::SinOp>(patterns, benefit, ctx, "sinf", "sin");
210 populatePatternsForOp<math::SinhOp>(patterns, benefit, ctx, "sinhf", "sinh");
211 populatePatternsForOp<math::SqrtOp>(patterns, benefit, ctx, "sqrtf", "sqrt");
212 populatePatternsForOp<math::RsqrtOp>(patterns, benefit, ctx, "rsqrtf",
213 "rsqrt");
214 populatePatternsForOp<math::TanOp>(patterns, benefit, ctx, "tanf", "tan");
215 populatePatternsForOp<math::TanhOp>(patterns, benefit, ctx, "tanhf", "tanh");
216 populatePatternsForOp<math::TruncOp>(patterns, benefit, ctx, "truncf",
217 "trunc");
218}
219
220namespace {
221struct ConvertMathToLibmPass
222 : public impl::ConvertMathToLibmPassBase<ConvertMathToLibmPass> {
223 void runOnOperation() override;
224};
225} // namespace
226
227void ConvertMathToLibmPass::runOnOperation() {
228 auto module = getOperation();
229
230 RewritePatternSet patterns(&getContext());
232
233 ConversionTarget target(getContext());
234 target.addLegalDialect<arith::ArithDialect, BuiltinDialect, func::FuncDialect,
235 vector::VectorDialect>();
236 target.addIllegalDialect<math::MathDialect>();
237 if (failed(applyPartialConversion(module, target, std::move(patterns))))
238 signalPassFailure();
239}
return success()
b getContext())
FloatType getF32Type()
Definition Builders.cpp:51
Location getUnknownLoc()
Definition Builders.cpp:25
MLIRContext * getContext() const
Definition Builders.h:56
static DenseElementsAttr get(ShapedType type, ArrayRef< Attribute > values)
Constructs a dense elements attribute from an array of element values.
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:63
RAII guard to reset the insertion point of the builder when destroyed.
Definition Builders.h:351
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
Definition Builders.h:434
Location getLoc()
The source location the operation was defined or derived from.
This provides public APIs that all operations should have.
InferredProperties< T > & getProperties()
This class represents the benefit of a pattern match in a unitless scheme that ranges from 0 (very li...
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
MLIRContext * getContext() const
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
static Operation * lookupSymbolIn(Operation *op, StringAttr symbol)
Returns the operation registered with the given symbol name with the regions of 'symbolTableOp'.
This class provides an abstraction over the various different ranges of value types.
Definition TypeRange.h:40
This class provides an abstraction over the different types of ranges over Values.
Definition ValueRange.h:389
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
NestedPattern Op(FilterFunctionType filter=defaultFilterFunction)
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:732
Include the generated interface declarations.
void populateMathToLibmConversionPatterns(RewritePatternSet &patterns, PatternBenefit benefit=1)
Populate the given list with patterns that convert from Math to Libm calls.
SmallVector< int64_t > computeStrides(ArrayRef< int64_t > sizes)
SmallVector< int64_t > delinearize(int64_t linearIndex, ArrayRef< int64_t > strides)
Given the strides together with a linear index in the dimension space, return the vector-space offset...
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...