MLIR 24.0.0git
MathToAPFloat.cpp
Go to the documentation of this file.
1//===- MathToAPFloat.cpp - Mathmetic to APFloat Conversion ----------------===//
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
9#include "Utils.h"
10
18#include "mlir/IR/Verifier.h"
19#include "mlir/Pass/Pass.h"
21
22namespace mlir {
23#define GEN_PASS_DEF_MATHTOAPFLOATCONVERSIONPASS
24#include "mlir/Conversion/Passes.h.inc"
25} // namespace mlir
26
27using namespace mlir;
28using namespace mlir::func;
29
30struct AbsFOpToAPFloatConversion final : OpRewritePattern<math::AbsFOp> {
31 AbsFOpToAPFloatConversion(MLIRContext *context, SymbolOpInterface symTable,
32 PatternBenefit benefit = 1)
33 : OpRewritePattern<math::AbsFOp>(context, benefit), symTable(symTable) {}
34
35 LogicalResult matchAndRewrite(math::AbsFOp op,
36 PatternRewriter &rewriter) const override {
37 if (failed(checkPreconditions(rewriter, op)))
38 return failure();
39 // Get APFloat function from runtime library.
40 auto i32Type = IntegerType::get(symTable->getContext(), 32);
41 auto i64Type = IntegerType::get(symTable->getContext(), 64);
42 FailureOr<FuncOp> fn = lookupOrCreateFnDecl(
43 rewriter, symTable, "_mlir_apfloat_abs", {i32Type, i64Type});
44 if (failed(fn))
45 return fn;
46 Location loc = op.getLoc();
47 rewriter.setInsertionPoint(op);
48 // Scalarize and convert to APFloat runtime calls.
50 rewriter, loc, op.getOperand(), /*operand2=*/Value(), op.getType(),
51 [&](Value operand, Value, Type resultType) {
52 auto floatTy = cast<FloatType>(operand.getType());
53 auto intWType = rewriter.getIntegerType(floatTy.getWidth());
54 Value operandBits = arith::ExtUIOp::create(
55 rewriter, loc, i64Type,
56 arith::BitcastOp::create(rewriter, loc, intWType, operand));
57 // Call APFloat function.
58 Value semValue = getAPFloatSemanticsValue(rewriter, loc, floatTy);
59 SmallVector<Value> params = {semValue, operandBits};
60 Value negatedBits =
61 func::CallOp::create(rewriter, loc, TypeRange(i64Type),
62 SymbolRefAttr::get(*fn), params)
63 ->getResult(0);
64 // Truncate result to the original width.
65 auto truncatedBits =
66 arith::TruncIOp::create(rewriter, loc, intWType, negatedBits);
67 return arith::BitcastOp::create(rewriter, loc, floatTy,
68 truncatedBits);
69 });
70
71 rewriter.replaceOp(op, repl);
72 return success();
73 }
74
75 SymbolOpInterface symTable;
76};
77
78template <typename OpTy>
81 SymbolOpInterface symTable,
82 PatternBenefit benefit = 1)
83 : OpRewritePattern<OpTy>(context, benefit), symTable(symTable),
85
86 LogicalResult matchAndRewrite(OpTy op,
87 PatternRewriter &rewriter) const override {
88 if (failed(checkPreconditions(rewriter, op)))
89 return failure();
90 // Get APFloat function from runtime library.
91 auto i1 = IntegerType::get(symTable->getContext(), 1);
92 auto i32Type = IntegerType::get(symTable->getContext(), 32);
93 auto i64Type = IntegerType::get(symTable->getContext(), 64);
94 std::string funcName =
95 (llvm::Twine("_mlir_apfloat_is") + APFloatName).str();
96 FailureOr<FuncOp> fn = lookupOrCreateFnDecl(
97 rewriter, symTable, funcName, {i32Type, i64Type}, nullptr, i1);
98 if (failed(fn))
99 return fn;
100 Location loc = op.getLoc();
101 rewriter.setInsertionPoint(op);
102 // Scalarize and convert to APFloat runtime calls.
104 rewriter, loc, op.getOperand(), /*operand2=*/Value(), op.getType(),
105 [&](Value operand, Value, Type resultType) {
106 auto floatTy = cast<FloatType>(operand.getType());
107 auto intWType = rewriter.getIntegerType(floatTy.getWidth());
108 Value operandBits = arith::ExtUIOp::create(
109 rewriter, loc, i64Type,
110 arith::BitcastOp::create(rewriter, loc, intWType, operand));
111
112 // Call APFloat function.
113 Value semValue = getAPFloatSemanticsValue(rewriter, loc, floatTy);
114 Value params[] = {semValue, operandBits};
115 return func::CallOp::create(rewriter, loc, TypeRange(i1),
116 SymbolRefAttr::get(*fn), params)
117 .getResult(0);
118 });
119 rewriter.replaceOp(op, repl);
120 return success();
121 }
122
123 SymbolOpInterface symTable;
124 const char *APFloatName;
125};
126
127struct FmaOpToAPFloatConversion final : OpRewritePattern<math::FmaOp> {
128 FmaOpToAPFloatConversion(MLIRContext *context, SymbolOpInterface symTable,
129 PatternBenefit benefit = 1)
130 : OpRewritePattern<math::FmaOp>(context, benefit), symTable(symTable) {};
131
132 LogicalResult matchAndRewrite(math::FmaOp op,
133 PatternRewriter &rewriter) const override {
134 if (failed(checkPreconditions(rewriter, op)))
135 return failure();
136 // Cast operands to 64-bit integers.
137 mlir::Type resType = op.getResult().getType();
138 auto floatTy = dyn_cast<FloatType>(resType);
139 if (!floatTy) {
140 auto vecTy1 = cast<VectorType>(resType);
141 floatTy = llvm::cast<FloatType>(vecTy1.getElementType());
142 }
143 auto i32Type = IntegerType::get(symTable->getContext(), 32);
144 auto i64Type = IntegerType::get(symTable->getContext(), 64);
145 FailureOr<FuncOp> fn = lookupOrCreateFnDecl(
146 rewriter, symTable, "_mlir_apfloat_fused_multiply_add",
147 {i32Type, i64Type, i64Type, i64Type});
148 if (failed(fn))
149 return fn;
150 Location loc = op.getLoc();
151 rewriter.setInsertionPoint(op);
152
153 IntegerType intWType = rewriter.getIntegerType(floatTy.getWidth());
154 IntegerType int64Type = rewriter.getI64Type();
155
156 auto scalarFMA = [&rewriter, &loc, &floatTy, &fn, &intWType,
157 &int64Type](Value a, Value b, Value c) {
158 Value operand = arith::ExtUIOp::create(
159 rewriter, loc, int64Type,
160 arith::BitcastOp::create(rewriter, loc, intWType, a));
161 Value multiplicand = arith::ExtUIOp::create(
162 rewriter, loc, int64Type,
163 arith::BitcastOp::create(rewriter, loc, intWType, b));
164 Value addend = arith::ExtUIOp::create(
165 rewriter, loc, int64Type,
166 arith::BitcastOp::create(rewriter, loc, intWType, c));
167 // Call APFloat function.
168 Value semValue = getAPFloatSemanticsValue(rewriter, loc, floatTy);
169 SmallVector<Value> params = {semValue, operand, multiplicand, addend};
170 auto resultOp =
171 func::CallOp::create(rewriter, loc, TypeRange(rewriter.getI64Type()),
172 SymbolRefAttr::get(*fn), params);
173
174 // Truncate result to the original width.
175 auto trunc = arith::TruncIOp::create(rewriter, loc, intWType,
176 resultOp->getResult(0));
177 return arith::BitcastOp::create(rewriter, loc, floatTy, trunc);
178 };
179
180 if (auto vecTy1 = dyn_cast<VectorType>(op.getA().getType())) {
181 // Sanity check: Operand types must match.
182 assert(vecTy1 == dyn_cast<VectorType>(op.getB().getType()) &&
183 "expected same vector types");
184 assert(vecTy1 == dyn_cast<VectorType>(op.getC().getType()) &&
185 "expected same vector types");
186 // Prepare scalar operands.
187 ResultRange scalarOperands =
188 vector::ToElementsOp::create(rewriter, loc, op.getA())->getResults();
189 ResultRange scalarMultiplicands =
190 vector::ToElementsOp::create(rewriter, loc, op.getB())->getResults();
191 ResultRange scalarAddends =
192 vector::ToElementsOp::create(rewriter, loc, op.getC())->getResults();
193 // Call the function for each pair of scalar operands.
194 SmallVector<Value> results;
195 for (auto [operand, multiplicand, addend] : llvm::zip_equal(
196 scalarOperands, scalarMultiplicands, scalarAddends)) {
197 results.push_back(scalarFMA(operand, multiplicand, addend));
198 }
199 // Package the results into a vector.
200 auto fromElements = vector::FromElementsOp::create(
201 rewriter, loc,
202 vecTy1.cloneWith(/*shape=*/std::nullopt, results.front().getType()),
203 results);
204 rewriter.replaceOp(op, fromElements);
205 return success();
206 }
207
208 Value repl = scalarFMA(op.getA(), op.getB(), op.getC());
209 rewriter.replaceOp(op, repl);
210 return success();
211 }
212
213 SymbolOpInterface symTable;
214};
215
216namespace {
217struct MathToAPFloatConversionPass final
218 : impl::MathToAPFloatConversionPassBase<MathToAPFloatConversionPass> {
219 using Base::Base;
220
221 void runOnOperation() override;
222};
223
224void MathToAPFloatConversionPass::runOnOperation() {
225 MLIRContext *context = &getContext();
226 RewritePatternSet patterns(context);
227
228 patterns.add<AbsFOpToAPFloatConversion>(context, getOperation());
229 patterns.add<IsOpToAPFloatConversion<math::IsFiniteOp>>(context, "finite",
230 getOperation());
231 patterns.add<IsOpToAPFloatConversion<math::IsInfOp>>(context, "infinite",
232 getOperation());
233 patterns.add<IsOpToAPFloatConversion<math::IsNaNOp>>(context, "nan",
234 getOperation());
235 patterns.add<IsOpToAPFloatConversion<math::IsNormalOp>>(context, "normal",
236 getOperation());
237 patterns.add<FmaOpToAPFloatConversion>(context, getOperation());
238
239 LogicalResult result = success();
240 ScopedDiagnosticHandler scopedHandler(context, [&result](Diagnostic &diag) {
241 if (diag.getSeverity() == DiagnosticSeverity::Error) {
242 result = failure();
243 }
244 // NB: if you don't return failure, no other diag handlers will fire (see
245 // mlir/lib/IR/Diagnostics.cpp:DiagnosticEngineImpl::emit).
246 return failure();
247 });
248 walkAndApplyPatterns(getOperation(), std::move(patterns));
249 if (failed(result))
250 return signalPassFailure();
251}
252} // namespace
return success()
b
Return true if permutation is a valid permutation of the outer_dims_perm (case OuterOrInnerPerm::Oute...
b getContext())
static std::string diag(const llvm::Value &value)
IntegerType getI64Type()
Definition Builders.cpp:73
IntegerType getIntegerType(unsigned width)
Definition Builders.cpp:75
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition Location.h:76
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:63
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
Definition Builders.h:401
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...
This class implements the result iterators for the Operation class.
Definition ValueRange.h:248
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
This class provides an abstraction over the various different ranges of value types.
Definition TypeRange.h:40
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
Type getType() const
Return the type of this value.
Definition Value.h:105
FailureOr< FuncOp > lookupOrCreateFnDecl(OpBuilder &b, SymbolOpInterface symTable, StringRef name, TypeRange paramTypes, SymbolTableCollection *symbolTables=nullptr, Type resultType={})
Helper function to look up or create the symbol for a runtime library function with the given paramet...
Definition Utils.cpp:302
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:733
Include the generated interface declarations.
LogicalResult checkPreconditions(RewriterBase &rewriter, Operation *op)
Check preconditions for the conversion:
Definition Utils.cpp:70
Value getAPFloatSemanticsValue(OpBuilder &b, Location loc, FloatType floatTy)
Definition Utils.cpp:21
Value forEachScalarValue(mlir::RewriterBase &rewriter, Location loc, Value operand1, Value operand2, Type resultType, llvm::function_ref< Value(Value, Value, Type)> fn)
Given two operands of vector type and vector result type (with the same shape), call the given functi...
Definition Utils.cpp:28
void walkAndApplyPatterns(Operation *op, const FrozenRewritePatternSet &patterns, RewriterBase::Listener *listener=nullptr)
A fast walk-based pattern rewrite driver.
LogicalResult matchAndRewrite(math::AbsFOp op, PatternRewriter &rewriter) const override
SymbolOpInterface symTable
AbsFOpToAPFloatConversion(MLIRContext *context, SymbolOpInterface symTable, PatternBenefit benefit=1)
SymbolOpInterface symTable
LogicalResult matchAndRewrite(math::FmaOp op, PatternRewriter &rewriter) const override
FmaOpToAPFloatConversion(MLIRContext *context, SymbolOpInterface symTable, PatternBenefit benefit=1)
SymbolOpInterface symTable
LogicalResult matchAndRewrite(OpTy op, PatternRewriter &rewriter) const override
IsOpToAPFloatConversion(MLIRContext *context, const char *APFloatName, SymbolOpInterface symTable, PatternBenefit benefit=1)
OpRewritePattern(MLIRContext *context, PatternBenefit benefit=1, ArrayRef< StringRef > generatedNames={})