CIRCT 23.0.0git
Loading...
Searching...
No Matches
HWTypes.cpp
Go to the documentation of this file.
1//===- HWTypes.cpp - HW types code defs -----------------------------------===//
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// Implementation logic for HW data types.
10//
11//===----------------------------------------------------------------------===//
12
18#include "circt/Support/LLVM.h"
19#include "mlir/IR/Builders.h"
20#include "mlir/IR/BuiltinTypes.h"
21#include "mlir/IR/Diagnostics.h"
22#include "mlir/IR/DialectImplementation.h"
23#include "mlir/IR/StorageUniquerSupport.h"
24#include "mlir/IR/Types.h"
25#include "mlir/Interfaces/MemorySlotInterfaces.h"
26#include "llvm/ADT/SmallSet.h"
27#include "llvm/ADT/StringExtras.h"
28#include "llvm/ADT/StringSet.h"
29#include "llvm/ADT/TypeSwitch.h"
30
31using namespace circt;
32using namespace circt::hw;
33using namespace circt::hw::detail;
34
35static ParseResult parseHWArray(AsmParser &parser, Attribute &dim,
36 Type &elementType);
37static void printHWArray(AsmPrinter &printer, Attribute dim, Type elementType);
38
39static ParseResult parseHWElementType(AsmParser &parser, Type &elementType);
40static void printHWElementType(AsmPrinter &printer, Type dim);
41
42#define GET_TYPEDEF_CLASSES
43#include "circt/Dialect/HW/HWTypes.cpp.inc"
44
45//===----------------------------------------------------------------------===//
46// Type Helpers
47//===----------------------------------------------------------------------===/
48
49mlir::Type circt::hw::getCanonicalType(mlir::Type type) {
50 Type canonicalType;
51 if (auto typeAlias = dyn_cast<TypeAliasType>(type))
52 canonicalType = typeAlias.getCanonicalType();
53 else
54 canonicalType = type;
55 return canonicalType;
56}
57
58/// Return true if the specified type is a value HW Integer type. This checks
59/// that it is a signless standard dialect type or a hw::IntType.
60bool circt::hw::isHWIntegerType(mlir::Type type) {
61 Type canonicalType = getCanonicalType(type);
62
63 if (isa<hw::IntType>(canonicalType))
64 return true;
65
66 auto intType = dyn_cast<IntegerType>(canonicalType);
67 if (!intType || !intType.isSignless())
68 return false;
69
70 return true;
71}
72
73bool circt::hw::isHWEnumType(mlir::Type type) {
74 return isa<hw::EnumType>(getCanonicalType(type));
75}
76
77/// Return true if the specified type can be used as an HW value type, that is
78/// the set of types that can be composed together to represent synthesized,
79/// hardware but not marker types like InOutType.
80bool circt::hw::isHWValueType(Type type) {
81 // Signless and signed integer types are both valid.
82 if (isa<IntegerType, IntType, EnumType>(type))
83 return true;
84
85 if (auto array = dyn_cast<ArrayType>(type))
86 return isHWValueType(array.getElementType());
87
88 if (auto array = dyn_cast<UnpackedArrayType>(type))
89 return isHWValueType(array.getElementType());
90
91 if (auto t = dyn_cast<StructType>(type))
92 return llvm::all_of(t.getElements(),
93 [](auto f) { return isHWValueType(f.type); });
94
95 if (auto t = dyn_cast<UnionType>(type))
96 return llvm::all_of(t.getElements(),
97 [](auto f) { return isHWValueType(f.type); });
98
99 if (auto t = dyn_cast<TypeAliasType>(type))
100 return isHWValueType(t.getCanonicalType());
101
102 return false;
103}
104
105/// Return the hardware bit width of a type. Does not reflect any encoding,
106/// padding, or storage scheme, just the bit (and wire width) of a
107/// statically-size type. Reflects the number of wires needed to transmit a
108/// value of this type. Returns -1 if the type is not known or cannot be
109/// statically computed.
110int64_t circt::hw::getBitWidth(mlir::Type type) {
111 // Handle built-in types that don't implement the interface. Do this first
112 // since it is faster than downcasting to an interface.
113 return llvm::TypeSwitch<::mlir::Type, int64_t>(type)
114 .Case<IntegerType>(
115 [](IntegerType t) { return t.getIntOrFloatBitWidth(); })
116 .Default([](Type type) -> int64_t {
117 // If type implements the BitWidthTypeInterface, use it.
118 if (auto iface = dyn_cast<BitWidthTypeInterface>(type)) {
119 std::optional<int64_t> width = iface.getBitWidth();
120 return width.has_value() ? *width : -1;
121 }
122 return -1;
123 });
124}
125
126/// Return true if the specified type contains known marker types like
127/// InOutType. Unlike isHWValueType, this is not conservative, it only returns
128/// false on known InOut types, rather than any unknown types.
129bool circt::hw::hasHWInOutType(Type type) {
130 if (auto array = dyn_cast<ArrayType>(type))
131 return hasHWInOutType(array.getElementType());
132
133 if (auto array = dyn_cast<UnpackedArrayType>(type))
134 return hasHWInOutType(array.getElementType());
135
136 if (auto t = dyn_cast<StructType>(type)) {
137 return std::any_of(t.getElements().begin(), t.getElements().end(),
138 [](const auto &f) { return hasHWInOutType(f.type); });
139 }
140
141 if (auto t = dyn_cast<TypeAliasType>(type))
142 return hasHWInOutType(t.getCanonicalType());
143
144 return isa<InOutType>(type);
145}
146
147namespace {
148struct AggregateAttrFrame {
149 SmallVector<Attribute> attrs;
150 SmallVector<Type> types;
151 unsigned remaining;
152
153 AggregateAttrFrame(SmallVector<Type> &&types)
154 : attrs(types.size()), types(std::move(types)), remaining(attrs.size()) {}
155
156 void addChild(Attribute attr) { attrs[--remaining] = attr; }
157 Type getNextChildType() { return types[remaining - 1]; }
158 bool isFinished() const { return remaining == 0; }
159};
160} // namespace
161
162/// Convert an APInt value into a nested aggregate attribute matching the given
163/// HWAggregateType. Returns failure() if the type is not an HWAggregateType or
164/// recursively contains a type other than HWAggregateType or IntegerType.
165LogicalResult circt::hw::apIntToAggregateAttr(Type aggregateType,
166 const APInt &intVal,
167 ArrayAttr &result) {
168 auto *ctx = aggregateType.getContext();
169 SmallVector<AggregateAttrFrame> stack;
170 auto bitWidth = intVal.getBitWidth();
171 unsigned nextExtraction = 0;
172
173 auto pushToStack = [&](Type type) -> bool {
174 return TypeSwitch<Type, bool>(type)
175 .Case<StructType>([&](auto structType) {
176 auto len = structType.getElements().size();
177 SmallVector<Type> types;
178 types.reserve(len);
179 for (auto &element : structType.getElements())
180 types.push_back(getCanonicalType(element.type));
181 stack.push_back(std::move(types));
182 return true;
183 })
184 .Case<ArrayType, UnpackedArrayType>([&](auto arrayType) {
185 SmallVector<Type> types(arrayType.getNumElements(),
186 getCanonicalType(arrayType.getElementType()));
187 stack.push_back(std::move(types));
188 return true;
189 })
190 .Default([](Type) {
191 // Unsupported type
192 return false;
193 });
194 };
195
196 if (!pushToStack(getCanonicalType(aggregateType)))
197 return failure();
198
199 while (!stack.empty()) {
200 if (stack.back().isFinished()) {
201 auto frame = stack.pop_back_val();
202 result = ArrayAttr::get(ctx, frame.attrs);
203 if (!stack.empty())
204 stack.back().addChild(result);
205 continue;
206 }
207
208 auto curType = stack.back().getNextChildType();
209 if (auto intType = dyn_cast<IntegerType>(curType)) {
210 auto width = intType.getWidth();
211 auto elemValue = width ? intVal.extractBits(width, nextExtraction)
212 : APInt(0, 0, false);
213 nextExtraction += width;
214 stack.back().addChild(IntegerAttr::get(intType, elemValue));
215 } else {
216 if (!pushToStack(curType))
217 return failure();
218 }
219 }
220
221 assert(nextExtraction == bitWidth && "constant wasn't fully processed");
222 return success();
223}
224
225/// Convert an ArrayAttr into an APInt value matching the given type.
226/// The type is used to determine the bit width of the resulting APInt.
227/// Returns failure() if the attribute recursively contains anything other than
228/// ArrayAttr or IntegerAttr.
229LogicalResult circt::hw::aggregateAttrToAPInt(Type type, ArrayAttr attr,
230 APInt &result) {
231 SmallVector<Attribute> worklist;
232 worklist.push_back(attr);
233 auto bitWidth = hw::getBitWidth(type);
234 assert(bitWidth >= 0 && "bit width must be known for constant");
235 result = APInt(bitWidth, 0);
236 unsigned nextInsertion = 0;
237
238 while (!worklist.empty()) {
239 auto current = worklist.pop_back_val();
240 if (auto innerArray = dyn_cast<ArrayAttr>(current)) {
241 worklist.append(innerArray.begin(), innerArray.end());
242 continue;
243 }
244
245 if (auto intAttr = dyn_cast<IntegerAttr>(current)) {
246 auto chunk = intAttr.getValue();
247 result.insertBits(chunk, nextInsertion);
248 nextInsertion += chunk.getBitWidth();
249 continue;
250 }
251
252 return failure();
253 }
254
255 assert(nextInsertion == bitWidth && "constant wasn't fully processed");
256 return success();
257}
258
259/// Parse and print nested HW types nicely. These helper methods allow eliding
260/// the "hw." prefix on array, inout, and other types when in a context that
261/// expects HW subelement types.
262static ParseResult parseHWElementType(AsmParser &p, Type &result) {
263 // If this is an HW dialect type, then we don't need/want the !hw. prefix
264 // redundantly specified.
265 auto fullString = static_cast<DialectAsmParser &>(p).getFullSymbolSpec();
266 auto *curPtr = p.getCurrentLocation().getPointer();
267 auto typeString =
268 StringRef(curPtr, fullString.size() - (curPtr - fullString.data()));
269
270 if (typeString.starts_with("array<") || typeString.starts_with("inout<") ||
271 typeString.starts_with("uarray<") || typeString.starts_with("struct<") ||
272 typeString.starts_with("typealias<") || typeString.starts_with("int<") ||
273 typeString.starts_with("enum<") || typeString.starts_with("union<")) {
274 llvm::StringRef mnemonic;
275 if (auto parseResult = generatedTypeParser(p, &mnemonic, result);
276 parseResult.has_value())
277 return *parseResult;
278 return p.emitError(p.getNameLoc(), "invalid type `") << typeString << "`";
279 }
280
281 return p.parseType(result);
282}
283
284static void printHWElementType(AsmPrinter &p, Type element) {
285 if (succeeded(generatedTypePrinter(element, p)))
286 return;
287 p.printType(element);
288}
289
290//===----------------------------------------------------------------------===//
291// Int Type
292//===----------------------------------------------------------------------===//
293
294Type IntType::get(mlir::TypedAttr width) {
295 // The width expression must always be a 32-bit wide integer type itself.
296 auto widthWidth = llvm::dyn_cast<IntegerType>(width.getType());
297 assert(widthWidth && widthWidth.getWidth() == 32 &&
298 "!hw.int width must be 32-bits");
299 (void)widthWidth;
300
301 if (auto cstWidth = llvm::dyn_cast<IntegerAttr>(width))
302 return IntegerType::get(width.getContext(),
303 cstWidth.getValue().getZExtValue());
304
305 return Base::get(width.getContext(), width);
306}
307
308Type IntType::parse(AsmParser &p) {
309 // The bitwidth of the parameter size is always 32 bits.
310 auto int32Type = p.getBuilder().getIntegerType(32);
311
312 mlir::TypedAttr width;
313 if (p.parseLess() || p.parseAttribute(width, int32Type) || p.parseGreater())
314 return Type();
315 return get(width);
316}
317
318void IntType::print(AsmPrinter &p) const {
319 p << "<";
320 p.printAttributeWithoutType(getWidth());
321 p << '>';
322}
323
324//===----------------------------------------------------------------------===//
325// Struct Type
326//===----------------------------------------------------------------------===//
327
328namespace circt {
329namespace hw {
330namespace detail {
331bool operator==(const FieldInfo &a, const FieldInfo &b) {
332 return a.name == b.name && a.type == b.type;
333}
334llvm::hash_code hash_value(const FieldInfo &fi) {
335 return llvm::hash_combine(fi.name, fi.type);
336}
337} // namespace detail
338} // namespace hw
339} // namespace circt
340
341/// Parse a list of unique field names and types within <>. E.g.:
342/// <foo: i7, bar: i8>
343static ParseResult parseFields(AsmParser &p,
344 SmallVectorImpl<FieldInfo> &parameters) {
345 llvm::StringSet<> nameSet;
346 bool hasDuplicateName = false;
347 auto parseResult = p.parseCommaSeparatedList(
348 mlir::AsmParser::Delimiter::LessGreater, [&]() -> ParseResult {
349 std::string name;
350 Type type;
351
352 auto fieldLoc = p.getCurrentLocation();
353 if (p.parseKeywordOrString(&name) || p.parseColon() ||
354 p.parseType(type))
355 return failure();
356
357 if (!nameSet.insert(name).second) {
358 p.emitError(fieldLoc, "duplicate field name \'" + name + "\'");
359 // Continue parsing to print all duplicates, but make sure to error
360 // eventually
361 hasDuplicateName = true;
362 }
363
364 parameters.push_back(
365 FieldInfo{StringAttr::get(p.getContext(), name), type});
366 return success();
367 });
368
369 if (hasDuplicateName)
370 return failure();
371 return parseResult;
372}
373
374/// Print out a list of named fields surrounded by <>.
375static void printFields(AsmPrinter &p, ArrayRef<FieldInfo> fields) {
376 p << '<';
377 llvm::interleaveComma(fields, p, [&](const FieldInfo &field) {
378 p.printKeywordOrString(field.name.getValue());
379 p << ": " << field.type;
380 });
381 p << ">";
382}
383
384Type StructType::parse(AsmParser &p) {
385 llvm::SmallVector<FieldInfo, 4> parameters;
386 if (parseFields(p, parameters))
387 return Type();
388 return get(p.getContext(), parameters);
389}
390
391LogicalResult StructType::verify(function_ref<InFlightDiagnostic()> emitError,
392 ArrayRef<StructType::FieldInfo> elements) {
393 llvm::SmallDenseSet<StringAttr> fieldNameSet;
394 LogicalResult result = success();
395 fieldNameSet.reserve(elements.size());
396 for (const auto &elt : elements)
397 if (!fieldNameSet.insert(elt.name).second) {
398 result = failure();
399 emitError() << "duplicate field name '" << elt.name.getValue()
400 << "' in hw.struct type";
401 }
402 return result;
403}
404
405void StructType::print(AsmPrinter &p) const { printFields(p, getElements()); }
406
407Type StructType::getFieldType(mlir::StringRef fieldName) {
408 for (const auto &field : getElements())
409 if (field.name == fieldName)
410 return field.type;
411 return Type();
412}
413
414std::optional<uint32_t> StructType::getFieldIndex(mlir::StringRef fieldName) {
415 ArrayRef<hw::StructType::FieldInfo> elems = getElements();
416 for (size_t idx = 0, numElems = elems.size(); idx < numElems; ++idx)
417 if (elems[idx].name == fieldName)
418 return idx;
419 return {};
420}
421
422std::optional<uint32_t> StructType::getFieldIndex(mlir::StringAttr fieldName) {
423 ArrayRef<hw::StructType::FieldInfo> elems = getElements();
424 for (size_t idx = 0, numElems = elems.size(); idx < numElems; ++idx)
425 if (elems[idx].name == fieldName)
426 return idx;
427 return {};
428}
429
430static std::pair<uint64_t, SmallVector<uint64_t>>
431getFieldIDsStruct(const StructType &st) {
432 uint64_t fieldID = 0;
433 auto elements = st.getElements();
434 SmallVector<uint64_t> fieldIDs;
435 fieldIDs.reserve(elements.size());
436 for (auto &element : elements) {
437 auto type = element.type;
438 fieldID += 1;
439 fieldIDs.push_back(fieldID);
440 // Increment the field ID for the next field by the number of subfields.
441 fieldID += hw::FieldIdImpl::getMaxFieldID(type);
442 }
443 return {fieldID, fieldIDs};
444}
445
446void StructType::getInnerTypes(SmallVectorImpl<Type> &types) {
447 for (const auto &field : getElements())
448 types.push_back(field.type);
449}
450
451uint64_t StructType::getMaxFieldID() const {
452 uint64_t fieldID = 0;
453 for (const auto &field : getElements())
454 fieldID += 1 + hw::FieldIdImpl::getMaxFieldID(field.type);
455 return fieldID;
456}
457
458std::pair<Type, uint64_t>
459StructType::getSubTypeByFieldID(uint64_t fieldID) const {
460 if (fieldID == 0)
461 return {*this, 0};
462 auto [maxId, fieldIDs] = getFieldIDsStruct(*this);
463 auto *it = std::prev(llvm::upper_bound(fieldIDs, fieldID));
464 auto subfieldIndex = std::distance(fieldIDs.begin(), it);
465 auto subfieldType = getElements()[subfieldIndex].type;
466 auto subfieldID = fieldID - fieldIDs[subfieldIndex];
467 return {subfieldType, subfieldID};
468}
469
470std::pair<uint64_t, bool>
471StructType::projectToChildFieldID(uint64_t fieldID, uint64_t index) const {
472 auto [maxId, fieldIDs] = getFieldIDsStruct(*this);
473 auto childRoot = fieldIDs[index];
474 auto rangeEnd =
475 index + 1 >= getElements().size() ? maxId : (fieldIDs[index + 1] - 1);
476 return std::make_pair(fieldID - childRoot,
477 fieldID >= childRoot && fieldID <= rangeEnd);
478}
479
480uint64_t StructType::getFieldID(uint64_t index) const {
481 auto [maxId, fieldIDs] = getFieldIDsStruct(*this);
482 return fieldIDs[index];
483}
484
485uint64_t StructType::getIndexForFieldID(uint64_t fieldID) const {
486 assert(!getElements().empty() && "Bundle must have >0 fields");
487 auto [maxId, fieldIDs] = getFieldIDsStruct(*this);
488 auto *it = std::prev(llvm::upper_bound(fieldIDs, fieldID));
489 return std::distance(fieldIDs.begin(), it);
490}
491
492std::pair<uint64_t, uint64_t>
493StructType::getIndexAndSubfieldID(uint64_t fieldID) const {
494 auto index = getIndexForFieldID(fieldID);
495 auto elementFieldID = getFieldID(index);
496 return {index, fieldID - elementFieldID};
497}
498
499std::optional<DenseMap<Attribute, Type>>
500hw::StructType::getSubelementIndexMap() const {
501 DenseMap<Attribute, Type> destructured;
502 for (auto [i, field] : llvm::enumerate(getElements()))
503 destructured.insert(
504 {IntegerAttr::get(IndexType::get(getContext()), i), field.type});
505 return destructured;
506}
507
508Type hw::StructType::getTypeAtIndex(Attribute index) const {
509 auto indexAttr = llvm::dyn_cast<IntegerAttr>(index);
510 if (!indexAttr)
511 return {};
512
513 return getSubTypeByFieldID(indexAttr.getInt()).first;
514}
515
516std::optional<int64_t> StructType::getBitWidth() const {
517 int64_t total = 0;
518 for (auto field : getElements()) {
519 int64_t fieldSize = hw::getBitWidth(field.type);
520 if (fieldSize < 0)
521 return std::nullopt;
522 total += fieldSize;
523 }
524 return total;
525}
526
527//===----------------------------------------------------------------------===//
528// Union Type
529//===----------------------------------------------------------------------===//
530
531namespace circt {
532namespace hw {
533namespace detail {
535 return a.name == b.name && a.type == b.type && a.offset == b.offset;
536}
537// NOLINTNEXTLINE
538llvm::hash_code hash_value(const OffsetFieldInfo &fi) {
539 return llvm::hash_combine(fi.name, fi.type, fi.offset);
540}
541} // namespace detail
542} // namespace hw
543} // namespace circt
544
545Type UnionType::parse(AsmParser &p) {
546 llvm::SmallVector<FieldInfo, 4> parameters;
547 llvm::StringSet<> nameSet;
548 bool hasDuplicateName = false;
549 if (p.parseCommaSeparatedList(
550 mlir::AsmParser::Delimiter::LessGreater, [&]() -> ParseResult {
551 StringRef name;
552 Type type;
553
554 auto fieldLoc = p.getCurrentLocation();
555 if (p.parseKeyword(&name) || p.parseColon() || p.parseType(type))
556 return failure();
557
558 if (!nameSet.insert(name).second) {
559 p.emitError(fieldLoc, "duplicate field name \'" + name +
560 "\' in hw.union type");
561 // Continue parsing to print all duplicates, but make sure to
562 // error eventually
563 hasDuplicateName = true;
564 }
565
566 size_t offset = 0;
567 if (succeeded(p.parseOptionalKeyword("offset")))
568 if (p.parseInteger(offset))
569 return failure();
570 parameters.push_back(UnionType::FieldInfo{
571 StringAttr::get(p.getContext(), name), type, offset});
572 return success();
573 }))
574 return Type();
575
576 if (hasDuplicateName)
577 return Type();
578
579 return get(p.getContext(), parameters);
580}
581
582void UnionType::print(AsmPrinter &odsPrinter) const {
583 odsPrinter << '<';
584 llvm::interleaveComma(
585 getElements(), odsPrinter, [&](const UnionType::FieldInfo &field) {
586 odsPrinter << field.name.getValue() << ": " << field.type;
587 if (field.offset)
588 odsPrinter << " offset " << field.offset;
589 });
590 odsPrinter << ">";
591}
592
593LogicalResult UnionType::verify(function_ref<InFlightDiagnostic()> emitError,
594 ArrayRef<UnionType::FieldInfo> elements) {
595 llvm::SmallDenseSet<StringAttr> fieldNameSet;
596 LogicalResult result = success();
597 fieldNameSet.reserve(elements.size());
598 for (const auto &elt : elements)
599 if (!fieldNameSet.insert(elt.name).second) {
600 result = failure();
601 emitError() << "duplicate field name '" << elt.name.getValue()
602 << "' in hw.union type";
603 }
604 return result;
605}
606
607std::optional<uint32_t> UnionType::getFieldIndex(mlir::StringAttr fieldName) {
608 ArrayRef<hw::UnionType::FieldInfo> elems = getElements();
609 for (size_t idx = 0, numElems = elems.size(); idx < numElems; ++idx)
610 if (elems[idx].name == fieldName)
611 return idx;
612 return {};
613}
614
615std::optional<uint32_t> UnionType::getFieldIndex(mlir::StringRef fieldName) {
616 return getFieldIndex(StringAttr::get(getContext(), fieldName));
617}
618
619UnionType::FieldInfo UnionType::getFieldInfo(::mlir::StringRef fieldName) {
620 if (auto fieldIndex = getFieldIndex(fieldName))
621 return getElements()[*fieldIndex];
622 return FieldInfo();
623}
624
625Type UnionType::getFieldType(mlir::StringRef fieldName) {
626 return getFieldInfo(fieldName).type;
627}
628
629std::optional<int64_t> UnionType::getBitWidth() const {
630 int64_t maxSize = 0;
631 for (auto field : getElements()) {
632 int64_t fieldSize = hw::getBitWidth(field.type);
633 if (fieldSize < 0)
634 return std::nullopt;
635 fieldSize += field.offset;
636 if (fieldSize > maxSize)
637 maxSize = fieldSize;
638 }
639 return maxSize;
640}
641
642//===----------------------------------------------------------------------===//
643// Enum Type
644//===----------------------------------------------------------------------===//
645
646Type EnumType::parse(AsmParser &p) {
647 llvm::SmallVector<Attribute> fields;
648
649 if (p.parseCommaSeparatedList(AsmParser::Delimiter::LessGreater, [&]() {
650 StringRef name;
651 if (p.parseKeyword(&name))
652 return failure();
653 fields.push_back(StringAttr::get(p.getContext(), name));
654 return success();
655 }))
656 return Type();
657
658 return get(p.getContext(), ArrayAttr::get(p.getContext(), fields));
659}
660
661void EnumType::print(AsmPrinter &p) const {
662 p << '<';
663 llvm::interleaveComma(getFields(), p, [&](Attribute enumerator) {
664 p << llvm::cast<StringAttr>(enumerator).getValue();
665 });
666 p << ">";
667}
668
669bool EnumType::contains(mlir::StringRef field) {
670 return indexOf(field).has_value();
671}
672
673std::optional<size_t> EnumType::indexOf(mlir::StringRef field) {
674 for (auto it : llvm::enumerate(getFields()))
675 if (llvm::cast<StringAttr>(it.value()).getValue() == field)
676 return it.index();
677 return {};
678}
679
680std::optional<int64_t> EnumType::getBitWidth() const {
681 auto w = getFields().size();
682 if (w > 1)
683 return llvm::Log2_64_Ceil(w);
684 return 1;
685}
686
687//===----------------------------------------------------------------------===//
688// ArrayType
689//===----------------------------------------------------------------------===//
690
691static ParseResult parseHWArray(AsmParser &p, Attribute &dim, Type &inner) {
692 uint64_t dimLiteral;
693 auto int64Type = p.getBuilder().getIntegerType(64);
694
695 if (auto res = p.parseOptionalInteger(dimLiteral); res.has_value()) {
696 if (failed(*res))
697 return failure();
698 dim = p.getBuilder().getI64IntegerAttr(dimLiteral);
699 } else if (auto res64 = p.parseOptionalAttribute(dim, int64Type);
700 res64.has_value()) {
701 if (failed(*res64))
702 return failure();
703 } else
704 return p.emitError(p.getNameLoc(), "expected integer");
705
706 if (!isa<IntegerAttr, ParamExprAttr, ParamDeclRefAttr>(dim)) {
707 p.emitError(p.getNameLoc(), "unsupported dimension kind in hw.array");
708 return failure();
709 }
710
711 if (p.parseXInDimensionList() || parseHWElementType(p, inner))
712 return failure();
713
714 return success();
715}
716
717static void printHWArray(AsmPrinter &p, Attribute dim, Type elementType) {
718 p.printAttributeWithoutType(dim);
719 p << "x";
721}
722
723size_t ArrayType::getNumElements() const {
724 if (auto intAttr = llvm::dyn_cast<IntegerAttr>(getSizeAttr()))
725 return intAttr.getInt();
726 return -1;
727}
728
729LogicalResult ArrayType::verify(function_ref<InFlightDiagnostic()> emitError,
730 Type innerType, Attribute size) {
731 if (hasHWInOutType(innerType))
732 return emitError() << "hw.array cannot contain InOut types";
733 return success();
734}
735
736uint64_t ArrayType::getMaxFieldID() const {
737 return getNumElements() *
738 (hw::FieldIdImpl::getMaxFieldID(getElementType()) + 1);
739}
740
741std::pair<Type, uint64_t>
742ArrayType::getSubTypeByFieldID(uint64_t fieldID) const {
743 if (fieldID == 0)
744 return {*this, 0};
745 return {getElementType(), getIndexAndSubfieldID(fieldID).second};
746}
747
748std::pair<uint64_t, bool>
749ArrayType::projectToChildFieldID(uint64_t fieldID, uint64_t index) const {
750 auto childRoot = getFieldID(index);
751 auto rangeEnd =
752 index >= getNumElements() ? getMaxFieldID() : (getFieldID(index + 1) - 1);
753 return std::make_pair(fieldID - childRoot,
754 fieldID >= childRoot && fieldID <= rangeEnd);
755}
756
757uint64_t ArrayType::getIndexForFieldID(uint64_t fieldID) const {
758 assert(fieldID && "fieldID must be at least 1");
759 // Divide the field ID by the number of fieldID's per element.
760 return (fieldID - 1) / (hw::FieldIdImpl::getMaxFieldID(getElementType()) + 1);
761}
762
763std::pair<uint64_t, uint64_t>
764ArrayType::getIndexAndSubfieldID(uint64_t fieldID) const {
765 auto index = getIndexForFieldID(fieldID);
766 auto elementFieldID = getFieldID(index);
767 return {index, fieldID - elementFieldID};
768}
769
770uint64_t ArrayType::getFieldID(uint64_t index) const {
771 return 1 + index * (hw::FieldIdImpl::getMaxFieldID(getElementType()) + 1);
772}
773
774std::optional<DenseMap<Attribute, Type>>
775hw::ArrayType::getSubelementIndexMap() const {
776 DenseMap<Attribute, Type> destructured;
777 for (unsigned i = 0; i < getNumElements(); ++i)
778 destructured.insert(
779 {IntegerAttr::get(IndexType::get(getContext()), i), getElementType()});
780 return destructured;
781}
782
783Type hw::ArrayType::getTypeAtIndex(Attribute index) const {
784 return getElementType();
785}
786
787std::optional<int64_t> hw::ArrayType::getBitWidth() const {
788 auto elementBitWidth = hw::getBitWidth(getElementType());
789 if (elementBitWidth < 0)
790 return std::nullopt;
791 int64_t numElements = getNumElements();
792 if (numElements < 0)
793 return std::nullopt;
794 return numElements * elementBitWidth;
795}
796
797//===----------------------------------------------------------------------===//
798// UnpackedArrayType
799//===----------------------------------------------------------------------===//
800
801LogicalResult
802UnpackedArrayType::verify(function_ref<InFlightDiagnostic()> emitError,
803 Type innerType, Attribute size) {
804 if (!isHWValueType(innerType))
805 return emitError() << "invalid element for uarray type";
806 return success();
807}
808
809size_t UnpackedArrayType::getNumElements() const {
810 if (auto intAttr = llvm::dyn_cast<IntegerAttr>(getSizeAttr()))
811 return intAttr.getInt();
812 return -1;
813}
814
815uint64_t UnpackedArrayType::getMaxFieldID() const {
816 return getNumElements() *
817 (hw::FieldIdImpl::getMaxFieldID(getElementType()) + 1);
818}
819
820std::pair<Type, uint64_t>
821UnpackedArrayType::getSubTypeByFieldID(uint64_t fieldID) const {
822 if (fieldID == 0)
823 return {*this, 0};
824 return {getElementType(), getIndexAndSubfieldID(fieldID).second};
825}
826
827std::pair<uint64_t, bool>
828UnpackedArrayType::projectToChildFieldID(uint64_t fieldID,
829 uint64_t index) const {
830 auto childRoot = getFieldID(index);
831 auto rangeEnd =
832 index >= getNumElements() ? getMaxFieldID() : (getFieldID(index + 1) - 1);
833 return std::make_pair(fieldID - childRoot,
834 fieldID >= childRoot && fieldID <= rangeEnd);
835}
836
837uint64_t UnpackedArrayType::getIndexForFieldID(uint64_t fieldID) const {
838 assert(fieldID && "fieldID must be at least 1");
839 // Divide the field ID by the number of fieldID's per element.
840 return (fieldID - 1) / (hw::FieldIdImpl::getMaxFieldID(getElementType()) + 1);
841}
842
843std::pair<uint64_t, uint64_t>
844UnpackedArrayType::getIndexAndSubfieldID(uint64_t fieldID) const {
845 auto index = getIndexForFieldID(fieldID);
846 auto elementFieldID = getFieldID(index);
847 return {index, fieldID - elementFieldID};
848}
849
850uint64_t UnpackedArrayType::getFieldID(uint64_t index) const {
851 return 1 + index * (hw::FieldIdImpl::getMaxFieldID(getElementType()) + 1);
852}
853
854std::optional<int64_t> UnpackedArrayType::getBitWidth() const {
855 auto elementBitWidth = hw::getBitWidth(getElementType());
856 if (elementBitWidth < 0)
857 return std::nullopt;
858 int64_t dimBitWidth = getNumElements();
859 if (dimBitWidth < 0)
860 return std::nullopt;
861 return (int64_t)getNumElements() * elementBitWidth;
862}
863
864//===----------------------------------------------------------------------===//
865// InOutType
866//===----------------------------------------------------------------------===//
867
868LogicalResult InOutType::verify(function_ref<InFlightDiagnostic()> emitError,
869 Type innerType) {
870 if (!isHWValueType(innerType))
871 return emitError() << "invalid element for hw.inout type " << innerType;
872 return success();
873}
874
875//===----------------------------------------------------------------------===//
876// TypeAliasType
877//===----------------------------------------------------------------------===//
878
879static Type computeCanonicalType(Type type) {
880 return llvm::TypeSwitch<Type, Type>(type)
881 .Case([](TypeAliasType t) {
882 return computeCanonicalType(t.getCanonicalType());
883 })
884 .Case([](ArrayType t) {
885 return ArrayType::get(computeCanonicalType(t.getElementType()),
886 t.getNumElements());
887 })
888 .Case([](UnpackedArrayType t) {
889 return UnpackedArrayType::get(computeCanonicalType(t.getElementType()),
890 t.getNumElements());
891 })
892 .Case([](StructType t) {
893 SmallVector<StructType::FieldInfo> fieldInfo;
894 for (auto field : t.getElements())
895 fieldInfo.push_back(StructType::FieldInfo{
896 field.name, computeCanonicalType(field.type)});
897 return StructType::get(t.getContext(), fieldInfo);
898 })
899 .Default([](Type t) { return t; });
900}
901
902TypeAliasType TypeAliasType::get(SymbolRefAttr ref, Type innerType) {
903 return get(ref.getContext(), ref, innerType, computeCanonicalType(innerType));
904}
905
906Type TypeAliasType::parse(AsmParser &p) {
907 SymbolRefAttr ref;
908 Type type;
909 if (p.parseLess() || p.parseAttribute(ref) || p.parseComma() ||
910 p.parseType(type) || p.parseGreater())
911 return Type();
912
913 return get(ref, type);
914}
915
916void TypeAliasType::print(AsmPrinter &p) const {
917 p << "<" << getRef() << ", " << getInnerType() << ">";
918}
919
920/// Return the Typedecl referenced by this TypeAlias, given the module to look
921/// in. This returns null when the IR is malformed.
922TypedeclOp TypeAliasType::getTypeDecl(const HWSymbolCache &cache) {
923 SymbolRefAttr ref = getRef();
924 auto typeScope = ::dyn_cast_or_null<TypeScopeOp>(
925 cache.getDefinition(ref.getRootReference()));
926 if (!typeScope)
927 return {};
928
929 return typeScope.lookupSymbol<TypedeclOp>(ref.getLeafReference());
930}
931
932std::optional<int64_t> TypeAliasType::getBitWidth() const {
933 auto width = hw::getBitWidth(getCanonicalType());
934 if (width < 0)
935 return std::nullopt;
936 return width;
937}
938
939//===----------------------------------------------------------------------===//
940// ModuleType
941//===----------------------------------------------------------------------===//
942
943LogicalResult ModuleType::verify(function_ref<InFlightDiagnostic()> emitError,
944 ArrayRef<ModulePort> ports) {
945 if (llvm::any_of(ports, [](const ModulePort &port) {
946 return hasHWInOutType(port.type);
947 }))
948 return emitError() << "Ports cannot be inout types";
949 return success();
950}
951
952size_t ModuleType::getPortIdForInputId(size_t idx) {
953 assert(idx < getImpl()->inputToAbs.size() && "input port out of range");
954 return getImpl()->inputToAbs[idx];
955}
956
957size_t ModuleType::getPortIdForOutputId(size_t idx) {
958 assert(idx < getImpl()->outputToAbs.size() && " output port out of range");
959 return getImpl()->outputToAbs[idx];
960}
961
962size_t ModuleType::getInputIdForPortId(size_t idx) {
963 auto nIdx = getImpl()->absToInput[idx];
964 assert(nIdx != ~0ULL);
965 return nIdx;
966}
967
968size_t ModuleType::getOutputIdForPortId(size_t idx) {
969 auto nIdx = getImpl()->absToOutput[idx];
970 assert(nIdx != ~0ULL);
971 return nIdx;
972}
973
974size_t ModuleType::getNumInputs() { return getImpl()->inputToAbs.size(); }
975
976size_t ModuleType::getNumOutputs() { return getImpl()->outputToAbs.size(); }
977
978size_t ModuleType::getNumPorts() { return getPorts().size(); }
979
980SmallVector<Type> ModuleType::getInputTypes() {
981 SmallVector<Type> retval;
982 for (auto &p : getPorts()) {
983 if (p.dir == ModulePort::Direction::Input)
984 retval.push_back(p.type);
985 else if (p.dir == ModulePort::Direction::InOut) {
986 retval.push_back(hw::InOutType::get(p.type));
987 }
988 }
989 return retval;
990}
991
992SmallVector<Type> ModuleType::getOutputTypes() {
993 SmallVector<Type> retval;
994 for (auto &p : getPorts())
995 if (p.dir == ModulePort::Direction::Output)
996 retval.push_back(p.type);
997 return retval;
998}
999
1000SmallVector<Type> ModuleType::getPortTypes() {
1001 SmallVector<Type> retval;
1002 for (auto &p : getPorts())
1003 retval.push_back(p.type);
1004 return retval;
1005}
1006
1007Type ModuleType::getInputType(size_t idx) {
1008 const auto &portInfo = getPorts()[getPortIdForInputId(idx)];
1009 if (portInfo.dir != ModulePort::InOut)
1010 return portInfo.type;
1011 return InOutType::get(portInfo.type);
1012}
1013
1014Type ModuleType::getOutputType(size_t idx) {
1015 return getPorts()[getPortIdForOutputId(idx)].type;
1016}
1017
1018SmallVector<Attribute> ModuleType::getInputNames() {
1019 SmallVector<Attribute> retval;
1020 for (auto &p : getPorts())
1021 if (p.dir != ModulePort::Direction::Output)
1022 retval.push_back(p.name);
1023 return retval;
1024}
1025
1026SmallVector<Attribute> ModuleType::getOutputNames() {
1027 SmallVector<Attribute> retval;
1028 for (auto &p : getPorts())
1029 if (p.dir == ModulePort::Direction::Output)
1030 retval.push_back(p.name);
1031 return retval;
1032}
1033
1034StringAttr ModuleType::getPortNameAttr(size_t idx) {
1035 return getPorts()[idx].name;
1036}
1037
1038StringRef ModuleType::getPortName(size_t idx) {
1039 auto sa = getPortNameAttr(idx);
1040 if (sa)
1041 return sa.getValue();
1042 return {};
1043}
1044
1045StringAttr ModuleType::getInputNameAttr(size_t idx) {
1046 return getPorts()[getPortIdForInputId(idx)].name;
1047}
1048
1049StringRef ModuleType::getInputName(size_t idx) {
1050 auto sa = getInputNameAttr(idx);
1051 if (sa)
1052 return sa.getValue();
1053 return {};
1054}
1055
1056StringAttr ModuleType::getOutputNameAttr(size_t idx) {
1057 return getPorts()[getPortIdForOutputId(idx)].name;
1058}
1059
1060StringRef ModuleType::getOutputName(size_t idx) {
1061 auto sa = getOutputNameAttr(idx);
1062 if (sa)
1063 return sa.getValue();
1064 return {};
1065}
1066
1067bool ModuleType::isOutput(size_t idx) {
1068 auto &p = getPorts()[idx];
1069 return p.dir == ModulePort::Direction::Output;
1070}
1071
1072FunctionType ModuleType::getFuncType() {
1073 SmallVector<Type> inputs, outputs;
1074 for (auto p : getPorts())
1075 if (p.dir == ModulePort::Input)
1076 inputs.push_back(p.type);
1077 else if (p.dir == ModulePort::InOut)
1078 inputs.push_back(InOutType::get(p.type));
1079 else
1080 outputs.push_back(p.type);
1081 return FunctionType::get(getContext(), inputs, outputs);
1082}
1083
1084ArrayRef<ModulePort> ModuleType::getPorts() const {
1085 return getImpl()->getPorts();
1086}
1087
1088FailureOr<ModuleType> ModuleType::resolveParametricTypes(ArrayAttr parameters,
1089 LocationAttr loc,
1090 bool emitErrors) {
1091 SmallVector<ModulePort, 8> resolvedPorts;
1092 for (ModulePort port : getPorts()) {
1093 FailureOr<Type> resolvedType =
1094 evaluateParametricType(loc, parameters, port.type, emitErrors);
1095 if (failed(resolvedType))
1096 return failure();
1097 port.type = *resolvedType;
1098 resolvedPorts.push_back(port);
1099 }
1100 return ModuleType::get(getContext(), resolvedPorts);
1101}
1102
1103static StringRef dirToStr(ModulePort::Direction dir) {
1104 switch (dir) {
1105 case ModulePort::Direction::Input:
1106 return "input";
1107 case ModulePort::Direction::Output:
1108 return "output";
1109 case ModulePort::Direction::InOut:
1110 return "inout";
1111 }
1112}
1113
1114static ModulePort::Direction strToDir(StringRef str) {
1115 if (str == "input")
1116 return ModulePort::Direction::Input;
1117 if (str == "output")
1118 return ModulePort::Direction::Output;
1119 if (str == "inout")
1120 return ModulePort::Direction::InOut;
1121 llvm::report_fatal_error("invalid direction");
1122}
1123
1124/// Parse a list of field names and types within <>. E.g.:
1125/// <input foo: i7, output bar: i8>
1126static ParseResult parsePorts(AsmParser &p,
1127 SmallVectorImpl<ModulePort> &ports) {
1128 return p.parseCommaSeparatedList(
1129 mlir::AsmParser::Delimiter::LessGreater, [&]() -> ParseResult {
1130 StringRef dir;
1131 std::string name;
1132 Type type;
1133 if (p.parseKeyword(&dir) || p.parseKeywordOrString(&name) ||
1134 p.parseColon() || p.parseType(type))
1135 return failure();
1136 ports.push_back(
1137 {StringAttr::get(p.getContext(), name), type, strToDir(dir)});
1138 return success();
1139 });
1140}
1141
1142/// Print out a list of named fields surrounded by <>.
1143static void printPorts(AsmPrinter &p, ArrayRef<ModulePort> ports) {
1144 p << '<';
1145 llvm::interleaveComma(ports, p, [&](const ModulePort &port) {
1146 p << dirToStr(port.dir) << " ";
1147 p.printKeywordOrString(port.name.getValue());
1148 p << " : " << port.type;
1149 });
1150 p << ">";
1151}
1152
1153Type ModuleType::parse(AsmParser &odsParser) {
1154 llvm::SmallVector<ModulePort, 4> ports;
1155 if (parsePorts(odsParser, ports))
1156 return Type();
1157 return get(odsParser.getContext(), ports);
1158}
1159
1160void ModuleType::print(AsmPrinter &odsPrinter) const {
1161 printPorts(odsPrinter, getPorts());
1162}
1163
1164ModuleType circt::hw::detail::fnToMod(Operation *op,
1165 ArrayRef<Attribute> inputNames,
1166 ArrayRef<Attribute> outputNames) {
1167 return fnToMod(
1168 cast<FunctionType>(cast<mlir::FunctionOpInterface>(op).getFunctionType()),
1169 inputNames, outputNames);
1170}
1171
1172ModuleType circt::hw::detail::fnToMod(FunctionType fnty,
1173 ArrayRef<Attribute> inputNames,
1174 ArrayRef<Attribute> outputNames) {
1175 SmallVector<ModulePort> ports;
1176 if (!inputNames.empty()) {
1177 for (auto [t, n] : llvm::zip_equal(fnty.getInputs(), inputNames))
1178 if (auto iot = dyn_cast<hw::InOutType>(t))
1179 ports.push_back({cast<StringAttr>(n), iot.getElementType(),
1180 ModulePort::Direction::InOut});
1181 else
1182 ports.push_back({cast<StringAttr>(n), t, ModulePort::Direction::Input});
1183 } else {
1184 for (auto t : fnty.getInputs())
1185 if (auto iot = dyn_cast<hw::InOutType>(t))
1186 ports.push_back(
1187 {{}, iot.getElementType(), ModulePort::Direction::InOut});
1188 else
1189 ports.push_back({{}, t, ModulePort::Direction::Input});
1190 }
1191 if (!outputNames.empty()) {
1192 for (auto [t, n] : llvm::zip_equal(fnty.getResults(), outputNames))
1193 ports.push_back({cast<StringAttr>(n), t, ModulePort::Direction::Output});
1194 } else {
1195 for (auto t : fnty.getResults())
1196 ports.push_back({{}, t, ModulePort::Direction::Output});
1197 }
1198 return ModuleType::get(fnty.getContext(), ports);
1199}
1200
1202 : ports(inPorts) {
1203 size_t nextInput = 0;
1204 size_t nextOutput = 0;
1205 for (auto [idx, p] : llvm::enumerate(ports)) {
1206 if (p.dir == ModulePort::Direction::Output) {
1207 outputToAbs.push_back(idx);
1208 absToOutput.push_back(nextOutput);
1209 absToInput.push_back(~0ULL);
1210 ++nextOutput;
1211 } else {
1212 inputToAbs.push_back(idx);
1213 absToInput.push_back(nextInput);
1214 absToOutput.push_back(~0ULL);
1215 ++nextInput;
1216 }
1217 }
1218}
1219
1220//===----------------------------------------------------------------------===//
1221// BoilerPlate
1222//===----------------------------------------------------------------------===//
1223
1224void HWDialect::registerTypes() {
1225 addTypes<
1226#define GET_TYPEDEF_LIST
1227#include "circt/Dialect/HW/HWTypes.cpp.inc"
1228 >();
1229}
assert(baseType &&"element must be base type")
MlirType uint64_t numElements
Definition CHIRRTL.cpp:30
MlirType elementType
Definition CHIRRTL.cpp:29
static ModulePort::Direction strToDir(StringRef str)
Definition HWTypes.cpp:1114
static void printPorts(AsmPrinter &p, ArrayRef< ModulePort > ports)
Print out a list of named fields surrounded by <>.
Definition HWTypes.cpp:1143
static void printFields(AsmPrinter &p, ArrayRef< FieldInfo > fields)
Print out a list of named fields surrounded by <>.
Definition HWTypes.cpp:375
static StringRef dirToStr(ModulePort::Direction dir)
Definition HWTypes.cpp:1103
static ParseResult parseHWArray(AsmParser &parser, Attribute &dim, Type &elementType)
Definition HWTypes.cpp:691
static ParseResult parseHWElementType(AsmParser &parser, Type &elementType)
Parse and print nested HW types nicely.
Definition HWTypes.cpp:262
static ParseResult parsePorts(AsmParser &p, SmallVectorImpl< ModulePort > &ports)
Parse a list of field names and types within <>.
Definition HWTypes.cpp:1126
static void printHWArray(AsmPrinter &printer, Attribute dim, Type elementType)
Definition HWTypes.cpp:717
static std::pair< uint64_t, SmallVector< uint64_t > > getFieldIDsStruct(const StructType &st)
Definition HWTypes.cpp:431
static ParseResult parseFields(AsmParser &p, SmallVectorImpl< FieldInfo > &parameters)
Parse a list of unique field names and types within <>.
Definition HWTypes.cpp:343
static Type computeCanonicalType(Type type)
Definition HWTypes.cpp:879
static void printHWElementType(AsmPrinter &printer, Type dim)
Definition HWTypes.cpp:284
@ Input
Definition HW.h:42
@ Output
Definition HW.h:42
static unsigned getFieldID(BundleType type, unsigned index)
static unsigned getIndexForFieldID(BundleType type, unsigned fieldID)
static unsigned getMaxFieldID(FIRRTLBaseType type)
static InstancePath empty
This stores lookup tables to make manipulating and working with the IR more efficient.
Definition HWSymCache.h:28
mlir::Operation * getDefinition(mlir::Attribute attr) const override
Lookup a definition for 'symbol' in the cache.
Definition HWSymCache.h:57
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition CalyxOps.cpp:56
Direction
The direction of a Component or Cell port.
Definition CalyxOps.h:76
uint64_t getWidth(Type t)
Definition ESIPasses.cpp:32
mlir::Type innerType(mlir::Type type)
Definition ESITypes.cpp:423
std::pair< uint64_t, uint64_t > getIndexAndSubfieldID(Type type, uint64_t fieldID)
std::pair<::mlir::Type, uint64_t > getSubTypeByFieldID(Type, uint64_t fieldID)
llvm::hash_code hash_value(const FieldInfo &fi)
Definition HWTypes.cpp:334
bool operator==(const FieldInfo &a, const FieldInfo &b)
Definition HWTypes.cpp:331
ModuleType fnToMod(Operation *op, ArrayRef< Attribute > inputNames, ArrayRef< Attribute > outputNames)
Definition HWTypes.cpp:1164
bool isHWIntegerType(mlir::Type type)
Return true if the specified type is a value HW Integer type.
Definition HWTypes.cpp:60
bool isHWValueType(mlir::Type type)
Return true if the specified type can be used as an HW value type, that is the set of types that can ...
LogicalResult aggregateAttrToAPInt(mlir::Type type, ArrayAttr attr, APInt &result)
Convert an ArrayAttr into an APInt value matching the given type.
mlir::FailureOr< mlir::Type > evaluateParametricType(mlir::Location loc, mlir::ArrayAttr parameters, mlir::Type type, bool emitErrors=true)
Returns a resolved version of 'type' wherein any parameter reference has been evaluated based on the ...
int64_t getBitWidth(mlir::Type type)
Return the hardware bit width of a type.
Definition HWTypes.cpp:110
LogicalResult apIntToAggregateAttr(mlir::Type aggregateType, const APInt &intVal, ArrayAttr &result)
Convert an APInt value into a nested aggregate attribute matching the given HWAggregateType.
bool isHWEnumType(mlir::Type type)
Return true if the specified type is a HW Enum type.
Definition HWTypes.cpp:73
mlir::Type getCanonicalType(mlir::Type type)
Definition HWTypes.cpp:49
bool hasHWInOutType(mlir::Type type)
Return true if the specified type contains known marker types like InOutType.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition hw.py:1
mlir::Type type
Definition HWTypes.h:32
mlir::StringAttr name
Definition HWTypes.h:31
Struct defining a field. Used in structs.
Definition HWTypes.h:93
mlir::StringAttr name
Definition HWTypes.h:94
SmallVector< ModulePort > ports
The parametric data held by the storage class.
Definition HWTypes.h:71
ModuleTypeStorage(ArrayRef< ModulePort > inPorts)
Definition HWTypes.cpp:1201
SmallVector< size_t > absToInput
Definition HWTypes.h:75
SmallVector< size_t > outputToAbs
Definition HWTypes.h:74
SmallVector< size_t > inputToAbs
Definition HWTypes.h:73
SmallVector< size_t > absToOutput
Definition HWTypes.h:76
Struct defining a field with an offset. Used in unions.
Definition HWTypes.h:99