CIRCT  20.0.0git
MooreTypes.cpp
Go to the documentation of this file.
1 //===- MooreTypes.cpp - Implement the Moore types -------------------------===//
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 file implements the Moore dialect type system.
10 //
11 //===----------------------------------------------------------------------===//
12 
15 #include "mlir/IR/Builders.h"
16 #include "mlir/IR/DialectImplementation.h"
17 #include "llvm/ADT/TypeSwitch.h"
18 
19 using namespace circt;
20 using namespace circt::moore;
21 using mlir::AsmParser;
22 using mlir::AsmPrinter;
23 
24 static LogicalResult parseMembers(AsmParser &parser,
25  SmallVector<StructLikeMember> &members);
26 static void printMembers(AsmPrinter &printer,
27  ArrayRef<StructLikeMember> members);
28 
29 static ParseResult parseMooreType(AsmParser &parser, Type &type);
30 static void printMooreType(Type type, AsmPrinter &printer);
31 
32 //===----------------------------------------------------------------------===//
33 // Unpacked Type
34 //===----------------------------------------------------------------------===//
35 
37  return TypeSwitch<UnpackedType, Domain>(*this)
38  .Case<PackedType>([](auto type) { return type.getDomain(); })
39  .Case<UnpackedArrayType, OpenUnpackedArrayType, AssocArrayType,
40  QueueType>(
41  [&](auto type) { return type.getElementType().getDomain(); })
42  .Case<UnpackedStructType, UnpackedUnionType>([](auto type) {
43  for (const auto &member : type.getMembers())
44  if (member.type.getDomain() == Domain::FourValued)
45  return Domain::FourValued;
46  return Domain::TwoValued;
47  })
48  .Default([](auto) { return Domain::TwoValued; });
49 }
50 
51 std::optional<unsigned> UnpackedType::getBitSize() const {
52  return TypeSwitch<UnpackedType, std::optional<unsigned>>(*this)
53  .Case<PackedType>([](auto type) { return type.getBitSize(); })
54  .Case<RealType>([](auto type) { return 64; })
55  .Case<UnpackedArrayType>([](auto type) -> std::optional<unsigned> {
56  if (auto size = type.getElementType().getBitSize())
57  return (*size) * type.getSize();
58  return {};
59  })
60  .Case<UnpackedStructType>([](auto type) -> std::optional<unsigned> {
61  unsigned size = 0;
62  for (const auto &member : type.getMembers()) {
63  if (auto memberSize = member.type.getBitSize()) {
64  size += *memberSize;
65  } else {
66  return std::nullopt;
67  }
68  }
69  return size;
70  })
71  .Case<UnpackedUnionType>([](auto type) -> std::optional<unsigned> {
72  unsigned size = 0;
73  for (const auto &member : type.getMembers()) {
74  if (auto memberSize = member.type.getBitSize()) {
75  size = (*memberSize > size) ? *memberSize : size;
76  } else {
77  return std::nullopt;
78  }
79  }
80  return size;
81  })
82  .Default([](auto) { return std::nullopt; });
83 }
84 
85 Type UnpackedType::parse(mlir::AsmParser &parser) {
86  Type type;
87  if (parseMooreType(parser, type))
88  return {};
89  return type;
90 }
91 
92 void UnpackedType::print(mlir::AsmPrinter &printer) const {
93  printMooreType(*this, printer);
94 }
95 
96 //===----------------------------------------------------------------------===//
97 // Packed Type
98 //===----------------------------------------------------------------------===//
99 
101  return TypeSwitch<PackedType, Domain>(*this)
102  .Case<VoidType>([](auto) { return Domain::TwoValued; })
103  .Case<IntType>([&](auto type) { return type.getDomain(); })
104  .Case<ArrayType, OpenArrayType>(
105  [&](auto type) { return type.getElementType().getDomain(); })
106  .Case<StructType, UnionType>([](auto type) {
107  for (const auto &member : type.getMembers())
108  if (member.type.getDomain() == Domain::FourValued)
109  return Domain::FourValued;
110  return Domain::TwoValued;
111  });
112 }
113 
114 std::optional<unsigned> PackedType::getBitSize() const {
115  return TypeSwitch<PackedType, std::optional<unsigned>>(*this)
116  .Case<VoidType>([](auto) { return 0; })
117  .Case<IntType>([](auto type) { return type.getWidth(); })
118  .Case<ArrayType>([](auto type) -> std::optional<unsigned> {
119  if (auto size = type.getElementType().getBitSize())
120  return (*size) * type.getSize();
121  return {};
122  })
123  .Case<OpenArrayType>([](auto) { return std::nullopt; })
124  .Case<StructType>([](auto type) -> std::optional<unsigned> {
125  unsigned size = 0;
126  for (const auto &member : type.getMembers()) {
127  if (auto memberSize = member.type.getBitSize()) {
128  size += *memberSize;
129  } else {
130  return std::nullopt;
131  }
132  }
133  return size;
134  })
135  .Case<UnionType>([](auto type) -> std::optional<unsigned> {
136  unsigned size = 0;
137  for (const auto &member : type.getMembers()) {
138  if (auto memberSize = member.type.getBitSize()) {
139  size = (*memberSize > size) ? *memberSize : size;
140  } else {
141  return std::nullopt;
142  }
143  }
144  return size;
145  })
146  .Default([](auto) { return std::nullopt; });
147 }
148 
149 //===----------------------------------------------------------------------===//
150 // Structs
151 //===----------------------------------------------------------------------===//
152 
153 /// Parse a list of struct members.
154 static LogicalResult parseMembers(AsmParser &parser,
155  SmallVector<StructLikeMember> &members) {
156  return parser.parseCommaSeparatedList(AsmParser::Delimiter::Braces, [&]() {
157  std::string name;
158  UnpackedType type;
159  if (parser.parseKeywordOrString(&name) || parser.parseColon() ||
160  parser.parseCustomTypeWithFallback(type))
161  return failure();
162 
163  members.push_back({StringAttr::get(parser.getContext(), name), type});
164  return success();
165  });
166 }
167 
168 /// Print a list of struct members.
169 static void printMembers(AsmPrinter &printer,
170  ArrayRef<StructLikeMember> members) {
171  printer << "{";
172  llvm::interleaveComma(members, printer.getStream(),
173  [&](const StructLikeMember &member) {
174  printer.printKeywordOrString(member.name);
175  printer << ": ";
176  printer.printStrippedAttrOrType(member.type);
177  });
178  printer << "}";
179 }
180 
181 static LogicalResult
182 verifyAllMembersPacked(function_ref<InFlightDiagnostic()> emitError,
183  ArrayRef<StructLikeMember> members) {
184  if (!llvm::all_of(members, [](const auto &member) {
185  return llvm::isa<PackedType>(member.type);
186  }))
187  return emitError() << "StructType/UnionType members must be packed types";
188  return success();
189 }
190 
191 LogicalResult StructType::verify(function_ref<InFlightDiagnostic()> emitError,
192  ArrayRef<StructLikeMember> members) {
193  return verifyAllMembersPacked(emitError, members);
194 }
195 
196 LogicalResult UnionType::verify(function_ref<InFlightDiagnostic()> emitError,
197  ArrayRef<StructLikeMember> members) {
198  return verifyAllMembersPacked(emitError, members);
199 }
200 
201 //===----------------------------------------------------------------------===//
202 // Interfaces for destructurable
203 //===----------------------------------------------------------------------===//
204 
205 static std::optional<DenseMap<Attribute, Type>>
206 getAllSubelementIndexMap(ArrayRef<StructLikeMember> members) {
207  DenseMap<Attribute, Type> destructured;
208  for (const auto &member : members)
209  destructured.insert({member.name, RefType::get(member.type)});
210  return destructured;
211 }
212 
213 static Type getTypeAtAllIndex(ArrayRef<StructLikeMember> members,
214  Attribute index) {
215  auto indexAttr = cast<StringAttr>(index);
216  if (!indexAttr)
217  return {};
218  for (const auto &member : members) {
219  if (member.name == indexAttr) {
220  return RefType::get(member.type);
221  }
222  }
223  return Type();
224 }
225 
226 static std::optional<uint32_t>
227 getFieldAllIndex(ArrayRef<StructLikeMember> members, StringAttr nameField) {
228  for (uint32_t fieldIndex = 0; fieldIndex < members.size(); fieldIndex++)
229  if (members[fieldIndex].name == nameField)
230  return fieldIndex;
231  return std::nullopt;
232 }
233 
234 std::optional<DenseMap<Attribute, Type>> StructType::getSubelementIndexMap() {
235  return getAllSubelementIndexMap(getMembers());
236 }
237 
238 Type StructType::getTypeAtIndex(Attribute index) {
239  return getTypeAtAllIndex(getMembers(), index);
240 }
241 
242 std::optional<uint32_t> StructType::getFieldIndex(StringAttr nameField) {
243  return getFieldAllIndex(getMembers(), nameField);
244 }
245 
246 std::optional<DenseMap<Attribute, Type>>
247 UnpackedStructType::getSubelementIndexMap() {
248  return getAllSubelementIndexMap(getMembers());
249 }
250 
251 Type UnpackedStructType::getTypeAtIndex(Attribute index) {
252  return getTypeAtAllIndex(getMembers(), index);
253 }
254 
255 std::optional<uint32_t>
256 UnpackedStructType::getFieldIndex(StringAttr nameField) {
257  return getFieldAllIndex(getMembers(), nameField);
258 }
259 
260 std::optional<DenseMap<Attribute, Type>> UnionType::getSubelementIndexMap() {
261  return getAllSubelementIndexMap(getMembers());
262 }
263 
264 Type UnionType::getTypeAtIndex(Attribute index) {
265  return getTypeAtAllIndex(getMembers(), index);
266 }
267 
268 std::optional<uint32_t> UnionType::getFieldIndex(StringAttr nameField) {
269  return getFieldAllIndex(getMembers(), nameField);
270 }
271 
272 std::optional<DenseMap<Attribute, Type>>
273 UnpackedUnionType::getSubelementIndexMap() {
274  return getAllSubelementIndexMap(getMembers());
275 }
276 
277 Type UnpackedUnionType::getTypeAtIndex(Attribute index) {
278  return getTypeAtAllIndex(getMembers(), index);
279 }
280 
281 std::optional<uint32_t> UnpackedUnionType::getFieldIndex(StringAttr nameField) {
282  return getFieldAllIndex(getMembers(), nameField);
283 }
284 
285 std::optional<DenseMap<Attribute, Type>> RefType::getSubelementIndexMap() {
286  return TypeSwitch<Type, std::optional<DenseMap<Attribute, Type>>>(
287  getNestedType())
288  .Case<StructType, UnpackedStructType>([](auto &type) {
289  return getAllSubelementIndexMap(type.getMembers());
290  })
291  .Default([](auto) { return std::nullopt; });
292 }
293 
294 Type RefType::getTypeAtIndex(Attribute index) {
295  return TypeSwitch<Type, Type>(getNestedType())
296  .Case<StructType, UnpackedStructType>([&index](auto &type) {
297  return getTypeAtAllIndex(type.getMembers(), index);
298  })
299  .Default([](auto) { return Type(); });
300 }
301 
302 std::optional<uint32_t> RefType::getFieldIndex(StringAttr nameField) {
303  return TypeSwitch<Type, std::optional<uint32_t>>(getNestedType())
304  .Case<StructType, UnpackedStructType>([&nameField](auto &type) {
305  return getFieldAllIndex(type.getMembers(), nameField);
306  })
307  .Default([](auto) { return std::nullopt; });
308 }
309 
310 //===----------------------------------------------------------------------===//
311 // Generated logic
312 //===----------------------------------------------------------------------===//
313 
314 #define GET_TYPEDEF_CLASSES
315 #include "circt/Dialect/Moore/MooreTypes.cpp.inc"
316 
317 void MooreDialect::registerTypes() {
318  addTypes<
319 #define GET_TYPEDEF_LIST
320 #include "circt/Dialect/Moore/MooreTypes.cpp.inc"
321  >();
322 }
323 
324 //===----------------------------------------------------------------------===//
325 // Parsing and printing
326 //===----------------------------------------------------------------------===//
327 
328 /// Parse a type registered with this dialect.
329 static ParseResult parseMooreType(AsmParser &parser, Type &type) {
330  llvm::SMLoc loc = parser.getCurrentLocation();
331 
332  // Try the generated parser first.
333  StringRef mnemonic;
334  if (auto result = generatedTypeParser(parser, &mnemonic, type);
335  result.has_value())
336  return result.value();
337 
338  // Handle abbreviated integer types such as `i42` and `l42`.
339  if (mnemonic.size() > 1 && (mnemonic[0] == 'i' || mnemonic[0] == 'l') &&
340  isdigit(mnemonic[1])) {
341  auto domain = mnemonic[0] == 'i' ? Domain::TwoValued : Domain::FourValued;
342  auto spelling = mnemonic.drop_front(1);
343  unsigned width;
344  if (spelling.getAsInteger(10, width))
345  return parser.emitError(loc, "integer width invalid");
346  type = IntType::get(parser.getContext(), width, domain);
347  return success();
348  }
349 
350  parser.emitError(loc) << "unknown type `" << mnemonic
351  << "` in dialect `moore`";
352  return failure();
353 }
354 
355 /// Print a type registered with this dialect.
356 static void printMooreType(Type type, AsmPrinter &printer) {
357  // Handle abbreviated integer types such as `i42` and `l42`.
358  if (auto intType = dyn_cast<IntType>(type)) {
359  printer << (intType.getDomain() == Domain::TwoValued ? "i" : "l");
360  printer << intType.getWidth();
361  return;
362  }
363 
364  // Otherwise fall back to the generated printer.
365  if (succeeded(generatedTypePrinter(type, printer)))
366  return;
367  assert(false && "no printer for unknown `moore` dialect type");
368 }
369 
370 /// Parse a type registered with this dialect.
371 Type MooreDialect::parseType(DialectAsmParser &parser) const {
372  Type type;
373  if (parseMooreType(parser, type))
374  return {};
375  return type;
376 }
377 
378 /// Print a type registered with this dialect.
379 void MooreDialect::printType(Type type, DialectAsmPrinter &printer) const {
380  printMooreType(type, printer);
381 }
assert(baseType &&"element must be base type")
#define isdigit(x)
Definition: FIRLexer.cpp:26
static ParseResult parseType(Type &result, StringRef name, AsmParser &parser)
Parse a type defined by this dialect.
int32_t width
Definition: FIRRTL.cpp:36
static LogicalResult verifyAllMembersPacked(function_ref< InFlightDiagnostic()> emitError, ArrayRef< StructLikeMember > members)
Definition: MooreTypes.cpp:182
static LogicalResult parseMembers(AsmParser &parser, SmallVector< StructLikeMember > &members)
Parse a list of struct members.
Definition: MooreTypes.cpp:154
static ParseResult parseMooreType(AsmParser &parser, Type &type)
Parse a type registered with this dialect.
Definition: MooreTypes.cpp:329
static std::optional< uint32_t > getFieldAllIndex(ArrayRef< StructLikeMember > members, StringAttr nameField)
Definition: MooreTypes.cpp:227
static std::optional< DenseMap< Attribute, Type > > getAllSubelementIndexMap(ArrayRef< StructLikeMember > members)
Definition: MooreTypes.cpp:206
static void printMembers(AsmPrinter &printer, ArrayRef< StructLikeMember > members)
Print a list of struct members.
Definition: MooreTypes.cpp:169
static void printMooreType(Type type, AsmPrinter &printer)
Print a type registered with this dialect.
Definition: MooreTypes.cpp:356
static Type getTypeAtAllIndex(ArrayRef< StructLikeMember > members, Attribute index)
Definition: MooreTypes.cpp:213
A packed SystemVerilog type.
Definition: MooreTypes.h:133
std::optional< unsigned > getBitSize() const
Get the size of this type in bits.
Definition: MooreTypes.cpp:114
Domain getDomain() const
Get the value domain of this type.
Definition: MooreTypes.cpp:100
An unpacked SystemVerilog type.
Definition: MooreTypes.h:82
std::optional< unsigned > getBitSize() const
Get the size of this type in bits.
Definition: MooreTypes.cpp:51
Domain getDomain() const
Get the value domain of this type.
Definition: MooreTypes.cpp:36
static Type parse(mlir::AsmParser &odsParser)
Definition: MooreTypes.cpp:85
void print(mlir::AsmPrinter &odsPrinter) const
Definition: MooreTypes.cpp:92
static LogicalResult verify(Value clock, bool eventExists, mlir::Location loc)
Definition: SVOps.cpp:2459
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition: CalyxOps.cpp:55
Domain
The number of values each bit of a type can assume.
Definition: MooreTypes.h:47
@ FourValued
Four-valued types such as logic or integer.
@ TwoValued
Two-valued types such as bit or int.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
A member of a struct.
Definition: MooreTypes.h:157