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