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