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 // EnumTypes must be changed into TypeAlias.
120 if (auto enumType = dyn_cast<EnumType>(type))
121 return getEnumTypeDecl(enumType);
122
123 if (auto funcType = dyn_cast<FunctionType>(type)) {
124 bool changed = false;
125 SmallVector<Type> inputs;
126 for (auto &type : funcType.getInputs()) {
127 if (auto newType = processType(type)) {
128 inputs.push_back(newType);
129 changed = true;
130 } else {
131 inputs.push_back(type);
132 }
133 }
134 SmallVector<Type> results;
135 for (auto &type : funcType.getResults()) {
136 if (auto newType = processType(type)) {
137 results.push_back(newType);
138 changed = true;
139 } else {
140 results.push_back(type);
141 }
142 }
143 if (changed)
144 return FunctionType::get(context, inputs, results);
145 return {};
146 }
147 if (auto modType = dyn_cast<ModuleType>(type)) {
148 bool changed = false;
149 SmallVector<ModulePort> ports;
150 for (auto &p : modType.getPorts()) {
151 ports.push_back(p);
152 if (auto newType = processType(p.type)) {
153 ports.back().type = newType;
154 changed = true;
155 }
156 }
157 if (changed)
158 return ModuleType::get(context, ports);
159 return {};
160 }
161
162 // Default case is that it is not an aggregate type.
163 return {};
164 };
165
166 void runOnOperation() override {
167 enumCount = 0;
168 typeScope = {};
169
170 // Perform the actual walk looking for anonymous enumeration types.
171 getOperation().walk([&](Operation *op) {
172 // If this is a constant operation, make sure to update the constant
173 // to reference the typedef, otherwise we will emit the wrong constant.
174 // Theoretically we should be searching all attributes on every operation
175 // for EnumFieldAttrs.
176 if (auto enumConst = dyn_cast<EnumConstantOp>(op)) {
177 auto fieldAttr = enumConst.getField();
178 if (auto newType = processType(fieldAttr.getType().getValue()))
179 enumConst.setFieldAttr(
180 EnumFieldAttr::get(op->getLoc(), fieldAttr.getField(), newType));
181 }
182
183 // Update the operation signature if it is function-like.
184 if (auto modLike = dyn_cast<HWModuleLike>(op))
185 if (auto newType = processType(modLike.getHWModuleType()))
186 modLike.setHWModuleType(cast<ModuleType>(newType));
187
188 // Update all operations results.
189 for (auto result : op->getResults())
190 if (auto newType = processType(result.getType()))
191 result.setType(newType);
192
193 // Update all block arguments.
194 for (auto &region : op->getRegions())
195 for (auto &block : region.getBlocks())
196 for (auto arg : block.getArguments())
197 if (auto newType = processType(arg.getType()))
198 arg.setType(newType);
199 });
200
201 enumTypeAliases.clear();
202 }
203
204 TypeScopeOp typeScope;
205 unsigned enumCount;
206 DenseMap<Type, Type> enumTypeAliases;
207};
208
209} // end anonymous namespace
static std::unique_ptr< Context > context
static Type processType(Type type)
create(str sym_name)
Definition hw.py:593
create(str sym_name, Type type, str verilog_name=None)
Definition hw.py:583
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition hw.py:1
Definition sv.py:1