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))
113 return llvm::TypeSwitch<::mlir::Type, int64_t>(type)
115 [](IntegerType t) {
return t.getIntOrFloatBitWidth(); })
116 .Default([](Type type) -> int64_t {
118 if (
auto iface = dyn_cast<BitWidthTypeInterface>(type)) {
119 std::optional<int64_t> width = iface.getBitWidth();
120 return width.has_value() ? *width : -1;
130 if (
auto array = dyn_cast<ArrayType>(type))
133 if (
auto array = dyn_cast<UnpackedArrayType>(type))
136 if (
auto t = dyn_cast<StructType>(type)) {
137 return std::any_of(t.getElements().begin(), t.getElements().end(),
138 [](
const auto &f) { return hasHWInOutType(f.type); });
141 if (
auto t = dyn_cast<TypeAliasType>(type))
144 return isa<InOutType>(type);
148struct AggregateAttrFrame {
149 SmallVector<Attribute> attrs;
150 SmallVector<Type> types;
153 AggregateAttrFrame(SmallVector<Type> &&types)
154 : attrs(types.size()), types(std::move(types)), remaining(attrs.size()) {}
156 void addChild(Attribute attr) { attrs[--remaining] = attr; }
157 Type getNextChildType() {
return types[remaining - 1]; }
158 bool isFinished()
const {
return remaining == 0; }
168 auto *ctx = aggregateType.getContext();
169 SmallVector<AggregateAttrFrame> stack;
170 auto bitWidth = intVal.getBitWidth();
171 unsigned nextExtraction = 0;
173 auto pushToStack = [&](Type type) ->
bool {
174 return TypeSwitch<Type, bool>(type)
175 .Case<StructType>([&](
auto structType) {
176 auto len = structType.getElements().size();
177 SmallVector<Type> types;
179 for (
auto &element : structType.getElements())
181 stack.push_back(std::move(types));
184 .Case<ArrayType, UnpackedArrayType>([&](
auto arrayType) {
185 SmallVector<Type> types(arrayType.getNumElements(),
187 stack.push_back(std::move(types));
199 while (!stack.empty()) {
200 if (stack.back().isFinished()) {
201 auto frame = stack.pop_back_val();
202 result = ArrayAttr::get(ctx, frame.attrs);
204 stack.back().addChild(result);
208 auto curType = stack.back().getNextChildType();
209 if (
auto intType = dyn_cast<IntegerType>(curType)) {
210 auto width = intType.getWidth();
211 auto elemValue = width ? intVal.extractBits(width, nextExtraction)
212 : APInt(0, 0,
false);
213 nextExtraction += width;
214 stack.back().addChild(IntegerAttr::get(intType, elemValue));
216 if (!pushToStack(curType))
221 assert(nextExtraction == bitWidth &&
"constant wasn't fully processed");
231 SmallVector<Attribute> worklist;
232 worklist.push_back(attr);
233 auto bitWidth = hw::getBitWidth(type);
234 assert(bitWidth >= 0 &&
"bit width must be known for constant");
235 result = APInt(bitWidth, 0);
236 unsigned nextInsertion = 0;
238 while (!worklist.empty()) {
239 auto current = worklist.pop_back_val();
240 if (
auto innerArray = dyn_cast<ArrayAttr>(current)) {
241 worklist.append(innerArray.begin(), innerArray.end());
245 if (
auto intAttr = dyn_cast<IntegerAttr>(current)) {
246 auto chunk = intAttr.getValue();
247 result.insertBits(chunk, nextInsertion);
248 nextInsertion += chunk.getBitWidth();
255 assert(nextInsertion == bitWidth &&
"constant wasn't fully processed");
265 auto fullString =
static_cast<DialectAsmParser &
>(p).getFullSymbolSpec();
266 auto *curPtr = p.getCurrentLocation().getPointer();
268 StringRef(curPtr, fullString.size() - (curPtr - fullString.data()));
270 if (typeString.starts_with(
"array<") || typeString.starts_with(
"inout<") ||
271 typeString.starts_with(
"uarray<") || typeString.starts_with(
"struct<") ||
272 typeString.starts_with(
"typealias<") || typeString.starts_with(
"int<") ||
273 typeString.starts_with(
"enum<") || typeString.starts_with(
"union<")) {
274 llvm::StringRef mnemonic;
275 if (
auto parseResult = generatedTypeParser(p, &mnemonic, result);
276 parseResult.has_value())
278 return p.emitError(p.getNameLoc(),
"invalid type `") << typeString <<
"`";
281 return p.parseType(result);
285 if (succeeded(generatedTypePrinter(element, p)))
287 p.printType(element);
294Type IntType::get(mlir::TypedAttr width) {
296 auto widthWidth = llvm::dyn_cast<IntegerType>(width.getType());
297 assert(widthWidth && widthWidth.getWidth() == 32 &&
298 "!hw.int width must be 32-bits");
301 if (
auto cstWidth = llvm::dyn_cast<IntegerAttr>(width))
302 return IntegerType::get(width.getContext(),
303 cstWidth.getValue().getZExtValue());
305 return Base::get(width.getContext(), width);
308Type IntType::parse(AsmParser &p) {
310 auto int32Type = p.getBuilder().getIntegerType(32);
312 mlir::TypedAttr width;
313 if (p.parseLess() || p.parseAttribute(width, int32Type) || p.parseGreater())
318void IntType::print(AsmPrinter &p)
const {
320 p.printAttributeWithoutType(
getWidth());
335 return llvm::hash_combine(fi.
name, fi.
type);
344 SmallVectorImpl<FieldInfo> ¶meters) {
345 llvm::StringSet<> nameSet;
346 bool hasDuplicateName =
false;
347 auto parseResult = p.parseCommaSeparatedList(
348 mlir::AsmParser::Delimiter::LessGreater, [&]() -> ParseResult {
352 auto fieldLoc = p.getCurrentLocation();
353 if (p.parseKeywordOrString(&name) || p.parseColon() ||
357 if (!nameSet.insert(name).second) {
358 p.emitError(fieldLoc,
"duplicate field name \'" + name +
"\'");
361 hasDuplicateName = true;
364 parameters.push_back(
365 FieldInfo{StringAttr::get(p.getContext(), name), type});
369 if (hasDuplicateName)
375static void printFields(AsmPrinter &p, ArrayRef<FieldInfo> fields) {
377 llvm::interleaveComma(fields, p, [&](
const FieldInfo &field) {
378 p.printKeywordOrString(field.
name.getValue());
379 p <<
": " << field.
type;
384Type StructType::parse(AsmParser &p) {
385 llvm::SmallVector<FieldInfo, 4> parameters;
388 return get(p.getContext(), parameters);
391LogicalResult StructType::verify(function_ref<InFlightDiagnostic()> emitError,
392 ArrayRef<StructType::FieldInfo> elements) {
393 llvm::SmallDenseSet<StringAttr> fieldNameSet;
394 LogicalResult result = success();
395 fieldNameSet.reserve(elements.size());
396 for (
const auto &elt : elements)
397 if (!fieldNameSet.insert(elt.name).second) {
399 emitError() <<
"duplicate field name '" << elt.name.getValue()
400 <<
"' in hw.struct type";
405void StructType::print(AsmPrinter &p)
const {
printFields(p, getElements()); }
407Type StructType::getFieldType(mlir::StringRef fieldName) {
408 for (
const auto &field : getElements())
409 if (field.name == fieldName)
414std::optional<uint32_t> StructType::getFieldIndex(mlir::StringRef fieldName) {
415 ArrayRef<hw::StructType::FieldInfo> elems = getElements();
416 for (
size_t idx = 0, numElems = elems.size(); idx < numElems; ++idx)
417 if (elems[idx].name == fieldName)
422std::optional<uint32_t> StructType::getFieldIndex(mlir::StringAttr fieldName) {
423 ArrayRef<hw::StructType::FieldInfo> elems = getElements();
424 for (
size_t idx = 0, numElems = elems.size(); idx < numElems; ++idx)
425 if (elems[idx].name == fieldName)
430static std::pair<uint64_t, SmallVector<uint64_t>>
432 uint64_t fieldID = 0;
433 auto elements = st.getElements();
434 SmallVector<uint64_t> fieldIDs;
435 fieldIDs.reserve(elements.size());
436 for (
auto &element : elements) {
437 auto type = element.type;
439 fieldIDs.push_back(fieldID);
443 return {fieldID, fieldIDs};
446void StructType::getInnerTypes(SmallVectorImpl<Type> &types) {
447 for (
const auto &field : getElements())
448 types.push_back(field.type);
451uint64_t StructType::getMaxFieldID()
const {
452 uint64_t fieldID = 0;
453 for (
const auto &field : getElements())
458std::pair<Type, uint64_t>
459StructType::getSubTypeByFieldID(uint64_t fieldID)
const {
463 auto *it = std::prev(llvm::upper_bound(fieldIDs, fieldID));
464 auto subfieldIndex = std::distance(fieldIDs.begin(), it);
465 auto subfieldType = getElements()[subfieldIndex].type;
466 auto subfieldID = fieldID - fieldIDs[subfieldIndex];
467 return {subfieldType, subfieldID};
470std::pair<uint64_t, bool>
471StructType::projectToChildFieldID(uint64_t fieldID, uint64_t index)
const {
473 auto childRoot = fieldIDs[index];
475 index + 1 >= getElements().size() ? maxId : (fieldIDs[index + 1] - 1);
476 return std::make_pair(fieldID - childRoot,
477 fieldID >= childRoot && fieldID <= rangeEnd);
480uint64_t StructType::getFieldID(uint64_t index)
const {
482 return fieldIDs[index];
485uint64_t StructType::getIndexForFieldID(uint64_t fieldID)
const {
486 assert(!getElements().
empty() &&
"Bundle must have >0 fields");
488 auto *it = std::prev(llvm::upper_bound(fieldIDs, fieldID));
489 return std::distance(fieldIDs.begin(), it);
492std::pair<uint64_t, uint64_t>
493StructType::getIndexAndSubfieldID(uint64_t fieldID)
const {
496 return {index, fieldID - elementFieldID};
499std::optional<DenseMap<Attribute, Type>>
500hw::StructType::getSubelementIndexMap()
const {
501 DenseMap<Attribute, Type> destructured;
502 for (
auto [i, field] :
llvm::enumerate(getElements()))
504 {IntegerAttr::get(IndexType::get(getContext()), i), field.type});
508Type hw::StructType::getTypeAtIndex(Attribute index)
const {
509 auto indexAttr = llvm::dyn_cast<IntegerAttr>(index);
516std::optional<int64_t> StructType::getBitWidth()
const {
518 for (
auto field : getElements()) {
519 int64_t fieldSize = hw::getBitWidth(field.type);
545Type UnionType::parse(AsmParser &p) {
546 llvm::SmallVector<FieldInfo, 4> parameters;
547 llvm::StringSet<> nameSet;
548 bool hasDuplicateName =
false;
549 if (p.parseCommaSeparatedList(
550 mlir::AsmParser::Delimiter::LessGreater, [&]() -> ParseResult {
554 auto fieldLoc = p.getCurrentLocation();
555 if (p.parseKeyword(&name) || p.parseColon() || p.parseType(type))
558 if (!nameSet.insert(name).second) {
559 p.emitError(fieldLoc,
"duplicate field name \'" + name +
560 "\' in hw.union type");
563 hasDuplicateName = true;
567 if (succeeded(p.parseOptionalKeyword(
"offset")))
568 if (p.parseInteger(offset))
570 parameters.push_back(UnionType::FieldInfo{
571 StringAttr::get(p.getContext(), name), type, offset});
576 if (hasDuplicateName)
579 return get(p.getContext(), parameters);
582void UnionType::print(AsmPrinter &odsPrinter)
const {
584 llvm::interleaveComma(
585 getElements(), odsPrinter, [&](
const UnionType::FieldInfo &field) {
586 odsPrinter << field.name.getValue() <<
": " << field.type;
588 odsPrinter <<
" offset " << field.offset;
593LogicalResult UnionType::verify(function_ref<InFlightDiagnostic()> emitError,
594 ArrayRef<UnionType::FieldInfo> elements) {
595 llvm::SmallDenseSet<StringAttr> fieldNameSet;
596 LogicalResult result = success();
597 fieldNameSet.reserve(elements.size());
598 for (
const auto &elt : elements)
599 if (!fieldNameSet.insert(elt.name).second) {
601 emitError() <<
"duplicate field name '" << elt.name.getValue()
602 <<
"' in hw.union type";
607std::optional<uint32_t> UnionType::getFieldIndex(mlir::StringAttr fieldName) {
608 ArrayRef<hw::UnionType::FieldInfo> elems = getElements();
609 for (
size_t idx = 0, numElems = elems.size(); idx < numElems; ++idx)
610 if (elems[idx].name == fieldName)
615std::optional<uint32_t> UnionType::getFieldIndex(mlir::StringRef fieldName) {
616 return getFieldIndex(StringAttr::get(getContext(), fieldName));
619UnionType::FieldInfo UnionType::getFieldInfo(::mlir::StringRef fieldName) {
620 if (
auto fieldIndex = getFieldIndex(fieldName))
621 return getElements()[*fieldIndex];
625Type UnionType::getFieldType(mlir::StringRef fieldName) {
626 return getFieldInfo(fieldName).type;
629std::optional<int64_t> UnionType::getBitWidth()
const {
631 for (
auto field : getElements()) {
632 int64_t fieldSize = hw::getBitWidth(field.type);
635 fieldSize += field.offset;
636 if (fieldSize > maxSize)
646Type EnumType::parse(AsmParser &p) {
647 llvm::SmallVector<Attribute> fields;
649 if (p.parseCommaSeparatedList(AsmParser::Delimiter::LessGreater, [&]() {
651 if (p.parseKeyword(&name))
653 fields.push_back(StringAttr::get(p.getContext(), name));
658 return get(p.getContext(), ArrayAttr::get(p.getContext(), fields));
661void EnumType::print(AsmPrinter &p)
const {
663 llvm::interleaveComma(getFields(), p, [&](Attribute enumerator) {
664 p << llvm::cast<StringAttr>(enumerator).getValue();
669bool EnumType::contains(mlir::StringRef field) {
670 return indexOf(field).has_value();
673std::optional<size_t> EnumType::indexOf(mlir::StringRef field) {
674 for (
auto it :
llvm::enumerate(getFields()))
675 if (
llvm::cast<StringAttr>(it.value()).getValue() == field)
680std::optional<int64_t> EnumType::getBitWidth()
const {
681 auto w = getFields().size();
683 return llvm::Log2_64_Ceil(w);
691static ParseResult
parseHWArray(AsmParser &p, Attribute &dim, Type &inner) {
693 auto int64Type = p.getBuilder().getIntegerType(64);
695 if (
auto res = p.parseOptionalInteger(dimLiteral); res.has_value()) {
698 dim = p.getBuilder().getI64IntegerAttr(dimLiteral);
699 }
else if (
auto res64 = p.parseOptionalAttribute(dim, int64Type);
704 return p.emitError(p.getNameLoc(),
"expected integer");
706 if (!isa<IntegerAttr, ParamExprAttr, ParamDeclRefAttr>(dim)) {
707 p.emitError(p.getNameLoc(),
"unsupported dimension kind in hw.array");
718 p.printAttributeWithoutType(dim);
723size_t ArrayType::getNumElements()
const {
724 if (
auto intAttr = llvm::dyn_cast<IntegerAttr>(getSizeAttr()))
725 return intAttr.getInt();
729LogicalResult ArrayType::verify(function_ref<InFlightDiagnostic()> emitError,
730 Type innerType, Attribute size) {
732 return emitError() <<
"hw.array cannot contain InOut types";
736uint64_t ArrayType::getMaxFieldID()
const {
737 return getNumElements() *
741std::pair<Type, uint64_t>
742ArrayType::getSubTypeByFieldID(uint64_t fieldID)
const {
748std::pair<uint64_t, bool>
749ArrayType::projectToChildFieldID(uint64_t fieldID, uint64_t index)
const {
753 return std::make_pair(fieldID - childRoot,
754 fieldID >= childRoot && fieldID <= rangeEnd);
757uint64_t ArrayType::getIndexForFieldID(uint64_t fieldID)
const {
758 assert(fieldID &&
"fieldID must be at least 1");
763std::pair<uint64_t, uint64_t>
764ArrayType::getIndexAndSubfieldID(uint64_t fieldID)
const {
767 return {index, fieldID - elementFieldID};
770uint64_t ArrayType::getFieldID(uint64_t index)
const {
774std::optional<DenseMap<Attribute, Type>>
775hw::ArrayType::getSubelementIndexMap()
const {
776 DenseMap<Attribute, Type> destructured;
777 for (
unsigned i = 0; i < getNumElements(); ++i)
779 {IntegerAttr::get(IndexType::get(getContext()), i), getElementType()});
783Type hw::ArrayType::getTypeAtIndex(Attribute index)
const {
784 return getElementType();
787std::optional<int64_t> hw::ArrayType::getBitWidth()
const {
788 auto elementBitWidth = hw::getBitWidth(getElementType());
789 if (elementBitWidth < 0)
802UnpackedArrayType::verify(function_ref<InFlightDiagnostic()> emitError,
803 Type innerType, Attribute size) {
805 return emitError() <<
"invalid element for uarray type";
809size_t UnpackedArrayType::getNumElements()
const {
810 if (
auto intAttr = llvm::dyn_cast<IntegerAttr>(getSizeAttr()))
811 return intAttr.getInt();
815uint64_t UnpackedArrayType::getMaxFieldID()
const {
816 return getNumElements() *
820std::pair<Type, uint64_t>
821UnpackedArrayType::getSubTypeByFieldID(uint64_t fieldID)
const {
827std::pair<uint64_t, bool>
828UnpackedArrayType::projectToChildFieldID(uint64_t fieldID,
829 uint64_t index)
const {
833 return std::make_pair(fieldID - childRoot,
834 fieldID >= childRoot && fieldID <= rangeEnd);
837uint64_t UnpackedArrayType::getIndexForFieldID(uint64_t fieldID)
const {
838 assert(fieldID &&
"fieldID must be at least 1");
843std::pair<uint64_t, uint64_t>
844UnpackedArrayType::getIndexAndSubfieldID(uint64_t fieldID)
const {
847 return {index, fieldID - elementFieldID};
850uint64_t UnpackedArrayType::getFieldID(uint64_t index)
const {
854std::optional<int64_t> UnpackedArrayType::getBitWidth()
const {
855 auto elementBitWidth = hw::getBitWidth(getElementType());
856 if (elementBitWidth < 0)
858 int64_t dimBitWidth = getNumElements();
861 return (int64_t)getNumElements() * elementBitWidth;
868LogicalResult InOutType::verify(function_ref<InFlightDiagnostic()> emitError,
871 return emitError() <<
"invalid element for hw.inout type " <<
innerType;
880 return llvm::TypeSwitch<Type, Type>(type)
881 .Case([](TypeAliasType t) {
884 .Case([](ArrayType t) {
888 .Case([](UnpackedArrayType t) {
892 .Case([](StructType t) {
893 SmallVector<StructType::FieldInfo> fieldInfo;
894 for (
auto field : t.getElements())
895 fieldInfo.push_back(StructType::FieldInfo{
897 return StructType::get(t.getContext(), fieldInfo);
899 .Default([](Type t) {
return t; });
902TypeAliasType TypeAliasType::get(SymbolRefAttr ref, Type innerType) {
906Type TypeAliasType::parse(AsmParser &p) {
909 if (p.parseLess() || p.parseAttribute(ref) || p.parseComma() ||
910 p.parseType(type) || p.parseGreater())
913 return get(ref, type);
916void TypeAliasType::print(AsmPrinter &p)
const {
917 p <<
"<" << getRef() <<
", " << getInnerType() <<
">";
922TypedeclOp TypeAliasType::getTypeDecl(
const HWSymbolCache &cache) {
923 SymbolRefAttr ref = getRef();
924 auto typeScope = ::dyn_cast_or_null<TypeScopeOp>(
929 return typeScope.lookupSymbol<TypedeclOp>(ref.getLeafReference());
932std::optional<int64_t> TypeAliasType::getBitWidth()
const {
943LogicalResult ModuleType::verify(function_ref<InFlightDiagnostic()> emitError,
944 ArrayRef<ModulePort> ports) {
945 if (llvm::any_of(ports, [](
const ModulePort &port) {
948 return emitError() <<
"Ports cannot be inout types";
952size_t ModuleType::getPortIdForInputId(
size_t idx) {
953 assert(idx < getImpl()->inputToAbs.size() &&
"input port out of range");
954 return getImpl()->inputToAbs[idx];
957size_t ModuleType::getPortIdForOutputId(
size_t idx) {
958 assert(idx < getImpl()->outputToAbs.size() &&
" output port out of range");
959 return getImpl()->outputToAbs[idx];
962size_t ModuleType::getInputIdForPortId(
size_t idx) {
963 auto nIdx = getImpl()->absToInput[idx];
968size_t ModuleType::getOutputIdForPortId(
size_t idx) {
969 auto nIdx = getImpl()->absToOutput[idx];
974size_t ModuleType::getNumInputs() {
return getImpl()->inputToAbs.size(); }
976size_t ModuleType::getNumOutputs() {
return getImpl()->outputToAbs.size(); }
978size_t ModuleType::getNumPorts() {
return getPorts().size(); }
980SmallVector<Type> ModuleType::getInputTypes() {
981 SmallVector<Type> retval;
982 for (
auto &p : getPorts()) {
983 if (p.dir == ModulePort::Direction::Input)
984 retval.push_back(p.type);
985 else if (p.dir == ModulePort::Direction::InOut) {
986 retval.push_back(hw::InOutType::get(p.type));
992SmallVector<Type> ModuleType::getOutputTypes() {
993 SmallVector<Type> retval;
994 for (
auto &p : getPorts())
996 retval.push_back(p.type);
1000SmallVector<Type> ModuleType::getPortTypes() {
1001 SmallVector<Type> retval;
1002 for (
auto &p : getPorts())
1003 retval.push_back(p.type);
1007Type ModuleType::getInputType(
size_t idx) {
1008 const auto &portInfo = getPorts()[getPortIdForInputId(idx)];
1010 return portInfo.type;
1011 return InOutType::get(portInfo.type);
1014Type ModuleType::getOutputType(
size_t idx) {
1015 return getPorts()[getPortIdForOutputId(idx)].type;
1018SmallVector<Attribute> ModuleType::getInputNames() {
1019 SmallVector<Attribute> retval;
1020 for (
auto &p : getPorts())
1022 retval.push_back(p.name);
1026SmallVector<Attribute> ModuleType::getOutputNames() {
1027 SmallVector<Attribute> retval;
1028 for (
auto &p : getPorts())
1030 retval.push_back(p.name);
1034StringAttr ModuleType::getPortNameAttr(
size_t idx) {
1035 return getPorts()[idx].name;
1038StringRef ModuleType::getPortName(
size_t idx) {
1039 auto sa = getPortNameAttr(idx);
1041 return sa.getValue();
1045StringAttr ModuleType::getInputNameAttr(
size_t idx) {
1046 return getPorts()[getPortIdForInputId(idx)].name;
1049StringRef ModuleType::getInputName(
size_t idx) {
1050 auto sa = getInputNameAttr(idx);
1052 return sa.getValue();
1056StringAttr ModuleType::getOutputNameAttr(
size_t idx) {
1057 return getPorts()[getPortIdForOutputId(idx)].name;
1060StringRef ModuleType::getOutputName(
size_t idx) {
1061 auto sa = getOutputNameAttr(idx);
1063 return sa.getValue();
1067bool ModuleType::isOutput(
size_t idx) {
1068 auto &p = getPorts()[idx];
1069 return p.dir == ModulePort::Direction::Output;
1072FunctionType ModuleType::getFuncType() {
1073 SmallVector<Type> inputs, outputs;
1074 for (
auto p : getPorts())
1076 inputs.push_back(p.type);
1078 inputs.push_back(InOutType::get(p.type));
1080 outputs.push_back(p.type);
1081 return FunctionType::get(getContext(), inputs, outputs);
1084ArrayRef<ModulePort> ModuleType::getPorts()
const {
1085 return getImpl()->getPorts();
1088FailureOr<ModuleType> ModuleType::resolveParametricTypes(ArrayAttr parameters,
1091 SmallVector<ModulePort, 8> resolvedPorts;
1093 FailureOr<Type> resolvedType =
1095 if (failed(resolvedType))
1097 port.type = *resolvedType;
1098 resolvedPorts.push_back(port);
1100 return ModuleType::get(getContext(), resolvedPorts);
1105 case ModulePort::Direction::Input:
1107 case ModulePort::Direction::Output:
1109 case ModulePort::Direction::InOut:
1116 return ModulePort::Direction::Input;
1117 if (str ==
"output")
1118 return ModulePort::Direction::Output;
1120 return ModulePort::Direction::InOut;
1121 llvm::report_fatal_error(
"invalid direction");
1127 SmallVectorImpl<ModulePort> &ports) {
1128 return p.parseCommaSeparatedList(
1129 mlir::AsmParser::Delimiter::LessGreater, [&]() -> ParseResult {
1133 if (p.parseKeyword(&dir) || p.parseKeywordOrString(&name) ||
1134 p.parseColon() || p.parseType(type))
1137 {StringAttr::get(p.getContext(), name), type,
strToDir(dir)});
1143static void printPorts(AsmPrinter &p, ArrayRef<ModulePort> ports) {
1145 llvm::interleaveComma(ports, p, [&](
const ModulePort &port) {
1147 p.printKeywordOrString(port.
name.getValue());
1148 p <<
" : " << port.
type;
1153Type ModuleType::parse(AsmParser &odsParser) {
1154 llvm::SmallVector<ModulePort, 4> ports;
1157 return get(odsParser.getContext(), ports);
1160void ModuleType::print(AsmPrinter &odsPrinter)
const {
1165 ArrayRef<Attribute> inputNames,
1166 ArrayRef<Attribute> outputNames) {
1168 cast<FunctionType>(cast<mlir::FunctionOpInterface>(op).getFunctionType()),
1169 inputNames, outputNames);
1173 ArrayRef<Attribute> inputNames,
1174 ArrayRef<Attribute> outputNames) {
1175 SmallVector<ModulePort> ports;
1176 if (!inputNames.empty()) {
1177 for (
auto [t, n] : llvm::zip_equal(fnty.getInputs(), inputNames))
1178 if (
auto iot = dyn_cast<hw::InOutType>(t))
1179 ports.push_back({cast<StringAttr>(n), iot.getElementType(),
1180 ModulePort::Direction::InOut});
1182 ports.push_back({cast<StringAttr>(n), t, ModulePort::Direction::Input});
1184 for (
auto t : fnty.getInputs())
1185 if (auto iot = dyn_cast<
hw::InOutType>(t))
1187 {{}, iot.getElementType(), ModulePort::Direction::InOut});
1189 ports.push_back({{}, t, ModulePort::Direction::Input});
1191 if (!outputNames.empty()) {
1192 for (
auto [t, n] :
llvm::zip_equal(fnty.getResults(), outputNames))
1193 ports.push_back({cast<StringAttr>(n), t, ModulePort::Direction::Output});
1195 for (
auto t : fnty.getResults())
1196 ports.push_back({{}, t, ModulePort::Direction::Output});
1198 return ModuleType::get(fnty.getContext(), ports);
1203 size_t nextInput = 0;
1204 size_t nextOutput = 0;
1205 for (
auto [idx, p] : llvm::enumerate(
ports)) {
1224void HWDialect::registerTypes() {
1226#define GET_TYPEDEF_LIST
1227#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 ...
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.
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.