15#include "mlir/Dialect/Func/IR/FuncOps.h"
16#include "mlir/IR/Builders.h"
17#include "mlir/IR/BuiltinOps.h"
18#include "mlir/IR/BuiltinTypes.h"
19#include "mlir/IR/Value.h"
20#include "mlir/Pass/Pass.h"
21#include "mlir/Support/LogicalResult.h"
22#include "mlir/Transforms/DialectConversion.h"
26#define GEN_PASS_DEF_REMOVEI0TYPES
27#include "circt/Dialect/Arc/ArcPasses.h.inc"
36struct RemoveI0TypesPass
37 :
public arc::impl::RemoveI0TypesBase<RemoveI0TypesPass> {
38 using RemoveI0TypesBase::RemoveI0TypesBase;
39 void runOnOperation()
override;
43 auto intType = dyn_cast<IntegerType>(type);
44 return intType && intType.getWidth() == 0;
48SmallVector<Value> flatten(ArrayRef<ValueRange> ranges) {
49 SmallVector<Value> flat;
50 for (
auto range : ranges) {
51 flat.insert(flat.end(), range.begin(), range.end());
64 matchAndRewrite(T op, OneToNOpAdaptor adaptor,
65 ConversionPatternRewriter &rewriter)
const override {
66 const TypeConverter &converter = *this->getTypeConverter();
67 auto result = convertOpResultTypes(op, flatten(adaptor.getOperands()),
74 Operation *newOp = *result;
75 auto newOpResultIt = newOp->result_begin();
76 SmallVector<Value> results;
77 for (
auto oldType : op->getResultTypes()) {
78 if (!converter.convertType(oldType)) {
79 results.push_back(
nullptr);
81 results.push_back(*newOpResultIt++);
84 assert(newOpResultIt == newOp->result_end() &&
"Didn't map all results!");
85 rewriter.replaceOp(op, results);
94struct ConvertGeneric :
public ConversionPattern {
95 ConvertGeneric(TypeConverter &converter, MLIRContext *
context)
96 : ConversionPattern(converter, MatchAnyOpTypeTag{},
100 matchAndRewrite(Operation *op, ArrayRef<ValueRange> operands,
101 ConversionPatternRewriter &rewriter)
const override {
102 const TypeConverter &converter = *getTypeConverter();
105 for (ValueRange range : operands) {
107 rewriter.eraseOp(op);
113 SmallVector<Type> resultTypes;
114 if (failed(converter.convertTypes(op->getResultTypes(), resultTypes)))
116 if (resultTypes.size() != op->getNumResults()) {
117 rewriter.eraseOp(op);
122 convertOpResultTypes(op, flatten(operands), converter, rewriter);
125 rewriter.replaceOp(op, *result);
136 ConversionPatternRewriter &rewriter)
const override {
137 if (adaptor.getIndex().empty()) {
138 assert(adaptor.getInput().size() == 1);
139 rewriter.replaceOp(op, adaptor.getInput().front());
152 ConversionPatternRewriter &rewriter)
const override {
153 if (adaptor.getInputs().size() == 1) {
154 rewriter.replaceOp(op, adaptor.getInputs().front());
166 matchAndRewrite(hw::ArrayInjectOp op, OneToNOpAdaptor adaptor,
167 ConversionPatternRewriter &rewriter)
const override {
168 if (adaptor.getIndex().empty()) {
169 rewriter.replaceOp(op, adaptor.getElement());
178struct ConvertAggregateConstant
182 matchAndRewrite(hw::AggregateConstantOp op, OpAdaptor adaptor,
183 ConversionPatternRewriter &rewriter)
const override {
184 Type resultType = getTypeConverter()->convertType(op.getResult().getType());
187 Attribute newFields =
188 rewriteArrayAttr(op.getFields(), op.getResult().getType());
190 if (!isa<ArrayAttr>(newFields)) {
192 IntegerAttr attr = cast<IntegerAttr>(newFields);
195 rewriter.replaceOp(op, result);
200 auto newOp = hw::AggregateConstantOp::create(
201 rewriter, op.getLoc(), resultType, cast<ArrayAttr>(newFields));
202 rewriter.replaceOp(op, newOp);
207 Attribute rewriteArrayAttr(ArrayAttr array, Type type)
const {
210 if (
auto arrayType = dyn_cast<hw::ArrayType>(type);
211 arrayType && arrayType.getNumElements() == 1) {
212 return *array.begin();
217 auto fieldIdInterface = cast<hw::FieldIDTypeInterface>(type);
218 SmallVector<Attribute> attrs;
219 for (
auto [index, attr] :
llvm::enumerate(array)) {
220 uint64_t fieldId = fieldIdInterface.getFieldID(index);
221 Type subType = fieldIdInterface.getSubTypeByFieldID(fieldId).first;
222 if (
auto subArrayAttr = dyn_cast<ArrayAttr>(attr))
223 attrs.push_back(rewriteArrayAttr(subArrayAttr, subType));
225 attrs.push_back(attr);
227 return ArrayAttr::get(array.getContext(), attrs);
233void RemoveI0TypesPass::runOnOperation() {
234 TypeConverter converter;
235 ConversionTarget target(getContext());
236 RewritePatternSet
patterns(&getContext());
239 converter.addConversion([](Type type, SmallVectorImpl<Type> &types) {
241 types.push_back(type);
246 converter.addConversion([&converter](hw::ArrayType type,
247 SmallVectorImpl<Type> &types) {
249 if (type.getNumElements() == 1) {
250 if (Type converted = converter.convertType(type.getElementType()))
251 types.push_back(converted);
255 types.push_back(hw::ArrayType::get(
256 converter.convertType(type.getElementType()), type.getNumElements()));
259 converter.addConversion([&converter](hw::StructType type) -> Type {
260 SmallVector<hw::StructType::FieldInfo> newMembers;
262 for (
auto &field : type.getElements()) {
263 SmallVector<Type> convertedTypes;
264 if (failed(converter.convertType(field.type, convertedTypes)))
266 if (!convertedTypes.empty()) {
267 assert(convertedTypes.size() == 1);
268 newMembers.push_back({field.name, convertedTypes[0]});
271 return hw::StructType::get(type.getContext(), newMembers);
273 converter.addConversion([&converter](hw::UnionType type) -> Type {
274 SmallVector<hw::UnionType::FieldInfo> newMembers;
276 for (
auto &field : type.getElements()) {
277 SmallVector<Type> convertedTypes;
278 if (failed(converter.convertType(field.type, convertedTypes)))
280 if (!convertedTypes.empty()) {
281 assert(convertedTypes.size() == 1);
282 newMembers.push_back({field.name, convertedTypes[0], field.offset});
285 return hw::UnionType::get(type.getContext(), newMembers);
287 converter.addConversion(
288 [&converter](hw::TypeAliasType type, SmallVectorImpl<Type> &types) {
289 return converter.convertType(type.getCanonicalType(), types);
291 converter.addConversion(
292 [&converter](arc::StateType type, SmallVectorImpl<Type> &types) {
293 if (failed(converter.convertType(type.getType(), types)))
295 assert(types.size() == 1);
296 types[0] = arc::StateType::get(types[0]);
300 target.markUnknownOpDynamicallyLegal(
301 [&](Operation *op) {
return converter.isLegal(op); });
302 target.addDynamicallyLegalOp<func::FuncOp>([&](func::FuncOp func) {
303 FunctionType fty = func.getFunctionType();
304 return converter.isLegal(fty.getInputs()) &&
305 converter.isLegal(fty.getResults());
308 populateFunctionOpInterfaceTypeConversionPattern<func::FuncOp>(
patterns,
311 patterns.add<LegalizeGeneric<func::ReturnOp>, LegalizeGeneric<func::CallOp>,
312 LegalizeGeneric<hw::StructCreateOp>, ConvertArrayGet,
313 ConvertArrayCreate, ConvertArrayInject, ConvertGeneric,
314 ConvertAggregateConstant>(converter, &getContext());
315 ConversionConfig config;
316 config.allowPatternRollback =
false;
317 if (failed(applyFullConversion(getOperation(), target, std::move(
patterns),
319 return signalPassFailure();
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
static FIRRTLBaseType convertType(FIRRTLBaseType type)
Returns null type if no conversion is needed.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.