CIRCT 22.0.0git
Loading...
Searching...
No Matches
ESILowerTypes.cpp
Go to the documentation of this file.
1//===- ESILowerTypes.cpp ----------------------------------------*- 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//
9// Lower high-level ESI types to HW conversions and pass.
10//
11//===----------------------------------------------------------------------===//
12
13#include "../PassDetails.h"
14
20
21#include "mlir/IR/BuiltinTypes.h"
22#include "mlir/Interfaces/ControlFlowInterfaces.h"
23#include "mlir/Pass/Pass.h"
24#include "mlir/Transforms/DialectConversion.h"
25
26namespace circt {
27namespace esi {
28#define GEN_PASS_DEF_LOWERESITYPES
29#include "circt/Dialect/ESI/ESIPasses.h.inc"
30} // namespace esi
31} // namespace circt
32
33using namespace circt;
34using namespace circt::esi;
35
36namespace {
37/// Lower all "high-level" ESI types on modules to some lower construct.
38struct ESILowerTypesPass
39 : public circt::esi::impl::LowerESITypesBase<ESILowerTypesPass> {
40 void runOnOperation() override;
41};
42} // anonymous namespace
43
44namespace {
45/// Materializations and type conversions to lower ESI data windows.
46class LowerTypesConverter : public TypeConverter {
47public:
48 LowerTypesConverter() {
49 addConversion([](Type t) { return t; });
50 addConversion([](WindowType window) { return window.getLoweredType(); });
51 addConversion([&](hw::ArrayType array) -> Type {
52 Type element = convertType(array.getElementType());
53 if (!element)
54 return Type();
55 if (element == array.getElementType())
56 return array;
57 return hw::ArrayType::get(element, array.getNumElements());
58 });
59 addConversion([&](hw::StructType structType) -> Type {
60 SmallVector<hw::StructType::FieldInfo> fields;
61 fields.reserve(structType.getElements().size());
62 bool changed = false;
63 for (auto field : structType.getElements()) {
64 Type lowered = convertType(field.type);
65 if (!lowered)
66 return Type();
67 changed |= lowered != field.type;
68 fields.push_back({field.name, lowered});
69 }
70 if (!changed)
71 return structType;
72 return hw::StructType::get(structType.getContext(), fields);
73 });
74 addConversion([&](hw::UnionType unionType) -> Type {
75 SmallVector<hw::UnionType::FieldInfo> fields;
76 fields.reserve(unionType.getElements().size());
77 bool changed = false;
78 for (auto field : unionType.getElements()) {
79 Type lowered = convertType(field.type);
80 if (!lowered)
81 return Type();
82 changed |= lowered != field.type;
83 fields.push_back({field.name, lowered, field.offset});
84 }
85 if (!changed)
86 return unionType;
87 return hw::UnionType::get(unionType.getContext(), fields);
88 });
89 addConversion([&](esi::ListType listType) -> Type {
90 Type element = convertType(listType.getElementType());
91 if (!element)
92 return Type();
93 if (element == listType.getElementType())
94 return listType;
95 return esi::ListType::get(listType.getContext(), element);
96 });
97 addConversion([&](hw::TypeAliasType alias) -> Type {
98 Type lowered = convertType(alias.getInnerType());
99 if (!lowered)
100 return Type();
101 if (lowered == alias.getInnerType())
102 return alias;
103 return hw::TypeAliasType::get(alias.getRef(), lowered);
104 });
105 addSourceMaterialization(wrapMaterialization);
106 addTargetMaterialization(unwrapMaterialization);
107 }
108
109private:
110 static mlir::Value wrapMaterialization(OpBuilder &b, WindowType resultType,
111 ValueRange inputs, Location loc) {
112 if (inputs.size() != 1)
113 return mlir::Value();
114 return b.createOrFold<WrapWindow>(loc, resultType, inputs[0]);
115 }
116
117 static mlir::Value unwrapMaterialization(OpBuilder &b, Type resultType,
118 ValueRange inputs, Location loc) {
119 if (inputs.size() != 1 || !isa<WindowType>(inputs[0].getType()))
120 return mlir::Value();
121 return b.createOrFold<UnwrapWindow>(loc, resultType, inputs[0]);
122 }
123};
124} // namespace
125
126static bool containsWindowType(Type type) {
127 return TypeSwitch<Type, bool>(type)
128 .Case([](WindowType) { return true; })
129 .Case<hw::ArrayType>([](hw::ArrayType array) {
130 return containsWindowType(array.getElementType());
131 })
132 .Case<hw::StructType>([](hw::StructType structType) {
133 for (auto field : structType.getElements())
134 if (containsWindowType(field.type))
135 return true;
136 return false;
137 })
138 .Case<hw::UnionType>([](hw::UnionType unionType) {
139 for (auto field : unionType.getElements())
140 if (containsWindowType(field.type))
141 return true;
142 return false;
143 })
144 .Case<esi::ListType>([](esi::ListType listType) {
145 return containsWindowType(listType.getElementType());
146 })
147 .Case<hw::TypeAliasType>([](hw::TypeAliasType aliasType) {
148 return containsWindowType(aliasType.getInnerType());
149 })
150 .Default([](Type) { return false; });
151}
152
153void ESILowerTypesPass::runOnOperation() {
154 ConversionTarget target(getContext());
155
156 target.addLegalOp<WrapWindow, UnwrapWindow>();
157
158 // We need to lower instances, modules, and outputs with data windows.
159 target.markUnknownOpDynamicallyLegal([](Operation *op) {
160 return TypeSwitch<Operation *, bool>(op)
161 .Case([](igraph::InstanceOpInterface inst) {
162 auto hasWindow = [](Type type) { return containsWindowType(type); };
163 return !(llvm::any_of(inst->getOperandTypes(), hasWindow) ||
164 llvm::any_of(inst->getResultTypes(), hasWindow));
165 })
166 .Case([](hw::HWMutableModuleLike mod) {
167 auto isWindowPort = [](hw::PortInfo p) {
168 return containsWindowType(p.type);
169 };
170 return !(llvm::any_of(mod.getPortList(), isWindowPort));
171 })
172 .Default([](Operation *op) {
173 if (llvm::any_of(op->getOperandTypes(), containsWindowType) ||
174 llvm::any_of(op->getResultTypes(), containsWindowType))
175 return false;
176 return true;
177 });
178 });
179
180 LowerTypesConverter types;
181 RewritePatternSet patterns(&getContext());
182 patterns.add<TypeConversionPattern>(types, &getContext());
183 if (failed(
184 applyPartialConversion(getOperation(), target, std::move(patterns))))
185 signalPassFailure();
186
187 // Now do a canonicalization pass to clean up any unnecessary wrap-unwrap
188 // pairs.
189 mlir::ConversionConfig config;
190 config.foldingMode = mlir::DialectConversionFoldingMode::BeforePatterns;
191 ConversionTarget partialCanonicalizedTarget(getContext());
192 RewritePatternSet partialPatterns(&getContext());
193 partialCanonicalizedTarget.addIllegalOp<WrapWindow, UnwrapWindow>();
194 WrapWindow::getCanonicalizationPatterns(partialPatterns, &getContext());
195 UnwrapWindow::getCanonicalizationPatterns(partialPatterns, &getContext());
196 if (failed(mlir::applyPartialConversion(getOperation(),
197 partialCanonicalizedTarget,
198 std::move(partialPatterns), config)))
199 signalPassFailure();
200}
201
202std::unique_ptr<OperationPass<ModuleOp>>
204 return std::make_unique<ESILowerTypesPass>();
205}
static FIRRTLBaseType convertType(FIRRTLBaseType type)
Returns null type if no conversion is needed.
Definition DropConst.cpp:32
static bool containsWindowType(Type type)
Lists represent variable-length sequences of elements of a single type.
Definition Types.h:319
const Type * getElementType() const
Definition Types.h:324
std::unique_ptr< OperationPass< ModuleOp > > createESITypeLoweringPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition esi.py:1
Generic pattern which replaces an operation by one of the same operation name, but with converted att...
This holds the name, type, direction of a module's ports.