19#include "mlir/IR/AttrTypeSubElements.h"
20#include "mlir/IR/Builders.h"
21#include "mlir/IR/BuiltinTypes.h"
22#include "mlir/IR/Diagnostics.h"
23#include "mlir/IR/DialectImplementation.h"
24#include "mlir/IR/StorageUniquerSupport.h"
25#include "mlir/IR/Types.h"
26#include "mlir/Interfaces/MemorySlotInterfaces.h"
27#include "llvm/ADT/SmallSet.h"
28#include "llvm/ADT/StringExtras.h"
29#include "llvm/ADT/StringSet.h"
30#include "llvm/ADT/TypeSwitch.h"
36static ParseResult
parseHWArray(AsmParser &parser, Attribute &dim,
43#define GET_TYPEDEF_CLASSES
44#include "circt/Dialect/HW/HWTypes.cpp.inc"
51 mlir::AttrTypeReplacer replacer;
52 replacer.addReplacement(
53 [](TypeAliasType alias) {
return alias.getCanonicalType(); });
54 return replacer.replace(type);
62 if (isa<hw::IntType>(canonicalType))
65 auto intType = dyn_cast<IntegerType>(canonicalType);
66 if (!intType || !intType.isSignless())
81 if (isa<IntegerType, IntType, EnumType>(type))
84 if (
auto array = dyn_cast<ArrayType>(type))
87 if (
auto array = dyn_cast<UnpackedArrayType>(type))
90 if (
auto t = dyn_cast<StructType>(type))
91 return llvm::all_of(t.getElements(),
92 [](
auto f) { return isHWValueType(f.type); });
94 if (
auto t = dyn_cast<UnionType>(type))
95 return llvm::all_of(t.getElements(),
96 [](
auto f) { return isHWValueType(f.type); });
98 if (
auto t = dyn_cast<TypeAliasType>(type))
108 if (isa<IntegerType>(type))
124 return llvm::TypeSwitch<::mlir::Type, int64_t>(type)
126 [](IntegerType t) {
return t.getIntOrFloatBitWidth(); })
127 .Default([](Type type) -> int64_t {
129 if (
auto iface = dyn_cast<BitWidthTypeInterface>(type)) {
130 std::optional<int64_t> width = iface.getBitWidth();
131 return width.has_value() ? *width : -1;
141 if (
auto array = dyn_cast<ArrayType>(type))
144 if (
auto array = dyn_cast<UnpackedArrayType>(type))
147 if (
auto t = dyn_cast<StructType>(type)) {
148 return std::any_of(t.getElements().begin(), t.getElements().end(),
149 [](
const auto &f) { return hasHWInOutType(f.type); });
152 if (
auto t = dyn_cast<TypeAliasType>(type))
155 return isa<InOutType>(type);
159struct AggregateAttrFrame {
160 SmallVector<Attribute> attrs;
161 SmallVector<Type> types;
164 AggregateAttrFrame(SmallVector<Type> &&types)
165 : attrs(types.size()), types(std::move(types)), remaining(attrs.size()) {}
167 void addChild(Attribute attr) { attrs[--remaining] = attr; }
168 Type getNextChildType() {
return types[remaining - 1]; }
169 bool isFinished()
const {
return remaining == 0; }
179 auto *ctx = aggregateType.getContext();
180 SmallVector<AggregateAttrFrame> stack;
181 unsigned nextExtraction = 0;
183 auto pushToStack = [&](Type type) ->
bool {
184 return TypeSwitch<Type, bool>(type)
185 .Case<StructType>([&](
auto structType) {
186 auto len = structType.getElements().size();
187 SmallVector<Type> types;
189 for (
auto &element : structType.getElements())
191 stack.push_back(std::move(types));
194 .Case<ArrayType, UnpackedArrayType>([&](
auto arrayType) {
195 SmallVector<Type> types(arrayType.getNumElements(),
197 stack.push_back(std::move(types));
209 while (!stack.empty()) {
210 if (stack.back().isFinished()) {
211 auto frame = stack.pop_back_val();
212 result = ArrayAttr::get(ctx, frame.attrs);
214 stack.back().addChild(result);
218 auto curType = stack.back().getNextChildType();
219 if (
auto intType = dyn_cast<IntegerType>(curType)) {
220 auto width = intType.getWidth();
221 auto elemValue = width ? intVal.extractBits(width, nextExtraction)
222 : APInt(0, 0,
false);
223 nextExtraction += width;
224 stack.back().addChild(IntegerAttr::get(intType, elemValue));
226 if (!pushToStack(curType))
231 assert(nextExtraction == intVal.getBitWidth() &&
232 "constant wasn't fully processed");
242 SmallVector<Attribute> worklist;
243 worklist.push_back(attr);
244 auto bitWidth = hw::getBitWidth(type);
245 assert(bitWidth >= 0 &&
"bit width must be known for constant");
246 result = APInt(bitWidth, 0);
247 unsigned nextInsertion = 0;
249 while (!worklist.empty()) {
250 auto current = worklist.pop_back_val();
251 if (
auto innerArray = dyn_cast<ArrayAttr>(current)) {
252 worklist.append(innerArray.begin(), innerArray.end());
256 if (
auto intAttr = dyn_cast<IntegerAttr>(current)) {
257 auto chunk = intAttr.getValue();
258 result.insertBits(chunk, nextInsertion);
259 nextInsertion += chunk.getBitWidth();
266 assert(nextInsertion == bitWidth &&
"constant wasn't fully processed");
276 auto fullString =
static_cast<DialectAsmParser &
>(p).getFullSymbolSpec();
277 auto *curPtr = p.getCurrentLocation().getPointer();
279 StringRef(curPtr, fullString.size() - (curPtr - fullString.data()));
281 if (typeString.starts_with(
"array<") || typeString.starts_with(
"inout<") ||
282 typeString.starts_with(
"uarray<") || typeString.starts_with(
"struct<") ||
283 typeString.starts_with(
"typealias<") || typeString.starts_with(
"int<") ||
284 typeString.starts_with(
"enum<") || typeString.starts_with(
"union<")) {
285 llvm::StringRef mnemonic;
286 if (
auto parseResult = generatedTypeParser(p, &mnemonic, result);
287 parseResult.has_value())
289 return p.emitError(p.getNameLoc(),
"invalid type `") << typeString <<
"`";
292 return p.parseType(result);
296 if (succeeded(generatedTypePrinter(element, p)))
298 p.printType(element);
305Type IntType::get(mlir::TypedAttr width) {
307 auto widthWidth = llvm::dyn_cast<IntegerType>(width.getType());
308 assert(widthWidth && widthWidth.getWidth() == 32 &&
309 "!hw.int width must be 32-bits");
312 if (
auto cstWidth = llvm::dyn_cast<IntegerAttr>(width))
313 return IntegerType::get(width.getContext(),
314 cstWidth.getValue().getZExtValue());
316 return Base::get(width.getContext(), width);
319Type IntType::parse(AsmParser &p) {
321 auto int32Type = p.getBuilder().getIntegerType(32);
323 mlir::TypedAttr width;
324 if (p.parseLess() || p.parseAttribute(width, int32Type) || p.parseGreater())
329void IntType::print(AsmPrinter &p)
const {
331 p.printAttributeWithoutType(
getWidth());
339Type StructType::parse(AsmParser &p) {
340 llvm::SmallVector<FieldInfo, 4> parameters;
341 SmallVector<std::pair<llvm::SMLoc, StringAttr>> duplicates;
343 for (
auto [loc, name] : duplicates)
344 p.emitError(loc) <<
"duplicate field name '" << name.getValue() <<
"'";
345 if (failed(parseResult) || !duplicates.empty())
347 return get(p.getContext(), parameters);
350LogicalResult StructType::verify(function_ref<InFlightDiagnostic()> emitError,
351 ArrayRef<StructType::FieldInfo> elements) {
352 llvm::SmallDenseSet<StringAttr> fieldNameSet;
353 LogicalResult result = success();
354 fieldNameSet.reserve(elements.size());
355 for (
const auto &elt : elements)
356 if (!fieldNameSet.insert(elt.name).second) {
358 emitError() <<
"duplicate field name '" << elt.name.getValue()
359 <<
"' in hw.struct type";
364void StructType::print(AsmPrinter &p)
const {
368Type StructType::getFieldType(mlir::StringRef fieldName) {
369 for (
const auto &field : getElements())
370 if (field.name == fieldName)
375std::optional<uint32_t> StructType::getFieldIndex(mlir::StringRef fieldName) {
376 ArrayRef<hw::StructType::FieldInfo> elems = getElements();
377 for (
size_t idx = 0, numElems = elems.size(); idx < numElems; ++idx)
378 if (elems[idx].name == fieldName)
383std::optional<uint32_t> StructType::getFieldIndex(mlir::StringAttr fieldName) {
384 ArrayRef<hw::StructType::FieldInfo> elems = getElements();
385 for (
size_t idx = 0, numElems = elems.size(); idx < numElems; ++idx)
386 if (elems[idx].name == fieldName)
391static std::pair<uint64_t, SmallVector<uint64_t>>
393 uint64_t fieldID = 0;
394 auto elements = st.getElements();
395 SmallVector<uint64_t> fieldIDs;
396 fieldIDs.reserve(elements.size());
397 for (
auto &element : elements) {
398 auto type = element.type;
400 fieldIDs.push_back(fieldID);
404 return {fieldID, fieldIDs};
407void StructType::getInnerTypes(SmallVectorImpl<Type> &types) {
408 for (
const auto &field : getElements())
409 types.push_back(field.type);
412uint64_t StructType::getMaxFieldID()
const {
413 uint64_t fieldID = 0;
414 for (
const auto &field : getElements())
419std::pair<Type, uint64_t>
420StructType::getSubTypeByFieldID(uint64_t fieldID)
const {
424 auto *it = std::prev(llvm::upper_bound(fieldIDs, fieldID));
425 auto subfieldIndex = std::distance(fieldIDs.begin(), it);
426 auto subfieldType = getElements()[subfieldIndex].type;
427 auto subfieldID = fieldID - fieldIDs[subfieldIndex];
428 return {subfieldType, subfieldID};
431std::pair<uint64_t, bool>
432StructType::projectToChildFieldID(uint64_t fieldID, uint64_t index)
const {
434 auto childRoot = fieldIDs[index];
436 index + 1 >= getElements().size() ? maxId : (fieldIDs[index + 1] - 1);
437 return std::make_pair(fieldID - childRoot,
438 fieldID >= childRoot && fieldID <= rangeEnd);
441uint64_t StructType::getFieldID(uint64_t index)
const {
443 return fieldIDs[index];
446uint64_t StructType::getIndexForFieldID(uint64_t fieldID)
const {
447 assert(!getElements().
empty() &&
"Bundle must have >0 fields");
449 auto *it = std::prev(llvm::upper_bound(fieldIDs, fieldID));
450 return std::distance(fieldIDs.begin(), it);
453std::pair<uint64_t, uint64_t>
454StructType::getIndexAndSubfieldID(uint64_t fieldID)
const {
457 return {index, fieldID - elementFieldID};
460std::optional<DenseMap<Attribute, Type>>
461hw::StructType::getSubelementIndexMap()
const {
462 DenseMap<Attribute, Type> destructured;
463 for (
auto [i, field] :
llvm::enumerate(getElements()))
465 {IntegerAttr::get(IndexType::get(getContext()), i), field.type});
469Type hw::StructType::getTypeAtIndex(Attribute index)
const {
470 auto indexAttr = llvm::dyn_cast<IntegerAttr>(index);
477std::optional<int64_t> StructType::getBitWidth()
const {
479 for (
auto field : getElements()) {
480 int64_t fieldSize = hw::getBitWidth(field.type);
506Type UnionType::parse(AsmParser &p) {
507 llvm::SmallVector<FieldInfo, 4> parameters;
508 llvm::StringSet<> nameSet;
509 bool hasDuplicateName =
false;
510 if (p.parseCommaSeparatedList(
511 mlir::AsmParser::Delimiter::LessGreater, [&]() -> ParseResult {
515 auto fieldLoc = p.getCurrentLocation();
516 if (p.parseKeyword(&name) || p.parseColon() || p.parseType(type))
519 if (!nameSet.insert(name).second) {
520 p.emitError(fieldLoc,
"duplicate field name \'" + name +
521 "\' in hw.union type");
524 hasDuplicateName = true;
528 if (succeeded(p.parseOptionalKeyword(
"offset")))
529 if (p.parseInteger(offset))
531 parameters.push_back(UnionType::FieldInfo{
532 StringAttr::get(p.getContext(), name), type, offset});
537 if (hasDuplicateName)
540 return get(p.getContext(), parameters);
543void UnionType::print(AsmPrinter &odsPrinter)
const {
545 llvm::interleaveComma(
546 getElements(), odsPrinter, [&](
const UnionType::FieldInfo &field) {
547 odsPrinter << field.name.getValue() <<
": " << field.type;
549 odsPrinter <<
" offset " << field.offset;
554LogicalResult UnionType::verify(function_ref<InFlightDiagnostic()> emitError,
555 ArrayRef<UnionType::FieldInfo> elements) {
556 llvm::SmallDenseSet<StringAttr> fieldNameSet;
557 LogicalResult result = success();
558 fieldNameSet.reserve(elements.size());
559 for (
const auto &elt : elements)
560 if (!fieldNameSet.insert(elt.name).second) {
562 emitError() <<
"duplicate field name '" << elt.name.getValue()
563 <<
"' in hw.union type";
568std::optional<uint32_t> UnionType::getFieldIndex(mlir::StringAttr fieldName) {
569 ArrayRef<hw::UnionType::FieldInfo> elems = getElements();
570 for (
size_t idx = 0, numElems = elems.size(); idx < numElems; ++idx)
571 if (elems[idx].name == fieldName)
576std::optional<uint32_t> UnionType::getFieldIndex(mlir::StringRef fieldName) {
577 return getFieldIndex(StringAttr::get(getContext(), fieldName));
580UnionType::FieldInfo UnionType::getFieldInfo(::mlir::StringRef fieldName) {
581 if (
auto fieldIndex = getFieldIndex(fieldName))
582 return getElements()[*fieldIndex];
586Type UnionType::getFieldType(mlir::StringRef fieldName) {
587 return getFieldInfo(fieldName).type;
590std::optional<int64_t> UnionType::getBitWidth()
const {
592 for (
auto field : getElements()) {
593 int64_t fieldSize = hw::getBitWidth(field.type);
596 fieldSize += field.offset;
597 if (fieldSize > maxSize)
607Type EnumType::parse(AsmParser &p) {
608 llvm::SmallVector<Attribute> fields;
610 if (p.parseCommaSeparatedList(AsmParser::Delimiter::LessGreater, [&]() {
612 if (p.parseKeyword(&name))
614 fields.push_back(StringAttr::get(p.getContext(), name));
619 return get(p.getContext(), ArrayAttr::get(p.getContext(), fields));
622void EnumType::print(AsmPrinter &p)
const {
624 llvm::interleaveComma(getFields(), p, [&](Attribute enumerator) {
625 p << llvm::cast<StringAttr>(enumerator).getValue();
630bool EnumType::contains(mlir::StringRef field) {
631 return indexOf(field).has_value();
634std::optional<size_t> EnumType::indexOf(mlir::StringRef field) {
635 for (
auto it :
llvm::enumerate(getFields()))
636 if (
llvm::cast<StringAttr>(it.value()).getValue() == field)
641std::optional<int64_t> EnumType::getBitWidth()
const {
642 auto w = getFields().size();
644 return llvm::Log2_64_Ceil(w);
652static ParseResult
parseHWArray(AsmParser &p, Attribute &dim, Type &inner) {
654 auto int64Type = p.getBuilder().getIntegerType(64);
656 if (
auto res = p.parseOptionalInteger(dimLiteral); res.has_value()) {
659 dim = p.getBuilder().getI64IntegerAttr(dimLiteral);
660 }
else if (
auto res64 = p.parseOptionalAttribute(dim, int64Type);
665 return p.emitError(p.getNameLoc(),
"expected integer");
667 if (!isa<IntegerAttr, ParamExprAttr, ParamDeclRefAttr>(dim)) {
668 p.emitError(p.getNameLoc(),
"unsupported dimension kind in hw.array");
679 p.printAttributeWithoutType(dim);
684size_t ArrayType::getNumElements()
const {
685 if (
auto intAttr = llvm::dyn_cast<IntegerAttr>(getSizeAttr()))
686 return intAttr.getInt();
690LogicalResult ArrayType::verify(function_ref<InFlightDiagnostic()> emitError,
691 Type innerType, Attribute size) {
693 return emitError() <<
"hw.array cannot contain InOut types";
697uint64_t ArrayType::getMaxFieldID()
const {
698 return getNumElements() *
702std::pair<Type, uint64_t>
703ArrayType::getSubTypeByFieldID(uint64_t fieldID)
const {
709std::pair<uint64_t, bool>
710ArrayType::projectToChildFieldID(uint64_t fieldID, uint64_t index)
const {
714 return std::make_pair(fieldID - childRoot,
715 fieldID >= childRoot && fieldID <= rangeEnd);
718uint64_t ArrayType::getIndexForFieldID(uint64_t fieldID)
const {
719 assert(fieldID &&
"fieldID must be at least 1");
724std::pair<uint64_t, uint64_t>
725ArrayType::getIndexAndSubfieldID(uint64_t fieldID)
const {
728 return {index, fieldID - elementFieldID};
731uint64_t ArrayType::getFieldID(uint64_t index)
const {
735std::optional<DenseMap<Attribute, Type>>
736hw::ArrayType::getSubelementIndexMap()
const {
737 DenseMap<Attribute, Type> destructured;
738 for (
unsigned i = 0; i < getNumElements(); ++i)
740 {IntegerAttr::get(IndexType::get(getContext()), i), getElementType()});
744Type hw::ArrayType::getTypeAtIndex(Attribute index)
const {
745 return getElementType();
748std::optional<int64_t> hw::ArrayType::getBitWidth()
const {
749 auto elementBitWidth = hw::getBitWidth(getElementType());
750 if (elementBitWidth < 0)
763UnpackedArrayType::verify(function_ref<InFlightDiagnostic()> emitError,
764 Type innerType, Attribute size) {
766 return emitError() <<
"invalid element for uarray type";
770size_t UnpackedArrayType::getNumElements()
const {
771 if (
auto intAttr = llvm::dyn_cast<IntegerAttr>(getSizeAttr()))
772 return intAttr.getInt();
776uint64_t UnpackedArrayType::getMaxFieldID()
const {
777 return getNumElements() *
781std::pair<Type, uint64_t>
782UnpackedArrayType::getSubTypeByFieldID(uint64_t fieldID)
const {
788std::pair<uint64_t, bool>
789UnpackedArrayType::projectToChildFieldID(uint64_t fieldID,
790 uint64_t index)
const {
794 return std::make_pair(fieldID - childRoot,
795 fieldID >= childRoot && fieldID <= rangeEnd);
798uint64_t UnpackedArrayType::getIndexForFieldID(uint64_t fieldID)
const {
799 assert(fieldID &&
"fieldID must be at least 1");
804std::pair<uint64_t, uint64_t>
805UnpackedArrayType::getIndexAndSubfieldID(uint64_t fieldID)
const {
808 return {index, fieldID - elementFieldID};
811uint64_t UnpackedArrayType::getFieldID(uint64_t index)
const {
815std::optional<int64_t> UnpackedArrayType::getBitWidth()
const {
816 auto elementBitWidth = hw::getBitWidth(getElementType());
817 if (elementBitWidth < 0)
819 int64_t dimBitWidth = getNumElements();
822 return (int64_t)getNumElements() * elementBitWidth;
829LogicalResult InOutType::verify(function_ref<InFlightDiagnostic()> emitError,
832 return emitError() <<
"invalid element for hw.inout type " <<
innerType;
840TypeAliasType TypeAliasType::get(SymbolRefAttr ref, Type innerType) {
841 return get(ref.getContext(), ref, innerType, hw::getCanonicalType(innerType));
845TypeAliasType::getChecked(function_ref<InFlightDiagnostic()> emitError,
846 SymbolRefAttr ref, Type innerType) {
847 return getChecked(emitError, ref.getContext(), ref, innerType,
848 hw::getCanonicalType(innerType));
852TypeAliasType::verify(function_ref<InFlightDiagnostic()> emitError,
853 SymbolRefAttr ref, Type innerType, Type canonicalType) {
854 if (ref.getNestedReferences().size() != 1)
856 <<
"expected exactly one nested reference in hw.typealias";
860Type TypeAliasType::parse(AsmParser &p) {
863 if (p.parseLess() || p.parseAttribute(ref) || p.parseComma() ||
864 p.parseType(type) || p.parseGreater())
867 return p.getChecked<TypeAliasType>(ref, type);
870void TypeAliasType::print(AsmPrinter &p)
const {
871 p <<
"<" << getRef() <<
", " << getInnerType() <<
">";
876TypedeclOp TypeAliasType::getTypeDecl(
const HWSymbolCache &cache) {
877 SymbolRefAttr ref = getRef();
878 auto typeScope = ::dyn_cast_or_null<TypeScopeLike>(
883 return dyn_cast_or_null<TypedeclOp>(
884 SymbolTable::lookupSymbolIn(typeScope, ref.getLeafReference()));
887std::optional<int64_t> TypeAliasType::getBitWidth()
const {
898LogicalResult ModuleType::verify(function_ref<InFlightDiagnostic()> emitError,
899 ArrayRef<ModulePort> ports) {
900 if (llvm::any_of(ports, [](
const ModulePort &port) {
903 return emitError() <<
"Ports cannot be inout types";
907size_t ModuleType::getPortIdForInputId(
size_t idx) {
908 assert(idx < getImpl()->inputToAbs.size() &&
"input port out of range");
909 return getImpl()->inputToAbs[idx];
912size_t ModuleType::getPortIdForOutputId(
size_t idx) {
913 assert(idx < getImpl()->outputToAbs.size() &&
" output port out of range");
914 return getImpl()->outputToAbs[idx];
917size_t ModuleType::getInputIdForPortId(
size_t idx) {
918 auto nIdx = getImpl()->absToInput[idx];
923size_t ModuleType::getOutputIdForPortId(
size_t idx) {
924 auto nIdx = getImpl()->absToOutput[idx];
929size_t ModuleType::getNumInputs() {
return getImpl()->inputToAbs.size(); }
931size_t ModuleType::getNumOutputs() {
return getImpl()->outputToAbs.size(); }
933size_t ModuleType::getNumPorts() {
return getPorts().size(); }
935SmallVector<Type> ModuleType::getInputTypes() {
936 SmallVector<Type> retval;
937 for (
auto &p : getPorts()) {
938 if (p.dir == ModulePort::Direction::Input)
939 retval.push_back(p.type);
940 else if (p.dir == ModulePort::Direction::InOut) {
941 retval.push_back(hw::InOutType::get(p.type));
947SmallVector<Type> ModuleType::getOutputTypes() {
948 SmallVector<Type> retval;
949 for (
auto &p : getPorts())
951 retval.push_back(p.type);
955SmallVector<Type> ModuleType::getPortTypes() {
956 SmallVector<Type> retval;
957 for (
auto &p : getPorts())
958 retval.push_back(p.type);
962Type ModuleType::getInputType(
size_t idx) {
963 const auto &portInfo = getPorts()[getPortIdForInputId(idx)];
965 return portInfo.type;
966 return InOutType::get(portInfo.type);
969Type ModuleType::getOutputType(
size_t idx) {
970 return getPorts()[getPortIdForOutputId(idx)].type;
973SmallVector<Attribute> ModuleType::getInputNames() {
974 SmallVector<Attribute> retval;
975 for (
auto &p : getPorts())
977 retval.push_back(p.name);
981SmallVector<Attribute> ModuleType::getOutputNames() {
982 SmallVector<Attribute> retval;
983 for (
auto &p : getPorts())
985 retval.push_back(p.name);
989StringAttr ModuleType::getPortNameAttr(
size_t idx) {
990 return getPorts()[idx].name;
993StringRef ModuleType::getPortName(
size_t idx) {
994 auto sa = getPortNameAttr(idx);
996 return sa.getValue();
1000StringAttr ModuleType::getInputNameAttr(
size_t idx) {
1001 return getPorts()[getPortIdForInputId(idx)].name;
1004StringRef ModuleType::getInputName(
size_t idx) {
1005 auto sa = getInputNameAttr(idx);
1007 return sa.getValue();
1011StringAttr ModuleType::getOutputNameAttr(
size_t idx) {
1012 return getPorts()[getPortIdForOutputId(idx)].name;
1015StringRef ModuleType::getOutputName(
size_t idx) {
1016 auto sa = getOutputNameAttr(idx);
1018 return sa.getValue();
1022bool ModuleType::isOutput(
size_t idx) {
1023 auto &p = getPorts()[idx];
1024 return p.dir == ModulePort::Direction::Output;
1027FunctionType ModuleType::getFuncType() {
1028 SmallVector<Type> inputs, outputs;
1029 for (
auto p : getPorts())
1031 inputs.push_back(p.type);
1033 inputs.push_back(InOutType::get(p.type));
1035 outputs.push_back(p.type);
1036 return FunctionType::get(getContext(), inputs, outputs);
1039ArrayRef<ModulePort> ModuleType::getPorts()
const {
1040 return getImpl()->getPorts();
1043FailureOr<ModuleType> ModuleType::resolveParametricTypes(ArrayAttr parameters,
1046 SmallVector<ModulePort, 8> resolvedPorts;
1048 FailureOr<Type> resolvedType =
1050 if (failed(resolvedType))
1052 port.type = *resolvedType;
1053 resolvedPorts.push_back(port);
1055 return ModuleType::get(getContext(), resolvedPorts);
1060 case ModulePort::Direction::Input:
1062 case ModulePort::Direction::Output:
1064 case ModulePort::Direction::InOut:
1071 return ModulePort::Direction::Input;
1072 if (str ==
"output")
1073 return ModulePort::Direction::Output;
1075 return ModulePort::Direction::InOut;
1076 llvm::report_fatal_error(
"invalid direction");
1082 SmallVectorImpl<ModulePort> &ports) {
1083 return p.parseCommaSeparatedList(
1084 mlir::AsmParser::Delimiter::LessGreater, [&]() -> ParseResult {
1088 if (p.parseKeyword(&dir) || p.parseKeywordOrString(&name) ||
1089 p.parseColon() || p.parseType(type))
1092 {StringAttr::get(p.getContext(), name), type,
strToDir(dir)});
1098static void printPorts(AsmPrinter &p, ArrayRef<ModulePort> ports) {
1100 llvm::interleaveComma(ports, p, [&](
const ModulePort &port) {
1102 p.printKeywordOrString(port.
name.getValue());
1103 p <<
" : " << port.
type;
1108Type ModuleType::parse(AsmParser &odsParser) {
1109 llvm::SmallVector<ModulePort, 4> ports;
1112 return get(odsParser.getContext(), ports);
1115void ModuleType::print(AsmPrinter &odsPrinter)
const {
1120 ArrayRef<Attribute> inputNames,
1121 ArrayRef<Attribute> outputNames) {
1123 cast<FunctionType>(cast<mlir::FunctionOpInterface>(op).getFunctionType()),
1124 inputNames, outputNames);
1128 ArrayRef<Attribute> inputNames,
1129 ArrayRef<Attribute> outputNames) {
1130 SmallVector<ModulePort> ports;
1131 if (!inputNames.empty()) {
1132 for (
auto [t, n] : llvm::zip_equal(fnty.getInputs(), inputNames))
1133 if (
auto iot = dyn_cast<hw::InOutType>(t))
1134 ports.push_back({cast<StringAttr>(n), iot.getElementType(),
1135 ModulePort::Direction::InOut});
1137 ports.push_back({cast<StringAttr>(n), t, ModulePort::Direction::Input});
1139 for (
auto t : fnty.getInputs())
1140 if (auto iot = dyn_cast<
hw::InOutType>(t))
1142 {{}, iot.getElementType(), ModulePort::Direction::InOut});
1144 ports.push_back({{}, t, ModulePort::Direction::Input});
1146 if (!outputNames.empty()) {
1147 for (
auto [t, n] :
llvm::zip_equal(fnty.getResults(), outputNames))
1148 ports.push_back({cast<StringAttr>(n), t, ModulePort::Direction::Output});
1150 for (
auto t : fnty.getResults())
1151 ports.push_back({{}, t, ModulePort::Direction::Output});
1153 return ModuleType::get(fnty.getContext(), ports);
1158 size_t nextInput = 0;
1159 size_t nextOutput = 0;
1160 for (
auto [idx, p] : llvm::enumerate(
ports)) {
1179void HWDialect::registerTypes() {
1181#define GET_TYPEDEF_LIST
1182#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 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 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 OffsetFieldInfo &fi)
bool operator==(const OffsetFieldInfo &a, const OffsetFieldInfo &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)
Recursively remove HW type aliases from a type and its subelements.
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.
ParseResult parseFieldList(AsmParser &p, SmallVectorImpl< FieldInfo > &fields, SmallVectorImpl< std::pair< llvm::SMLoc, StringAttr > > &duplicates)
Parse a list of named fields within <>, e.g.
void printFieldList(AsmPrinter &p, ArrayRef< FieldInfo > fields)
Print a list of fields within <>, e.g. <foo: i7, bar: i8>.
A named and typed field of an aggregate type.
Interface for dialects to classify their types as valid probe payloads.
virtual bool isValidProbeElementType(mlir::Type type) const =0
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.