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"
35static ParseResult
parseHWArray(AsmParser &parser, Attribute &dim,
42#define GET_TYPEDEF_CLASSES
43#include "circt/Dialect/HW/HWTypes.cpp.inc"
51 if (
auto typeAlias = dyn_cast<TypeAliasType>(type))
52 canonicalType = typeAlias.getCanonicalType();
63 if (isa<hw::IntType>(canonicalType))
66 auto intType = dyn_cast<IntegerType>(canonicalType);
67 if (!intType || !intType.isSignless())
82 if (isa<IntegerType, IntType, EnumType>(type))
85 if (
auto array = dyn_cast<ArrayType>(type))
88 if (
auto array = dyn_cast<UnpackedArrayType>(type))
91 if (
auto t = dyn_cast<StructType>(type))
92 return llvm::all_of(t.getElements(),
93 [](
auto f) { return isHWValueType(f.type); });
95 if (
auto t = dyn_cast<UnionType>(type))
96 return llvm::all_of(t.getElements(),
97 [](
auto f) { return isHWValueType(f.type); });
99 if (
auto t = dyn_cast<TypeAliasType>(type))
109 if (isa<IntegerType>(type))
125 return llvm::TypeSwitch<::mlir::Type, int64_t>(type)
127 [](IntegerType t) {
return t.getIntOrFloatBitWidth(); })
128 .Default([](Type type) -> int64_t {
130 if (
auto iface = dyn_cast<BitWidthTypeInterface>(type)) {
131 std::optional<int64_t> width = iface.getBitWidth();
132 return width.has_value() ? *width : -1;
142 if (
auto array = dyn_cast<ArrayType>(type))
145 if (
auto array = dyn_cast<UnpackedArrayType>(type))
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); });
153 if (
auto t = dyn_cast<TypeAliasType>(type))
156 return isa<InOutType>(type);
160struct AggregateAttrFrame {
161 SmallVector<Attribute> attrs;
162 SmallVector<Type> types;
165 AggregateAttrFrame(SmallVector<Type> &&types)
166 : attrs(types.size()), types(std::move(types)), remaining(attrs.size()) {}
168 void addChild(Attribute attr) { attrs[--remaining] = attr; }
169 Type getNextChildType() {
return types[remaining - 1]; }
170 bool isFinished()
const {
return remaining == 0; }
180 auto *ctx = aggregateType.getContext();
181 SmallVector<AggregateAttrFrame> stack;
182 unsigned nextExtraction = 0;
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;
190 for (
auto &element : structType.getElements())
192 stack.push_back(std::move(types));
195 .Case<ArrayType, UnpackedArrayType>([&](
auto arrayType) {
196 SmallVector<Type> types(arrayType.getNumElements(),
198 stack.push_back(std::move(types));
210 while (!stack.empty()) {
211 if (stack.back().isFinished()) {
212 auto frame = stack.pop_back_val();
213 result = ArrayAttr::get(ctx, frame.attrs);
215 stack.back().addChild(result);
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));
227 if (!pushToStack(curType))
232 assert(nextExtraction == intVal.getBitWidth() &&
233 "constant wasn't fully processed");
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;
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());
257 if (
auto intAttr = dyn_cast<IntegerAttr>(current)) {
258 auto chunk = intAttr.getValue();
259 result.insertBits(chunk, nextInsertion);
260 nextInsertion += chunk.getBitWidth();
267 assert(nextInsertion == bitWidth &&
"constant wasn't fully processed");
277 auto fullString =
static_cast<DialectAsmParser &
>(p).getFullSymbolSpec();
278 auto *curPtr = p.getCurrentLocation().getPointer();
280 StringRef(curPtr, fullString.size() - (curPtr - fullString.data()));
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())
290 return p.emitError(p.getNameLoc(),
"invalid type `") << typeString <<
"`";
293 return p.parseType(result);
297 if (succeeded(generatedTypePrinter(element, p)))
299 p.printType(element);
306Type IntType::get(mlir::TypedAttr width) {
308 auto widthWidth = llvm::dyn_cast<IntegerType>(width.getType());
309 assert(widthWidth && widthWidth.getWidth() == 32 &&
310 "!hw.int width must be 32-bits");
313 if (
auto cstWidth = llvm::dyn_cast<IntegerAttr>(width))
314 return IntegerType::get(width.getContext(),
315 cstWidth.getValue().getZExtValue());
317 return Base::get(width.getContext(), width);
320Type IntType::parse(AsmParser &p) {
322 auto int32Type = p.getBuilder().getIntegerType(32);
324 mlir::TypedAttr width;
325 if (p.parseLess() || p.parseAttribute(width, int32Type) || p.parseGreater())
330void IntType::print(AsmPrinter &p)
const {
332 p.printAttributeWithoutType(
getWidth());
347 return llvm::hash_combine(fi.
name, fi.
type);
356 SmallVectorImpl<FieldInfo> ¶meters) {
357 llvm::StringSet<> nameSet;
358 bool hasDuplicateName =
false;
359 auto parseResult = p.parseCommaSeparatedList(
360 mlir::AsmParser::Delimiter::LessGreater, [&]() -> ParseResult {
364 auto fieldLoc = p.getCurrentLocation();
365 if (p.parseKeywordOrString(&name) || p.parseColon() ||
369 if (!nameSet.insert(name).second) {
370 p.emitError(fieldLoc,
"duplicate field name \'" + name +
"\'");
373 hasDuplicateName = true;
376 parameters.push_back(
377 FieldInfo{StringAttr::get(p.getContext(), name), type});
381 if (hasDuplicateName)
387static void printFields(AsmPrinter &p, ArrayRef<FieldInfo> fields) {
389 llvm::interleaveComma(fields, p, [&](
const FieldInfo &field) {
390 p.printKeywordOrString(field.
name.getValue());
391 p <<
": " << field.
type;
396Type StructType::parse(AsmParser &p) {
397 llvm::SmallVector<FieldInfo, 4> parameters;
400 return get(p.getContext(), parameters);
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) {
411 emitError() <<
"duplicate field name '" << elt.name.getValue()
412 <<
"' in hw.struct type";
417void StructType::print(AsmPrinter &p)
const {
printFields(p, getElements()); }
419Type StructType::getFieldType(mlir::StringRef fieldName) {
420 for (
const auto &field : getElements())
421 if (field.name == fieldName)
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)
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)
442static std::pair<uint64_t, SmallVector<uint64_t>>
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;
451 fieldIDs.push_back(fieldID);
455 return {fieldID, fieldIDs};
458void StructType::getInnerTypes(SmallVectorImpl<Type> &types) {
459 for (
const auto &field : getElements())
460 types.push_back(field.type);
463uint64_t StructType::getMaxFieldID()
const {
464 uint64_t fieldID = 0;
465 for (
const auto &field : getElements())
470std::pair<Type, uint64_t>
471StructType::getSubTypeByFieldID(uint64_t fieldID)
const {
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};
482std::pair<uint64_t, bool>
483StructType::projectToChildFieldID(uint64_t fieldID, uint64_t index)
const {
485 auto childRoot = fieldIDs[index];
487 index + 1 >= getElements().size() ? maxId : (fieldIDs[index + 1] - 1);
488 return std::make_pair(fieldID - childRoot,
489 fieldID >= childRoot && fieldID <= rangeEnd);
492uint64_t StructType::getFieldID(uint64_t index)
const {
494 return fieldIDs[index];
497uint64_t StructType::getIndexForFieldID(uint64_t fieldID)
const {
498 assert(!getElements().
empty() &&
"Bundle must have >0 fields");
500 auto *it = std::prev(llvm::upper_bound(fieldIDs, fieldID));
501 return std::distance(fieldIDs.begin(), it);
504std::pair<uint64_t, uint64_t>
505StructType::getIndexAndSubfieldID(uint64_t fieldID)
const {
508 return {index, fieldID - elementFieldID};
511std::optional<DenseMap<Attribute, Type>>
512hw::StructType::getSubelementIndexMap()
const {
513 DenseMap<Attribute, Type> destructured;
514 for (
auto [i, field] :
llvm::enumerate(getElements()))
516 {IntegerAttr::get(IndexType::get(getContext()), i), field.type});
520Type hw::StructType::getTypeAtIndex(Attribute index)
const {
521 auto indexAttr = llvm::dyn_cast<IntegerAttr>(index);
528std::optional<int64_t> StructType::getBitWidth()
const {
530 for (
auto field : getElements()) {
531 int64_t fieldSize = hw::getBitWidth(field.type);
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 {
566 auto fieldLoc = p.getCurrentLocation();
567 if (p.parseKeyword(&name) || p.parseColon() || p.parseType(type))
570 if (!nameSet.insert(name).second) {
571 p.emitError(fieldLoc,
"duplicate field name \'" + name +
572 "\' in hw.union type");
575 hasDuplicateName = true;
579 if (succeeded(p.parseOptionalKeyword(
"offset")))
580 if (p.parseInteger(offset))
582 parameters.push_back(UnionType::FieldInfo{
583 StringAttr::get(p.getContext(), name), type, offset});
588 if (hasDuplicateName)
591 return get(p.getContext(), parameters);
594void UnionType::print(AsmPrinter &odsPrinter)
const {
596 llvm::interleaveComma(
597 getElements(), odsPrinter, [&](
const UnionType::FieldInfo &field) {
598 odsPrinter << field.name.getValue() <<
": " << field.type;
600 odsPrinter <<
" offset " << field.offset;
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) {
613 emitError() <<
"duplicate field name '" << elt.name.getValue()
614 <<
"' in hw.union type";
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)
627std::optional<uint32_t> UnionType::getFieldIndex(mlir::StringRef fieldName) {
628 return getFieldIndex(StringAttr::get(getContext(), fieldName));
631UnionType::FieldInfo UnionType::getFieldInfo(::mlir::StringRef fieldName) {
632 if (
auto fieldIndex = getFieldIndex(fieldName))
633 return getElements()[*fieldIndex];
637Type UnionType::getFieldType(mlir::StringRef fieldName) {
638 return getFieldInfo(fieldName).type;
641std::optional<int64_t> UnionType::getBitWidth()
const {
643 for (
auto field : getElements()) {
644 int64_t fieldSize = hw::getBitWidth(field.type);
647 fieldSize += field.offset;
648 if (fieldSize > maxSize)
658Type EnumType::parse(AsmParser &p) {
659 llvm::SmallVector<Attribute> fields;
661 if (p.parseCommaSeparatedList(AsmParser::Delimiter::LessGreater, [&]() {
663 if (p.parseKeyword(&name))
665 fields.push_back(StringAttr::get(p.getContext(), name));
670 return get(p.getContext(), ArrayAttr::get(p.getContext(), fields));
673void EnumType::print(AsmPrinter &p)
const {
675 llvm::interleaveComma(getFields(), p, [&](Attribute enumerator) {
676 p << llvm::cast<StringAttr>(enumerator).getValue();
681bool EnumType::contains(mlir::StringRef field) {
682 return indexOf(field).has_value();
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)
692std::optional<int64_t> EnumType::getBitWidth()
const {
693 auto w = getFields().size();
695 return llvm::Log2_64_Ceil(w);
703static ParseResult
parseHWArray(AsmParser &p, Attribute &dim, Type &inner) {
705 auto int64Type = p.getBuilder().getIntegerType(64);
707 if (
auto res = p.parseOptionalInteger(dimLiteral); res.has_value()) {
710 dim = p.getBuilder().getI64IntegerAttr(dimLiteral);
711 }
else if (
auto res64 = p.parseOptionalAttribute(dim, int64Type);
716 return p.emitError(p.getNameLoc(),
"expected integer");
718 if (!isa<IntegerAttr, ParamExprAttr, ParamDeclRefAttr>(dim)) {
719 p.emitError(p.getNameLoc(),
"unsupported dimension kind in hw.array");
730 p.printAttributeWithoutType(dim);
735size_t ArrayType::getNumElements()
const {
736 if (
auto intAttr = llvm::dyn_cast<IntegerAttr>(getSizeAttr()))
737 return intAttr.getInt();
741LogicalResult ArrayType::verify(function_ref<InFlightDiagnostic()> emitError,
742 Type innerType, Attribute size) {
744 return emitError() <<
"hw.array cannot contain InOut types";
748uint64_t ArrayType::getMaxFieldID()
const {
749 return getNumElements() *
753std::pair<Type, uint64_t>
754ArrayType::getSubTypeByFieldID(uint64_t fieldID)
const {
760std::pair<uint64_t, bool>
761ArrayType::projectToChildFieldID(uint64_t fieldID, uint64_t index)
const {
765 return std::make_pair(fieldID - childRoot,
766 fieldID >= childRoot && fieldID <= rangeEnd);
769uint64_t ArrayType::getIndexForFieldID(uint64_t fieldID)
const {
770 assert(fieldID &&
"fieldID must be at least 1");
775std::pair<uint64_t, uint64_t>
776ArrayType::getIndexAndSubfieldID(uint64_t fieldID)
const {
779 return {index, fieldID - elementFieldID};
782uint64_t ArrayType::getFieldID(uint64_t index)
const {
786std::optional<DenseMap<Attribute, Type>>
787hw::ArrayType::getSubelementIndexMap()
const {
788 DenseMap<Attribute, Type> destructured;
789 for (
unsigned i = 0; i < getNumElements(); ++i)
791 {IntegerAttr::get(IndexType::get(getContext()), i), getElementType()});
795Type hw::ArrayType::getTypeAtIndex(Attribute index)
const {
796 return getElementType();
799std::optional<int64_t> hw::ArrayType::getBitWidth()
const {
800 auto elementBitWidth = hw::getBitWidth(getElementType());
801 if (elementBitWidth < 0)
814UnpackedArrayType::verify(function_ref<InFlightDiagnostic()> emitError,
815 Type innerType, Attribute size) {
817 return emitError() <<
"invalid element for uarray type";
821size_t UnpackedArrayType::getNumElements()
const {
822 if (
auto intAttr = llvm::dyn_cast<IntegerAttr>(getSizeAttr()))
823 return intAttr.getInt();
827uint64_t UnpackedArrayType::getMaxFieldID()
const {
828 return getNumElements() *
832std::pair<Type, uint64_t>
833UnpackedArrayType::getSubTypeByFieldID(uint64_t fieldID)
const {
839std::pair<uint64_t, bool>
840UnpackedArrayType::projectToChildFieldID(uint64_t fieldID,
841 uint64_t index)
const {
845 return std::make_pair(fieldID - childRoot,
846 fieldID >= childRoot && fieldID <= rangeEnd);
849uint64_t UnpackedArrayType::getIndexForFieldID(uint64_t fieldID)
const {
850 assert(fieldID &&
"fieldID must be at least 1");
855std::pair<uint64_t, uint64_t>
856UnpackedArrayType::getIndexAndSubfieldID(uint64_t fieldID)
const {
859 return {index, fieldID - elementFieldID};
862uint64_t UnpackedArrayType::getFieldID(uint64_t index)
const {
866std::optional<int64_t> UnpackedArrayType::getBitWidth()
const {
867 auto elementBitWidth = hw::getBitWidth(getElementType());
868 if (elementBitWidth < 0)
870 int64_t dimBitWidth = getNumElements();
873 return (int64_t)getNumElements() * elementBitWidth;
880LogicalResult InOutType::verify(function_ref<InFlightDiagnostic()> emitError,
883 return emitError() <<
"invalid element for hw.inout type " <<
innerType;
892 return llvm::TypeSwitch<Type, Type>(type)
893 .Case([](TypeAliasType t) {
896 .Case([](ArrayType t) {
900 .Case([](UnpackedArrayType t) {
904 .Case([](StructType t) {
905 SmallVector<StructType::FieldInfo> fieldInfo;
906 for (
auto field : t.getElements())
907 fieldInfo.push_back(StructType::FieldInfo{
909 return StructType::get(t.getContext(), fieldInfo);
911 .Default([](Type t) {
return t; });
914TypeAliasType TypeAliasType::get(SymbolRefAttr ref, Type innerType) {
918Type TypeAliasType::parse(AsmParser &p) {
921 if (p.parseLess() || p.parseAttribute(ref) || p.parseComma() ||
922 p.parseType(type) || p.parseGreater())
925 return get(ref, type);
928void TypeAliasType::print(AsmPrinter &p)
const {
929 p <<
"<" << getRef() <<
", " << getInnerType() <<
">";
934TypedeclOp TypeAliasType::getTypeDecl(
const HWSymbolCache &cache) {
935 SymbolRefAttr ref = getRef();
936 auto typeScope = ::dyn_cast_or_null<TypeScopeOp>(
941 return typeScope.lookupSymbol<TypedeclOp>(ref.getLeafReference());
944std::optional<int64_t> TypeAliasType::getBitWidth()
const {
955LogicalResult ModuleType::verify(function_ref<InFlightDiagnostic()> emitError,
956 ArrayRef<ModulePort> ports) {
957 if (llvm::any_of(ports, [](
const ModulePort &port) {
960 return emitError() <<
"Ports cannot be inout types";
964size_t ModuleType::getPortIdForInputId(
size_t idx) {
965 assert(idx < getImpl()->inputToAbs.size() &&
"input port out of range");
966 return getImpl()->inputToAbs[idx];
969size_t ModuleType::getPortIdForOutputId(
size_t idx) {
970 assert(idx < getImpl()->outputToAbs.size() &&
" output port out of range");
971 return getImpl()->outputToAbs[idx];
974size_t ModuleType::getInputIdForPortId(
size_t idx) {
975 auto nIdx = getImpl()->absToInput[idx];
980size_t ModuleType::getOutputIdForPortId(
size_t idx) {
981 auto nIdx = getImpl()->absToOutput[idx];
986size_t ModuleType::getNumInputs() {
return getImpl()->inputToAbs.size(); }
988size_t ModuleType::getNumOutputs() {
return getImpl()->outputToAbs.size(); }
990size_t ModuleType::getNumPorts() {
return getPorts().size(); }
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));
1004SmallVector<Type> ModuleType::getOutputTypes() {
1005 SmallVector<Type> retval;
1006 for (
auto &p : getPorts())
1008 retval.push_back(p.type);
1012SmallVector<Type> ModuleType::getPortTypes() {
1013 SmallVector<Type> retval;
1014 for (
auto &p : getPorts())
1015 retval.push_back(p.type);
1019Type ModuleType::getInputType(
size_t idx) {
1020 const auto &portInfo = getPorts()[getPortIdForInputId(idx)];
1022 return portInfo.type;
1023 return InOutType::get(portInfo.type);
1026Type ModuleType::getOutputType(
size_t idx) {
1027 return getPorts()[getPortIdForOutputId(idx)].type;
1030SmallVector<Attribute> ModuleType::getInputNames() {
1031 SmallVector<Attribute> retval;
1032 for (
auto &p : getPorts())
1034 retval.push_back(p.name);
1038SmallVector<Attribute> ModuleType::getOutputNames() {
1039 SmallVector<Attribute> retval;
1040 for (
auto &p : getPorts())
1042 retval.push_back(p.name);
1046StringAttr ModuleType::getPortNameAttr(
size_t idx) {
1047 return getPorts()[idx].name;
1050StringRef ModuleType::getPortName(
size_t idx) {
1051 auto sa = getPortNameAttr(idx);
1053 return sa.getValue();
1057StringAttr ModuleType::getInputNameAttr(
size_t idx) {
1058 return getPorts()[getPortIdForInputId(idx)].name;
1061StringRef ModuleType::getInputName(
size_t idx) {
1062 auto sa = getInputNameAttr(idx);
1064 return sa.getValue();
1068StringAttr ModuleType::getOutputNameAttr(
size_t idx) {
1069 return getPorts()[getPortIdForOutputId(idx)].name;
1072StringRef ModuleType::getOutputName(
size_t idx) {
1073 auto sa = getOutputNameAttr(idx);
1075 return sa.getValue();
1079bool ModuleType::isOutput(
size_t idx) {
1080 auto &p = getPorts()[idx];
1081 return p.dir == ModulePort::Direction::Output;
1084FunctionType ModuleType::getFuncType() {
1085 SmallVector<Type> inputs, outputs;
1086 for (
auto p : getPorts())
1088 inputs.push_back(p.type);
1090 inputs.push_back(InOutType::get(p.type));
1092 outputs.push_back(p.type);
1093 return FunctionType::get(getContext(), inputs, outputs);
1096ArrayRef<ModulePort> ModuleType::getPorts()
const {
1097 return getImpl()->getPorts();
1100FailureOr<ModuleType> ModuleType::resolveParametricTypes(ArrayAttr parameters,
1103 SmallVector<ModulePort, 8> resolvedPorts;
1105 FailureOr<Type> resolvedType =
1107 if (failed(resolvedType))
1109 port.type = *resolvedType;
1110 resolvedPorts.push_back(port);
1112 return ModuleType::get(getContext(), resolvedPorts);
1117 case ModulePort::Direction::Input:
1119 case ModulePort::Direction::Output:
1121 case ModulePort::Direction::InOut:
1128 return ModulePort::Direction::Input;
1129 if (str ==
"output")
1130 return ModulePort::Direction::Output;
1132 return ModulePort::Direction::InOut;
1133 llvm::report_fatal_error(
"invalid direction");
1139 SmallVectorImpl<ModulePort> &ports) {
1140 return p.parseCommaSeparatedList(
1141 mlir::AsmParser::Delimiter::LessGreater, [&]() -> ParseResult {
1145 if (p.parseKeyword(&dir) || p.parseKeywordOrString(&name) ||
1146 p.parseColon() || p.parseType(type))
1149 {StringAttr::get(p.getContext(), name), type,
strToDir(dir)});
1155static void printPorts(AsmPrinter &p, ArrayRef<ModulePort> ports) {
1157 llvm::interleaveComma(ports, p, [&](
const ModulePort &port) {
1159 p.printKeywordOrString(port.
name.getValue());
1160 p <<
" : " << port.
type;
1165Type ModuleType::parse(AsmParser &odsParser) {
1166 llvm::SmallVector<ModulePort, 4> ports;
1169 return get(odsParser.getContext(), ports);
1172void ModuleType::print(AsmPrinter &odsPrinter)
const {
1177 ArrayRef<Attribute> inputNames,
1178 ArrayRef<Attribute> outputNames) {
1180 cast<FunctionType>(cast<mlir::FunctionOpInterface>(op).getFunctionType()),
1181 inputNames, outputNames);
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});
1194 ports.push_back({cast<StringAttr>(n), t, ModulePort::Direction::Input});
1196 for (
auto t : fnty.getInputs())
1197 if (auto iot = dyn_cast<
hw::InOutType>(t))
1199 {{}, iot.getElementType(), ModulePort::Direction::InOut});
1201 ports.push_back({{}, t, ModulePort::Direction::Input});
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});
1207 for (
auto t : fnty.getResults())
1208 ports.push_back({{}, t, ModulePort::Direction::Output});
1210 return ModuleType::get(fnty.getContext(), ports);
1215 size_t nextInput = 0;
1216 size_t nextOutput = 0;
1217 for (
auto [idx, p] : llvm::enumerate(
ports)) {
1236void HWDialect::registerTypes() {
1238#define GET_TYPEDEF_LIST
1239#include "circt/Dialect/HW/HWTypes.cpp.inc"
assert(baseType &&"element must be base type")
MlirType uint64_t numElements
static ModulePort::Direction strToDir(StringRef str)
static void printPorts(AsmPrinter &p, ArrayRef< ModulePort > ports)
Print out a list of named fields surrounded by <>.
static void printFields(AsmPrinter &p, ArrayRef< FieldInfo > fields)
Print out a list of named fields surrounded by <>.
static StringRef dirToStr(ModulePort::Direction dir)
static ParseResult parseHWArray(AsmParser &parser, Attribute &dim, Type &elementType)
static ParseResult parseHWElementType(AsmParser &parser, Type &elementType)
Parse and print nested HW types nicely.
static ParseResult parsePorts(AsmParser &p, SmallVectorImpl< ModulePort > &ports)
Parse a list of field names and types within <>.
static void printHWArray(AsmPrinter &printer, Attribute dim, Type elementType)
static std::pair< uint64_t, SmallVector< uint64_t > > getFieldIDsStruct(const StructType &st)
static ParseResult parseFields(AsmParser &p, SmallVectorImpl< FieldInfo > ¶meters)
Parse a list of unique field names and types within <>.
static Type computeCanonicalType(Type type)
static void printHWElementType(AsmPrinter &printer, Type dim)
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.
mlir::Operation * getDefinition(mlir::Attribute attr) const override
Lookup a definition for 'symbol' in the cache.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Direction
The direction of a Component or Cell port.
uint64_t getWidth(Type t)
mlir::Type innerType(mlir::Type type)
std::pair< uint64_t, uint64_t > getIndexAndSubfieldID(Type type, uint64_t fieldID)
std::pair<::mlir::Type, uint64_t > getSubTypeByFieldID(Type, uint64_t fieldID)
uint64_t getMaxFieldID(Type)
llvm::hash_code hash_value(const FieldInfo &fi)
bool operator==(const FieldInfo &a, const FieldInfo &b)
ModuleType fnToMod(Operation *op, ArrayRef< Attribute > inputNames, ArrayRef< Attribute > outputNames)
bool isHWIntegerType(mlir::Type type)
Return true if the specified type is a value HW Integer type.
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.
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.
mlir::Type getCanonicalType(mlir::Type type)
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.
Interface for dialects to classify their types as valid probe payloads.
virtual bool isValidProbeElementType(mlir::Type type) const =0
Struct defining a field. Used in structs.
SmallVector< ModulePort > ports
The parametric data held by the storage class.
ModuleTypeStorage(ArrayRef< ModulePort > inPorts)
SmallVector< size_t > absToInput
SmallVector< size_t > outputToAbs
SmallVector< size_t > inputToAbs
SmallVector< size_t > absToOutput
Struct defining a field with an offset. Used in unions.