MLIR 24.0.0git
EmulateUnsupportedFloats.cpp
Go to the documentation of this file.
1//===- EmulateUnsupportedFloats.cpp - Promote small floats --*- C++ -*-===//
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// This pass promotes small floats (of some unsupported types T) to a supported
9// type U by wrapping all float operations on Ts with expansion to and
10// truncation from U, then operating on U.
11//===----------------------------------------------------------------------===//
12
14
19#include "mlir/IR/Location.h"
22#include "llvm/ADT/STLExtras.h"
23#include "llvm/Support/ErrorHandling.h"
24#include <optional>
25
26namespace mlir::arith {
27#define GEN_PASS_DEF_ARITHEMULATEUNSUPPORTEDFLOATS
28#include "mlir/Dialect/Arith/Transforms/Passes.h.inc"
29} // namespace mlir::arith
30
31using namespace mlir;
32
33namespace {
34struct EmulateUnsupportedFloatsPass
35 : arith::impl::ArithEmulateUnsupportedFloatsBase<
36 EmulateUnsupportedFloatsPass> {
37 using arith::impl::ArithEmulateUnsupportedFloatsBase<
38 EmulateUnsupportedFloatsPass>::ArithEmulateUnsupportedFloatsBase;
39
40 void runOnOperation() override;
41};
42
43struct EmulateFloatPattern final : ConversionPattern {
44 EmulateFloatPattern(const TypeConverter &converter, MLIRContext *ctx)
45 : ConversionPattern::ConversionPattern(
46 converter, Pattern::MatchAnyOpTypeTag(), 1, ctx) {}
47
48 LogicalResult
49 matchAndRewrite(Operation *op, ArrayRef<Value> operands,
50 ConversionPatternRewriter &rewriter) const override;
51};
52} // end namespace
53
54LogicalResult EmulateFloatPattern::matchAndRewrite(
55 Operation *op, ArrayRef<Value> operands,
56 ConversionPatternRewriter &rewriter) const {
57 if (getTypeConverter()->isLegal(op))
58 return failure();
59 // The rewrite doesn't handle cloning regions.
60 if (op->getNumRegions() != 0)
61 return failure();
62
63 Location loc = op->getLoc();
64 const TypeConverter *converter = getTypeConverter();
65 SmallVector<Type> resultTypes;
66 if (failed(converter->convertTypes(op->getResultTypes(), resultTypes))) {
67 // Note to anyone looking for this error message: this is a "can't happen".
68 // If you're seeing it, there's a bug.
69 return op->emitOpError("type conversion failed in float emulation");
70 }
71 OperationState state(loc, op->getName(), operands, resultTypes,
72 op->getDiscardableAttrDictionary().getValue(),
73 op->getSuccessors());
74 state.propertiesAttr = op->getPropertiesAsAttribute();
75 Operation *expandedOp = rewriter.create(state);
76 SmallVector<Value> newResults(expandedOp->getResults());
77 for (auto [res, oldType, newType] : llvm::zip_equal(
78 MutableArrayRef{newResults}, op->getResultTypes(), resultTypes)) {
79 if (oldType != newType) {
80 auto truncFOp = arith::TruncFOp::create(rewriter, loc, oldType, res);
81 truncFOp.setFastmath(arith::FastMathFlags::contract);
82 res = truncFOp.getResult();
83 }
84 }
85 rewriter.replaceOp(op, newResults);
86 return success();
87}
88
90 TypeConverter &converter, ArrayRef<Type> sourceTypes, Type targetType) {
91 converter.addConversion([sourceTypes = SmallVector<Type>(sourceTypes),
92 targetType](Type type) -> std::optional<Type> {
93 if (llvm::is_contained(sourceTypes, type))
94 return targetType;
95 if (auto shaped = dyn_cast<ShapedType>(type))
96 if (llvm::is_contained(sourceTypes, shaped.getElementType()))
97 return shaped.clone(targetType);
98 // All other types legal
99 return type;
100 });
101 converter.addTargetMaterialization(
102 [](OpBuilder &b, Type target, ValueRange input, Location loc) {
103 auto extFOp = arith::ExtFOp::create(b, loc, target, input.front(),
104 arith::FastMathFlagsAttr{});
105 extFOp.setFastmath(arith::FastMathFlags::contract);
106 return extFOp;
107 });
108}
109
111 RewritePatternSet &patterns, const TypeConverter &converter) {
112 patterns.add<EmulateFloatPattern>(converter, patterns.getContext());
113}
114
116 ConversionTarget &target, const TypeConverter &converter) {
117 // Don't try to legalize functions and other ops that don't need expansion.
118 target.markUnknownOpDynamicallyLegal([](Operation *op) { return true; });
119 target.addDynamicallyLegalDialect<arith::ArithDialect>(
120 [&](Operation *op) -> std::optional<bool> {
121 return converter.isLegal(op);
122 });
123 // Manually mark arithmetic-performing vector instructions.
124 target.addDynamicallyLegalOp<vector::ContractionOp, vector::ReductionOp,
125 vector::MultiDimReductionOp, vector::FMAOp,
126 vector::OuterProductOp, vector::ScanOp>(
127 [&](Operation *op) { return converter.isLegal(op); });
128 target.addLegalOp<arith::BitcastOp, arith::ExtFOp, arith::TruncFOp,
129 arith::ConstantOp, arith::SelectOp, vector::BroadcastOp>();
130}
131
132void EmulateUnsupportedFloatsPass::runOnOperation() {
133 MLIRContext *ctx = &getContext();
134 Operation *op = getOperation();
135 SmallVector<Type> sourceTypes;
136 Type targetType;
137
138 FloatType parsedTargetType = arith::parseFloatType(ctx, targetTypeStr);
139 if (!parsedTargetType) {
140 emitError(UnknownLoc::get(ctx), "could not map target type '" +
141 targetTypeStr +
142 "' to a known floating-point type");
143 return signalPassFailure();
144 }
145 targetType = parsedTargetType;
146 for (StringRef sourceTypeStr : sourceTypeStrs) {
147 FloatType sourceType = arith::parseFloatType(ctx, sourceTypeStr);
148 if (!sourceType) {
149 emitError(UnknownLoc::get(ctx), "could not map source type '" +
150 sourceTypeStr +
151 "' to a known floating-point type");
152 return signalPassFailure();
153 }
154 sourceTypes.push_back(sourceType);
155 }
156 if (sourceTypes.empty())
158 std::nullopt,
159 "no source types specified, float emulation will do nothing");
160
161 if (llvm::is_contained(sourceTypes, targetType)) {
162 emitError(UnknownLoc::get(ctx),
163 "target type cannot be an unsupported source type");
164 return signalPassFailure();
165 }
166 TypeConverter converter;
167 arith::populateEmulateUnsupportedFloatsConversions(converter, sourceTypes,
168 targetType);
169 RewritePatternSet patterns(ctx);
170 arith::populateEmulateUnsupportedFloatsPatterns(patterns, converter);
171 ConversionTarget target(getContext());
172 arith::populateEmulateUnsupportedFloatsLegality(target, converter);
173
174 if (failed(applyPartialConversion(op, target, std::move(patterns))))
175 signalPassFailure();
176}
return success()
b
Return true if permutation is a valid permutation of the outer_dims_perm (case OuterOrInnerPerm::Oute...
b getContext())
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
This class helps build Operations.
Definition Builders.h:210
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
unsigned getNumRegions()
Returns the number of regions held by this operation.
Definition Operation.h:726
Location getLoc()
The source location the operation was defined or derived from.
Definition Operation.h:240
Attribute getPropertiesAsAttribute()
Return the properties converted to an attribute.
OperationName getName()
The name of an operation is the key identifier for it.
Definition Operation.h:115
DictionaryAttr getDiscardableAttrDictionary()
Return all of the discardable attributes on this operation as a DictionaryAttr.
Definition Operation.h:553
result_type_range getResultTypes()
Definition Operation.h:453
SuccessorRange getSuccessors()
Definition Operation.h:755
result_range getResults()
Definition Operation.h:440
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
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.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
This class provides an abstraction over the different types of ranges over Values.
Definition ValueRange.h:389
FloatType parseFloatType(MLIRContext *ctx, StringRef name)
Definition Utils.cpp:365
void populateEmulateUnsupportedFloatsPatterns(RewritePatternSet &patterns, const TypeConverter &converter)
Add rewrite patterns for converting operations that use illegal float types to ones that use legal on...
void populateEmulateUnsupportedFloatsLegality(ConversionTarget &target, const TypeConverter &converter)
Set up a dialect conversion to reject arithmetic operations on unsupported float types.
void populateEmulateUnsupportedFloatsConversions(TypeConverter &converter, ArrayRef< Type > sourceTypes, Type targetType)
Populate the type conversions needed to emulate the unsupported sourceTypes with destType
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:732
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
LogicalResult emitOptionalWarning(std::optional< Location > loc, Args &&...args)