26 #include "mlir/IR/BuiltinTypes.h"
27 #include "mlir/IR/Diagnostics.h"
28 #include "mlir/IR/DialectImplementation.h"
29 #include "mlir/IR/PatternMatch.h"
30 #include "mlir/IR/SymbolTable.h"
31 #include "mlir/Interfaces/FunctionImplementation.h"
32 #include "llvm/ADT/BitVector.h"
33 #include "llvm/ADT/DenseMap.h"
34 #include "llvm/ADT/DenseSet.h"
35 #include "llvm/ADT/STLExtras.h"
36 #include "llvm/ADT/SmallSet.h"
37 #include "llvm/ADT/StringExtras.h"
38 #include "llvm/ADT/TypeSwitch.h"
39 #include "llvm/Support/FormatVariadic.h"
41 using llvm::SmallDenseSet;
42 using mlir::RegionRange;
43 using namespace circt;
44 using namespace firrtl;
45 using namespace chirrtl;
56 const llvm::BitVector &indicesToDrop) {
59 int lastIndex = indicesToDrop.find_last();
61 assert((
size_t)lastIndex < input.size() &&
"index out of range");
71 size_t lastCopied = 0;
72 SmallVector<T> result;
73 result.reserve(input.size() - indicesToDrop.count());
75 for (
unsigned indexToDrop : indicesToDrop.set_bits()) {
77 if (indexToDrop > lastCopied) {
78 result.append(input.begin() + lastCopied, input.begin() + indexToDrop);
79 lastCopied = indexToDrop;
86 if (lastCopied < input.size())
87 result.append(input.begin() + lastCopied, input.end());
93 template <
typename RetTy =
FIRRTLType,
typename... Args>
95 const Twine &message, Args &&...args) {
97 (mlir::emitError(*loc, message) << ... << std::forward<Args>(args));
103 while (Operation *op = val.getDefiningOp()) {
105 TypeSwitch<Operation *, std::optional<bool>>(op)
106 .Case<SubfieldOp, SubindexOp, SubaccessOp>([&val](
auto op) {
110 .Case<RegOp, RegResetOp, WireOp>([](
auto) {
return true; })
111 .Default([](
auto) {
return false; });
118 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
119 MemOp::computeDataFlow() {
122 if (getReadLatency() > 0)
124 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
126 for (
auto memPort : getResults())
127 if (
auto type = type_dyn_cast<BundleType>(memPort.getType())) {
132 FieldRef(memPort,
static_cast<unsigned>(dataFieldId)),
133 FieldRef(memPort,
static_cast<unsigned>(enableFieldId)));
135 FieldRef(memPort,
static_cast<unsigned>(dataFieldId)),
136 FieldRef(memPort,
static_cast<unsigned>(addressFieldId)));
143 constexpr
unsigned int addr = 1 << 0;
144 constexpr
unsigned int en = 1 << 1;
145 constexpr
unsigned int clk = 1 << 2;
146 constexpr
unsigned int data = 1 << 3;
147 constexpr
unsigned int mask = 1 << 4;
148 constexpr
unsigned int rdata = 1 << 5;
149 constexpr
unsigned int wdata = 1 << 6;
150 constexpr
unsigned int wmask = 1 << 7;
151 constexpr
unsigned int wmode = 1 << 8;
152 constexpr
unsigned int def = 1 << 9;
154 auto portType = type_dyn_cast<BundleType>(type);
156 return MemOp::PortKind::Debug;
159 for (
auto elem : portType.getElements()) {
160 fields |= llvm::StringSwitch<unsigned>(elem.name.getValue())
166 .Case(
"rdata",
rdata)
167 .Case(
"wdata",
wdata)
168 .Case(
"wmask",
wmask)
169 .Case(
"wmode",
wmode)
173 return MemOp::PortKind::Read;
175 return MemOp::PortKind::Write;
177 return MemOp::PortKind::ReadWrite;
178 return MemOp::PortKind::Debug;
193 llvm_unreachable(
"Unsupported Flow type.");
201 return "source flow";
205 return "duplex flow";
208 llvm_unreachable(
"Unsupported Flow type.");
213 if (
auto blockArg = dyn_cast<BlockArgument>(val)) {
214 auto *op = val.getParentBlock()->getParentOp();
215 if (
auto moduleLike = dyn_cast<FModuleLike>(op)) {
216 auto direction = moduleLike.getPortDirection(blockArg.getArgNumber());
220 return accumulatedFlow;
223 Operation *op = val.getDefiningOp();
225 return TypeSwitch<Operation *, Flow>(op)
226 .Case<SubfieldOp, OpenSubfieldOp>([&](
auto op) {
227 return foldFlow(op.getInput(), op.isFieldFlipped()
231 .Case<SubindexOp, SubaccessOp, OpenSubindexOp, RefSubOp>(
232 [&](
auto op) {
return foldFlow(op.getInput(), accumulatedFlow); })
234 .Case<RegOp, RegResetOp, WireOp, MemoryPortOp>(
236 .Case<InstanceOp, InstanceChoiceOp>([&](
auto inst) {
237 auto resultNo = cast<OpResult>(val).getResultNumber();
239 return accumulatedFlow;
242 .Case<MemOp>([&](
auto op) {
244 if (type_isa<RefType>(val.getType()))
248 .Case<ObjectSubfieldOp>([&](ObjectSubfieldOp op) {
249 auto input = op.getInput();
250 auto *inputOp = input.getDefiningOp();
253 if (
auto objectOp = dyn_cast_or_null<ObjectOp>(inputOp)) {
254 auto classType = input.getType();
255 auto direction = classType.getElement(op.getIndex()).direction;
267 auto classType = input.getType();
268 auto direction = classType.getElement(op.getIndex()).direction;
272 op = dyn_cast_or_null<ObjectSubfieldOp>(inputOp);
274 input = op.getInput();
275 inputOp = input.getDefiningOp();
279 return accumulatedFlow;
283 .Default([&](
auto) {
return accumulatedFlow; });
289 Operation *op = val.getDefiningOp();
293 return TypeSwitch<Operation *, DeclKind>(op)
295 .Case<SubfieldOp, SubindexOp, SubaccessOp, OpenSubfieldOp, OpenSubindexOp,
301 if (
auto module = dyn_cast<FModuleLike>(op))
302 return module.getNumPorts();
303 return op->getNumResults();
317 if (
auto *op = value.getDefiningOp())
319 auto arg = dyn_cast<BlockArgument>(value);
320 auto module = cast<FModuleOp>(arg.getOwner()->getParentOp());
321 return (module.getPortSymbolAttr(arg.getArgNumber())) ||
332 auto *block = ®ion.front();
335 auto argAttr = parentOp->getAttrOfType<ArrayAttr>(
"portNames");
337 if (!argAttr || argAttr.size() != block->getNumArguments())
340 for (
size_t i = 0, e = block->getNumArguments(); i != e; ++i) {
341 auto str = cast<StringAttr>(argAttr[i]).getValue();
343 setNameFn(block->getArgument(i), str);
349 firrtl::NameKindEnumAttr &result);
356 struct CompareSymbolRefAttr {
358 bool operator()(SymbolRefAttr lhs, SymbolRefAttr rhs)
const {
359 auto cmp = lhs.getRootReference().compare(rhs.getRootReference());
364 auto lhsNested = lhs.getNestedReferences();
365 auto rhsNested = rhs.getNestedReferences();
366 auto lhsNestedSize = lhsNested.size();
367 auto rhsNestedSize = rhsNested.size();
368 auto e = std::min(lhsNestedSize, rhsNestedSize);
369 for (
unsigned i = 0; i < e; ++i) {
370 auto cmp = lhsNested[i].getAttr().compare(rhsNested[i].
getAttr());
376 return lhsNestedSize < rhsNestedSize;
388 for (; op !=
nullptr; op = op->getParentOp()) {
389 if (
auto module = dyn_cast<FModuleLike>(op)) {
390 auto layers = module.getLayersAttr().getAsRange<SymbolRefAttr>();
391 result.insert(layers.begin(), layers.end());
394 if (
auto layerblock = dyn_cast<LayerBlockOp>(op)) {
395 result.insert(layerblock.getLayerName());
413 if (
auto type = dyn_cast<RefType>(value.getType()))
414 if (
auto layer = type.getLayer())
415 result.insert(type.getLayer());
424 mlir::SymbolRefAttr dstLayer) {
434 if (srcLayer.getRootReference() != dstLayer.getRootReference())
437 auto srcNames = srcLayer.getNestedReferences();
438 auto dstNames = dstLayer.getNestedReferences();
439 if (dstNames.size() < srcNames.size())
442 return llvm::all_of(llvm::zip_first(srcNames, dstNames),
443 [](
auto x) {
return std::get<0>(x) == std::get<1>(x); });
450 if (dstLayers.contains(srcLayer))
455 return any_of(dstLayers, [=](SymbolRefAttr dstLayer) {
464 SmallVectorImpl<SymbolRefAttr> &missing) {
465 for (
auto srcLayer : src)
467 missing.push_back(srcLayer);
469 llvm::sort(missing, CompareSymbolRefAttr());
470 return missing.empty();
477 void CircuitOp::build(OpBuilder &builder, OperationState &result,
478 StringAttr name, ArrayAttr annotations) {
480 result.addAttribute(builder.getStringAttr(
"name"), name);
483 annotations = builder.getArrayAttr({});
484 result.addAttribute(
"annotations", annotations);
487 Region *bodyRegion = result.addRegion();
489 bodyRegion->push_back(body);
493 NamedAttrList &resultAttrs) {
494 auto result = parser.parseOptionalAttrDictWithKeyword(resultAttrs);
495 if (!resultAttrs.get(
"annotations"))
496 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
502 DictionaryAttr attr) {
504 SmallVector<StringRef> elidedAttrs = {
"name"};
506 auto annotationsAttr = op->getAttrOfType<ArrayAttr>(
"annotations");
507 if (annotationsAttr.empty())
508 elidedAttrs.push_back(
"annotations");
510 p.printOptionalAttrDictWithKeyword(op->getAttrs(), elidedAttrs);
513 LogicalResult CircuitOp::verifyRegions() {
518 emitOpError(
"must have a non-empty name");
522 mlir::SymbolTable symtbl(getOperation());
524 auto *mainModule = symtbl.lookup(
main);
526 return emitOpError().append(
527 "does not contain module with same name as circuit");
528 if (!isa<FModuleLike>(mainModule))
529 return mainModule->emitError(
530 "entity with name of circuit must be a module");
531 if (symtbl.getSymbolVisibility(mainModule) !=
532 mlir::SymbolTable::Visibility::Public)
533 return mainModule->emitError(
"main module must be public");
538 llvm::DenseMap<Attribute, FExtModuleOp> defnameMap;
540 auto verifyExtModule = [&](FExtModuleOp extModule) -> LogicalResult {
544 auto defname = extModule.getDefnameAttr();
550 if (
auto collidingModule = symtbl.lookup<FModuleOp>(defname.getValue()))
551 return extModule.emitOpError()
552 .append(
"attribute 'defname' with value ", defname,
553 " conflicts with the name of another module in the circuit")
554 .attachNote(collidingModule.getLoc())
555 .append(
"previous module declared here");
563 FExtModuleOp collidingExtModule;
564 if (
auto &value = defnameMap[defname]) {
565 collidingExtModule = value;
566 if (!value.getParameters().empty() && extModule.getParameters().empty())
576 SmallVector<PortInfo> ports = extModule.getPorts();
577 SmallVector<PortInfo> collidingPorts = collidingExtModule.getPorts();
579 if (ports.size() != collidingPorts.size())
580 return extModule.emitOpError()
581 .append(
"with 'defname' attribute ", defname,
" has ", ports.size(),
582 " ports which is different from a previously defined "
583 "extmodule with the same 'defname' which has ",
584 collidingPorts.size(),
" ports")
585 .attachNote(collidingExtModule.getLoc())
586 .append(
"previous extmodule definition occurred here");
592 for (
auto p : llvm::zip(ports, collidingPorts)) {
593 StringAttr aName = std::get<0>(p).name, bName = std::get<1>(p).name;
594 Type aType = std::get<0>(p).type, bType = std::get<1>(p).type;
597 return extModule.emitOpError()
598 .append(
"with 'defname' attribute ", defname,
599 " has a port with name ", aName,
600 " which does not match the name of the port in the same "
601 "position of a previously defined extmodule with the same "
602 "'defname', expected port to have name ",
604 .attachNote(collidingExtModule.getLoc())
605 .append(
"previous extmodule definition occurred here");
607 if (!extModule.getParameters().empty() ||
608 !collidingExtModule.getParameters().empty()) {
610 if (
auto base = type_dyn_cast<FIRRTLBaseType>(aType))
611 aType = base.getWidthlessType();
612 if (
auto base = type_dyn_cast<FIRRTLBaseType>(bType))
613 bType = base.getWidthlessType();
616 return extModule.emitOpError()
617 .append(
"with 'defname' attribute ", defname,
618 " has a port with name ", aName,
619 " which has a different type ", aType,
620 " which does not match the type of the port in the same "
621 "position of a previously defined extmodule with the same "
622 "'defname', expected port to have type ",
624 .attachNote(collidingExtModule.getLoc())
625 .append(
"previous extmodule definition occurred here");
632 if (
auto extModule = dyn_cast<FExtModuleOp>(op)) {
633 if (verifyExtModule(extModule).failed())
648 SmallVector<PortInfo> results;
649 for (
unsigned i = 0, e = module.getNumPorts(); i < e; ++i) {
650 results.push_back({module.getPortNameAttr(i), module.getPortType(i),
651 module.getPortDirection(i), module.getPortSymbolAttr(i),
652 module.getPortLocation(i),
671 assert(0 &&
"invalid direction");
676 SmallVector<hw::PortInfo> results;
678 hw::HWModuleLike::getPortSymbolAttrName());
680 for (
unsigned i = 0, e =
getNumPorts(module); i < e; ++i) {
681 auto sym = module.getPortSymbolAttr(i);
683 {{module.getPortNameAttr(i), module.getPortType(i),
684 dirFtoH(module.getPortDirection(i))},
688 ArrayRef<mlir::NamedAttribute>{NamedAttribute{aname, sym}})
690 module.getPortLocation(i)});
712 return {{module.getPortNameAttr(idx), module.getPortType(idx),
713 dirFtoH(module.getPortDirection(idx))},
717 ArrayRef<mlir::NamedAttribute>{NamedAttribute{
718 StringAttr::get(module.getContext(),
719 hw::HWModuleLike::getPortSymbolAttrName()),
720 module.getPortSymbolAttr(idx)}}),
721 module.getPortLocation(idx)};
741 BlockArgument FModuleOp::getArgument(
size_t portNumber) {
749 ArrayRef<std::pair<unsigned, PortInfo>> ports,
750 bool supportsInternalPaths =
false) {
753 unsigned oldNumArgs = op.getNumPorts();
754 unsigned newNumArgs = oldNumArgs + ports.size();
757 auto existingDirections = op.getPortDirectionsAttr();
758 ArrayRef<Attribute> existingNames = op.getPortNames();
759 ArrayRef<Attribute> existingTypes = op.getPortTypes();
760 ArrayRef<Attribute> existingLocs = op.getPortLocations();
761 assert(existingDirections.size() == oldNumArgs);
762 assert(existingNames.size() == oldNumArgs);
763 assert(existingTypes.size() == oldNumArgs);
764 assert(existingLocs.size() == oldNumArgs);
765 SmallVector<Attribute> internalPaths;
767 if (supportsInternalPaths) {
768 if (
auto internalPathsAttr = op->getAttrOfType<ArrayAttr>(
"internalPaths"))
769 llvm::append_range(internalPaths, internalPathsAttr);
771 internalPaths.resize(oldNumArgs, emptyInternalPath);
772 assert(internalPaths.size() == oldNumArgs);
775 SmallVector<bool> newDirections;
776 SmallVector<Attribute> newNames, newTypes, newAnnos, newSyms, newLocs,
778 newDirections.reserve(newNumArgs);
779 newNames.reserve(newNumArgs);
780 newTypes.reserve(newNumArgs);
781 newAnnos.reserve(newNumArgs);
782 newSyms.reserve(newNumArgs);
783 newLocs.reserve(newNumArgs);
784 newInternalPaths.reserve(newNumArgs);
789 auto migrateOldPorts = [&](
unsigned untilOldIdx) {
790 while (oldIdx < oldNumArgs && oldIdx < untilOldIdx) {
791 newDirections.push_back(existingDirections[oldIdx]);
792 newNames.push_back(existingNames[oldIdx]);
793 newTypes.push_back(existingTypes[oldIdx]);
794 newAnnos.push_back(op.getAnnotationsAttrForPort(oldIdx));
795 newSyms.push_back(op.getPortSymbolAttr(oldIdx));
796 newLocs.push_back(existingLocs[oldIdx]);
797 if (supportsInternalPaths)
798 newInternalPaths.push_back(internalPaths[oldIdx]);
802 for (
auto pair : llvm::enumerate(ports)) {
803 auto idx = pair.value().first;
804 auto &port = pair.value().second;
805 migrateOldPorts(idx);
807 newNames.push_back(port.name);
809 auto annos = port.annotations.getArrayAttr();
810 newAnnos.push_back(annos ? annos : emptyArray);
811 newSyms.push_back(port.sym);
812 newLocs.push_back(port.loc);
813 if (supportsInternalPaths)
814 newInternalPaths.push_back(emptyInternalPath);
816 migrateOldPorts(oldNumArgs);
820 if (llvm::all_of(newAnnos, [](Attribute attr) {
821 return cast<ArrayAttr>(attr).empty();
826 op->setAttr(
"portDirections",
828 op->setAttr(
"portNames",
ArrayAttr::get(op.getContext(), newNames));
829 op->setAttr(
"portTypes",
ArrayAttr::get(op.getContext(), newTypes));
830 op->setAttr(
"portAnnotations",
ArrayAttr::get(op.getContext(), newAnnos));
831 op.setPortSymbols(newSyms);
832 op->setAttr(
"portLocations",
ArrayAttr::get(op.getContext(), newLocs));
833 if (supportsInternalPaths) {
835 auto empty = llvm::all_of(newInternalPaths, [](Attribute attr) {
836 return !cast<InternalPathAttr>(attr).getPath();
839 op->removeAttr(
"internalPaths");
841 op->setAttr(
"internalPaths",
847 static void erasePorts(FModuleLike op,
const llvm::BitVector &portIndices) {
848 if (portIndices.none())
852 ArrayRef<bool> portDirections = op.getPortDirectionsAttr().asArrayRef();
853 ArrayRef<Attribute> portNames = op.getPortNames();
854 ArrayRef<Attribute> portTypes = op.getPortTypes();
855 ArrayRef<Attribute> portAnnos = op.getPortAnnotations();
856 ArrayRef<Attribute> portSyms = op.getPortSymbols();
857 ArrayRef<Attribute> portLocs = op.getPortLocations();
858 auto numPorts = op.getNumPorts();
860 assert(portDirections.size() == numPorts);
861 assert(portNames.size() == numPorts);
862 assert(portAnnos.size() == numPorts || portAnnos.empty());
863 assert(portTypes.size() == numPorts);
864 assert(portSyms.size() == numPorts || portSyms.empty());
865 assert(portLocs.size() == numPorts);
867 SmallVector<bool> newPortDirections =
868 removeElementsAtIndices<bool>(portDirections, portIndices);
869 SmallVector<Attribute> newPortNames, newPortTypes, newPortAnnos, newPortSyms,
876 op->setAttr(
"portDirections",
878 op->setAttr(
"portNames",
ArrayAttr::get(op.getContext(), newPortNames));
879 op->setAttr(
"portAnnotations",
ArrayAttr::get(op.getContext(), newPortAnnos));
880 op->setAttr(
"portTypes",
ArrayAttr::get(op.getContext(), newPortTypes));
881 FModuleLike::fixupPortSymsArray(newPortSyms, op.getContext());
882 op->setAttr(
"portSyms",
ArrayAttr::get(op.getContext(), newPortSyms));
883 op->setAttr(
"portLocations",
ArrayAttr::get(op.getContext(), newPortLocs));
886 template <
typename T>
889 auto internalPaths = op.getInternalPaths();
897 auto empty = llvm::all_of(newPaths, [](Attribute attr) {
898 return !cast<InternalPathAttr>(attr).getPath();
901 op.removeInternalPathsAttr();
903 op.setInternalPathsAttr(
ArrayAttr::get(op.getContext(), newPaths));
907 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
912 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
917 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
921 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
933 for (
size_t i = 0, e = ports.size(); i < e; ++i) {
936 auto &[index, port] = ports[i];
937 body->insertArgument(index + i, port.type, port.loc);
959 StringAttr name, ArrayRef<PortInfo> ports,
960 ArrayAttr annotations, ArrayAttr layers,
961 bool withAnnotations,
bool withLayers) {
963 result.addAttribute(::mlir::SymbolTable::getSymbolAttrName(), name);
966 SmallVector<Direction, 4> portDirections;
967 SmallVector<Attribute, 4> portNames;
968 SmallVector<Attribute, 4> portTypes;
969 SmallVector<Attribute, 4> portAnnotations;
970 SmallVector<Attribute, 4> portSyms;
971 SmallVector<Attribute, 4> portLocs;
972 for (
const auto &port : ports) {
973 portDirections.push_back(port.direction);
974 portNames.push_back(port.name);
976 portAnnotations.push_back(port.annotations.getArrayAttr());
977 portSyms.push_back(port.sym);
978 portLocs.push_back(port.loc);
983 if (llvm::all_of(portAnnotations, [](Attribute attr) {
984 return cast<ArrayAttr>(attr).empty();
986 portAnnotations.clear();
988 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
993 result.addAttribute(
"portNames", builder.getArrayAttr(portNames));
994 result.addAttribute(
"portTypes", builder.getArrayAttr(portTypes));
995 result.addAttribute(
"portSyms", builder.getArrayAttr(portSyms));
996 result.addAttribute(
"portLocations", builder.getArrayAttr(portLocs));
998 if (withAnnotations) {
1000 annotations = builder.getArrayAttr({});
1001 result.addAttribute(
"annotations", annotations);
1002 result.addAttribute(
"portAnnotations",
1003 builder.getArrayAttr(portAnnotations));
1008 layers = builder.getArrayAttr({});
1009 result.addAttribute(
"layers", layers);
1016 StringAttr name, ArrayRef<PortInfo> ports,
1017 ArrayAttr annotations, ArrayAttr layers) {
1022 static void buildClass(OpBuilder &builder, OperationState &result,
1023 StringAttr name, ArrayRef<PortInfo> ports) {
1029 void FModuleOp::build(OpBuilder &builder, OperationState &result,
1030 StringAttr name, ConventionAttr convention,
1031 ArrayRef<PortInfo> ports, ArrayAttr annotations,
1033 buildModule(builder, result, name, ports, annotations, layers);
1034 result.addAttribute(
"convention", convention);
1037 auto *bodyRegion = result.regions[0].get();
1039 bodyRegion->push_back(body);
1042 for (
auto &elt : ports)
1043 body->addArgument(elt.type, elt.loc);
1046 void FExtModuleOp::build(OpBuilder &builder, OperationState &result,
1047 StringAttr name, ConventionAttr convention,
1048 ArrayRef<PortInfo> ports, StringRef defnameAttr,
1049 ArrayAttr annotations, ArrayAttr parameters,
1050 ArrayAttr internalPaths, ArrayAttr layers) {
1051 buildModule(builder, result, name, ports, annotations, layers);
1052 result.addAttribute(
"convention", convention);
1053 if (!defnameAttr.empty())
1054 result.addAttribute(
"defname", builder.getStringAttr(defnameAttr));
1056 parameters = builder.getArrayAttr({});
1057 result.addAttribute(getParametersAttrName(result.name), parameters);
1058 if (internalPaths && !internalPaths.empty())
1059 result.addAttribute(getInternalPathsAttrName(result.name), internalPaths);
1062 void FIntModuleOp::build(OpBuilder &builder, OperationState &result,
1063 StringAttr name, ArrayRef<PortInfo> ports,
1064 StringRef intrinsicNameStr, ArrayAttr annotations,
1065 ArrayAttr parameters, ArrayAttr internalPaths,
1067 buildModule(builder, result, name, ports, annotations, layers);
1068 result.addAttribute(
"intrinsic", builder.getStringAttr(intrinsicNameStr));
1070 parameters = builder.getArrayAttr({});
1071 result.addAttribute(getParametersAttrName(result.name), parameters);
1072 if (internalPaths && !internalPaths.empty())
1073 result.addAttribute(getInternalPathsAttrName(result.name), internalPaths);
1076 void FMemModuleOp::build(OpBuilder &builder, OperationState &result,
1077 StringAttr name, ArrayRef<PortInfo> ports,
1078 uint32_t numReadPorts, uint32_t numWritePorts,
1079 uint32_t numReadWritePorts, uint32_t dataWidth,
1080 uint32_t maskBits, uint32_t readLatency,
1081 uint32_t writeLatency, uint64_t depth,
1082 ArrayAttr annotations, ArrayAttr layers) {
1083 auto *context = builder.getContext();
1084 buildModule(builder, result, name, ports, annotations, layers);
1087 result.addAttribute(
"numReadPorts",
IntegerAttr::get(ui32Type, numReadPorts));
1088 result.addAttribute(
"numWritePorts",
1090 result.addAttribute(
"numReadWritePorts",
1094 result.addAttribute(
"readLatency",
IntegerAttr::get(ui32Type, readLatency));
1095 result.addAttribute(
"writeLatency",
IntegerAttr::get(ui32Type, writeLatency));
1114 ArrayRef<Attribute> portNames, ArrayRef<Attribute> portTypes,
1115 ArrayRef<Attribute> portAnnotations,
1116 ArrayRef<Attribute> portSyms, ArrayRef<Attribute> portLocs) {
1119 bool printedNamesDontMatch =
false;
1121 mlir::OpPrintingFlags flags;
1125 SmallString<32> resultNameStr;
1127 for (
unsigned i = 0, e = portTypes.size(); i < e; ++i) {
1138 resultNameStr.clear();
1139 llvm::raw_svector_ostream tmpStream(resultNameStr);
1140 p.printOperand(block->getArgument(i), tmpStream);
1143 auto portName = cast<StringAttr>(portNames[i]).getValue();
1144 if (!portName.empty() && tmpStream.str().drop_front() != portName)
1145 printedNamesDontMatch =
true;
1146 p << tmpStream.str();
1148 p.printKeywordOrString(cast<StringAttr>(portNames[i]).getValue());
1153 auto portType = cast<TypeAttr>(portTypes[i]).getValue();
1154 p.printType(portType);
1157 if (!portSyms.empty()) {
1158 if (!cast<hw::InnerSymAttr>(portSyms[i]).
empty()) {
1160 cast<hw::InnerSymAttr>(portSyms[i]).print(p);
1166 if (!portAnnotations.empty() &&
1167 !cast<ArrayAttr>(portAnnotations[i]).empty()) {
1169 p.printAttribute(portAnnotations[i]);
1176 if (flags.shouldPrintDebugInfo() && !portLocs.empty())
1177 p.printOptionalLocationSpecifier(cast<LocationAttr>(portLocs[i]));
1181 return printedNamesDontMatch;
1188 bool supportsSymbols,
1189 SmallVectorImpl<OpAsmParser::Argument> &entryArgs,
1190 SmallVectorImpl<Direction> &portDirections,
1191 SmallVectorImpl<Attribute> &portNames,
1192 SmallVectorImpl<Attribute> &portTypes,
1193 SmallVectorImpl<Attribute> &portAnnotations,
1194 SmallVectorImpl<Attribute> &portSyms,
1195 SmallVectorImpl<Attribute> &portLocs) {
1196 auto *context = parser.getContext();
1198 auto parseArgument = [&]() -> ParseResult {
1200 if (succeeded(parser.parseOptionalKeyword(
"out")))
1201 portDirections.push_back(Direction::Out);
1202 else if (succeeded(parser.parseKeyword(
"in",
"or 'out'")))
1203 portDirections.push_back(Direction::In);
1211 if (hasSSAIdentifiers) {
1212 OpAsmParser::Argument arg;
1213 if (parser.parseArgument(arg))
1215 entryArgs.push_back(arg);
1219 assert(arg.ssaName.name.size() > 1 && arg.ssaName.name[0] ==
'%' &&
1220 "Unknown MLIR name");
1221 if (
isdigit(arg.ssaName.name[1]))
1224 portNames.push_back(
1228 irLoc = arg.ssaName.location;
1232 irLoc = parser.getCurrentLocation();
1233 std::string portName;
1234 if (parser.parseKeywordOrString(&portName))
1241 if (parser.parseColonType(portType))
1245 if (hasSSAIdentifiers)
1246 entryArgs.back().type = portType;
1249 if (supportsSymbols) {
1250 hw::InnerSymAttr innerSymAttr;
1251 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
1252 NamedAttrList dummyAttrs;
1253 if (parser.parseCustomAttributeWithFallback(
1254 innerSymAttr, ::mlir::Type{},
1256 return ::mlir::failure();
1259 portSyms.push_back(innerSymAttr);
1264 auto parseResult = parser.parseOptionalAttribute(annos);
1265 if (!parseResult.has_value())
1266 annos = parser.getBuilder().getArrayAttr({});
1267 else if (failed(*parseResult))
1269 portAnnotations.push_back(annos);
1272 std::optional<Location> maybeLoc;
1273 if (failed(parser.parseOptionalLocationSpecifier(maybeLoc)))
1275 Location loc = maybeLoc ? *maybeLoc : parser.getEncodedSourceLoc(irLoc);
1276 portLocs.push_back(loc);
1277 if (hasSSAIdentifiers)
1278 entryArgs.back().sourceLoc = loc;
1284 return parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
1290 ArrayAttr parameters) {
1291 if (!parameters || parameters.empty())
1295 llvm::interleaveComma(parameters, p, [&](Attribute param) {
1296 auto paramAttr = cast<ParamDeclAttr>(param);
1297 p << paramAttr.getName().getValue() <<
": " << paramAttr.getType();
1298 if (
auto value = paramAttr.getValue()) {
1300 p.printAttributeWithoutType(value);
1306 static void printFModuleLikeOp(OpAsmPrinter &p, FModuleLike op) {
1309 // Print the visibility of the module.
1310 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
1311 if (auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
1312 p << visibility.getValue() << ' ';
1314 // Print the operation and the function name.
1315 p.printSymbolName(op.getModuleName());
1317 // Print the parameter list (if non-empty).
1318 printParameterList(p, op, op->getAttrOfType<ArrayAttr>("parameters"));
1320 // Both modules and external modules have a body, but it is always empty for
1321 // external modules.
1322 Block *body = nullptr;
1323 if (!op->getRegion(0).empty())
1324 body = &op->getRegion(0).front();
1326 auto needPortNamesAttr = printModulePorts(
1327 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
1328 op.getPortAnnotations(), op.getPortSymbols(), op.getPortLocations());
1330 SmallVector<StringRef, 12> omittedAttrs = {
1331 "sym_name", "portDirections", "portTypes", "portAnnotations",
1332 "portSyms", "portLocations", "parameters", visibilityAttrName};
1334 if (op.getConvention() == Convention::Internal)
1335 omittedAttrs.push_back("convention");
1337 // We can omit the portNames if they were able to be printed as properly as
1339 if (!needPortNamesAttr)
1340 omittedAttrs.push_back("portNames");
1342 // If there are no annotations we can omit the empty array.
1343 if (op->getAttrOfType<ArrayAttr>("annotations").empty())
1344 omittedAttrs.push_back("annotations");
1346 // If there are no enabled layers, then omit the empty array.
1347 if (auto layers = op->getAttrOfType<ArrayAttr>("layers"))
1349 omittedAttrs.push_back("layers");
1351 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
1354 void FExtModuleOp::print(OpAsmPrinter &p) { printFModuleLikeOp(p, *this); }
1356 void FIntModuleOp::print(OpAsmPrinter &p) { printFModuleLikeOp(p, *this); }
1358 void FMemModuleOp::print(OpAsmPrinter &p) { printFModuleLikeOp(p, *this); }
1360 void FModuleOp::print(OpAsmPrinter &p) {
1361 printFModuleLikeOp(p, *this);
1363 // Print the body if this is not an external function. Since this block does
1364 // not have terminators, printing the terminator actually just prints the last
1366 Region &fbody = getBody();
1367 if (!fbody.empty()) {
1369 p.printRegion(fbody, /*printEntryBlockArgs=*/false,
1370 /*printBlockTerminators=*/true);
1380 parseOptionalParameters(OpAsmParser &parser,
1381 SmallVectorImpl<Attribute> ¶meters) {
1383 return parser.parseCommaSeparatedList(
1384 OpAsmParser::Delimiter::OptionalLessGreater, [&]() {
1389 if (parser.parseKeywordOrString(&name) || parser.parseColonType(type))
1392 // Parse the default value if present.
1393 if (succeeded(parser.parseOptionalEqual())) {
1394 if (parser.parseAttribute(value, type))
1398 auto &builder = parser.getBuilder();
1399 parameters.push_back(ParamDeclAttr::get(
1400 builder.getContext(), builder.getStringAttr(name), type, value));
1406 static ParseResult parseParameterList(OpAsmParser &parser,
1407 ArrayAttr ¶meters) {
1408 SmallVector<Attribute> parseParameters;
1409 if (failed(parseOptionalParameters(parser, parseParameters)))
1412 parameters = ArrayAttr::get(parser.getContext(), parseParameters);
1417 static ParseResult parseFModuleLikeOp(OpAsmParser &parser,
1418 OperationState &result,
1419 bool hasSSAIdentifiers) {
1420 auto *context = result.getContext();
1421 auto &builder = parser.getBuilder();
1423 // Parse the visibility attribute.
1424 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
1426 // Parse the name as a symbol.
1427 StringAttr nameAttr;
1428 if (parser.parseSymbolName(nameAttr, ::mlir::SymbolTable::getSymbolAttrName(),
1432 // Parse optional parameters.
1433 SmallVector<Attribute, 4> parameters;
1434 if (parseOptionalParameters(parser, parameters))
1436 result.addAttribute("parameters", builder.getArrayAttr(parameters));
1438 // Parse the module ports.
1439 SmallVector<OpAsmParser::Argument> entryArgs;
1440 SmallVector<Direction, 4> portDirections;
1441 SmallVector<Attribute, 4> portNames;
1442 SmallVector<Attribute, 4> portTypes;
1443 SmallVector<Attribute, 4> portAnnotations;
1444 SmallVector<Attribute, 4> portSyms;
1445 SmallVector<Attribute, 4> portLocs;
1446 if (parseModulePorts(parser, hasSSAIdentifiers, /*supportsSymbols=*/true,
1447 entryArgs, portDirections, portNames, portTypes,
1448 portAnnotations, portSyms, portLocs))
1451 // If module attributes are present, parse them.
1452 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
1455 assert(portNames.size() == portTypes.size());
1457 // Record the argument and result types as an attribute. This is necessary
1458 // for external modules.
1460 // Add port directions.
1461 if (!result.attributes.get("portDirections"))
1462 result.addAttribute("portDirections",
1463 direction::packAttribute(context, portDirections));
1466 if (!result.attributes.get("portNames"))
1467 result.addAttribute("portNames", builder.getArrayAttr(portNames));
1469 // Add the port types.
1470 if (!result.attributes.get("portTypes"))
1471 result.addAttribute("portTypes", ArrayAttr::get(context, portTypes));
1473 // Add the port annotations.
1474 if (!result.attributes.get("portAnnotations")) {
1475 // If there are no portAnnotations, don't add the attribute.
1476 if (llvm::any_of(portAnnotations, [&](Attribute anno) {
1477 return !cast<ArrayAttr>(anno).empty();
1479 result.addAttribute(
"portAnnotations",
1484 if (!result.attributes.get(
"portSyms")) {
1485 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1486 result.addAttribute(
"portSyms", builder.getArrayAttr(portSyms));
1490 if (!result.attributes.get(
"portLocations"))
1491 result.addAttribute(
"portLocations",
ArrayAttr::get(context, portLocs));
1494 if (!result.attributes.get(
"annotations"))
1495 result.addAttribute(
"annotations", builder.getArrayAttr({}));
1499 if (!result.attributes.get(
"portAnnotations"))
1500 result.addAttribute(
"portAnnotations", builder.getArrayAttr({}));
1503 auto *body = result.addRegion();
1505 if (hasSSAIdentifiers) {
1506 if (parser.parseRegion(*body, entryArgs))
1509 body->push_back(
new Block());
1514 ParseResult FModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1517 if (!result.attributes.get(
"convention"))
1518 result.addAttribute(
1521 if (!result.attributes.get(
"layers"))
1522 result.addAttribute(
"layers",
ArrayAttr::get(parser.getContext(), {}));
1526 ParseResult FExtModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1529 if (!result.attributes.get(
"convention"))
1530 result.addAttribute(
1536 ParseResult FIntModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1540 ParseResult FMemModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1547 auto portTypes = getPortTypes();
1548 auto portLocs = getPortLocations();
1549 auto numPorts = portTypes.size();
1552 if (body->getNumArguments() != numPorts)
1553 return emitOpError(
"entry block must have ")
1554 << numPorts <<
" arguments to match module signature";
1557 for (
auto [arg, type, loc] : zip(body->getArguments(), portTypes, portLocs)) {
1558 if (arg.getType() != cast<TypeAttr>(type).getValue())
1559 return emitOpError(
"block argument types should match signature types");
1560 if (arg.getLoc() != cast<LocationAttr>(loc))
1562 "block argument locations should match signature locations");
1568 static LogicalResult
1570 std::optional<::mlir::ArrayAttr> internalPaths) {
1575 if (internalPaths->size() != op.getNumPorts())
1576 return op.emitError(
"module has inconsistent internal path array with ")
1577 << internalPaths->size() <<
" entries for " << op.getNumPorts()
1581 for (
auto [idx, path, typeattr] : llvm::enumerate(
1582 internalPaths->getAsRange<InternalPathAttr>(), op.getPortTypes())) {
1583 if (path.getPath() &&
1584 !type_isa<RefType>(cast<TypeAttr>(typeattr).getValue())) {
1586 op.emitError(
"module has internal path for non-ref-type port ")
1587 << op.getPortNameAttr(idx);
1588 return diag.attachNote(op.getPortLocation(idx)) <<
"this port";
1599 auto params = getParameters();
1603 auto checkParmValue = [&](Attribute elt) ->
bool {
1604 auto param = cast<ParamDeclAttr>(elt);
1605 auto value = param.getValue();
1606 if (isa<IntegerAttr, StringAttr, FloatAttr, hw::ParamVerbatimAttr>(value))
1608 emitError() <<
"has unknown extmodule parameter value '"
1609 << param.getName().getValue() <<
"' = " << value;
1613 if (!llvm::all_of(params, checkParmValue))
1623 auto params = getParameters();
1627 auto checkParmValue = [&](Attribute elt) ->
bool {
1628 auto param = cast<ParamDeclAttr>(elt);
1629 auto value = param.getValue();
1630 if (isa<IntegerAttr, StringAttr, FloatAttr>(value))
1632 emitError() <<
"has unknown intmodule parameter value '"
1633 << param.getName().getValue() <<
"' = " << value;
1637 if (!llvm::all_of(params, checkParmValue))
1644 CircuitOp circuitOp,
1645 SymbolTableCollection &symbolTable,
1647 auto layer = refType.getLayer();
1650 auto *layerOp = symbolTable.lookupSymbolIn(circuitOp, layer);
1652 return emitError(loc) << start <<
" associated with layer '" << layer
1653 <<
"', but this layer was not defined";
1654 if (!isa<LayerOp>(layerOp)) {
1655 auto diag = emitError(loc)
1656 << start <<
" associated with layer '" << layer
1657 <<
"', but symbol '" << layer <<
"' does not refer to a '"
1658 << LayerOp::getOperationName() <<
"' op";
1659 return diag.attachNote(layerOp->getLoc()) <<
"symbol refers to this op";
1665 SymbolTableCollection &symbolTable) {
1667 auto circuitOp = module->getParentOfType<CircuitOp>();
1668 for (
size_t i = 0, e = module.getNumPorts(); i < e; ++i) {
1669 auto type = module.getPortType(i);
1671 if (
auto refType = type_dyn_cast<RefType>(type)) {
1673 refType, module.getPortLocation(i), circuitOp, symbolTable,
1674 Twine(
"probe port '") + module.getPortName(i) +
"' is")))
1679 if (
auto classType = dyn_cast<ClassType>(type)) {
1680 auto className = classType.getNameAttr();
1681 auto classOp = dyn_cast_or_null<ClassLike>(
1682 symbolTable.lookupSymbolIn(circuitOp, className));
1684 return module.emitOpError() <<
"references unknown class " << className;
1687 if (failed(classOp.verifyType(classType,
1688 [&]() { return module.emitOpError(); })))
1697 LogicalResult FModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1702 auto circuitOp = (*this)->getParentOfType<CircuitOp>();
1703 for (
auto layer : getLayers()) {
1704 if (!symbolTable.lookupSymbolIn(circuitOp, cast<SymbolRefAttr>(layer)))
1705 return emitOpError() <<
"enables unknown layer '" << layer <<
"'";
1712 FExtModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1717 FIntModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1722 FMemModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1726 void FModuleOp::getAsmBlockArgumentNames(mlir::Region ®ion,
1731 void FExtModuleOp::getAsmBlockArgumentNames(
1736 void FIntModuleOp::getAsmBlockArgumentNames(
1741 void FMemModuleOp::getAsmBlockArgumentNames(
1746 ArrayAttr FMemModuleOp::getParameters() {
return {}; }
1748 ArrayAttr FModuleOp::getParameters() {
return {}; }
1750 Convention FIntModuleOp::getConvention() {
return Convention::Internal; }
1752 ConventionAttr FIntModuleOp::getConventionAttr() {
1756 Convention FMemModuleOp::getConvention() {
return Convention::Internal; }
1758 ConventionAttr FMemModuleOp::getConventionAttr() {
1767 ClassLike classOp, ClassType type,
1768 function_ref<InFlightDiagnostic()> emitError) {
1770 auto name = type.getNameAttr().getAttr();
1771 auto expectedName = classOp.getModuleNameAttr();
1772 if (name != expectedName)
1773 return emitError() <<
"type has wrong name, got " << name <<
", expected "
1776 auto elements = type.getElements();
1778 auto expectedNumElements = classOp.getNumPorts();
1780 return emitError() <<
"has wrong number of ports, got " <<
numElements
1781 <<
", expected " << expectedNumElements;
1783 auto portNames = classOp.getPortNames();
1784 auto portDirections = classOp.getPortDirections();
1785 auto portTypes = classOp.getPortTypes();
1788 auto element = elements[i];
1790 auto name = element.name;
1791 auto expectedName = portNames[i];
1792 if (name != expectedName)
1793 return emitError() <<
"port #" << i <<
" has wrong name, got " << name
1794 <<
", expected " << expectedName;
1796 auto direction = element.direction;
1797 auto expectedDirection =
Direction(portDirections[i]);
1798 if (direction != expectedDirection)
1799 return emitError() <<
"port " << name <<
" has wrong direction, got "
1803 auto type = element.type;
1804 auto expectedType = cast<TypeAttr>(portTypes[i]).getValue();
1805 if (type != expectedType)
1806 return emitError() <<
"port " << name <<
" has wrong type, got " << type
1807 <<
", expected " << expectedType;
1814 auto n = classOp.getNumPorts();
1815 SmallVector<ClassElement> elements;
1816 elements.reserve(n);
1817 for (
size_t i = 0; i < n; ++i)
1818 elements.push_back({classOp.getPortNameAttr(i), classOp.getPortType(i),
1819 classOp.getPortDirection(i)});
1825 bool hasSSAIdentifiers) {
1826 auto *context = result.getContext();
1827 auto &builder = parser.getBuilder();
1830 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
1833 StringAttr nameAttr;
1834 if (parser.parseSymbolName(nameAttr, ::mlir::SymbolTable::getSymbolAttrName(),
1839 SmallVector<OpAsmParser::Argument> entryArgs;
1840 SmallVector<Direction, 4> portDirections;
1841 SmallVector<Attribute, 4> portNames;
1842 SmallVector<Attribute, 4> portTypes;
1843 SmallVector<Attribute, 4> portAnnotations;
1844 SmallVector<Attribute, 4> portSyms;
1845 SmallVector<Attribute, 4> portLocs;
1847 false, entryArgs, portDirections,
1848 portNames, portTypes, portAnnotations, portSyms,
1853 for (
auto annos : portAnnotations)
1854 if (!cast<ArrayAttr>(annos).empty())
1858 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
1861 assert(portNames.size() == portTypes.size());
1867 if (!result.attributes.get(
"portDirections"))
1868 result.addAttribute(
"portDirections",
1872 if (!result.attributes.get(
"portNames"))
1873 result.addAttribute(
"portNames", builder.getArrayAttr(portNames));
1876 if (!result.attributes.get(
"portTypes"))
1877 result.addAttribute(
"portTypes", builder.getArrayAttr(portTypes));
1880 if (!result.attributes.get(
"portSyms")) {
1881 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1882 result.addAttribute(
"portSyms", builder.getArrayAttr(portSyms));
1886 if (!result.attributes.get(
"portLocations"))
1887 result.addAttribute(
"portLocations",
ArrayAttr::get(context, portLocs));
1893 auto *bodyRegion = result.addRegion();
1895 if (hasSSAIdentifiers) {
1896 if (parser.parseRegion(*bodyRegion, entryArgs))
1898 if (bodyRegion->empty())
1899 bodyRegion->push_back(
new Block());
1909 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
1910 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
1911 p << visibility.getValue() <<
' ';
1914 p.printSymbolName(op.getName());
1918 Region ®ion = op->getRegion(0);
1919 Block *body =
nullptr;
1920 if (!region.empty())
1921 body = ®ion.front();
1924 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
1925 {}, op.getPortSymbols(), op.getPortLocations());
1928 SmallVector<StringRef, 8> omittedAttrs = {
1929 "sym_name",
"portNames",
"portTypes",
"portDirections",
1930 "portSyms",
"portLocations", visibilityAttrName};
1934 if (!needPortNamesAttr)
1935 omittedAttrs.push_back(
"portNames");
1937 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
1940 if (!region.empty()) {
1942 auto printEntryBlockArgs =
false;
1943 auto printBlockTerminators =
false;
1944 p.printRegion(region, printEntryBlockArgs, printBlockTerminators);
1952 void ClassOp::build(OpBuilder &builder, OperationState &result, StringAttr name,
1953 ArrayRef<PortInfo> ports) {
1956 [](
const auto &port) {
return port.annotations.empty(); }) &&
1957 "class ports may not have annotations");
1962 auto *bodyRegion = result.regions[0].get();
1964 bodyRegion->push_back(body);
1967 for (
auto &elt : ports)
1968 body->addArgument(elt.type, elt.loc);
1971 void ClassOp::print(OpAsmPrinter &p) {
1975 ParseResult ClassOp::parse(OpAsmParser &parser, OperationState &result) {
1976 auto hasSSAIdentifiers =
true;
1982 auto type = operand.getType();
1983 if (!isa<PropertyType>(type)) {
1984 emitOpError(
"ports on a class must be properties");
1993 ClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
1997 void ClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2002 SmallVector<PortInfo> ClassOp::getPorts() {
2007 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2012 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2015 Convention ClassOp::getConvention() {
return Convention::Internal; }
2017 ConventionAttr ClassOp::getConventionAttr() {
2021 ArrayAttr ClassOp::getParameters() {
return {}; }
2023 ArrayAttr ClassOp::getPortAnnotationsAttr() {
2027 ArrayAttr ClassOp::getLayersAttr() {
return ArrayAttr::get(getContext(), {}); }
2029 ArrayRef<Attribute> ClassOp::getLayers() {
return getLayersAttr(); }
2039 BlockArgument ClassOp::getArgument(
size_t portNumber) {
2043 bool ClassOp::canDiscardOnUseEmpty() {
2054 void ExtClassOp::build(OpBuilder &builder, OperationState &result,
2055 StringAttr name, ArrayRef<PortInfo> ports) {
2058 [](
const auto &port) {
return port.annotations.empty(); }) &&
2059 "class ports may not have annotations");
2064 void ExtClassOp::print(OpAsmPrinter &p) {
2068 ParseResult ExtClassOp::parse(OpAsmParser &parser, OperationState &result) {
2069 auto hasSSAIdentifiers =
false;
2074 ExtClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2078 void ExtClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2083 SmallVector<PortInfo> ExtClassOp::getPorts() {
2088 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2092 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2095 Convention ExtClassOp::getConvention() {
return Convention::Internal; }
2097 ConventionAttr ExtClassOp::getConventionAttr() {
2101 ArrayAttr ExtClassOp::getLayersAttr() {
2105 ArrayRef<Attribute> ExtClassOp::getLayers() {
return getLayersAttr(); }
2107 ArrayAttr ExtClassOp::getParameters() {
return {}; }
2109 ArrayAttr ExtClassOp::getPortAnnotationsAttr() {
2121 bool ExtClassOp::canDiscardOnUseEmpty() {
2132 void InstanceOp::build(
2133 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2134 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2135 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2136 ArrayRef<Attribute> annotations, ArrayRef<Attribute> portAnnotations,
2137 ArrayRef<Attribute> layers,
bool lowerToBind, StringAttr innerSym) {
2138 build(builder, result, resultTypes, moduleName, name, nameKind,
2139 portDirections, portNames, annotations, portAnnotations, layers,
2144 void InstanceOp::build(
2145 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2146 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2147 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2148 ArrayRef<Attribute> annotations, ArrayRef<Attribute> portAnnotations,
2149 ArrayRef<Attribute> layers,
bool lowerToBind, hw::InnerSymAttr innerSym) {
2150 result.addTypes(resultTypes);
2151 result.addAttribute(
"moduleName",
2153 result.addAttribute(
"name", builder.getStringAttr(name));
2154 result.addAttribute(
2157 result.addAttribute(
"portNames", builder.getArrayAttr(portNames));
2158 result.addAttribute(
"annotations", builder.getArrayAttr(annotations));
2159 result.addAttribute(
"layers", builder.getArrayAttr(layers));
2161 result.addAttribute(
"lowerToBind", builder.getUnitAttr());
2163 result.addAttribute(
"inner_sym", innerSym);
2164 result.addAttribute(
"nameKind",
2167 if (portAnnotations.empty()) {
2168 SmallVector<Attribute, 16> portAnnotationsVec(resultTypes.size(),
2169 builder.getArrayAttr({}));
2170 result.addAttribute(
"portAnnotations",
2171 builder.getArrayAttr(portAnnotationsVec));
2173 assert(portAnnotations.size() == resultTypes.size());
2174 result.addAttribute(
"portAnnotations",
2175 builder.getArrayAttr(portAnnotations));
2179 void InstanceOp::build(OpBuilder &builder, OperationState &result,
2180 FModuleLike module, StringRef name,
2181 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2182 ArrayRef<Attribute> portAnnotations,
bool lowerToBind,
2183 hw::InnerSymAttr innerSym) {
2186 SmallVector<Type> resultTypes;
2187 resultTypes.reserve(module.getNumPorts());
2189 module.getPortTypes(), std::back_inserter(resultTypes),
2190 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2193 ArrayAttr portAnnotationsAttr;
2194 if (portAnnotations.empty()) {
2195 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2196 resultTypes.size(), builder.getArrayAttr({})));
2198 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2202 builder, result, resultTypes,
2204 builder.getStringAttr(name),
2206 module.getPortDirectionsAttr(), module.getPortNamesAttr(),
2207 builder.getArrayAttr(annotations), portAnnotationsAttr,
2208 module.getLayersAttr(), lowerToBind ? builder.getUnitAttr() : UnitAttr(),
2212 void InstanceOp::build(OpBuilder &builder, OperationState &odsState,
2213 ArrayRef<PortInfo> ports, StringRef moduleName,
2214 StringRef name, NameKindEnum nameKind,
2215 ArrayRef<Attribute> annotations,
2216 ArrayRef<Attribute> layers,
bool lowerToBind,
2217 hw::InnerSymAttr innerSym) {
2219 SmallVector<Type> newResultTypes;
2220 SmallVector<Direction> newPortDirections;
2221 SmallVector<Attribute> newPortNames;
2222 SmallVector<Attribute> newPortAnnotations;
2223 for (
auto &p : ports) {
2224 newResultTypes.push_back(p.type);
2225 newPortDirections.push_back(p.direction);
2226 newPortNames.push_back(p.name);
2227 newPortAnnotations.push_back(p.annotations.getArrayAttr());
2230 return build(builder, odsState, newResultTypes, moduleName, name, nameKind,
2231 newPortDirections, newPortNames, annotations, newPortAnnotations,
2232 layers, lowerToBind, innerSym);
2238 SmallVector<SymbolRefAttr> missingLayers;
2239 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
2241 missingLayers.push_back(layer);
2243 if (missingLayers.empty())
2247 emitOpError(
"ambient layers are insufficient to instantiate module");
2248 auto ¬e = diag.attachNote();
2249 note <<
"missing layer requirements: ";
2250 interleaveComma(missingLayers, note);
2257 const llvm::BitVector &portIndices) {
2258 assert(portIndices.size() >= getNumResults() &&
2259 "portIndices is not at least as large as getNumResults()");
2261 if (portIndices.none())
2264 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
2265 SmallVector<Type>(result_type_begin(), result_type_end()), portIndices);
2266 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
2268 SmallVector<Attribute> newPortNames =
2270 SmallVector<Attribute> newPortAnnotations =
2273 auto newOp = builder.create<InstanceOp>(
2274 getLoc(), newResultTypes, getModuleName(),
getName(), getNameKind(),
2275 newPortDirections, newPortNames, getAnnotations().getValue(),
2276 newPortAnnotations, getLayers(), getLowerToBind(), getInnerSymAttr());
2278 for (
unsigned oldIdx = 0, newIdx = 0, numOldPorts = getNumResults();
2279 oldIdx != numOldPorts; ++oldIdx) {
2280 if (portIndices.test(oldIdx)) {
2281 assert(getResult(oldIdx).use_empty() &&
"removed instance port has uses");
2284 getResult(oldIdx).replaceAllUsesWith(newOp.getResult(newIdx));
2292 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2293 newOp->setAttr(
"output_file", outputFile);
2298 ArrayAttr InstanceOp::getPortAnnotation(
unsigned portIdx) {
2299 assert(portIdx < getNumResults() &&
2300 "index should be smaller than result number");
2301 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
2304 void InstanceOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
2305 assert(annotations.size() == getNumResults() &&
2306 "number of annotations is not equal to result number");
2307 (*this)->setAttr(
"portAnnotations",
2312 InstanceOp::cloneAndInsertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2313 auto portSize = ports.size();
2314 auto newPortCount = getNumResults() + portSize;
2315 SmallVector<Direction> newPortDirections;
2316 newPortDirections.reserve(newPortCount);
2317 SmallVector<Attribute> newPortNames;
2318 newPortNames.reserve(newPortCount);
2319 SmallVector<Type> newPortTypes;
2320 newPortTypes.reserve(newPortCount);
2321 SmallVector<Attribute> newPortAnnos;
2322 newPortAnnos.reserve(newPortCount);
2324 unsigned oldIndex = 0;
2325 unsigned newIndex = 0;
2326 while (oldIndex + newIndex < newPortCount) {
2328 if (newIndex < portSize && ports[newIndex].first == oldIndex) {
2329 auto &newPort = ports[newIndex].second;
2330 newPortDirections.push_back(newPort.direction);
2331 newPortNames.push_back(newPort.name);
2332 newPortTypes.push_back(newPort.type);
2333 newPortAnnos.push_back(newPort.annotations.getArrayAttr());
2337 newPortDirections.push_back(getPortDirection(oldIndex));
2338 newPortNames.push_back(getPortName(oldIndex));
2339 newPortTypes.push_back(getType(oldIndex));
2340 newPortAnnos.push_back(getPortAnnotation(oldIndex));
2346 return OpBuilder(*this).create<InstanceOp>(
2347 getLoc(), newPortTypes, getModuleName(),
getName(), getNameKind(),
2348 newPortDirections, newPortNames, getAnnotations().getValue(),
2349 newPortAnnos, getLayers(), getLowerToBind(), getInnerSymAttr());
2352 LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2354 getModuleNameAttr());
2359 StringAttr InstanceOp::getInstanceNameAttr() {
return getNameAttr(); }
2361 void InstanceOp::print(OpAsmPrinter &p) {
2364 p.printKeywordOrString(
getName());
2365 if (
auto attr = getInnerSymAttr()) {
2367 p.printSymbolName(attr.getSymName());
2369 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2370 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2373 SmallVector<StringRef, 10> omittedAttrs = {
2374 "moduleName",
"name",
"portDirections",
2375 "portNames",
"portTypes",
"portAnnotations",
2376 "inner_sym",
"nameKind"};
2377 if (getAnnotations().
empty())
2378 omittedAttrs.push_back(
"annotations");
2379 if (getLayers().
empty())
2380 omittedAttrs.push_back(
"layers");
2381 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2385 p.printSymbolName(getModuleName());
2388 SmallVector<Attribute> portTypes;
2389 portTypes.reserve(getNumResults());
2390 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2393 getPortNames().getValue(), portTypes,
2394 getPortAnnotations().getValue(), {}, {});
2397 ParseResult InstanceOp::parse(OpAsmParser &parser, OperationState &result) {
2398 auto *context = parser.getContext();
2399 auto &resultAttrs = result.attributes;
2402 hw::InnerSymAttr innerSymAttr;
2403 FlatSymbolRefAttr moduleName;
2404 SmallVector<OpAsmParser::Argument> entryArgs;
2405 SmallVector<Direction, 4> portDirections;
2406 SmallVector<Attribute, 4> portNames;
2407 SmallVector<Attribute, 4> portTypes;
2408 SmallVector<Attribute, 4> portAnnotations;
2409 SmallVector<Attribute, 4> portSyms;
2410 SmallVector<Attribute, 4> portLocs;
2411 NameKindEnumAttr nameKind;
2413 if (parser.parseKeywordOrString(&name))
2415 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
2416 if (parser.parseCustomAttributeWithFallback(
2417 innerSymAttr, ::mlir::Type{},
2418 hw::InnerSymbolTable::getInnerSymbolAttrName(),
2419 result.attributes)) {
2420 return ::mlir::failure();
2424 parser.parseOptionalAttrDict(result.attributes) ||
2425 parser.parseAttribute(moduleName,
"moduleName", resultAttrs) ||
2427 false, entryArgs, portDirections,
2428 portNames, portTypes, portAnnotations, portSyms,
2434 if (!resultAttrs.get(
"moduleName"))
2435 result.addAttribute(
"moduleName", moduleName);
2436 if (!resultAttrs.get(
"name"))
2438 result.addAttribute(
"nameKind", nameKind);
2439 if (!resultAttrs.get(
"portDirections"))
2440 result.addAttribute(
"portDirections",
2442 if (!resultAttrs.get(
"portNames"))
2443 result.addAttribute(
"portNames",
ArrayAttr::get(context, portNames));
2444 if (!resultAttrs.get(
"portAnnotations"))
2445 result.addAttribute(
"portAnnotations",
2450 if (!resultAttrs.get(
"annotations"))
2451 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
2452 if (!resultAttrs.get(
"layers"))
2453 resultAttrs.append(
"layers", parser.getBuilder().getArrayAttr({}));
2456 result.types.reserve(portTypes.size());
2458 portTypes, std::back_inserter(result.types),
2459 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2469 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
2470 setNameFn(getResult(i), (base +
"_" + getPortNameStr(i)).str());
2474 std::optional<size_t> InstanceOp::getTargetResultIndex() {
2476 return std::nullopt;
2483 void InstanceChoiceOp::build(
2484 OpBuilder &builder, OperationState &result, FModuleLike defaultModule,
2485 ArrayRef<std::pair<OptionCaseOp, FModuleLike>> cases, StringRef name,
2486 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2487 ArrayRef<Attribute> portAnnotations, StringAttr innerSym) {
2489 SmallVector<Type> resultTypes;
2490 for (Attribute portType : defaultModule.getPortTypes())
2491 resultTypes.push_back(cast<TypeAttr>(portType).getValue());
2494 ArrayAttr portAnnotationsAttr;
2495 if (portAnnotations.empty()) {
2496 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2497 resultTypes.size(), builder.getArrayAttr({})));
2499 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2503 SmallVector<Attribute> moduleNames, caseNames;
2505 for (
auto [caseOption, caseModule] : cases) {
2506 auto caseGroup = caseOption->getParentOfType<OptionOp>();
2508 {SymbolRefAttr::get(caseOption)}));
2512 return build(builder, result, resultTypes, builder.getArrayAttr(moduleNames),
2513 builder.getArrayAttr(caseNames), builder.getStringAttr(name),
2515 defaultModule.getPortDirectionsAttr(),
2516 defaultModule.getPortNamesAttr(),
2517 builder.getArrayAttr(annotations), portAnnotationsAttr,
2518 defaultModule.getLayersAttr(),
2522 std::optional<size_t> InstanceChoiceOp::getTargetResultIndex() {
2523 return std::nullopt;
2526 void InstanceChoiceOp::print(OpAsmPrinter &p) {
2529 p.printKeywordOrString(
getName());
2530 if (
auto attr = getInnerSymAttr()) {
2532 p.printSymbolName(attr.getSymName());
2534 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2535 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2538 SmallVector<StringRef, 10> omittedAttrs = {
2539 "moduleNames",
"caseNames",
"name",
2540 "portDirections",
"portNames",
"portTypes",
2541 "portAnnotations",
"inner_sym",
"nameKind"};
2542 if (getAnnotations().
empty())
2543 omittedAttrs.push_back(
"annotations");
2544 if (getLayers().
empty())
2545 omittedAttrs.push_back(
"layers");
2546 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2551 auto moduleNames = getModuleNamesAttr();
2552 auto caseNames = getCaseNamesAttr();
2554 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[0]).getValue());
2556 p <<
" alternatives ";
2558 cast<SymbolRefAttr>(caseNames[0]).getRootReference().getValue());
2560 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
2564 auto symbol = cast<SymbolRefAttr>(caseNames[i]);
2565 p.printSymbolName(symbol.getNestedReferences()[0].getValue());
2567 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[i + 1]).getValue());
2573 SmallVector<Attribute> portTypes;
2574 portTypes.reserve(getNumResults());
2575 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2578 getPortNames().getValue(), portTypes,
2579 getPortAnnotations().getValue(), {}, {});
2582 ParseResult InstanceChoiceOp::parse(OpAsmParser &parser,
2583 OperationState &result) {
2584 auto *context = parser.getContext();
2585 auto &resultAttrs = result.attributes;
2588 hw::InnerSymAttr innerSymAttr;
2589 SmallVector<Attribute> moduleNames;
2590 SmallVector<Attribute> caseNames;
2591 SmallVector<OpAsmParser::Argument> entryArgs;
2592 SmallVector<Direction, 4> portDirections;
2593 SmallVector<Attribute, 4> portNames;
2594 SmallVector<Attribute, 4> portTypes;
2595 SmallVector<Attribute, 4> portAnnotations;
2596 SmallVector<Attribute, 4> portSyms;
2597 SmallVector<Attribute, 4> portLocs;
2598 NameKindEnumAttr nameKind;
2600 if (parser.parseKeywordOrString(&name))
2602 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
2603 if (parser.parseCustomAttributeWithFallback(
2604 innerSymAttr, Type{},
2605 hw::InnerSymbolTable::getInnerSymbolAttrName(),
2606 result.attributes)) {
2611 parser.parseOptionalAttrDict(result.attributes))
2614 FlatSymbolRefAttr defaultModuleName;
2615 if (parser.parseAttribute(defaultModuleName))
2617 moduleNames.push_back(defaultModuleName);
2621 FlatSymbolRefAttr optionName;
2622 if (parser.parseKeyword(
"alternatives") ||
2623 parser.parseAttribute(optionName) || parser.parseLBrace())
2626 FlatSymbolRefAttr moduleName;
2627 StringAttr caseName;
2628 while (succeeded(parser.parseOptionalSymbolName(caseName))) {
2629 if (parser.parseArrow() || parser.parseAttribute(moduleName))
2631 moduleNames.push_back(moduleName);
2633 optionName.getAttr(), {FlatSymbolRefAttr::get(caseName)}));
2634 if (failed(parser.parseOptionalComma()))
2637 if (parser.parseRBrace())
2642 false, entryArgs, portDirections,
2643 portNames, portTypes, portAnnotations, portSyms,
2649 if (!resultAttrs.get(
"moduleNames"))
2650 result.addAttribute(
"moduleNames",
ArrayAttr::get(context, moduleNames));
2651 if (!resultAttrs.get(
"caseNames"))
2652 result.addAttribute(
"caseNames",
ArrayAttr::get(context, caseNames));
2653 if (!resultAttrs.get(
"name"))
2655 result.addAttribute(
"nameKind", nameKind);
2656 if (!resultAttrs.get(
"portDirections"))
2657 result.addAttribute(
"portDirections",
2659 if (!resultAttrs.get(
"portNames"))
2660 result.addAttribute(
"portNames",
ArrayAttr::get(context, portNames));
2661 if (!resultAttrs.get(
"portAnnotations"))
2662 result.addAttribute(
"portAnnotations",
2667 if (!resultAttrs.get(
"annotations"))
2668 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
2669 if (!resultAttrs.get(
"layers"))
2670 resultAttrs.append(
"layers", parser.getBuilder().getArrayAttr({}));
2673 result.types.reserve(portTypes.size());
2675 portTypes, std::back_inserter(result.types),
2676 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2683 for (
auto [result, name] : llvm::zip(getResults(), getPortNames()))
2684 setNameFn(result, (base +
"_" + cast<StringAttr>(name).getValue()).str());
2688 if (getCaseNamesAttr().
empty())
2689 return emitOpError() <<
"must have at least one case";
2690 if (getModuleNamesAttr().size() != getCaseNamesAttr().size() + 1)
2691 return emitOpError() <<
"number of referenced modules does not match the "
2692 "number of options";
2697 SmallVector<SymbolRefAttr> missingLayers;
2698 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
2700 missingLayers.push_back(layer);
2702 if (missingLayers.empty())
2706 emitOpError(
"ambient layers are insufficient to instantiate module");
2707 auto ¬e = diag.attachNote();
2708 note <<
"missing layer requirements: ";
2709 interleaveComma(missingLayers, note);
2714 InstanceChoiceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2715 auto caseNames = getCaseNamesAttr();
2716 for (
auto moduleName : getModuleNamesAttr()) {
2718 *
this, symbolTable, cast<FlatSymbolRefAttr>(moduleName))))
2722 auto root = cast<SymbolRefAttr>(caseNames[0]).getRootReference();
2723 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
2724 auto ref = cast<SymbolRefAttr>(caseNames[i]);
2725 auto refRoot = ref.getRootReference();
2726 if (ref.getRootReference() != root)
2727 return emitOpError() <<
"case " << ref
2728 <<
" is not in the same option group as "
2731 if (!symbolTable.lookupNearestSymbolFrom<OptionOp>(*
this, refRoot))
2732 return emitOpError() <<
"option " << refRoot <<
" does not exist";
2734 if (!symbolTable.lookupNearestSymbolFrom<OptionCaseOp>(*
this, ref))
2735 return emitOpError() <<
"option " << refRoot
2736 <<
" does not contain option case " << ref;
2743 InstanceChoiceOp::getTargetOrDefaultAttr(OptionCaseOp option) {
2744 auto caseNames = getCaseNamesAttr();
2745 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
2746 StringAttr caseSym = cast<SymbolRefAttr>(caseNames[i]).getLeafReference();
2747 if (caseSym == option.getSymName())
2748 return cast<FlatSymbolRefAttr>(getModuleNamesAttr()[i + 1]);
2750 return getDefaultTargetAttr();
2753 SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1>
2754 InstanceChoiceOp::getTargetChoices() {
2755 auto caseNames = getCaseNamesAttr();
2756 auto moduleNames = getModuleNamesAttr();
2757 SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1> choices;
2758 for (
size_t i = 0; i < caseNames.size(); ++i) {
2759 choices.emplace_back(cast<SymbolRefAttr>(caseNames[i]),
2760 cast<FlatSymbolRefAttr>(moduleNames[i + 1]));
2768 const llvm::BitVector &portIndices) {
2769 assert(portIndices.size() >= getNumResults() &&
2770 "portIndices is not at least as large as getNumResults()");
2772 if (portIndices.none())
2775 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
2776 SmallVector<Type>(result_type_begin(), result_type_end()), portIndices);
2777 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
2779 SmallVector<Attribute> newPortNames =
2781 SmallVector<Attribute> newPortAnnotations =
2784 auto newOp = builder.create<InstanceChoiceOp>(
2785 getLoc(), newResultTypes, getModuleNames(), getCaseNames(),
getName(),
2787 ArrayAttr::get(getContext(), newPortNames), getAnnotationsAttr(),
2791 for (
unsigned oldIdx = 0, newIdx = 0, numOldPorts = getNumResults();
2792 oldIdx != numOldPorts; ++oldIdx) {
2793 if (portIndices.test(oldIdx)) {
2794 assert(getResult(oldIdx).use_empty() &&
"removed instance port has uses");
2797 getResult(oldIdx).replaceAllUsesWith(newOp.getResult(newIdx));
2805 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2806 newOp->setAttr(
"output_file", outputFile);
2815 void MemOp::build(OpBuilder &builder, OperationState &result,
2816 TypeRange resultTypes, uint32_t readLatency,
2817 uint32_t writeLatency, uint64_t depth, RUWAttr ruw,
2818 ArrayRef<Attribute> portNames, StringRef name,
2819 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2820 ArrayRef<Attribute> portAnnotations,
2821 hw::InnerSymAttr innerSym) {
2822 result.addAttribute(
2824 builder.getIntegerAttr(builder.getIntegerType(32), readLatency));
2825 result.addAttribute(
2827 builder.getIntegerAttr(builder.getIntegerType(32), writeLatency));
2828 result.addAttribute(
2829 "depth", builder.getIntegerAttr(builder.getIntegerType(64), depth));
2831 result.addAttribute(
"portNames", builder.getArrayAttr(portNames));
2832 result.addAttribute(
"name", builder.getStringAttr(name));
2833 result.addAttribute(
"nameKind",
2835 result.addAttribute(
"annotations", builder.getArrayAttr(annotations));
2837 result.addAttribute(
"inner_sym", innerSym);
2838 result.addTypes(resultTypes);
2840 if (portAnnotations.empty()) {
2841 SmallVector<Attribute, 16> portAnnotationsVec(resultTypes.size(),
2842 builder.getArrayAttr({}));
2843 result.addAttribute(
"portAnnotations",
2844 builder.getArrayAttr(portAnnotationsVec));
2846 assert(portAnnotations.size() == resultTypes.size());
2847 result.addAttribute(
"portAnnotations",
2848 builder.getArrayAttr(portAnnotations));
2852 void MemOp::build(OpBuilder &builder, OperationState &result,
2853 TypeRange resultTypes, uint32_t readLatency,
2854 uint32_t writeLatency, uint64_t depth, RUWAttr ruw,
2855 ArrayRef<Attribute> portNames, StringRef name,
2856 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2857 ArrayRef<Attribute> portAnnotations, StringAttr innerSym) {
2858 build(builder, result, resultTypes, readLatency, writeLatency, depth, ruw,
2859 portNames, name, nameKind, annotations, portAnnotations,
2863 ArrayAttr MemOp::getPortAnnotation(
unsigned portIdx) {
2864 assert(portIdx < getNumResults() &&
2865 "index should be smaller than result number");
2866 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
2869 void MemOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
2870 assert(annotations.size() == getNumResults() &&
2871 "number of annotations is not equal to result number");
2872 (*this)->setAttr(
"portAnnotations",
2878 size_t &numReadWritePorts,
size_t &numDbgsPorts) {
2881 numReadWritePorts = 0;
2883 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
2884 auto portKind = getPortKind(i);
2885 if (portKind == MemOp::PortKind::Debug)
2887 else if (portKind == MemOp::PortKind::Read)
2889 else if (portKind == MemOp::PortKind::Write) {
2892 ++numReadWritePorts;
2901 llvm::SmallDenseSet<Attribute, 8> portNamesSet;
2907 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
2908 auto portName = getPortName(i);
2913 BundleType portBundleType =
2914 type_dyn_cast<BundleType>(getResult(i).getType());
2917 if (!portNamesSet.insert(portName).second) {
2918 emitOpError() <<
"has non-unique port name " << portName;
2926 auto elt = getPortNamed(portName);
2928 emitOpError() <<
"could not get port with name " << portName;
2931 auto firrtlType = type_cast<FIRRTLType>(elt.getType());
2934 if (portKind == MemOp::PortKind::Debug &&
2935 !type_isa<RefType>(getResult(i).getType()))
2936 return emitOpError() <<
"has an invalid type on port " << portName
2937 <<
" (expected Read/Write/ReadWrite/Debug)";
2938 if (type_isa<RefType>(firrtlType) && e == 1)
2939 return emitOpError()
2940 <<
"cannot have only one port of debug type. Debug port can only "
2941 "exist alongside other read/write/read-write port";
2946 if (portKind == MemOp::PortKind::Debug) {
2947 auto resType = type_cast<RefType>(getResult(i).getType());
2948 if (!(resType && type_isa<FVectorType>(resType.getType())))
2949 return emitOpError() <<
"debug ports must be a RefType of FVectorType";
2950 dataType = type_cast<FVectorType>(resType.getType()).getElementType();
2952 auto dataTypeOption = portBundleType.getElement(
"data");
2953 if (!dataTypeOption && portKind == MemOp::PortKind::ReadWrite)
2954 dataTypeOption = portBundleType.getElement(
"wdata");
2955 if (!dataTypeOption) {
2956 emitOpError() <<
"has no data field on port " << portName
2957 <<
" (expected to see \"data\" for a read or write "
2958 "port or \"rdata\" for a read/write port)";
2961 dataType = dataTypeOption->type;
2963 if (portKind == MemOp::PortKind::Read) {
2970 emitOpError() <<
"has non-passive data type on port " << portName
2971 <<
" (memory types must be passive)";
2976 if (dataType.containsAnalog()) {
2977 emitOpError() <<
"has a data type that contains an analog type on port "
2979 <<
" (memory types cannot contain analog types)";
2987 getTypeForPort(getDepth(), dataType, portKind,
2988 dataType.isGround() ? getMaskBits() : 0);
2991 auto originalType = getResult(i).getType();
2992 if (originalType != expectedType) {
2993 StringRef portKindName;
2995 case MemOp::PortKind::Read:
2996 portKindName =
"read";
2998 case MemOp::PortKind::Write:
2999 portKindName =
"write";
3001 case MemOp::PortKind::ReadWrite:
3002 portKindName =
"readwrite";
3004 case MemOp::PortKind::Debug:
3005 portKindName =
"dbg";
3008 emitOpError() <<
"has an invalid type for port " << portName
3009 <<
" of determined kind \"" << portKindName
3010 <<
"\" (expected " << expectedType <<
", but got "
3011 << originalType <<
")";
3017 if (oldDataType && oldDataType != dataType) {
3018 emitOpError() <<
"port " << getPortName(i)
3019 <<
" has a different type than port " << getPortName(i - 1)
3020 <<
" (expected " << oldDataType <<
", but got " << dataType
3025 oldDataType = dataType;
3028 auto maskWidth = getMaskBits();
3030 auto dataWidth = getDataType().getBitWidthOrSentinel();
3031 if (dataWidth > 0 && maskWidth > (
size_t)dataWidth)
3032 return emitOpError(
"the mask width cannot be greater than "
3035 if (getPortAnnotations().size() != getNumResults())
3036 return emitOpError(
"the number of result annotations should be "
3037 "equal to the number of results");
3043 return std::max(1U, llvm::Log2_64_Ceil(depth));
3049 PortKind portKind,
size_t maskBits) {
3051 auto *context = dataType.getContext();
3052 if (portKind == PortKind::Debug)
3061 auto getId = [&](StringRef name) -> StringAttr {
3065 SmallVector<BundleType::BundleElement, 7> portFields;
3069 portFields.push_back({getId(
"addr"),
false, addressType});
3070 portFields.push_back({getId(
"en"),
false,
UIntType::get(context, 1)});
3071 portFields.push_back({getId(
"clk"),
false,
ClockType::get(context)});
3074 case PortKind::Read:
3075 portFields.push_back({getId(
"data"),
true, dataType});
3078 case PortKind::Write:
3079 portFields.push_back({getId(
"data"),
false, dataType});
3080 portFields.push_back({getId(
"mask"),
false, maskType});
3083 case PortKind::ReadWrite:
3084 portFields.push_back({getId(
"rdata"),
true, dataType});
3085 portFields.push_back({getId(
"wmode"),
false,
UIntType::get(context, 1)});
3086 portFields.push_back({getId(
"wdata"),
false, dataType});
3087 portFields.push_back({getId(
"wmask"),
false, maskType});
3090 llvm::report_fatal_error(
"memory port kind not handled");
3098 SmallVector<MemOp::NamedPort> MemOp::getPorts() {
3099 SmallVector<MemOp::NamedPort> result;
3101 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3103 auto portType = type_cast<FIRRTLType>(getResult(i).getType());
3110 MemOp::PortKind MemOp::getPortKind(StringRef portName) {
3112 type_cast<FIRRTLType>(getPortNamed(portName).getType()));
3116 MemOp::PortKind MemOp::getPortKind(
size_t resultNo) {
3118 type_cast<FIRRTLType>(getResult(resultNo).getType()));
3122 size_t MemOp::getMaskBits() {
3124 for (
auto res : getResults()) {
3125 if (type_isa<RefType>(res.getType()))
3127 auto firstPortType = type_cast<FIRRTLBaseType>(res.getType());
3133 for (
auto t : type_cast<BundleType>(firstPortType.getPassiveType())) {
3134 if (t.name.getValue().contains(
"mask"))
3137 if (type_isa<UIntType>(mType))
3147 assert(getNumResults() != 0 &&
"Mems with no read/write ports are illegal");
3149 if (
auto refType = type_dyn_cast<RefType>(getResult(0).getType()))
3150 return type_cast<FVectorType>(refType.getType()).getElementType();
3151 auto firstPortType = type_cast<FIRRTLBaseType>(getResult(0).getType());
3153 StringRef dataFieldName =
"data";
3155 dataFieldName =
"rdata";
3157 return type_cast<BundleType>(firstPortType.getPassiveType())
3158 .getElementType(dataFieldName);
3161 StringAttr MemOp::getPortName(
size_t resultNo) {
3162 return cast<StringAttr>(getPortNames()[resultNo]);
3166 return type_cast<FIRRTLBaseType>(getResults()[resultNo].getType());
3169 Value MemOp::getPortNamed(StringAttr name) {
3170 auto namesArray = getPortNames();
3171 for (
size_t i = 0, e = namesArray.size(); i != e; ++i) {
3172 if (namesArray[i] == name) {
3173 assert(i < getNumResults() &&
" names array out of sync with results");
3174 return getResult(i);
3183 size_t numReadPorts = 0;
3184 size_t numWritePorts = 0;
3185 size_t numReadWritePorts = 0;
3187 SmallVector<int32_t> writeClockIDs;
3189 for (
size_t i = 0, e = op.getNumResults(); i != e; ++i) {
3190 auto portKind = op.getPortKind(i);
3191 if (portKind == MemOp::PortKind::Read)
3193 else if (portKind == MemOp::PortKind::Write) {
3194 for (
auto *a : op.getResult(i).getUsers()) {
3195 auto subfield = dyn_cast<SubfieldOp>(a);
3196 if (!subfield || subfield.getFieldIndex() != 2)
3198 auto clockPort = a->getResult(0);
3199 for (
auto *b : clockPort.getUsers()) {
3200 if (
auto connect = dyn_cast<FConnectLike>(b)) {
3201 if (
connect.getDest() == clockPort) {
3204 connect.getSrc(),
true,
true,
true),
3206 if (result.second) {
3207 writeClockIDs.push_back(numWritePorts);
3209 writeClockIDs.push_back(result.first->second);
3218 ++numReadWritePorts;
3225 op.emitError(
"'firrtl.mem' should have simple type and known width");
3226 MemoryInitAttr init = op->getAttrOfType<MemoryInitAttr>(
"init");
3228 if (op->hasAttr(
"modName"))
3229 modName = op->getAttrOfType<StringAttr>(
"modName");
3231 SmallString<8> clocks;
3232 for (
auto a : writeClockIDs)
3233 clocks.append(Twine((
char)(a +
'a')).str());
3234 SmallString<32> initStr;
3239 for (
auto c : init.getFilename().getValue())
3240 if ((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') ||
3241 (c >=
'0' && c <=
'9'))
3242 initStr.push_back(c);
3243 initStr.push_back(
'_');
3244 initStr.push_back(init.getIsBinary() ?
't' :
'f');
3245 initStr.push_back(
'_');
3246 initStr.push_back(init.getIsInline() ?
't' :
'f');
3251 "{0}FIRRTLMem_{1}_{2}_{3}_{4}_{5}_{6}_{7}_{8}_{9}_{10}{11}{12}",
3252 op.getPrefix().value_or(
""), numReadPorts, numWritePorts,
3253 numReadWritePorts, (
size_t)
width, op.getDepth(),
3254 op.getReadLatency(), op.getWriteLatency(), op.getMaskBits(),
3255 (
unsigned)op.getRuw(), (
unsigned)seq::WUW::PortOrder,
3256 clocks.empty() ?
"" :
"_" + clocks, init ? initStr.str() :
""));
3258 return {numReadPorts,
3263 op.getReadLatency(),
3264 op.getWriteLatency(),
3266 *seq::symbolizeRUW(
unsigned(op.getRuw())),
3267 seq::WUW::PortOrder,
3270 op.getMaskBits() > 1,
3281 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
3282 setNameFn(getResult(i), (base +
"_" + getPortNameStr(i)).str());
3286 std::optional<size_t> MemOp::getTargetResultIndex() {
3288 return std::nullopt;
3292 StringAttr FirMemory::getFirMemoryName()
const {
return modName; }
3299 setNameFn(op.getDataRaw(), name);
3300 if (op.isForceable())
3301 setNameFn(op.getDataRef(), (name +
"_ref").str());
3309 mlir::MLIRContext *context, std::optional<mlir::Location> location,
3310 ::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes,
3311 ::mlir::OpaqueProperties properties, ::mlir::RegionRange regions,
3312 ::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
3313 if (operands.empty())
3315 inferredReturnTypes.push_back(operands[0].getType());
3316 for (
auto &attr : attributes)
3317 if (attr.getName() == Forceable::getForceableAttrName()) {
3318 auto forceableType =
3320 if (!forceableType) {
3322 ::mlir::emitError(*location,
"cannot force a node of type ")
3323 << operands[0].getType();
3326 inferredReturnTypes.push_back(forceableType);
3331 std::optional<size_t> NodeOp::getTargetResultIndex() {
return 0; }
3337 std::optional<size_t> RegOp::getTargetResultIndex() {
return 0; }
3339 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3340 RegOp::computeDataFlow() {
3346 auto reset = getResetValue();
3353 return emitError(
"type mismatch between register ")
3354 << regType <<
" and reset value " << resetType;
3359 std::optional<size_t> RegResetOp::getTargetResultIndex() {
return 0; }
3370 FormalOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
3372 auto referencedModule = symbolTable.lookupNearestSymbolFrom<FModuleOp>(
3373 *
this, getModuleNameAttr());
3374 if (!referencedModule)
3375 return (*this)->emitOpError(
"invalid symbol reference");
3388 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3389 RegResetOp::computeDataFlow() {
3394 std::optional<size_t> WireOp::getTargetResultIndex() {
return 0; }
3396 LogicalResult WireOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3397 auto refType = type_dyn_cast<RefType>(getType(0));
3402 refType, getLoc(), getOperation()->getParentOfType<CircuitOp>(),
3403 symbolTable, Twine(
"'") + getOperationName() +
"' op is");
3410 void ObjectOp::build(OpBuilder &builder, OperationState &state, ClassLike klass,
3412 build(builder, state, klass.getInstanceType(),
3418 LogicalResult ObjectOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3419 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
3420 auto classType = getType();
3421 auto className = classType.getNameAttr();
3424 auto classOp = dyn_cast_or_null<ClassLike>(
3425 symbolTable.lookupSymbolIn(circuitOp, className));
3427 return emitOpError() <<
"references unknown class " << className;
3430 if (failed(classOp.verifyType(classType, [&]() { return emitOpError(); })))
3436 StringAttr ObjectOp::getClassNameAttr() {
3437 return getType().getNameAttr().getAttr();
3440 StringRef ObjectOp::getClassName() {
return getType().getName(); }
3442 ClassLike ObjectOp::getReferencedClass(
const SymbolTable &symbolTable) {
3443 auto symRef = getType().getNameAttr();
3444 return symbolTable.lookup<ClassLike>(symRef.getLeafReference());
3447 Operation *ObjectOp::getReferencedOperation(
const SymbolTable &symtbl) {
3448 return getReferencedClass(symtbl);
3453 StringAttr ObjectOp::getInstanceNameAttr() {
return getNameAttr(); }
3455 StringRef ObjectOp::getReferencedModuleName() {
return getClassName(); }
3457 StringAttr ObjectOp::getReferencedModuleNameAttr() {
3458 return getClassNameAttr();
3462 setNameFn(getResult(),
getName());
3471 std::optional<int32_t> commonWidth;
3472 for (
auto operand : getOperands()) {
3473 auto thisWidth = type_cast<AnalogType>(operand.getType()).getWidth();
3477 commonWidth = thisWidth;
3480 if (commonWidth != thisWidth)
3481 return emitOpError(
"is inavlid as not all known operand widths match");
3488 Value dst =
connect->getOperand(0);
3489 Value src =
connect->getOperand(1);
3500 auto diag = emitError(
connect->getLoc());
3501 diag <<
"connect has invalid flow: the source expression ";
3503 diag <<
"\"" << srcName <<
"\" ";
3504 diag <<
"has " <<
toString(srcFlow) <<
", expected source or duplex flow";
3505 return diag.attachNote(srcRef.getLoc()) <<
"the source was defined here";
3513 auto diag = emitError(
connect->getLoc());
3514 diag <<
"connect has invalid flow: the destination expression ";
3516 diag <<
"\"" << dstName <<
"\" ";
3517 diag <<
"has " <<
toString(dstFlow) <<
", expected sink or duplex flow";
3518 return diag.attachNote(dstRef.getLoc())
3519 <<
"the destination was defined here";
3528 bool outerTypeIsConst =
false) {
3529 auto typeIsConst = outerTypeIsConst || type.
isConst();
3534 if (
auto bundleType = type_dyn_cast<BundleType>(type))
3535 return llvm::any_of(bundleType.getElements(), [&](
auto &element) {
3536 return isConstFieldDriven(element.type, isFlip ^ element.isFlip,
3540 if (
auto vectorType = type_dyn_cast<FVectorType>(type))
3552 auto dest =
connect.getDest();
3553 auto destType = type_dyn_cast<FIRRTLBaseType>(dest.getType());
3555 auto srcType = type_dyn_cast<FIRRTLBaseType>(src.getType());
3556 if (!destType || !srcType)
3559 auto destRefinedType = destType;
3560 auto srcRefinedType = srcType;
3565 auto findFieldDeclarationRefiningFieldType =
3567 while (
auto *definingOp = value.getDefiningOp()) {
3568 bool shouldContinue =
true;
3569 TypeSwitch<Operation *>(definingOp)
3570 .Case<SubfieldOp, SubindexOp>([&](
auto op) { value = op.getInput(); })
3571 .Case<SubaccessOp>([&](SubaccessOp op) {
3575 .getElementTypePreservingConst()
3577 originalFieldType = originalFieldType.getConstType(
true);
3578 value = op.getInput();
3580 .Default([&](Operation *) { shouldContinue =
false; });
3581 if (!shouldContinue)
3587 auto destDeclaration =
3588 findFieldDeclarationRefiningFieldType(dest, destRefinedType);
3589 auto srcDeclaration =
3590 findFieldDeclarationRefiningFieldType(src, srcRefinedType);
3592 auto checkConstConditionality = [&](Value value,
FIRRTLBaseType type,
3593 Value declaration) -> LogicalResult {
3594 auto *declarationBlock = declaration.getParentBlock();
3595 auto *block =
connect->getBlock();
3596 while (block && block != declarationBlock) {
3597 auto *parentOp = block->getParentOp();
3599 if (
auto whenOp = dyn_cast<WhenOp>(parentOp);
3600 whenOp && !whenOp.getCondition().getType().isConst()) {
3603 <<
"assignment to 'const' type " << type
3604 <<
" is dependent on a non-'const' condition";
3606 <<
"assignment to nested 'const' member of type " << type
3607 <<
" is dependent on a non-'const' condition";
3610 block = parentOp->getBlock();
3615 auto emitSubaccessError = [&] {
3617 "assignment to non-'const' subaccess of 'const' type is disallowed");
3623 if (destType != destRefinedType)
3624 return emitSubaccessError();
3626 if (failed(checkConstConditionality(dest, destType, destDeclaration)))
3631 if (srcRefinedType.containsConst() &&
3634 if (srcType != srcRefinedType)
3635 return emitSubaccessError();
3636 if (failed(checkConstConditionality(src, srcType, srcDeclaration)))
3644 auto dstType = getDest().getType();
3645 auto srcType = getSrc().getType();
3646 auto dstBaseType = type_dyn_cast<FIRRTLBaseType>(dstType);
3647 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(srcType);
3648 if (!dstBaseType || !srcBaseType) {
3649 if (dstType != srcType)
3650 return emitError(
"may not connect different non-base types");
3653 if (dstBaseType.containsAnalog() || srcBaseType.containsAnalog())
3654 return emitError(
"analog types may not be connected");
3658 return emitError(
"type mismatch between destination ")
3659 << dstBaseType <<
" and source " << srcBaseType;
3664 return emitError(
"destination ")
3665 << dstBaseType <<
" is not as wide as the source " << srcBaseType;
3679 if (
auto type = type_dyn_cast<FIRRTLType>(getDest().getType())) {
3680 auto baseType = type_cast<FIRRTLBaseType>(type);
3683 if (baseType && baseType.containsAnalog())
3684 return emitError(
"analog types may not be connected");
3689 "`SameAnonTypeOperands` trait should have already rejected "
3690 "structurally non-equivalent types");
3713 for (
auto *user : getDest().getUsers()) {
3714 if (
auto conn = dyn_cast<FConnectLike>(user);
3715 conn && conn.getDest() == getDest() && conn != *
this)
3716 return emitError(
"destination reference cannot be reused by multiple "
3717 "operations, it can only capture a unique dataflow");
3721 if (
auto *op = getDest().getDefiningOp()) {
3723 if (isa<RefSubOp>(op))
3725 "destination reference cannot be a sub-element of a reference");
3726 if (isa<RefCastOp>(op))
3728 "destination reference cannot be a cast of another reference");
3736 SmallVector<SymbolRefAttr> missingLayers;
3738 auto diag = emitOpError(
"has more layer requirements than destination");
3739 auto ¬e = diag.attachNote();
3740 note <<
"additional layers required: ";
3741 interleaveComma(missingLayers, note);
3754 for (
auto *user : getDest().getUsers()) {
3755 if (
auto conn = dyn_cast<FConnectLike>(user);
3756 conn && conn.getDest() == getDest() && conn != *
this)
3757 return emitError(
"destination property cannot be reused by multiple "
3758 "operations, it can only capture a unique dataflow");
3764 void WhenOp::createElseRegion() {
3765 assert(!hasElseRegion() &&
"already has an else region");
3766 getElseRegion().push_back(
new Block());
3769 void WhenOp::build(OpBuilder &builder, OperationState &result, Value condition,
3770 bool withElseRegion, std::function<
void()> thenCtor,
3771 std::function<
void()> elseCtor) {
3772 OpBuilder::InsertionGuard guard(builder);
3773 result.addOperands(condition);
3776 builder.createBlock(result.addRegion());
3781 Region *elseRegion = result.addRegion();
3782 if (withElseRegion) {
3783 builder.createBlock(elseRegion);
3794 FEnumType type = getInput().getType();
3797 auto numCases = getTags().size();
3798 auto numRegions = getNumRegions();
3799 if (numRegions != numCases)
3800 return emitOpError(
"expected ")
3801 << numRegions <<
" tags but got " << numCases;
3803 auto numTags = type.getNumElements();
3805 SmallDenseSet<int64_t> seen;
3806 for (
const auto &[tag, region] : llvm::zip(getTags(), getRegions())) {
3807 auto tagIndex = size_t(cast<IntegerAttr>(tag).
getInt());
3810 if (region.getNumArguments() != 1)
3811 return emitOpError(
"region should have exactly one argument");
3814 if (tagIndex >= numTags)
3815 return emitOpError(
"the tag index ")
3816 << tagIndex <<
" is out of the range of valid tags in " << type;
3819 auto [it, inserted] = seen.insert(tagIndex);
3821 return emitOpError(
"the tag ") << type.getElementNameAttr(tagIndex)
3822 <<
" is matched more than once";
3825 auto expectedType = type.getElementTypePreservingConst(tagIndex);
3826 auto regionType = region.getArgument(0).getType();
3827 if (regionType != expectedType)
3828 return emitOpError(
"region type ")
3829 << regionType <<
" does not match the expected type "
3834 for (
size_t i = 0, e = type.getNumElements(); i < e; ++i)
3835 if (!seen.contains(i))
3836 return emitOpError(
"missing case for tag ") << type.getElementNameAttr(i);
3841 void MatchOp::print(OpAsmPrinter &p) {
3842 auto input = getInput();
3843 FEnumType type = input.getType();
3844 auto regions = getRegions();
3845 p <<
" " << input <<
" : " << type;
3846 SmallVector<StringRef> elided = {
"tags"};
3847 p.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elided);
3850 for (
const auto &[tag, region] : llvm::zip(getTags(), regions)) {
3853 p.printKeywordOrString(
3854 type.getElementName(cast<IntegerAttr>(tag).getInt()));
3856 p.printRegionArgument(region.front().getArgument(0), {},
3859 p.printRegion(region,
false);
3866 ParseResult MatchOp::parse(OpAsmParser &parser, OperationState &result) {
3867 auto *context = parser.getContext();
3868 OpAsmParser::UnresolvedOperand input;
3869 if (parser.parseOperand(input) || parser.parseColon())
3872 auto loc = parser.getCurrentLocation();
3874 if (parser.parseType(type))
3876 auto enumType = type_dyn_cast<FEnumType>(type);
3878 return parser.emitError(loc,
"expected enumeration type but got") << type;
3880 if (parser.resolveOperand(input, type, result.operands) ||
3881 parser.parseOptionalAttrDictWithKeyword(result.attributes) ||
3882 parser.parseLBrace())
3886 SmallVector<Attribute> tags;
3889 if (failed(parser.parseOptionalKeyword(
"case")))
3893 auto nameLoc = parser.getCurrentLocation();
3895 OpAsmParser::Argument arg;
3896 auto *region = result.addRegion();
3897 if (parser.parseKeywordOrString(&name) || parser.parseLParen() ||
3898 parser.parseArgument(arg) || parser.parseRParen())
3902 auto index = enumType.getElementIndex(name);
3904 return parser.emitError(nameLoc,
"the tag \"")
3905 << name <<
"\" is not a member of the enumeration " << enumType;
3909 arg.type = enumType.getElementTypePreservingConst(*index);
3910 if (parser.parseRegion(*region, arg))
3915 return parser.parseRBrace();
3918 void MatchOp::build(OpBuilder &builder, OperationState &result, Value input,
3920 MutableArrayRef<std::unique_ptr<Region>> regions) {
3921 result.addOperands(input);
3922 result.addAttribute(
"tags", tags);
3923 result.addRegions(regions);
3936 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
3937 DictionaryAttr attrs, mlir::OpaqueProperties properties,
3938 RegionRange regions, SmallVectorImpl<Type> &results,
3939 llvm::function_ref<
FIRRTLType(ValueRange, ArrayRef<NamedAttribute>,
3940 std::optional<Location>)>
3942 auto type = callback(
3943 operands, attrs ? attrs.getValue() : ArrayRef<NamedAttribute>{}, loc);
3945 results.push_back(type);
3953 static Attribute
maybeGetAttr(ArrayRef<NamedAttribute> attrs, StringRef name) {
3954 for (
auto attr : attrs)
3955 if (attr.getName() == name)
3956 return attr.getValue();
3962 static Attribute
getAttr(ArrayRef<NamedAttribute> attrs, StringRef name) {
3965 llvm::report_fatal_error(
"attribute '" + name +
"' not found");
3969 template <
typename AttrClass>
3970 AttrClass
getAttr(ArrayRef<NamedAttribute> attrs, StringRef name) {
3971 return cast<AttrClass>(
getAttr(attrs, name));
3976 struct IsExprClassifier :
public ExprVisitor<IsExprClassifier, bool> {
3977 bool visitInvalidExpr(Operation *op) {
return false; }
3978 bool visitUnhandledExpr(Operation *op) {
return true; }
3987 if (
auto ty = type_dyn_cast<IntType>(getType())) {
3988 const char *base = ty.isSigned() ?
"invalid_si" :
"invalid_ui";
3989 auto width = ty.getWidthOrSentinel();
3993 name = (Twine(base) + Twine(
width)).str();
3994 }
else if (
auto ty = type_dyn_cast<AnalogType>(getType())) {
3995 auto width = ty.getWidthOrSentinel();
3997 name =
"invalid_analog";
3999 name = (
"invalid_analog" + Twine(
width)).str();
4000 }
else if (type_isa<AsyncResetType>(getType()))
4001 name =
"invalid_asyncreset";
4002 else if (type_isa<ResetType>(getType()))
4003 name =
"invalid_reset";
4004 else if (type_isa<ClockType>(getType()))
4005 name =
"invalid_clock";
4009 setNameFn(getResult(), name);
4012 void ConstantOp::print(OpAsmPrinter &p) {
4014 p.printAttributeWithoutType(getValueAttr());
4016 p.printType(getType());
4017 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4020 ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
4023 auto loc = parser.getCurrentLocation();
4024 auto valueResult = parser.parseOptionalInteger(value);
4025 if (!valueResult.has_value())
4026 return parser.emitError(loc,
"expected integer value");
4030 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4031 parser.parseOptionalAttrDict(result.attributes))
4033 result.addTypes(resultType);
4039 if (
width > value.getBitWidth()) {
4043 value = value.sext(
width);
4044 }
else if (
width < value.getBitWidth()) {
4047 unsigned neededBits = value.isNegative() ? value.getSignificantBits()
4048 : value.getActiveBits();
4049 if (
width < neededBits)
4050 return parser.emitError(loc,
"constant out of range for result type ")
4052 value = value.trunc(
width);
4056 auto intType = parser.getBuilder().getIntegerType(value.getBitWidth(),
4058 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4059 result.addAttribute(
"value", valueAttr);
4069 "firrtl.constant attribute bitwidth doesn't match return type");
4072 auto attrType = type_cast<IntegerType>(getValueAttr().getType());
4073 if (attrType.isSignless() || attrType.isSigned() != intType.
isSigned())
4074 return emitError(
"firrtl.constant attribute has wrong sign");
4081 void ConstantOp::build(OpBuilder &builder, OperationState &result,
IntType type,
4082 const APInt &value) {
4086 "incorrect attribute bitwidth for firrtl.constant");
4090 return build(builder, result, type, attr);
4095 void ConstantOp::build(OpBuilder &builder, OperationState &result,
4096 const APSInt &value) {
4099 IntType::get(builder.getContext(), value.isSigned(), value.getBitWidth());
4100 return build(builder, result, type, attr);
4110 SmallString<32> specialNameBuffer;
4111 llvm::raw_svector_ostream specialName(specialNameBuffer);
4113 getValue().print(specialName, intTy.
isSigned());
4115 specialName << (intTy.
isSigned() ?
"_si" :
"_ui");
4118 specialName <<
width;
4119 setNameFn(getResult(), specialName.str());
4122 void SpecialConstantOp::print(OpAsmPrinter &p) {
4125 p << static_cast<unsigned>(getValue());
4127 p.printType(getType());
4128 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4131 ParseResult SpecialConstantOp::parse(OpAsmParser &parser,
4132 OperationState &result) {
4136 auto loc = parser.getCurrentLocation();
4137 auto valueResult = parser.parseOptionalInteger(value);
4138 if (!valueResult.has_value())
4139 return parser.emitError(loc,
"expected integer value");
4142 if (value != 0 && value != 1)
4143 return parser.emitError(loc,
"special constants can only be 0 or 1.");
4147 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4148 parser.parseOptionalAttrDict(result.attributes))
4150 result.addTypes(resultType);
4153 auto valueAttr = parser.getBuilder().getBoolAttr(value == 1);
4154 result.addAttribute(
"value", valueAttr);
4159 SmallString<32> specialNameBuffer;
4160 llvm::raw_svector_ostream specialName(specialNameBuffer);
4162 specialName << static_cast<unsigned>(getValue());
4163 auto type = getType();
4164 if (type_isa<ClockType>(type)) {
4165 specialName <<
"_clock";
4166 }
else if (type_isa<ResetType>(type)) {
4167 specialName <<
"_reset";
4168 }
else if (type_isa<AsyncResetType>(type)) {
4169 specialName <<
"_asyncreset";
4171 setNameFn(getResult(), specialName.str());
4178 if (type.isGround()) {
4179 if (!isa<IntegerAttr>(attr)) {
4180 op->emitOpError(
"Ground type is not an integer attribute");
4185 auto attrlist = dyn_cast<ArrayAttr>(attr);
4187 op->emitOpError(
"expected array attribute for aggregate constant");
4190 if (
auto array = type_dyn_cast<FVectorType>(type)) {
4191 if (array.getNumElements() != attrlist.size()) {
4192 op->emitOpError(
"array attribute (")
4193 << attrlist.size() <<
") has wrong size for vector constant ("
4194 << array.getNumElements() <<
")";
4197 return llvm::all_of(attrlist, [&array, op](Attribute attr) {
4201 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4202 if (bundle.getNumElements() != attrlist.size()) {
4203 op->emitOpError(
"array attribute (")
4204 << attrlist.size() <<
") has wrong size for bundle constant ("
4205 << bundle.getNumElements() <<
")";
4208 for (
size_t i = 0; i < bundle.getNumElements(); ++i) {
4209 if (bundle.getElement(i).isFlip) {
4210 op->emitOpError(
"Cannot have constant bundle type with flip");
4218 op->emitOpError(
"Unknown aggregate type");
4228 Attribute AggregateConstantOp::getAttributeFromFieldID(uint64_t fieldID) {
4230 Attribute value = getFields();
4231 while (fieldID != 0) {
4232 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4233 auto index = bundle.getIndexForFieldID(fieldID);
4234 fieldID -= bundle.getFieldID(index);
4235 type = bundle.getElementType(index);
4236 value = cast<ArrayAttr>(value)[index];
4238 auto vector = type_cast<FVectorType>(type);
4239 auto index = vector.getIndexForFieldID(fieldID);
4240 fieldID -= vector.getFieldID(index);
4241 type = vector.getElementType();
4242 value = cast<ArrayAttr>(value)[index];
4248 void FIntegerConstantOp::print(OpAsmPrinter &p) {
4250 p.printAttributeWithoutType(getValueAttr());
4251 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4254 ParseResult FIntegerConstantOp::parse(OpAsmParser &parser,
4255 OperationState &result) {
4256 auto *context = parser.getContext();
4258 if (parser.parseInteger(value) ||
4259 parser.parseOptionalAttrDict(result.attributes))
4264 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4265 result.addAttribute(
"value", valueAttr);
4269 ParseResult ListCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4270 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
4273 if (parser.parseOperandList(operands) ||
4274 parser.parseOptionalAttrDict(result.attributes) ||
4275 parser.parseColonType(type))
4277 result.addTypes(type);
4279 return parser.resolveOperands(operands, type.getElementType(),
4283 void ListCreateOp::print(OpAsmPrinter &p) {
4285 p.printOperands(getElements());
4286 p.printOptionalAttrDict((*this)->getAttrs());
4287 p <<
" : " << getType();
4291 if (getElements().
empty())
4294 auto elementType = getElements().front().getType();
4295 auto listElementType = getType().getElementType();
4297 return emitOpError(
"has elements of type ")
4298 <<
elementType <<
" instead of " << listElementType;
4304 BundleType resultType = getType();
4305 if (resultType.getNumElements() != getFields().size())
4306 return emitOpError(
"number of fields doesn't match type");
4307 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4309 resultType.getElementTypePreservingConst(i),
4310 type_cast<FIRRTLBaseType>(getOperand(i).getType())))
4311 return emitOpError(
"type of element doesn't match bundle for field ")
4312 << resultType.getElement(i).name;
4318 FVectorType resultType = getType();
4319 if (resultType.getNumElements() != getFields().size())
4320 return emitOpError(
"number of fields doesn't match type");
4321 auto elemTy = resultType.getElementTypePreservingConst();
4322 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4324 elemTy, type_cast<FIRRTLBaseType>(getOperand(i).getType())))
4325 return emitOpError(
"type of element doesn't match vector element");
4335 FEnumType resultType = getResult().getType();
4336 auto elementIndex = resultType.getElementIndex(
getFieldName());
4338 return emitOpError(
"label ")
4339 <<
getFieldName() <<
" is not a member of the enumeration type "
4342 resultType.getElementTypePreservingConst(*elementIndex),
4343 getInput().getType()))
4344 return emitOpError(
"type of element doesn't match enum element");
4348 void FEnumCreateOp::print(OpAsmPrinter &printer) {
4351 printer <<
'(' << getInput() <<
')';
4352 SmallVector<StringRef> elidedAttrs = {
"fieldIndex"};
4353 printer.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elidedAttrs);
4355 printer.printFunctionalType(ArrayRef<Type>{getInput().getType()},
4356 ArrayRef<Type>{getResult().getType()});
4359 ParseResult FEnumCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4360 auto *context = parser.getContext();
4362 OpAsmParser::UnresolvedOperand input;
4363 std::string fieldName;
4364 mlir::FunctionType functionType;
4365 if (parser.parseKeywordOrString(&fieldName) || parser.parseLParen() ||
4366 parser.parseOperand(input) || parser.parseRParen() ||
4367 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4368 parser.parseType(functionType))
4371 if (functionType.getNumInputs() != 1)
4372 return parser.emitError(parser.getNameLoc(),
"single input type required");
4373 if (functionType.getNumResults() != 1)
4374 return parser.emitError(parser.getNameLoc(),
"single result type required");
4376 auto inputType = functionType.getInput(0);
4377 if (parser.resolveOperand(input, inputType, result.operands))
4380 auto outputType = functionType.getResult(0);
4381 auto enumType = type_dyn_cast<FEnumType>(outputType);
4383 return parser.emitError(parser.getNameLoc(),
4384 "output must be enum type, got ")
4386 auto fieldIndex = enumType.getElementIndex(fieldName);
4388 return parser.emitError(parser.getNameLoc(),
4389 "unknown field " + fieldName +
" in enum type ")
4392 result.addAttribute(
4396 result.addTypes(enumType);
4406 if (getFieldIndex() >= getInput().getType().base().getNumElements())
4407 return emitOpError(
"element index is greater than the number of fields in "
4412 void IsTagOp::print(::mlir::OpAsmPrinter &printer) {
4413 printer <<
' ' << getInput() <<
' ';
4415 SmallVector<::llvm::StringRef, 1> elidedAttrs = {
"fieldIndex"};
4416 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
4417 printer <<
" : " << getInput().getType();
4420 ParseResult IsTagOp::parse(OpAsmParser &parser, OperationState &result) {
4421 auto *context = parser.getContext();
4423 OpAsmParser::UnresolvedOperand input;
4424 std::string fieldName;
4426 if (parser.parseOperand(input) || parser.parseKeywordOrString(&fieldName) ||
4427 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4428 parser.parseType(inputType))
4431 if (parser.resolveOperand(input, inputType, result.operands))
4434 auto enumType = type_dyn_cast<FEnumType>(inputType);
4436 return parser.emitError(parser.getNameLoc(),
4437 "input must be enum type, got ")
4439 auto fieldIndex = enumType.getElementIndex(fieldName);
4441 return parser.emitError(parser.getNameLoc(),
4442 "unknown field " + fieldName +
" in enum type ")
4445 result.addAttribute(
4454 FIRRTLType IsTagOp::inferReturnType(ValueRange operands,
4455 ArrayRef<NamedAttribute> attrs,
4456 std::optional<Location> loc) {
4458 isConst(operands[0].getType()));
4461 template <
typename OpTy>
4463 auto *context = parser.getContext();
4465 OpAsmParser::UnresolvedOperand input;
4466 std::string fieldName;
4468 if (parser.parseOperand(input) || parser.parseLSquare() ||
4469 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
4470 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4471 parser.parseType(inputType))
4474 if (parser.resolveOperand(input, inputType, result.operands))
4477 auto bundleType = type_dyn_cast<typename OpTy::InputType>(inputType);
4479 return parser.emitError(parser.getNameLoc(),
4480 "input must be bundle type, got ")
4482 auto fieldIndex = bundleType.getElementIndex(fieldName);
4484 return parser.emitError(parser.getNameLoc(),
4485 "unknown field " + fieldName +
" in bundle type ")
4488 result.addAttribute(
4492 SmallVector<Type> inferredReturnTypes;
4494 result.attributes.getDictionary(context),
4495 result.getRawProperties(), result.regions,
4496 inferredReturnTypes)))
4498 result.addTypes(inferredReturnTypes);
4503 ParseResult SubtagOp::parse(OpAsmParser &parser, OperationState &result) {
4504 auto *context = parser.getContext();
4506 OpAsmParser::UnresolvedOperand input;
4507 std::string fieldName;
4509 if (parser.parseOperand(input) || parser.parseLSquare() ||
4510 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
4511 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4512 parser.parseType(inputType))
4515 if (parser.resolveOperand(input, inputType, result.operands))
4518 auto enumType = type_dyn_cast<FEnumType>(inputType);
4520 return parser.emitError(parser.getNameLoc(),
4521 "input must be enum type, got ")
4523 auto fieldIndex = enumType.getElementIndex(fieldName);
4525 return parser.emitError(parser.getNameLoc(),
4526 "unknown field " + fieldName +
" in enum type ")
4529 result.addAttribute(
4533 SmallVector<Type> inferredReturnTypes;
4535 context, result.location, result.operands,
4536 result.attributes.getDictionary(context), result.getRawProperties(),
4537 result.regions, inferredReturnTypes)))
4539 result.addTypes(inferredReturnTypes);
4544 ParseResult SubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
4545 return parseSubfieldLikeOp<SubfieldOp>(parser, result);
4547 ParseResult OpenSubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
4548 return parseSubfieldLikeOp<OpenSubfieldOp>(parser, result);
4551 template <
typename OpTy>
4553 printer <<
' ' << op.getInput() <<
'[';
4554 printer.printKeywordOrString(op.getFieldName());
4556 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
4557 elidedAttrs.push_back(
"fieldIndex");
4558 printer.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
4559 printer <<
" : " << op.getInput().getType();
4561 void SubfieldOp::print(::mlir::OpAsmPrinter &printer) {
4562 return printSubfieldLikeOp<SubfieldOp>(*
this, printer);
4564 void OpenSubfieldOp::print(::mlir::OpAsmPrinter &printer) {
4565 return printSubfieldLikeOp<OpenSubfieldOp>(*
this, printer);
4568 void SubtagOp::print(::mlir::OpAsmPrinter &printer) {
4569 printer <<
' ' << getInput() <<
'[';
4572 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
4573 elidedAttrs.push_back(
"fieldIndex");
4574 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
4575 printer <<
" : " << getInput().getType();
4578 template <
typename OpTy>
4580 if (op.getFieldIndex() >=
4581 firrtl::type_cast<typename OpTy::InputType>(op.getInput().getType())
4583 return op.emitOpError(
"subfield element index is greater than the number "
4584 "of fields in the bundle type");
4588 return verifySubfieldLike<SubfieldOp>(*
this);
4591 return verifySubfieldLike<OpenSubfieldOp>(*
this);
4595 if (getFieldIndex() >= getInput().getType().base().getNumElements())
4596 return emitOpError(
"subfield element index is greater than the number "
4597 "of fields in the bundle type");
4607 SmallVector<Operation *, 8> worklist({op});
4611 bool constant =
true;
4617 while (constant && !(worklist.empty()))
4618 TypeSwitch<Operation *>(worklist.pop_back_val())
4619 .Case<NodeOp, AsSIntPrimOp, AsUIntPrimOp>([&](
auto op) {
4620 if (
auto definingOp = op.getInput().getDefiningOp())
4621 worklist.push_back(definingOp);
4624 .Case<WireOp, SubindexOp, SubfieldOp>([&](
auto op) {
4625 for (
auto &use : op.getResult().getUses())
4626 worklist.push_back(use.getOwner());
4628 .Case<ConstantOp, SpecialConstantOp, AggregateConstantOp>([](
auto) {})
4629 .Default([&](
auto) { constant =
false; });
4638 if (
auto *op = value.getDefiningOp())
4645 return emitOpError() << getInput().getType()
4646 <<
" is not 'const'-castable to "
4647 << getResult().getType();
4651 FIRRTLType SubfieldOp::inferReturnType(ValueRange operands,
4652 ArrayRef<NamedAttribute> attrs,
4653 std::optional<Location> loc) {
4654 auto inType = type_cast<BundleType>(operands[0].getType());
4656 getAttr<IntegerAttr>(attrs,
"fieldIndex").getValue().getZExtValue();
4658 if (fieldIndex >= inType.getNumElements())
4660 "subfield element index is greater than the "
4661 "number of fields in the bundle type");
4665 return inType.getElementTypePreservingConst(fieldIndex);
4668 FIRRTLType OpenSubfieldOp::inferReturnType(ValueRange operands,
4669 ArrayRef<NamedAttribute> attrs,
4670 std::optional<Location> loc) {
4671 auto inType = type_cast<OpenBundleType>(operands[0].getType());
4673 getAttr<IntegerAttr>(attrs,
"fieldIndex").getValue().getZExtValue();
4675 if (fieldIndex >= inType.getNumElements())
4677 "subfield element index is greater than the "
4678 "number of fields in the bundle type");
4682 return inType.getElementTypePreservingConst(fieldIndex);
4685 bool SubfieldOp::isFieldFlipped() {
4686 BundleType bundle = getInput().getType();
4687 return bundle.getElement(getFieldIndex()).isFlip;
4689 bool OpenSubfieldOp::isFieldFlipped() {
4690 auto bundle = getInput().getType();
4691 return bundle.getElement(getFieldIndex()).isFlip;
4694 FIRRTLType SubindexOp::inferReturnType(ValueRange operands,
4695 ArrayRef<NamedAttribute> attrs,
4696 std::optional<Location> loc) {
4697 Type inType = operands[0].getType();
4699 getAttr<IntegerAttr>(attrs,
"index").getValue().getZExtValue();
4701 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
4702 if (fieldIdx < vectorType.getNumElements())
4703 return vectorType.getElementTypePreservingConst();
4705 "' in vector type ", inType);
4711 FIRRTLType OpenSubindexOp::inferReturnType(ValueRange operands,
4712 ArrayRef<NamedAttribute> attrs,
4713 std::optional<Location> loc) {
4714 Type inType = operands[0].getType();
4716 getAttr<IntegerAttr>(attrs,
"index").getValue().getZExtValue();
4718 if (
auto vectorType = type_dyn_cast<OpenVectorType>(inType)) {
4719 if (fieldIdx < vectorType.getNumElements())
4720 return vectorType.getElementTypePreservingConst();
4722 "' in vector type ", inType);
4728 FIRRTLType SubtagOp::inferReturnType(ValueRange operands,
4729 ArrayRef<NamedAttribute> attrs,
4730 std::optional<Location> loc) {
4731 auto inType = type_cast<FEnumType>(operands[0].getType());
4733 getAttr<IntegerAttr>(attrs,
"fieldIndex").getValue().getZExtValue();
4735 if (fieldIndex >= inType.getNumElements())
4737 "subtag element index is greater than the "
4738 "number of fields in the enum type");
4742 auto elementType = inType.getElement(fieldIndex).type;
4746 FIRRTLType SubaccessOp::inferReturnType(ValueRange operands,
4747 ArrayRef<NamedAttribute> attrs,
4748 std::optional<Location> loc) {
4749 auto inType = operands[0].getType();
4750 auto indexType = operands[1].getType();
4752 if (!type_isa<UIntType>(indexType))
4756 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
4758 return vectorType.getElementTypePreservingConst();
4759 return vectorType.getElementType().getAllConstDroppedType();
4766 FIRRTLType TagExtractOp::inferReturnType(ValueRange operands,
4767 ArrayRef<NamedAttribute> attrs,
4768 std::optional<Location> loc) {
4769 auto inType = type_cast<FEnumType>(operands[0].getType());
4770 auto i = llvm::Log2_32_Ceil(inType.getNumElements());
4774 ParseResult MultibitMuxOp::parse(OpAsmParser &parser, OperationState &result) {
4775 OpAsmParser::UnresolvedOperand index;
4776 SmallVector<OpAsmParser::UnresolvedOperand, 16> inputs;
4777 Type indexType, elemType;
4779 if (parser.parseOperand(index) || parser.parseComma() ||
4780 parser.parseOperandList(inputs) ||
4781 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4782 parser.parseType(indexType) || parser.parseComma() ||
4783 parser.parseType(elemType))
4786 if (parser.resolveOperand(index, indexType, result.operands))
4789 result.addTypes(elemType);
4791 return parser.resolveOperands(inputs, elemType, result.operands);
4794 void MultibitMuxOp::print(OpAsmPrinter &p) {
4795 p <<
" " << getIndex() <<
", ";
4796 p.printOperands(getInputs());
4797 p.printOptionalAttrDict((*this)->getAttrs());
4798 p <<
" : " << getIndex().getType() <<
", " << getType();
4801 FIRRTLType MultibitMuxOp::inferReturnType(ValueRange operands,
4802 ArrayRef<NamedAttribute> attrs,
4803 std::optional<Location> loc) {
4804 if (operands.size() < 2)
4808 if (!llvm::all_of(operands.drop_front(2), [&](
auto op) {
4809 return operands[1].getType() == op.getType();
4813 return type_cast<FIRRTLType>(operands[1].getType());
4821 MLIRContext *context, std::optional<mlir::Location> location,
4822 ValueRange operands, DictionaryAttr attributes, OpaqueProperties properties,
4823 RegionRange regions, llvm::SmallVectorImpl<Type> &inferredReturnTypes) {
4824 auto type = inferReturnType(operands, attributes.getValue(), location);
4827 inferredReturnTypes.push_back(type);
4831 Type ObjectSubfieldOp::inferReturnType(ValueRange operands,
4832 ArrayRef<NamedAttribute> attrs,
4833 std::optional<Location> loc) {
4834 auto classType = dyn_cast<ClassType>(operands[0].getType());
4838 auto index = getAttr<IntegerAttr>(attrs,
"index").getValue().getZExtValue();
4839 if (classType.getNumElements() <= index)
4841 "number of fields in the object");
4843 return classType.getElement(index).type;
4846 void ObjectSubfieldOp::print(OpAsmPrinter &p) {
4847 auto input = getInput();
4848 auto classType = input.getType();
4849 p <<
' ' << input <<
"[";
4850 p.printKeywordOrString(classType.getElement(getIndex()).name);
4852 p.printOptionalAttrDict((*this)->getAttrs(), std::array{StringRef(
"index")});
4853 p <<
" : " << classType;
4856 ParseResult ObjectSubfieldOp::parse(OpAsmParser &parser,
4857 OperationState &result) {
4858 auto *context = parser.getContext();
4860 OpAsmParser::UnresolvedOperand input;
4861 std::string fieldName;
4862 ClassType inputType;
4863 if (parser.parseOperand(input) || parser.parseLSquare() ||
4864 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
4865 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4866 parser.parseType(inputType) ||
4867 parser.resolveOperand(input, inputType, result.operands))
4870 auto index = inputType.getElementIndex(fieldName);
4872 return parser.emitError(parser.getNameLoc(),
4873 "unknown field " + fieldName +
" in class type ")
4875 result.addAttribute(
"index",
4878 SmallVector<Type> inferredReturnTypes;
4880 result.attributes.getDictionary(context),
4881 result.getRawProperties(), result.regions,
4882 inferredReturnTypes)))
4884 result.addTypes(inferredReturnTypes);
4901 int32_t &rhsWidth,
bool &isConstResult,
4902 std::optional<Location> loc) {
4904 auto lhsi = type_dyn_cast<IntType>(lhs);
4905 auto rhsi = type_dyn_cast<IntType>(rhs);
4906 if (!lhsi || !rhsi || lhsi.isSigned() != rhsi.isSigned()) {
4909 mlir::emitError(*loc,
"second operand must be an integer type, not ")
4911 else if (!lhsi && rhsi)
4912 mlir::emitError(*loc,
"first operand must be an integer type, not ")
4914 else if (!lhsi && !rhsi)
4915 mlir::emitError(*loc,
"operands must be integer types, not ")
4916 << lhs <<
" and " << rhs;
4918 mlir::emitError(*loc,
"operand signedness must match");
4923 lhsWidth = lhsi.getWidthOrSentinel();
4924 rhsWidth = rhsi.getWidthOrSentinel();
4925 isConstResult = lhsi.isConst() && rhsi.isConst();
4930 assert(op->getNumOperands() == 2 &&
4931 "SameOperandsIntTypeKind on non-binary op");
4932 int32_t lhsWidth, rhsWidth;
4935 op->getOperand(1).getType(), lhsWidth,
4936 rhsWidth, isConstResult, op->getLoc()));
4940 ArrayRef<NamedAttribute> attrs,
4942 if (operands.size() != 2 || !attrs.empty()) {
4943 mlir::emitError(loc,
"operation requires two operands and no constants");
4950 std::optional<Location> loc) {
4951 int32_t lhsWidth, rhsWidth, resultWidth = -1;
4952 bool isConstResult =
false;
4956 if (lhsWidth != -1 && rhsWidth != -1)
4957 resultWidth = std::max(lhsWidth, rhsWidth) + 1;
4958 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
4963 std::optional<Location> loc) {
4964 int32_t lhsWidth, rhsWidth, resultWidth = -1;
4965 bool isConstResult =
false;
4969 if (lhsWidth != -1 && rhsWidth != -1)
4970 resultWidth = lhsWidth + rhsWidth;
4972 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
4977 std::optional<Location> loc) {
4978 int32_t lhsWidth, rhsWidth;
4979 bool isConstResult =
false;
4984 if (type_isa<UIntType>(lhs))
4985 return UIntType::get(lhs.getContext(), lhsWidth, isConstResult);
4988 int32_t resultWidth = lhsWidth != -1 ? lhsWidth + 1 : -1;
4989 return SIntType::get(lhs.getContext(), resultWidth, isConstResult);
4993 std::optional<Location> loc) {
4994 int32_t lhsWidth, rhsWidth, resultWidth = -1;
4995 bool isConstResult =
false;
4999 if (lhsWidth != -1 && rhsWidth != -1)
5000 resultWidth = std::min(lhsWidth, rhsWidth);
5001 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5006 std::optional<Location> loc) {
5007 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5008 bool isConstResult =
false;
5012 if (lhsWidth != -1 && rhsWidth != -1) {
5013 resultWidth = std::max(lhsWidth, rhsWidth);
5014 if (lhsWidth == resultWidth && lhs.
isConst() == isConstResult &&
5017 if (rhsWidth == resultWidth && rhs.
isConst() == isConstResult &&
5021 return UIntType::get(lhs.getContext(), resultWidth, isConstResult);
5025 std::optional<Location> loc) {
5026 if (!type_isa<FVectorType>(lhs) || !type_isa<FVectorType>(rhs))
5029 auto lhsVec = type_cast<FVectorType>(lhs);
5030 auto rhsVec = type_cast<FVectorType>(rhs);
5032 if (lhsVec.getNumElements() != rhsVec.getNumElements())
5037 rhsVec.getElementTypePreservingConst(), loc);
5040 auto elemBaseType = type_cast<FIRRTLBaseType>(elemType);
5042 lhsVec.isConst() && rhsVec.isConst() &&
5043 elemBaseType.isConst());
5047 std::optional<Location> loc) {
5052 std::optional<Location> loc) {
5053 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5054 bool isConstResult =
false;
5058 if (lhsWidth != -1 && rhsWidth != -1)
5059 resultWidth = lhsWidth + rhsWidth;
5060 return UIntType::get(lhs.getContext(), resultWidth, isConstResult);
5064 std::optional<Location> loc) {
5065 auto lhsi = type_dyn_cast<IntType>(lhs);
5066 auto rhsui = type_dyn_cast<UIntType>(rhs);
5067 if (!rhsui || !lhsi)
5069 loc,
"first operand should be integer, second unsigned int");
5073 auto width = lhsi.getWidthOrSentinel();
5074 if (
width == -1 || !rhsui.getWidth().has_value()) {
5077 auto amount = *rhsui.getWidth();
5080 "shift amount too large: second operand of "
5081 "dshl is wider than 31 bits");
5082 int64_t newWidth = (int64_t)
width + ((int64_t)1 << amount) - 1;
5083 if (newWidth > INT32_MAX)
5085 loc,
"shift amount too large: first operand shifted by maximum "
5086 "amount exceeds maximum width");
5090 lhsi.isConst() && rhsui.isConst());
5094 std::optional<Location> loc) {
5095 auto lhsi = type_dyn_cast<IntType>(lhs);
5096 auto rhsu = type_dyn_cast<UIntType>(rhs);
5099 loc,
"first operand should be integer, second unsigned int");
5100 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5104 std::optional<Location> loc) {
5105 auto lhsi = type_dyn_cast<IntType>(lhs);
5106 auto rhsu = type_dyn_cast<UIntType>(rhs);
5109 loc,
"first operand should be integer, second unsigned int");
5110 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5118 ArrayRef<NamedAttribute> attrs,
5120 if (operands.size() != 1 || !attrs.empty()) {
5121 mlir::emitError(loc,
"operation requires one operand and no constants");
5128 SizeOfIntrinsicOp::inferUnaryReturnType(
FIRRTLType input,
5129 std::optional<Location> loc) {
5134 std::optional<Location> loc) {
5135 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5138 int32_t
width = base.getBitWidthOrSentinel();
5145 std::optional<Location> loc) {
5146 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5149 int32_t
width = base.getBitWidthOrSentinel();
5156 AsAsyncResetPrimOp::inferUnaryReturnType(
FIRRTLType input,
5157 std::optional<Location> loc) {
5158 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5161 "operand must be single bit scalar base type");
5162 int32_t
width = base.getBitWidthOrSentinel();
5169 std::optional<Location> loc) {
5174 std::optional<Location> loc) {
5175 if (
auto uiType = type_dyn_cast<UIntType>(input)) {
5176 auto width = uiType.getWidthOrSentinel();
5182 if (type_isa<SIntType>(input))
5189 std::optional<Location> loc) {
5190 auto inputi = type_dyn_cast<IntType>(input);
5193 int32_t
width = inputi.getWidthOrSentinel();
5200 std::optional<Location> loc) {
5201 auto inputi = type_dyn_cast<IntType>(input);
5204 if (isa<UIntType>(inputi))
5206 return UIntType::get(input.getContext(), inputi.getWidthOrSentinel(),
5211 std::optional<Location> loc) {
5219 LogicalResult BitsPrimOp::validateArguments(ValueRange operands,
5220 ArrayRef<NamedAttribute> attrs,
5222 if (operands.size() != 1 || attrs.size() != 2) {
5223 mlir::emitError(loc,
"operation requires one operand and two constants");
5229 FIRRTLType BitsPrimOp::inferReturnType(ValueRange operands,
5230 ArrayRef<NamedAttribute> attrs,
5231 std::optional<Location> loc) {
5232 auto input = operands[0].getType();
5233 auto high = getAttr<IntegerAttr>(attrs,
"hi").getValue().getSExtValue();
5234 auto low = getAttr<IntegerAttr>(attrs,
"lo").getValue().getSExtValue();
5236 auto inputi = type_dyn_cast<IntType>(input);
5239 loc,
"input type should be the int type but got ", input);
5244 loc,
"high must be equal or greater than low, but got high = ", high,
5252 int32_t
width = inputi.getWidthOrSentinel();
5256 "high must be smaller than the width of input, but got high = ", high,
5257 ", width = ",
width);
5263 ArrayRef<NamedAttribute> attrs,
5265 if (operands.size() != 1 || attrs.size() != 1) {
5266 mlir::emitError(loc,
"operation requires one operand and one constant");
5272 FIRRTLType HeadPrimOp::inferReturnType(ValueRange operands,
5273 ArrayRef<NamedAttribute> attrs,
5274 std::optional<Location> loc) {
5275 auto input = operands[0].getType();
5276 auto amount = getAttr<IntegerAttr>(attrs,
"amount").getValue().getSExtValue();
5278 auto inputi = type_dyn_cast<IntType>(input);
5279 if (amount < 0 || !inputi)
5281 loc,
"operand must have integer type and amount must be >= 0");
5283 int32_t
width = inputi.getWidthOrSentinel();
5290 LogicalResult MuxPrimOp::validateArguments(ValueRange operands,
5291 ArrayRef<NamedAttribute> attrs,
5293 if (operands.size() != 3 || attrs.size() != 0) {
5294 mlir::emitError(loc,
"operation requires three operands and no constants");
5312 bool isConstCondition,
5313 std::optional<Location> loc) {
5319 if (high.getTypeID() != low.getTypeID())
5320 return emitInferRetTypeError<FIRRTLBaseType>(
5321 loc,
"incompatible mux operand types, true value type: ", high,
5322 ", false value type: ", low);
5324 bool outerTypeIsConst = isConstCondition && low.
isConst() && high.
isConst();
5329 if (type_isa<IntType>(low)) {
5334 if (highWidth == -1)
5336 return (lowWidth > highWidth ? low : high).
getConstType(outerTypeIsConst);
5340 auto highVector = type_dyn_cast<FVectorType>(high);
5341 auto lowVector = type_dyn_cast<FVectorType>(low);
5342 if (highVector && lowVector &&
5343 highVector.getNumElements() == lowVector.getNumElements()) {
5345 lowVector.getElementTypePreservingConst(),
5346 isConstCondition, loc);
5354 auto highBundle = type_dyn_cast<BundleType>(high);
5355 auto lowBundle = type_dyn_cast<BundleType>(low);
5356 if (highBundle && lowBundle) {
5357 auto highElements = highBundle.getElements();
5358 auto lowElements = lowBundle.getElements();
5361 SmallVector<BundleType::BundleElement> newElements;
5363 bool failed =
false;
5365 if (highElements[i].name != lowElements[i].name ||
5366 highElements[i].isFlip != lowElements[i].isFlip) {
5370 auto element = highElements[i];
5372 highBundle.getElementTypePreservingConst(i),
5373 lowBundle.getElementTypePreservingConst(i), isConstCondition, loc);
5376 newElements.push_back(element);
5379 return BundleType::get(low.getContext(), newElements, outerTypeIsConst);
5381 return emitInferRetTypeError<FIRRTLBaseType>(
5382 loc,
"incompatible mux operand bundle fields, true value type: ", high,
5383 ", false value type: ", low);
5388 return emitInferRetTypeError<FIRRTLBaseType>(
5389 loc,
"invalid mux operand types, true value type: ", high,
5390 ", false value type: ", low);
5393 FIRRTLType MuxPrimOp::inferReturnType(ValueRange operands,
5394 ArrayRef<NamedAttribute> attrs,
5395 std::optional<Location> loc) {
5396 auto highType = type_dyn_cast<FIRRTLBaseType>(operands[1].getType());
5397 auto lowType = type_dyn_cast<FIRRTLBaseType>(operands[2].getType());
5398 if (!highType || !lowType)
5404 FIRRTLType Mux2CellIntrinsicOp::inferReturnType(ValueRange operands,
5405 ArrayRef<NamedAttribute> attrs,
5406 std::optional<Location> loc) {
5407 auto highType = type_dyn_cast<FIRRTLBaseType>(operands[1].getType());
5408 auto lowType = type_dyn_cast<FIRRTLBaseType>(operands[2].getType());
5409 if (!highType || !lowType)
5415 FIRRTLType Mux4CellIntrinsicOp::inferReturnType(ValueRange operands,
5416 ArrayRef<NamedAttribute> attrs,
5417 std::optional<Location> loc) {
5418 SmallVector<FIRRTLBaseType> types;
5420 for (
unsigned i = 1; i < 5; i++) {
5421 types.push_back(type_dyn_cast<FIRRTLBaseType>(operands[i].getType()));
5426 isConst(operands[0].getType()), loc);
5430 result = types.back();
5436 FIRRTLType PadPrimOp::inferReturnType(ValueRange operands,
5437 ArrayRef<NamedAttribute> attrs,
5438 std::optional<Location> loc) {
5439 auto input = operands[0].getType();
5440 auto amount = getAttr<IntegerAttr>(attrs,
"amount").getValue().getSExtValue();
5442 auto inputi = type_dyn_cast<IntType>(input);
5443 if (amount < 0 || !inputi)
5445 loc,
"pad input must be integer and amount must be >= 0");
5447 int32_t
width = inputi.getWidthOrSentinel();
5456 FIRRTLType ShlPrimOp::inferReturnType(ValueRange operands,
5457 ArrayRef<NamedAttribute> attrs,
5458 std::optional<Location> loc) {
5459 auto input = operands[0].getType();
5460 auto amount = getAttr<IntegerAttr>(attrs,
"amount").getValue().getSExtValue();
5462 auto inputi = type_dyn_cast<IntType>(input);
5463 if (amount < 0 || !inputi)
5465 loc,
"shl input must be integer and amount must be >= 0");
5467 int32_t
width = inputi.getWidthOrSentinel();
5475 FIRRTLType ShrPrimOp::inferReturnType(ValueRange operands,
5476 ArrayRef<NamedAttribute> attrs,
5477 std::optional<Location> loc) {
5478 auto input = operands[0].getType();
5479 auto amount = getAttr<IntegerAttr>(attrs,
"amount").getValue().getSExtValue();
5481 auto inputi = type_dyn_cast<IntType>(input);
5482 if (amount < 0 || !inputi)
5484 loc,
"shr input must be integer and amount must be >= 0");
5486 int32_t
width = inputi.getWidthOrSentinel();
5489 int32_t minWidth = inputi.isUnsigned() ? 0 : 1;
5490 width = std::max<int32_t>(minWidth,
width - amount);
5497 FIRRTLType TailPrimOp::inferReturnType(ValueRange operands,
5498 ArrayRef<NamedAttribute> attrs,
5499 std::optional<Location> loc) {
5500 auto input = operands[0].getType();
5501 auto amount = getAttr<IntegerAttr>(attrs,
"amount").getValue().getSExtValue();
5503 auto inputi = type_dyn_cast<IntType>(input);
5504 if (amount < 0 || !inputi)
5506 loc,
"tail input must be integer and amount must be >= 0");
5508 int32_t
width = inputi.getWidthOrSentinel();
5512 loc,
"amount must be less than or equal operand width");
5524 function_ref<
void(Value, StringRef)> setNameFn) {
5528 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
5529 auto name = getText();
5531 if (name.starts_with(
"`"))
5532 name = name.drop_front();
5533 name = name.take_while(isOkCharacter);
5535 setNameFn(getResult(), name);
5543 function_ref<
void(Value, StringRef)> setNameFn) {
5547 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
5548 auto name = getText();
5550 if (name.starts_with(
"`"))
5551 name = name.drop_front();
5552 name = name.take_while(isOkCharacter);
5554 setNameFn(getResult(), name);
5565 op->emitError() <<
"unknown width is not allowed for DPI";
5566 return WalkResult::interrupt();
5570 return WalkResult::advance();
5572 <<
"integer types used by DPI functions must have a "
5573 "specific bit width; "
5574 "it must be equal to 1(bit), 8(byte), 16(shortint), "
5575 "32(int), 64(longint) "
5576 "or greater than 64, but got "
5578 return WalkResult::interrupt();
5584 if (
auto inputNames = getInputNames()) {
5585 if (getInputs().size() != inputNames->size())
5586 return emitError() <<
"inputNames has " << inputNames->size()
5587 <<
" elements but there are " << getInputs().size()
5588 <<
" input arguments";
5590 if (
auto outputName = getOutputName())
5591 if (getNumResults() == 0)
5592 return emitError() <<
"output name is given but there is no result";
5594 auto checkType = [
this](Type type) {
5597 return success(llvm::all_of(this->getResultTypes(), checkType) &&
5598 llvm::all_of(this->getOperandTypes(), checkType));
5601 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
5602 DPICallIntrinsicOp::computeDataFlow() {
5606 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
5608 for (
auto operand : getOperands()) {
5609 auto type = type_cast<FIRRTLBaseType>(operand.getType());
5611 SmallVector<circt::FieldRef> operandFields;
5614 operandFields.push_back(baseFieldRef.getSubField(dstIndex));
5618 for (
auto result : getResults())
5621 for (
auto field : operandFields)
5634 BundleType bundleType;
5635 hw::StructType structType;
5636 if ((bundleType = type_dyn_cast<BundleType>(getOperand().getType()))) {
5637 structType = dyn_cast<hw::StructType>(getType());
5639 return emitError(
"result type must be a struct");
5640 }
else if ((bundleType = type_dyn_cast<BundleType>(getType()))) {
5641 structType = dyn_cast<hw::StructType>(getOperand().getType());
5643 return emitError(
"operand type must be a struct");
5645 return emitError(
"either source or result type must be a bundle type");
5648 auto firFields = bundleType.getElements();
5649 auto hwFields = structType.getElements();
5650 if (firFields.size() != hwFields.size())
5651 return emitError(
"bundle and struct have different number of fields");
5653 for (
size_t findex = 0, fend = firFields.size(); findex < fend; ++findex) {
5654 if (firFields[findex].name.getValue() != hwFields[findex].name)
5655 return emitError(
"field names don't match '")
5656 << firFields[findex].name.getValue() <<
"', '"
5657 << hwFields[findex].name.getValue() <<
"'";
5661 if (firWidth > 0 && hwWidth > 0 && firWidth != hwWidth)
5662 return emitError(
"size of field '")
5663 << hwFields[findex].name.getValue() <<
"' don't match " << firWidth
5671 auto inTypeBits =
getBitWidth(getInput().getType(),
true);
5673 if (inTypeBits.has_value() && resTypeBits.has_value()) {
5675 if (*inTypeBits == *resTypeBits) {
5678 return emitError(
"cannot cast non-'const' input type ")
5679 << getOperand().getType() <<
" to 'const' result type "
5683 return emitError(
"the bitwidth of input (")
5684 << *inTypeBits <<
") and result (" << *resTypeBits
5687 if (!inTypeBits.has_value())
5688 return emitError(
"bitwidth cannot be determined for input operand type ")
5689 << getInput().getType();
5690 return emitError(
"bitwidth cannot be determined for result type ")
5701 NamedAttrList &resultAttrs) {
5702 auto result = parser.parseOptionalAttrDict(resultAttrs);
5703 if (!resultAttrs.get(
"annotations"))
5704 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
5710 DictionaryAttr attr,
5711 ArrayRef<StringRef> extraElides = {}) {
5712 SmallVector<StringRef> elidedAttrs(extraElides.begin(), extraElides.end());
5714 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
5715 elidedAttrs.push_back(
"annotations");
5717 elidedAttrs.push_back(
"nameKind");
5719 p.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
5725 NamedAttrList &resultAttrs) {
5728 if (!resultAttrs.get(
"portAnnotations")) {
5729 SmallVector<Attribute, 16> portAnnotations(
5730 parser.getNumResults(), parser.getBuilder().getArrayAttr({}));
5731 resultAttrs.append(
"portAnnotations",
5732 parser.getBuilder().getArrayAttr(portAnnotations));
5739 DictionaryAttr attr,
5740 ArrayRef<StringRef> extraElides = {}) {
5741 SmallVector<StringRef, 2> elidedAttrs(extraElides.begin(), extraElides.end());
5743 if (llvm::all_of(op->getAttrOfType<ArrayAttr>(
"portAnnotations"),
5744 [&](Attribute a) { return cast<ArrayAttr>(a).empty(); }))
5745 elidedAttrs.push_back(
"portAnnotations");
5754 firrtl::NameKindEnumAttr &result) {
5757 if (!parser.parseOptionalKeyword(&keyword,
5758 {
"interesting_name",
"droppable_name"})) {
5759 auto kind = symbolizeNameKindEnum(keyword);
5771 firrtl::NameKindEnumAttr attr,
5772 ArrayRef<StringRef> extraElides = {}) {
5773 if (attr.getValue() != NameKindEnum::DroppableName)
5774 p <<
" " << stringifyNameKindEnum(attr.getValue());
5782 NamedAttrList &resultAttrs) {
5790 DictionaryAttr attrs) {
5791 SmallVector<StringRef, 4> elides;
5793 elides.push_back(Forceable::getForceableAttrName());
5802 static ParseResult
parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs) {
5807 static void printMemOp(OpAsmPrinter &p, Operation *op, DictionaryAttr attr) {
5818 if (ClassType::parseInterface(parser, type))
5825 type.printInterface(p);
5833 NamedAttrList &resultAttrs) {
5834 auto result = p.parseOptionalAttrDict(resultAttrs);
5835 if (!resultAttrs.get(
"name"))
5836 resultAttrs.append(
"name", p.getBuilder().getStringAttr(
""));
5842 DictionaryAttr attr,
5843 ArrayRef<StringRef> extraElides = {}) {
5844 SmallVector<StringRef> elides(extraElides.begin(), extraElides.end());
5845 if (op->getAttrOfType<StringAttr>(
"name").getValue().empty())
5846 elides.push_back(
"name");
5848 p.printOptionalAttrDict(op->getAttrs(), elides);
5852 NamedAttrList &resultAttrs) {
5857 DictionaryAttr attr) {
5866 DictionaryAttr attr) {
5875 DictionaryAttr attr) {
5887 if (op->getNumResults() == 1)
5888 if (
auto nameAttr = op->getAttrOfType<StringAttr>(
"name"))
5889 setNameFn(op->getResult(0), nameAttr.getValue());
6114 FIRRTLType RefResolveOp::inferReturnType(ValueRange operands,
6115 ArrayRef<NamedAttribute> attrs,
6116 std::optional<Location> loc) {
6117 Type inType = operands[0].getType();
6118 auto inRefType = type_dyn_cast<RefType>(inType);
6121 loc,
"ref.resolve operand must be ref type, not ", inType);
6122 return inRefType.getType();
6125 FIRRTLType RefSendOp::inferReturnType(ValueRange operands,
6126 ArrayRef<NamedAttribute> attrs,
6127 std::optional<Location> loc) {
6128 Type inType = operands[0].getType();
6129 auto inBaseType = type_dyn_cast<FIRRTLBaseType>(inType);
6132 loc,
"ref.send operand must be base type, not ", inType);
6136 FIRRTLType RefSubOp::inferReturnType(ValueRange operands,
6137 ArrayRef<NamedAttribute> attrs,
6138 std::optional<Location> loc) {
6139 auto refType = type_dyn_cast<RefType>(operands[0].getType());
6142 auto inType = refType.getType();
6144 getAttr<IntegerAttr>(attrs,
"index").getValue().getZExtValue();
6150 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
6151 if (fieldIdx < vectorType.getNumElements())
6153 vectorType.getElementType().getConstType(
6154 vectorType.isConst() || vectorType.getElementType().isConst()),
6155 refType.getForceable(), refType.getLayer());
6157 "' in RefType of vector type ", refType);
6159 if (
auto bundleType = type_dyn_cast<BundleType>(inType)) {
6160 if (fieldIdx >= bundleType.getNumElements()) {
6162 "subfield element index is greater than "
6163 "the number of fields in the bundle type");
6165 return RefType::get(bundleType.getElement(fieldIdx).type.getConstType(
6166 bundleType.isConst() ||
6167 bundleType.getElement(fieldIdx).type.isConst()),
6168 refType.getForceable(), refType.getLayer());
6172 loc,
"ref.sub op requires a RefType of vector or bundle base type");
6178 SmallVector<SymbolRefAttr> missingLayers;
6181 emitOpError(
"cannot discard layer requirements of input reference");
6182 auto ¬e = diag.attachNote();
6183 note <<
"discarding layer requirements: ";
6184 llvm::interleaveComma(missingLayers, note);
6193 SmallVector<SymbolRefAttr> missingLayers;
6196 emitOpError(
"ambient layers are insufficient to resolve reference");
6197 auto ¬e = diag.attachNote();
6198 note <<
"missing layer requirements: ";
6199 interleaveComma(missingLayers, note);
6205 LogicalResult RWProbeOp::verifyInnerRefs(hw::InnerRefNamespace &ns) {
6206 auto targetRef = getTarget();
6207 if (targetRef.getModule() !=
6208 (*this)->getParentOfType<FModuleLike>().getModuleNameAttr())
6209 return emitOpError() <<
"has non-local target";
6211 auto target = ns.lookup(targetRef);
6213 return emitOpError() <<
"has target that cannot be resolved: " << targetRef;
6215 auto checkFinalType = [&](
auto type, Location loc) -> LogicalResult {
6220 auto baseType = type_dyn_cast<FIRRTLBaseType>(fType);
6221 if (!baseType || baseType.getPassiveType() != getType().getType()) {
6222 auto diag = emitOpError(
"has type mismatch: target resolves to ")
6223 << fType <<
" instead of expected " << getType().getType();
6224 diag.attachNote(loc) <<
"target resolves here";
6230 auto checkLayers = [&](Location loc) -> LogicalResult {
6233 SmallVector<SymbolRefAttr> missingLayers;
6235 auto diag = emitOpError(
"target has insufficient layer requirements");
6236 auto ¬e = diag.attachNote(loc);
6237 note <<
"target is missing layer requirements: ";
6238 llvm::interleaveComma(missingLayers, note);
6243 auto checks = [&](
auto type, Location loc) {
6244 if (failed(checkLayers(loc)))
6246 return checkFinalType(type, loc);
6249 if (target.isPort()) {
6250 auto mod = cast<FModuleLike>(target.getOp());
6251 return checks(mod.getPortType(target.getPort()),
6252 mod.getPortLocation(target.getPort()));
6254 hw::InnerSymbolOpInterface symOp =
6255 cast<hw::InnerSymbolOpInterface>(target.getOp());
6256 if (!symOp.getTargetResult())
6257 return emitOpError(
"has target that cannot be probed")
6258 .attachNote(symOp.getLoc())
6259 .append(
"target resolves here");
6261 symOp.getTargetResult().getParentBlock()->findAncestorOpInBlock(**
this);
6262 if (!ancestor || !symOp->isBeforeInBlock(ancestor))
6263 return emitOpError(
"is not dominated by target")
6264 .attachNote(symOp.getLoc())
6265 .append(
"target here");
6266 return checks(symOp.getTargetResult().getType(), symOp.getLoc());
6274 auto layerName = getLayerName();
6275 auto *parentOp = (*this)->getParentOp();
6278 while (isa<WhenOp, MatchOp>(parentOp))
6279 parentOp = parentOp->getParentOp();
6283 auto nestedReferences = layerName.getNestedReferences();
6284 if (nestedReferences.empty()) {
6285 if (!isa<FModuleOp>(parentOp)) {
6286 auto diag = emitOpError() <<
"has an un-nested layer symbol, but does "
6287 "not have a 'firrtl.module' op as a parent";
6288 return diag.attachNote(parentOp->getLoc())
6289 <<
"illegal parent op defined here";
6292 auto parentLayerBlock = dyn_cast<LayerBlockOp>(parentOp);
6293 if (!parentLayerBlock) {
6294 auto diag = emitOpError()
6295 <<
"has a nested layer symbol, but does not have a '"
6296 << getOperationName() <<
"' op as a parent'";
6297 return diag.attachNote(parentOp->getLoc())
6298 <<
"illegal parent op defined here";
6300 auto parentLayerBlockName = parentLayerBlock.getLayerName();
6301 if (parentLayerBlockName.getRootReference() !=
6302 layerName.getRootReference() ||
6303 parentLayerBlockName.getNestedReferences() !=
6304 layerName.getNestedReferences().drop_back()) {
6305 auto diag = emitOpError() <<
"is nested under an illegal layer block";
6306 return diag.attachNote(parentLayerBlock->getLoc())
6307 <<
"illegal parent layer block defined here";
6313 auto result = getBody(0)->walk<mlir::WalkOrder::PreOrder>(
6314 [&](Operation *op) -> WalkResult {
6316 if (isa<LayerBlockOp>(op))
6317 return WalkResult::skip();
6321 for (
auto operand : op->getOperands()) {
6323 if (
auto *definingOp = operand.getDefiningOp())
6324 if (getOperation()->isAncestor(definingOp))
6327 auto type = operand.getType();
6330 if (isa<PropertyType>(type)) {
6331 auto diag = emitOpError() <<
"captures a property operand";
6332 diag.attachNote(operand.getLoc()) <<
"operand is defined here";
6333 diag.attachNote(op->getLoc()) <<
"operand is used here";
6334 return WalkResult::interrupt();
6339 if (
auto connect = dyn_cast<FConnectLike>(op)) {
6341 if (isa<RefDefineOp>(
connect))
6342 return WalkResult::advance();
6349 bool passive =
true;
6351 type_dyn_cast<FIRRTLBaseType>(
connect.getDest().getType()))
6352 passive = type.isPassive();