MLIR-AIE 1.4.5.dev
AIETransformBfpTypes.cpp
Go to the documentation of this file.
1//===- AIETransformBfpTypes.cpp --------------------------------*- C++ -*-===//
2//
3// Copyright (C) 2025 Advanced Micro Devices, Inc.
4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5//
6//===----------------------------------------------------------------------===//
7
12
13#include "mlir/IR/Attributes.h"
14#include "mlir/IR/BuiltinAttributes.h"
15#include "mlir/IR/BuiltinTypes.h"
16#include "mlir/IR/Diagnostics.h"
17#include "mlir/Pass/Pass.h"
18#include "mlir/Support/LLVM.h"
19#include "mlir/Transforms/DialectConversion.h"
20#include "llvm/ADT/SmallVector.h"
21#include "llvm/IR/Type.h"
22#include "llvm/Support/raw_ostream.h"
23
24namespace xilinx::AIEX {
25#define GEN_PASS_DEF_AIETRANSFORMBFPTYPES
26#include "aie/Dialect/AIEX/Transforms/AIEXPasses.h.inc"
27} // namespace xilinx::AIEX
28
29#define DEBUG_TYPE "transform-bfp-types"
30
31using namespace mlir;
32using namespace xilinx;
33using namespace xilinx::AIE;
34using namespace xilinx::AIEX;
35
36using namespace mlir;
37
38class BfpToIntegerConverter : public mlir::TypeConverter {
39public:
41 addTypeAttributeConversion([&](Type type, Attribute attr) {
42 auto newType = convertType(type);
43 if (!newType) {
44 llvm::errs() << "Failed to convert type: " << type << "\n";
45 return AttributeConversionResult::abort();
46 }
47 return AttributeConversionResult(TypeAttr::get(newType));
48 });
49
50 // Note that the most recently added conversions will be invoked first
51
52 // Leave other types unchanged
53 addConversion([](Type type) -> std::optional<Type> { return type; });
54
55 // Add a conversion for bfpTypes to an integer type
56 addConversion([&](BlockFloatType blockType) -> std::optional<IntegerType> {
57 bool isSupported =
58 targetModel.isSupportedBlockFormat(blockType.getBlockType().str());
59 if (!isSupported) {
60 llvm::errs() << "Block type " << blockType.getBlockType()
61 << " is not supported in the specified model\n";
62 // Note that returning a nullptr here will stop the conversion while
63 // returning a std::nullopt will allow the converter to keep trying the
64 // remaining conversions (thus reaching the default one in this case)
65 return nullptr;
66 }
67
68 return mlir::IntegerType::get(blockType.getContext(),
69 blockType.getTotalSizeInBits());
70 });
71
72 // Add a conversion for MemRefType
73 addConversion([&](MemRefType memRefType) -> std::optional<MemRefType> {
74 auto newElementType = convertType(memRefType.getElementType());
75 if (!newElementType) {
76 llvm::errs() << "Failed to convert memref element type\n";
77 return nullptr;
78 }
79 return MemRefType::get(memRefType.getShape(), newElementType,
80 memRefType.getLayout(),
81 memRefType.getMemorySpace());
82 });
83
84 // Add a conversion for ObjectFifoType
85 addConversion([&](AIEObjectFifoType objectFifoType)
86 -> std::optional<AIEObjectFifoType> {
87 auto newElementType = convertType(objectFifoType.getElementType());
88 if (!newElementType) {
89 llvm::errs() << "Failed to convert ObjectFifoType element type\n";
90 return nullptr;
91 }
92
93 if (auto newMemRef = dyn_cast<MemRefType>(newElementType))
94 return AIEObjectFifoType::get(objectFifoType.getContext(), newMemRef);
95
96 llvm::errs()
97 << "ObjectFifoType converted element type is not a MemRefType\n";
98 return nullptr;
99 });
100
101 // Add a conversion for FunctionType
102 addConversion([&](FunctionType funcType) -> std::optional<FunctionType> {
103 llvm::SmallVector<Type> newInputTypes;
104 auto check = convertTypes(funcType.getInputs(), newInputTypes);
105 if (check.failed()) {
106 llvm::errs() << "Failed to convert function input types\n";
107 return nullptr;
108 }
109
110 llvm::SmallVector<Type> newOutputTypes;
111 check = convertTypes(funcType.getResults(), newOutputTypes);
112 if (check.failed()) {
113 llvm::errs() << "Failed to convert function output types\n";
114 return nullptr;
115 }
116
117 return FunctionType::get(funcType.getContext(), newInputTypes,
118 newOutputTypes);
119 });
120
121 // Add conversions for other types as needed (llvm arrays?)
122 }
123};
124
126public:
127 BfpToIntegerConversionPattern(TypeConverter &typeConverter,
128 MLIRContext *context, bool &conversionFailed)
129 : ConversionPattern(typeConverter, MatchAnyOpTypeTag(), 1, context),
130 conversionFailed(conversionFailed) {}
131
132 LogicalResult
133 matchAndRewrite(Operation *op, ArrayRef<Value> operands,
134 ConversionPatternRewriter &rewriter) const override {
135
136 // The objective is to replace all bfp operations by an integer of the
137 // appropriate width. This pass currently does not have any other
138 // functionality.
139
140 // Operation results
141 for (auto result : op->getResults()) {
142 auto conversion = typeConverter->convertType(result.getType());
143 if (!conversion) {
144 conversionFailed = true;
145 return op->emitError()
146 << "Failed to convert result type: " << result.getType();
147 }
148 result.setType(conversion);
149 }
150
151 // Operation operands
152 for (auto operand : op->getOperands()) {
153 auto conversion = typeConverter->convertType(operand.getType());
154 if (!conversion) {
155 conversionFailed = true;
156 return op->emitError()
157 << "Failed to convert operand type: " << operand.getType();
158 }
159 operand.setType(conversion);
160 }
161
162 // Operation attributes
163 // Note that the attribute list is immutable and
164 // needs to be recreated from scratch. Also note that type attributes cannot
165 // access their type and must therefore be managed through
166 // the convertTypeAttribute conversion instead
167 SmallVector<NamedAttribute> newAttrs;
168 for (auto attr : op->getAttrs()) {
169 if (auto typeAttr = dyn_cast<TypeAttr>(attr.getValue())) {
170 auto conversion = typeConverter->convertTypeAttribute(
171 typeAttr.getValue(), attr.getValue());
172 if (!conversion) {
173 conversionFailed = true;
174 return op->emitError()
175 << "Failed to convert attribute type: " << typeAttr.getValue();
176 }
177 newAttrs.push_back(NamedAttribute(attr.getName(), conversion.value()));
178 } else {
179 newAttrs.push_back(attr);
180 }
181 }
182 op->setAttrs(DictionaryAttr::get(op->getContext(), newAttrs));
183
184 return success();
185 }
186
187private:
188 bool &conversionFailed;
189};
190
193 AIETransformBfpTypesPass> {
194public:
195 void runOnOperation() override {
196 DeviceOp device = getOperation();
197 MLIRContext *context = device.getContext();
198
199 BfpToIntegerConverter typeConverter(device.getTargetModel());
200
201 // Set up an empty conversion target, since we have to iterate over all ops
202 ConversionTarget target(*context);
203
204 RewritePatternSet patterns(context);
205 bool conversionFailed = false;
206 patterns.add<BfpToIntegerConversionPattern>(typeConverter, context,
207 conversionFailed);
208
209 if (failed(applyPartialConversion(device, target, std::move(patterns))) ||
210 conversionFailed) {
211 signalPassFailure();
212 }
213 }
214};
215
216std::unique_ptr<OperationPass<DeviceOp>>
218 return std::make_unique<AIETransformBfpTypesPass>();
219}
LogicalResult matchAndRewrite(Operation *op, ArrayRef< Value > operands, ConversionPatternRewriter &rewriter) const override
BfpToIntegerConversionPattern(TypeConverter &typeConverter, MLIRContext *context, bool &conversionFailed)
BfpToIntegerConverter(const AIETargetModel &targetModel)
virtual bool isSupportedBlockFormat(std::string const &format) const
std::unique_ptr< mlir::OperationPass< AIE::DeviceOp > > createAIETransformBfpTypesPass()