CIRCT 20.0.0git
Loading...
Searching...
No Matches
LegalizeAnonEnums.cpp
Go to the documentation of this file.
1//===- LegalizeAnonEnums.cpp - Legalizes anonymous enumerations -----------===//
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// This pass replaces all anonymous enumeration with typedecls in the output
10// Verilog.
11//
12//===----------------------------------------------------------------------===//
13
16#include "mlir/IR/ImplicitLocOpBuilder.h"
17#include "mlir/Pass/Pass.h"
18#include "llvm/ADT/DenseSet.h"
19
20namespace circt {
21#define GEN_PASS_DEF_LEGALIZEANONENUMS
22#include "circt/Conversion/Passes.h.inc"
23} // namespace circt
24
25using namespace circt;
26using namespace hw;
27using namespace sv;
28
29namespace {
30struct LegalizeAnonEnums
31 : public circt::impl::LegalizeAnonEnumsBase<LegalizeAnonEnums> {
32 /// Creates a TypeScope on demand for anonymous enumerations.
33 TypeScopeOp getTypeScope() {
34 auto topLevel = getOperation();
35 if (!typeScope) {
36 auto builder = OpBuilder::atBlockBegin(&topLevel.getRegion().front());
37 typeScope = builder.create<TypeScopeOp>(topLevel.getLoc(), "Enums");
38 typeScope.getBodyRegion().push_back(new Block());
39 mlir::SymbolTable symbolTable(topLevel);
40 symbolTable.insert(typeScope);
41 }
42 return typeScope;
43 }
44
45 /// Helper to create TypeDecls and TypeAliases for EnumTypes;
46 Type getEnumTypeDecl(EnumType type) {
47 auto &typeAlias = enumTypeAliases[type];
48 if (typeAlias)
49 return typeAlias;
50 auto *context = &getContext();
51 auto loc = UnknownLoc::get(context);
52 auto typeScope = getTypeScope();
53 auto builder = OpBuilder::atBlockEnd(&typeScope.getRegion().front());
54 auto declName = StringAttr::get(context, "enum" + Twine(enumCount++));
55 builder.create<TypedeclOp>(loc, declName, TypeAttr::get(type), nullptr);
56 auto symRef = SymbolRefAttr::get(typeScope.getSymNameAttr(),
57 FlatSymbolRefAttr::get(declName));
58 typeAlias = TypeAliasType::get(symRef, type);
59 return typeAlias;
60 }
61
62 /// Process a type, replacing any anonymous enumerations contained within.
63 Type processType(Type type) {
64 auto *context = &getContext();
65 if (auto structType = dyn_cast<StructType>(type)) {
66 bool changed = false;
67 SmallVector<StructType::FieldInfo> fields;
68 for (auto &element : structType.getElements()) {
69 if (auto newFieldType = processType(element.type)) {
70 changed = true;
71 fields.push_back({element.name, newFieldType});
72 } else {
73 fields.push_back(element);
74 }
75 }
76 if (changed)
77 return StructType::get(context, fields);
78 return {};
79 }
80
81 if (auto arrayType = dyn_cast<ArrayType>(type)) {
82 if (auto newElementType = processType(arrayType.getElementType()))
83 return ArrayType::get(newElementType, arrayType.getNumElements());
84 return {};
85 }
86
87 if (auto unionType = dyn_cast<UnionType>(type)) {
88 bool changed = false;
89 SmallVector<UnionType::FieldInfo> fields;
90 for (const auto &element : unionType.getElements()) {
91 if (auto newFieldType = processType(element.type)) {
92 fields.push_back({element.name, newFieldType, element.offset});
93 changed = true;
94 } else {
95 fields.push_back(element);
96 }
97 }
98 if (changed)
99 return UnionType::get(context, fields);
100 return {};
101 }
102
103 if (auto typeAlias = dyn_cast<TypeAliasType>(type)) {
104 // Enum type aliases have already been handled.
105 if (isa<EnumType>(typeAlias.getInnerType()))
106 return {};
107 // Otherwise recursively update the type alias.
108 return processType(typeAlias.getInnerType());
109 }
110
111 if (auto inoutType = dyn_cast<InOutType>(type)) {
112 if (auto newType = processType(inoutType.getElementType()))
113 return InOutType::get(newType);
114 return {};
115 }
116
117 // EnumTypes must be changed into TypeAlias.
118 if (auto enumType = dyn_cast<EnumType>(type))
119 return getEnumTypeDecl(enumType);
120
121 if (auto funcType = dyn_cast<FunctionType>(type)) {
122 bool changed = false;
123 SmallVector<Type> inputs;
124 for (auto &type : funcType.getInputs()) {
125 if (auto newType = processType(type)) {
126 inputs.push_back(newType);
127 changed = true;
128 } else {
129 inputs.push_back(type);
130 }
131 }
132 SmallVector<Type> results;
133 for (auto &type : funcType.getResults()) {
134 if (auto newType = processType(type)) {
135 results.push_back(newType);
136 changed = true;
137 } else {
138 results.push_back(type);
139 }
140 }
141 if (changed)
142 return FunctionType::get(context, inputs, results);
143 return {};
144 }
145 if (auto modType = dyn_cast<ModuleType>(type)) {
146 bool changed = false;
147 SmallVector<ModulePort> ports;
148 for (auto &p : modType.getPorts()) {
149 ports.push_back(p);
150 if (auto newType = processType(p.type)) {
151 ports.back().type = newType;
152 changed = true;
153 }
154 }
155 if (changed)
156 return ModuleType::get(context, ports);
157 return {};
158 }
159
160 // Default case is that it is not an aggregate type.
161 return {};
162 };
163
164 void runOnOperation() override {
165 enumCount = 0;
166 typeScope = {};
167
168 // Perform the actual walk looking for anonymous enumeration types.
169 getOperation().walk([&](Operation *op) {
170 // If this is a constant operation, make sure to update the constant
171 // to reference the typedef, otherwise we will emit the wrong constant.
172 // Theoretically we should be searching all attributes on every operation
173 // for EnumFieldAttrs.
174 if (auto enumConst = dyn_cast<EnumConstantOp>(op)) {
175 auto fieldAttr = enumConst.getField();
176 if (auto newType = processType(fieldAttr.getType().getValue()))
177 enumConst.setFieldAttr(
178 EnumFieldAttr::get(op->getLoc(), fieldAttr.getField(), newType));
179 }
180
181 // Update the operation signature if it is function-like.
182 if (auto modLike = dyn_cast<HWModuleLike>(op))
183 if (auto newType = processType(modLike.getHWModuleType()))
184 modLike.setHWModuleType(cast<ModuleType>(newType));
185
186 // Update all operations results.
187 for (auto result : op->getResults())
188 if (auto newType = processType(result.getType()))
189 result.setType(newType);
190
191 // Update all block arguments.
192 for (auto &region : op->getRegions())
193 for (auto &block : region.getBlocks())
194 for (auto arg : block.getArguments())
195 if (auto newType = processType(arg.getType()))
196 arg.setType(newType);
197 });
198
199 enumTypeAliases.clear();
200 }
201
202 TypeScopeOp typeScope;
203 unsigned enumCount;
204 DenseMap<Type, Type> enumTypeAliases;
205};
206
207} // end anonymous namespace
208
209std::unique_ptr<mlir::Pass> circt::createLegalizeAnonEnumsPass() {
210 return std::make_unique<LegalizeAnonEnums>();
211}
static Type processType(Type type)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
std::unique_ptr< mlir::Pass > createLegalizeAnonEnumsPass()
Definition hw.py:1
Definition sv.py:1