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