28#include "mlir/IR/BuiltinTypes.h"
29#include "mlir/IR/Diagnostics.h"
30#include "mlir/IR/DialectImplementation.h"
31#include "mlir/IR/PatternMatch.h"
32#include "mlir/IR/SymbolTable.h"
33#include "mlir/Interfaces/FunctionImplementation.h"
34#include "llvm/ADT/BitVector.h"
35#include "llvm/ADT/DenseMap.h"
36#include "llvm/ADT/DenseSet.h"
37#include "llvm/ADT/STLExtras.h"
38#include "llvm/ADT/SmallSet.h"
39#include "llvm/ADT/StringExtras.h"
40#include "llvm/ADT/TypeSwitch.h"
41#include "llvm/Support/Casting.h"
42#include "llvm/Support/FormatVariadic.h"
44using llvm::SmallDenseSet;
45using mlir::RegionRange;
47using namespace firrtl;
48using namespace chirrtl;
59 const llvm::BitVector &indicesToDrop) {
62 int lastIndex = indicesToDrop.find_last();
64 assert((
size_t)lastIndex < input.size() &&
"index out of range");
74 size_t lastCopied = 0;
75 SmallVector<T> result;
76 result.reserve(input.size() - indicesToDrop.count());
78 for (
unsigned indexToDrop : indicesToDrop.set_bits()) {
80 if (indexToDrop > lastCopied) {
81 result.append(input.begin() + lastCopied, input.begin() + indexToDrop);
82 lastCopied = indexToDrop;
89 if (lastCopied < input.size())
90 result.append(input.begin() + lastCopied, input.end());
96template <
typename RetTy =
FIRRTLType,
typename... Args>
98 const Twine &message, Args &&...args) {
100 (mlir::emitError(*loc, message) << ... << std::forward<Args>(args));
106 while (Operation *op = val.getDefiningOp()) {
108 TypeSwitch<Operation *, std::optional<bool>>(op)
109 .Case<SubfieldOp, SubindexOp, SubaccessOp>([&val](
auto op) {
113 .Case<RegOp, RegResetOp, WireOp>([](
auto) {
return true; })
114 .Default([](
auto) {
return false; });
121SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
122MemOp::computeDataFlow() {
125 if (getReadLatency() > 0)
127 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
129 for (
auto memPort : getResults())
130 if (auto type =
type_dyn_cast<BundleType>(memPort.getType())) {
131 auto enableFieldId = type.getFieldID((
unsigned)ReadPortSubfield::en);
132 auto addressFieldId = type.getFieldID((
unsigned)ReadPortSubfield::addr);
133 auto dataFieldId = type.getFieldID((
unsigned)ReadPortSubfield::data);
135 FieldRef(memPort,
static_cast<unsigned>(dataFieldId)),
136 FieldRef(memPort,
static_cast<unsigned>(enableFieldId)));
138 FieldRef(memPort,
static_cast<unsigned>(dataFieldId)),
139 FieldRef(memPort,
static_cast<unsigned>(addressFieldId)));
146 constexpr unsigned int addr = 1 << 0;
147 constexpr unsigned int en = 1 << 1;
148 constexpr unsigned int clk = 1 << 2;
149 constexpr unsigned int data = 1 << 3;
150 constexpr unsigned int mask = 1 << 4;
151 constexpr unsigned int rdata = 1 << 5;
152 constexpr unsigned int wdata = 1 << 6;
153 constexpr unsigned int wmask = 1 << 7;
154 constexpr unsigned int wmode = 1 << 8;
155 constexpr unsigned int def = 1 << 9;
157 auto portType = type_dyn_cast<BundleType>(type);
159 return MemOp::PortKind::Debug;
162 for (
auto elem : portType.getElements()) {
163 fields |= llvm::StringSwitch<unsigned>(elem.name.getValue())
169 .Case(
"rdata",
rdata)
170 .Case(
"wdata",
wdata)
171 .Case(
"wmask",
wmask)
172 .Case(
"wmode",
wmode)
176 return MemOp::PortKind::Read;
178 return MemOp::PortKind::Write;
180 return MemOp::PortKind::ReadWrite;
181 return MemOp::PortKind::Debug;
196 llvm_unreachable(
"Unsupported Flow type.");
204 return "source flow";
208 return "duplex flow";
211 llvm_unreachable(
"Unsupported Flow type.");
216 if (
auto blockArg = dyn_cast<BlockArgument>(val)) {
217 auto *op = val.getParentBlock()->getParentOp();
218 if (
auto moduleLike = dyn_cast<FModuleLike>(op)) {
219 auto direction = moduleLike.getPortDirection(blockArg.getArgNumber());
220 if (direction == Direction::Out)
223 return accumulatedFlow;
226 Operation *op = val.getDefiningOp();
228 return TypeSwitch<Operation *, Flow>(op)
229 .Case<SubfieldOp, OpenSubfieldOp>([&](
auto op) {
230 return foldFlow(op.getInput(), op.isFieldFlipped()
234 .Case<SubindexOp, SubaccessOp, OpenSubindexOp, RefSubOp>(
235 [&](
auto op) {
return foldFlow(op.getInput(), accumulatedFlow); })
237 .Case<RegOp, RegResetOp, WireOp, MemoryPortOp>(
238 [](
auto) {
return Flow::Duplex; })
239 .Case<InstanceOp, InstanceChoiceOp>([&](
auto inst) {
240 auto resultNo = cast<OpResult>(val).getResultNumber();
241 if (inst.getPortDirection(resultNo) == Direction::Out)
242 return accumulatedFlow;
245 .Case<MemOp>([&](
auto op) {
247 if (type_isa<RefType>(val.getType()))
251 .Case<ObjectSubfieldOp>([&](ObjectSubfieldOp op) {
252 auto input = op.getInput();
253 auto *inputOp = input.getDefiningOp();
256 if (
auto objectOp = dyn_cast_or_null<ObjectOp>(inputOp)) {
257 auto classType = input.getType();
258 auto direction = classType.getElement(op.getIndex()).direction;
259 if (direction == Direction::In)
270 auto classType = input.getType();
271 auto direction = classType.getElement(op.getIndex()).direction;
272 if (direction == Direction::In)
275 op = dyn_cast_or_null<ObjectSubfieldOp>(inputOp);
277 input = op.getInput();
278 inputOp = input.getDefiningOp();
282 return accumulatedFlow;
286 .Default([&](
auto) {
return accumulatedFlow; });
292 Operation *op = val.getDefiningOp();
294 return DeclKind::Port;
296 return TypeSwitch<Operation *, DeclKind>(op)
297 .Case<InstanceOp>([](
auto) {
return DeclKind::Instance; })
298 .Case<SubfieldOp, SubindexOp, SubaccessOp, OpenSubfieldOp, OpenSubindexOp,
300 .Default([](
auto) {
return DeclKind::Other; });
304 if (
auto module = dyn_cast<FModuleLike>(op))
305 return module.getNumPorts();
306 return op->getNumResults();
320 if (
auto *op = value.getDefiningOp())
322 auto arg = dyn_cast<BlockArgument>(value);
323 auto module = dyn_cast<FModuleOp>(arg.getOwner()->getParentOp());
326 return (module.getPortSymbolAttr(arg.getArgNumber())) ||
333 OpAsmSetValueNameFn setNameFn) {
337 auto *block = ®ion.front();
340 auto argAttr = parentOp->getAttrOfType<ArrayAttr>(
"portNames");
342 if (!argAttr || argAttr.size() != block->getNumArguments())
345 for (
size_t i = 0, e = block->getNumArguments(); i != e; ++i) {
346 auto str = cast<StringAttr>(argAttr[i]).getValue();
348 setNameFn(block->getArgument(i), str);
354 firrtl::NameKindEnumAttr &result);
365 for (; op !=
nullptr; op = op->getParentOp()) {
366 if (
auto module = dyn_cast<FModuleLike>(op)) {
367 auto layers =
module.getLayersAttr().getAsRange<SymbolRefAttr>();
368 result.insert(layers.begin(), layers.end());
371 if (
auto layerblock = dyn_cast<LayerBlockOp>(op)) {
372 result.insert(layerblock.getLayerName());
390 if (
auto type = dyn_cast<RefType>(value.getType()))
391 if (
auto layer = type.getLayer())
392 result.insert(type.getLayer());
401 mlir::SymbolRefAttr dstLayer) {
411 if (srcLayer.getRootReference() != dstLayer.getRootReference())
414 auto srcNames = srcLayer.getNestedReferences();
415 auto dstNames = dstLayer.getNestedReferences();
416 if (dstNames.size() < srcNames.size())
419 return llvm::all_of(llvm::zip_first(srcNames, dstNames),
420 [](
auto x) {
return std::get<0>(x) == std::get<1>(x); });
427 if (dstLayers.contains(srcLayer))
432 return any_of(dstLayers, [=](SymbolRefAttr dstLayer) {
441 SmallVectorImpl<SymbolRefAttr> &missing) {
442 for (
auto srcLayer : src)
444 missing.push_back(srcLayer);
447 return missing.empty();
452 const Twine &errorMsg,
453 const Twine ¬eMsg = Twine(
"missing layer requirements")) {
454 SmallVector<SymbolRefAttr> missing;
457 interleaveComma(missing, op->emitOpError(errorMsg).attachNote()
466void CircuitOp::build(OpBuilder &builder, OperationState &result,
467 StringAttr name, ArrayAttr annotations) {
469 result.getOrAddProperties<Properties>().setName(name);
472 annotations = builder.getArrayAttr({});
473 result.getOrAddProperties<Properties>().setAnnotations(annotations);
476 Region *bodyRegion = result.addRegion();
478 bodyRegion->push_back(body);
482 NamedAttrList &resultAttrs) {
483 auto result = parser.parseOptionalAttrDictWithKeyword(resultAttrs);
484 if (!resultAttrs.get(
"annotations"))
485 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
491 DictionaryAttr attr) {
493 SmallVector<StringRef> elidedAttrs = {
"name"};
495 auto annotationsAttr = op->getAttrOfType<ArrayAttr>(
"annotations");
496 if (annotationsAttr.empty())
497 elidedAttrs.push_back(
"annotations");
499 p.printOptionalAttrDictWithKeyword(op->getAttrs(), elidedAttrs);
502LogicalResult CircuitOp::verifyRegions() {
507 emitOpError(
"must have a non-empty name");
511 mlir::SymbolTable symtbl(getOperation());
513 auto *mainModule = symtbl.lookup(
main);
515 return emitOpError().append(
516 "does not contain module with same name as circuit");
517 if (!isa<FModuleLike>(mainModule))
518 return mainModule->emitError(
519 "entity with name of circuit must be a module");
520 if (symtbl.getSymbolVisibility(mainModule) !=
521 mlir::SymbolTable::Visibility::Public)
522 return mainModule->emitError(
"main module must be public");
527 llvm::DenseMap<Attribute, FExtModuleOp> defnameMap;
529 auto verifyExtModule = [&](FExtModuleOp extModule) -> LogicalResult {
533 auto defname = extModule.getDefnameAttr();
539 if (
auto collidingModule = symtbl.lookup<FModuleOp>(defname.getValue()))
540 return extModule.emitOpError()
541 .append(
"attribute 'defname' with value ", defname,
542 " conflicts with the name of another module in the circuit")
543 .attachNote(collidingModule.getLoc())
544 .append(
"previous module declared here");
552 FExtModuleOp collidingExtModule;
553 if (
auto &value = defnameMap[defname]) {
554 collidingExtModule = value;
555 if (!value.getParameters().empty() && extModule.getParameters().empty())
565 SmallVector<PortInfo> ports = extModule.getPorts();
566 SmallVector<PortInfo> collidingPorts = collidingExtModule.getPorts();
568 if (ports.size() != collidingPorts.size())
569 return extModule.emitOpError()
570 .append(
"with 'defname' attribute ", defname,
" has ", ports.size(),
571 " ports which is different from a previously defined "
572 "extmodule with the same 'defname' which has ",
573 collidingPorts.size(),
" ports")
574 .attachNote(collidingExtModule.getLoc())
575 .append(
"previous extmodule definition occurred here");
581 for (
auto p :
llvm::zip(ports, collidingPorts)) {
582 StringAttr aName = std::get<0>(p).name, bName = std::get<1>(p).name;
583 Type aType = std::get<0>(p).type, bType = std::get<1>(p).type;
586 return extModule.emitOpError()
587 .append(
"with 'defname' attribute ", defname,
588 " has a port with name ", aName,
589 " which does not match the name of the port in the same "
590 "position of a previously defined extmodule with the same "
591 "'defname', expected port to have name ",
593 .attachNote(collidingExtModule.getLoc())
594 .append(
"previous extmodule definition occurred here");
596 if (!extModule.getParameters().empty() ||
597 !collidingExtModule.getParameters().empty()) {
599 if (
auto base = type_dyn_cast<FIRRTLBaseType>(aType))
600 aType = base.getWidthlessType();
601 if (
auto base = type_dyn_cast<FIRRTLBaseType>(bType))
602 bType = base.getWidthlessType();
605 return extModule.emitOpError()
606 .append(
"with 'defname' attribute ", defname,
607 " has a port with name ", aName,
608 " which has a different type ", aType,
609 " which does not match the type of the port in the same "
610 "position of a previously defined extmodule with the same "
611 "'defname', expected port to have type ",
613 .attachNote(collidingExtModule.getLoc())
614 .append(
"previous extmodule definition occurred here");
619 SmallVector<FModuleOp, 1> dutModules;
622 if (
auto moduleOp = dyn_cast<FModuleOp>(op)) {
624 dutModules.push_back(moduleOp);
629 if (
auto extModule = dyn_cast<FExtModuleOp>(op)) {
630 if (verifyExtModule(extModule).failed())
636 if (dutModules.size() > 1) {
637 auto diag = dutModules[0]->emitOpError()
638 <<
"is annotated as the design-under-test (DUT), but other "
639 "modules are also annotated";
640 for (
auto moduleOp : ArrayRef(dutModules).drop_front())
641 diag.attachNote(moduleOp.
getLoc()) <<
"is also annotated as the DUT";
648Block *CircuitOp::getBodyBlock() {
return &getBody().front(); }
655 SmallVector<PortInfo> results;
656 ArrayRef<Attribute> domains =
module.getDomainInfo();
657 for (
unsigned i = 0, e = module.getNumPorts(); i < e; ++i) {
658 results.push_back({
module.getPortNameAttr(i), module.getPortType(i),
659 module.getPortDirection(i), module.getPortSymbolAttr(i),
660 module.getPortLocation(i),
661 AnnotationSet::forPort(module, i),
662 domains.empty() ? Attribute{} : domains[i]});
667SmallVector<PortInfo> FModuleOp::getPorts() { return ::getPortImpl(*
this); }
669SmallVector<PortInfo> FExtModuleOp::getPorts() { return ::getPortImpl(*
this); }
671SmallVector<PortInfo> FIntModuleOp::getPorts() { return ::getPortImpl(*
this); }
673SmallVector<PortInfo> FMemModuleOp::getPorts() { return ::getPortImpl(*
this); }
676 if (dir == Direction::In)
677 return hw::ModulePort::Direction::Input;
678 if (dir == Direction::Out)
679 return hw::ModulePort::Direction::Output;
680 assert(0 &&
"invalid direction");
685 SmallVector<hw::PortInfo> results;
686 auto aname = StringAttr::get(module.getContext(),
687 hw::HWModuleLike::getPortSymbolAttrName());
688 auto emptyDict = DictionaryAttr::get(module.getContext());
689 for (
unsigned i = 0, e =
getNumPorts(module); i < e; ++i) {
690 auto sym =
module.getPortSymbolAttr(i);
692 {{
module.getPortNameAttr(i), module.getPortType(i),
693 dirFtoH(module.getPortDirection(i))},
695 sym ? DictionaryAttr::get(
697 ArrayRef<mlir::NamedAttribute>{NamedAttribute{aname, sym}})
699 module.getPortLocation(i)});
704SmallVector<::circt::hw::PortInfo> FModuleOp::getPortList() {
705 return ::getPortListImpl(*
this);
708SmallVector<::circt::hw::PortInfo> FExtModuleOp::getPortList() {
709 return ::getPortListImpl(*
this);
712SmallVector<::circt::hw::PortInfo> FIntModuleOp::getPortList() {
713 return ::getPortListImpl(*
this);
716SmallVector<::circt::hw::PortInfo> FMemModuleOp::getPortList() {
717 return ::getPortListImpl(*
this);
721 return {{
module.getPortNameAttr(idx), module.getPortType(idx),
722 dirFtoH(module.getPortDirection(idx))},
726 ArrayRef<mlir::NamedAttribute>{NamedAttribute{
727 StringAttr::get(module.getContext(),
728 hw::HWModuleLike::getPortSymbolAttrName()),
729 module.getPortSymbolAttr(idx)}}),
730 module.getPortLocation(idx)};
734 return ::getPortImpl(*
this, idx);
738 return ::getPortImpl(*
this, idx);
742 return ::getPortImpl(*
this, idx);
746 return ::getPortImpl(*
this, idx);
750BlockArgument FModuleOp::getArgument(
size_t portNumber) {
758 const SmallVectorImpl<unsigned> &numInserted) {
760 auto di = dyn_cast_or_null<ArrayAttr>(domainInfoAttr);
762 return domainInfoAttr;
764 SmallVector<Attribute> domainInfo;
765 for (
auto attr : di) {
766 auto oldIdx = cast<IntegerAttr>(attr).getUInt();
767 auto newIdx = oldIdx + numInserted[oldIdx];
768 if (oldIdx == newIdx)
769 domainInfo.push_back(attr);
771 domainInfo.push_back(IntegerAttr::get(
772 IntegerType::get(context, 32, IntegerType::Unsigned), newIdx));
774 return ArrayAttr::get(context, domainInfo);
781 ArrayRef<std::pair<unsigned, PortInfo>> ports,
782 bool supportsInternalPaths =
false) {
785 unsigned oldNumArgs = op.getNumPorts();
786 unsigned newNumArgs = oldNumArgs + ports.size();
789 auto existingDirections = op.getPortDirectionsAttr();
790 ArrayRef<Attribute> existingNames = op.getPortNames();
791 ArrayRef<Attribute> existingTypes = op.getPortTypes();
792 ArrayRef<Attribute> existingLocs = op.getPortLocations();
793 assert(existingDirections.size() == oldNumArgs);
794 assert(existingNames.size() == oldNumArgs);
795 assert(existingTypes.size() == oldNumArgs);
796 assert(existingLocs.size() == oldNumArgs);
797 SmallVector<Attribute> internalPaths;
798 auto emptyInternalPath = InternalPathAttr::get(op.getContext());
799 if (supportsInternalPaths) {
800 if (
auto internalPathsAttr = op->getAttrOfType<ArrayAttr>(
"internalPaths"))
801 llvm::append_range(internalPaths, internalPathsAttr);
803 internalPaths.resize(oldNumArgs, emptyInternalPath);
804 assert(internalPaths.size() == oldNumArgs);
807 SmallVector<bool> newDirections;
808 SmallVector<Attribute> newNames, newTypes, newDomains, newAnnos, newSyms,
809 newLocs, newInternalPaths;
810 SmallVector<unsigned> numInserted;
811 newDirections.reserve(newNumArgs);
812 newNames.reserve(newNumArgs);
813 newTypes.reserve(newNumArgs);
814 newDomains.reserve(newNumArgs);
815 newAnnos.reserve(newNumArgs);
816 newSyms.reserve(newNumArgs);
817 newLocs.reserve(newNumArgs);
818 newInternalPaths.reserve(newNumArgs);
819 numInserted.resize(op.getNumPorts());
821 auto emptyArray = ArrayAttr::get(op.getContext(), {});
824 auto migrateOldPorts = [&](
unsigned untilOldIdx) {
825 while (oldIdx < oldNumArgs && oldIdx < untilOldIdx) {
826 newDirections.push_back(existingDirections[oldIdx]);
827 newNames.push_back(existingNames[oldIdx]);
828 newTypes.push_back(existingTypes[oldIdx]);
830 op.getContext(), op.getDomainInfoAttrForPort(oldIdx), numInserted));
831 newAnnos.push_back(op.getAnnotationsAttrForPort(oldIdx));
832 newSyms.push_back(op.getPortSymbolAttr(oldIdx));
833 newLocs.push_back(existingLocs[oldIdx]);
834 if (supportsInternalPaths)
835 newInternalPaths.push_back(internalPaths[oldIdx]);
839 numInserted[oldIdx] = numInserted[oldIdx - 1];
843 for (
auto pair : llvm::enumerate(ports)) {
844 auto idx = pair.value().first;
845 auto &port = pair.value().second;
846 migrateOldPorts(idx);
848 newNames.push_back(port.name);
849 newTypes.push_back(TypeAttr::get(port.type));
852 port.domains ? port.domains : ArrayAttr::get(op.getContext(), {}),
854 auto annos = port.annotations.getArrayAttr();
855 newAnnos.push_back(annos ? annos : emptyArray);
856 newSyms.push_back(port.sym);
857 newLocs.push_back(port.loc);
858 if (supportsInternalPaths)
859 newInternalPaths.push_back(emptyInternalPath);
860 if (idx < oldNumArgs)
861 numInserted[idx] += 1;
863 migrateOldPorts(oldNumArgs);
867 if (llvm::all_of(newAnnos, [](Attribute attr) {
868 return cast<ArrayAttr>(attr).empty();
874 if (llvm::all_of(newDomains, [](Attribute attr) {
877 if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr))
878 return arrayAttr.empty();
884 op->setAttr(
"portDirections",
886 op->setAttr(
"portNames", ArrayAttr::get(op.getContext(), newNames));
887 op->setAttr(
"portTypes", ArrayAttr::get(op.getContext(), newTypes));
888 op->setAttr(
"domainInfo", ArrayAttr::get(op.getContext(), newDomains));
889 op->setAttr(
"portAnnotations", ArrayAttr::get(op.getContext(), newAnnos));
890 FModuleLike::fixupPortSymsArray(newSyms, op.getContext());
891 op.setPortSymbols(newSyms);
892 op->setAttr(
"portLocations", ArrayAttr::get(op.getContext(), newLocs));
893 if (supportsInternalPaths) {
895 auto empty = llvm::all_of(newInternalPaths, [](Attribute attr) {
896 return !cast<InternalPathAttr>(attr).getPath();
899 op->removeAttr(
"internalPaths");
901 op->setAttr(
"internalPaths",
902 ArrayAttr::get(op.getContext(), newInternalPaths));
914 ArrayAttr domainInfoAttr,
915 const llvm::BitVector &portIndices,
916 bool supportsEmptyAttr) {
917 if (supportsEmptyAttr && domainInfoAttr.empty())
918 return domainInfoAttr;
922 SmallVector<unsigned> numDeleted;
923 numDeleted.resize(portIndices.size());
924 size_t deletionIndex = portIndices.find_first();
925 for (
size_t i = 0, e = portIndices.size(); i != e; ++i) {
926 if (i == deletionIndex) {
930 numDeleted[i] = numDeleted[i - 1] + 1;
931 deletionIndex = portIndices.find_next(i);
937 numDeleted[i] = numDeleted[i - 1];
942 auto getEmpty = [&]() {
944 eEmpty = ArrayAttr::get(context, {});
949 SmallVector<Attribute> newDomainInfo;
950 newDomainInfo.reserve(portIndices.size() - portIndices.count());
951 for (
size_t i = 0, e = portIndices.size(); i != e; ++i) {
953 if (portIndices.test(i))
956 if (domainInfoAttr.empty()) {
957 newDomainInfo.push_back(getEmpty());
960 auto attr = domainInfoAttr[i];
962 auto domains = dyn_cast<ArrayAttr>(attr);
963 if (!domains || domains.empty()) {
964 newDomainInfo.push_back(attr);
968 SmallVector<Attribute> newDomains;
969 for (
auto domain : domains) {
971 auto oldIdx = cast<IntegerAttr>(domain).getUInt();
972 if (portIndices.test(oldIdx))
975 auto newIdx = oldIdx - numDeleted[oldIdx];
976 if (oldIdx == newIdx) {
977 newDomainInfo.push_back(attr);
981 newDomains.push_back(IntegerAttr::get(
982 IntegerType::get(context, 32, IntegerType::Unsigned), newIdx));
984 newDomainInfo.push_back(ArrayAttr::get(context, newDomains));
987 return ArrayAttr::get(context, newDomainInfo);
991static void erasePorts(FModuleLike op,
const llvm::BitVector &portIndices) {
992 if (portIndices.none())
996 ArrayRef<bool> portDirections = op.getPortDirectionsAttr().asArrayRef();
997 ArrayRef<Attribute> portNames = op.getPortNames();
998 ArrayRef<Attribute> portTypes = op.getPortTypes();
999 ArrayRef<Attribute> portAnnos = op.getPortAnnotations();
1000 ArrayRef<Attribute> portSyms = op.getPortSymbols();
1001 ArrayRef<Attribute> portLocs = op.getPortLocations();
1002 ArrayRef<Attribute> portDomains = op.getDomainInfo();
1003 auto numPorts = op.getNumPorts();
1005 assert(portDirections.size() == numPorts);
1006 assert(portNames.size() == numPorts);
1007 assert(portAnnos.size() == numPorts || portAnnos.empty());
1008 assert(portTypes.size() == numPorts);
1009 assert(portSyms.size() == numPorts || portSyms.empty());
1010 assert(portLocs.size() == numPorts);
1011 assert(portDomains.size() == numPorts || portDomains.empty());
1013 SmallVector<bool> newPortDirections =
1014 removeElementsAtIndices<bool>(portDirections, portIndices);
1015 SmallVector<Attribute> newPortNames, newPortTypes, newPortAnnos, newPortSyms,
1023 op->setAttr(
"portDirections",
1025 op->setAttr(
"portNames", ArrayAttr::get(op.getContext(), newPortNames));
1026 op->setAttr(
"portAnnotations", ArrayAttr::get(op.getContext(), newPortAnnos));
1027 op->setAttr(
"portTypes", ArrayAttr::get(op.getContext(), newPortTypes));
1028 FModuleLike::fixupPortSymsArray(newPortSyms, op.getContext());
1029 op->setAttr(
"portSymbols", ArrayAttr::get(op.getContext(), newPortSyms));
1030 op->setAttr(
"portLocations", ArrayAttr::get(op.getContext(), newPortLocs));
1031 op->setAttr(
"domainInfo",
1033 portIndices,
true));
1036template <
typename T>
1039 auto internalPaths = op.getInternalPaths();
1047 auto empty = llvm::all_of(newPaths, [](Attribute attr) {
1048 return !cast<InternalPathAttr>(attr).getPath();
1051 op.removeInternalPathsAttr();
1053 op.setInternalPathsAttr(ArrayAttr::get(op.getContext(), newPaths));
1056void FExtModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1057 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1061void FIntModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1062 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1066void FMemModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1067 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1070void FModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1071 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1078void FModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1079 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1083 for (
size_t i = 0, e = ports.size(); i < e; ++i) {
1086 auto &[index, port] = ports[i];
1087 body->insertArgument(index + i, port.type, port.loc);
1091void FExtModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1096void FIntModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1104void FMemModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1105 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1108template <
typename OpTy>
1110 StringAttr name, ArrayRef<PortInfo> ports) {
1112 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
1113 properties.setSymName(name);
1116 SmallVector<Direction, 4> portDirections;
1117 SmallVector<Attribute, 4> portNames;
1118 SmallVector<Attribute, 4> portTypes;
1119 SmallVector<Attribute, 4> portSyms;
1120 SmallVector<Attribute, 4> portLocs;
1121 SmallVector<Attribute, 4> portDomains;
1122 for (
const auto &port : ports) {
1123 portDirections.push_back(port.direction);
1124 portNames.push_back(port.name);
1125 portTypes.push_back(TypeAttr::get(port.type));
1126 portSyms.push_back(port.sym);
1127 portLocs.push_back(port.loc);
1128 portDomains.push_back(port.domains);
1130 if (llvm::all_of(portDomains, [](Attribute attr) {
1133 if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr))
1134 return arrayAttr.empty();
1137 portDomains.clear();
1139 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1142 properties.setPortDirections(
1144 properties.setPortNames(builder.getArrayAttr(portNames));
1145 properties.setPortTypes(builder.getArrayAttr(portTypes));
1146 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1147 properties.setPortLocations(builder.getArrayAttr(portLocs));
1148 properties.setDomainInfo(builder.getArrayAttr(portDomains));
1153template <
typename OpTy>
1155 StringAttr name, ArrayRef<PortInfo> ports,
1156 ArrayAttr annotations, ArrayAttr layers) {
1157 buildModuleLike<OpTy>(builder, result, name, ports);
1158 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
1161 annotations = builder.getArrayAttr({});
1162 properties.setAnnotations(annotations);
1166 SmallVector<Attribute, 4> portAnnotations;
1167 for (
const auto &port : ports)
1168 portAnnotations.push_back(port.annotations.getArrayAttr());
1169 if (llvm::all_of(portAnnotations, [](Attribute attr) {
1170 return cast<ArrayAttr>(attr).empty();
1172 portAnnotations.clear();
1173 properties.setPortAnnotations(builder.getArrayAttr(portAnnotations));
1177 layers = builder.getArrayAttr({});
1178 properties.setLayers(layers);
1181template <
typename OpTy>
1182static void buildClass(OpBuilder &builder, OperationState &result,
1183 StringAttr name, ArrayRef<PortInfo> ports) {
1184 return buildModuleLike<OpTy>(builder, result, name, ports);
1187void FModuleOp::build(OpBuilder &builder, OperationState &result,
1188 StringAttr name, ConventionAttr convention,
1189 ArrayRef<PortInfo> ports, ArrayAttr annotations,
1191 buildModule<FModuleOp>(builder, result, name, ports, annotations, layers);
1192 auto &properties = result.getOrAddProperties<Properties>();
1193 properties.setConvention(convention);
1196 auto *bodyRegion = result.regions[0].get();
1198 bodyRegion->push_back(body);
1201 for (
auto &elt : ports)
1202 body->addArgument(elt.type, elt.loc);
1205void FExtModuleOp::build(OpBuilder &builder, OperationState &result,
1206 StringAttr name, ConventionAttr convention,
1207 ArrayRef<PortInfo> ports, ArrayAttr knownLayers,
1208 StringRef defnameAttr, ArrayAttr annotations,
1209 ArrayAttr parameters, ArrayAttr internalPaths,
1211 buildModule<FExtModuleOp>(builder, result, name, ports, annotations, layers);
1212 auto &properties = result.getOrAddProperties<Properties>();
1213 properties.setConvention(convention);
1215 knownLayers = builder.getArrayAttr({});
1216 properties.setKnownLayers(knownLayers);
1217 if (!defnameAttr.empty())
1218 properties.setDefname(builder.getStringAttr(defnameAttr));
1220 parameters = builder.getArrayAttr({});
1221 properties.setParameters(parameters);
1222 if (internalPaths && !internalPaths.empty())
1223 properties.setInternalPaths(internalPaths);
1226void FIntModuleOp::build(OpBuilder &builder, OperationState &result,
1227 StringAttr name, ArrayRef<PortInfo> ports,
1228 StringRef intrinsicNameStr, ArrayAttr annotations,
1229 ArrayAttr parameters, ArrayAttr internalPaths,
1231 buildModule<FIntModuleOp>(builder, result, name, ports, annotations, layers);
1232 auto &properties = result.getOrAddProperties<Properties>();
1233 properties.setIntrinsic(builder.getStringAttr(intrinsicNameStr));
1235 parameters = builder.getArrayAttr({});
1236 properties.setParameters(parameters);
1237 if (internalPaths && !internalPaths.empty())
1238 properties.setInternalPaths(internalPaths);
1241void FMemModuleOp::build(OpBuilder &builder, OperationState &result,
1242 StringAttr name, ArrayRef<PortInfo> ports,
1243 uint32_t numReadPorts, uint32_t numWritePorts,
1244 uint32_t numReadWritePorts, uint32_t dataWidth,
1245 uint32_t maskBits, uint32_t readLatency,
1246 uint32_t writeLatency, uint64_t depth, RUWBehavior ruw,
1247 ArrayAttr annotations, ArrayAttr layers) {
1248 auto *context = builder.getContext();
1249 buildModule<FMemModuleOp>(builder, result, name, ports, annotations, layers);
1250 auto ui32Type = IntegerType::get(context, 32, IntegerType::Unsigned);
1251 auto ui64Type = IntegerType::get(context, 64, IntegerType::Unsigned);
1252 auto &properties = result.getOrAddProperties<Properties>();
1253 properties.setNumReadPorts(IntegerAttr::get(ui32Type, numReadPorts));
1254 properties.setNumWritePorts(IntegerAttr::get(ui32Type, numWritePorts));
1255 properties.setNumReadWritePorts(
1256 IntegerAttr::get(ui32Type, numReadWritePorts));
1257 properties.setDataWidth(IntegerAttr::get(ui32Type, dataWidth));
1258 properties.setMaskBits(IntegerAttr::get(ui32Type, maskBits));
1259 properties.setReadLatency(IntegerAttr::get(ui32Type, readLatency));
1260 properties.setWriteLatency(IntegerAttr::get(ui32Type, writeLatency));
1261 properties.setDepth(IntegerAttr::get(ui64Type, depth));
1262 properties.setExtraPorts(ArrayAttr::get(context, {}));
1263 properties.setRuw(RUWBehaviorAttr::get(context, ruw));
1280 ArrayRef<Attribute> portNames, ArrayRef<Attribute> portTypes,
1281 ArrayRef<Attribute> portAnnotations,
1282 ArrayRef<Attribute> portSyms, ArrayRef<Attribute> portLocs,
1283 ArrayRef<Attribute> domainInfo) {
1286 bool printedNamesDontMatch =
false;
1288 mlir::OpPrintingFlags flags;
1292 SmallString<32> resultNameStr;
1293 DenseMap<unsigned, std::string> domainPortNames;
1295 for (
unsigned i = 0, e = portTypes.size(); i < e; ++i) {
1304 auto portType = cast<TypeAttr>(portTypes[i]).getValue();
1307 resultNameStr.clear();
1308 llvm::raw_svector_ostream tmpStream(resultNameStr);
1309 p.printOperand(block->getArgument(i), tmpStream);
1312 auto portName = cast<StringAttr>(portNames[i]).getValue();
1313 if (tmpStream.str().drop_front() != portName)
1314 printedNamesDontMatch =
true;
1315 p << tmpStream.str();
1316 if (isa<DomainType>(portType))
1317 domainPortNames[i] = tmpStream.str();
1319 auto name = cast<StringAttr>(portNames[i]).getValue();
1320 p.printKeywordOrString(name);
1321 if (isa<DomainType>(portType))
1322 domainPortNames[i] = name.str();
1327 p.printType(portType);
1330 if (!portSyms.empty()) {
1331 if (!cast<hw::InnerSymAttr>(portSyms[i]).
empty()) {
1333 cast<hw::InnerSymAttr>(portSyms[i]).print(p);
1338 if (!domainInfo.empty()) {
1339 if (
auto domainKind = dyn_cast<FlatSymbolRefAttr>(domainInfo[i])) {
1340 p <<
" of " << domainKind;
1342 auto domains = cast<ArrayAttr>(domainInfo[i]);
1343 if (!domains.empty()) {
1345 llvm::interleaveComma(domains, p, [&](Attribute attr) {
1346 p << domainPortNames[cast<IntegerAttr>(attr).getUInt()];
1355 if (!portAnnotations.empty() &&
1356 !cast<ArrayAttr>(portAnnotations[i]).empty()) {
1358 p.printAttribute(portAnnotations[i]);
1365 if (flags.shouldPrintDebugInfo() && !portLocs.empty())
1366 p.printOptionalLocationSpecifier(cast<LocationAttr>(portLocs[i]));
1370 return printedNamesDontMatch;
1376 OpAsmParser &parser,
bool hasSSAIdentifiers,
bool supportsSymbols,
1377 bool supportsDomains, SmallVectorImpl<OpAsmParser::Argument> &entryArgs,
1378 SmallVectorImpl<Direction> &portDirections,
1379 SmallVectorImpl<Attribute> &portNames,
1380 SmallVectorImpl<Attribute> &portTypes,
1381 SmallVectorImpl<Attribute> &portAnnotations,
1382 SmallVectorImpl<Attribute> &portSyms, SmallVectorImpl<Attribute> &portLocs,
1383 SmallVectorImpl<Attribute> &domains) {
1384 auto *context = parser.getContext();
1387 DenseMap<Attribute, size_t> domainIndex;
1389 auto parseArgument = [&]() -> ParseResult {
1391 if (succeeded(parser.parseOptionalKeyword(
"out")))
1392 portDirections.push_back(Direction::Out);
1393 else if (succeeded(parser.parseKeyword(
"in",
" or 'out'")))
1394 portDirections.push_back(Direction::In);
1402 if (hasSSAIdentifiers) {
1403 OpAsmParser::Argument arg;
1404 if (parser.parseArgument(arg))
1406 entryArgs.push_back(arg);
1410 assert(arg.ssaName.name.size() > 1 && arg.ssaName.name[0] ==
'%' &&
1411 "Unknown MLIR name");
1412 if (
isdigit(arg.ssaName.name[1]))
1413 portNames.push_back(StringAttr::get(context,
""));
1415 portNames.push_back(
1416 StringAttr::get(context, arg.ssaName.name.drop_front()));
1419 irLoc = arg.ssaName.location;
1423 irLoc = parser.getCurrentLocation();
1424 std::string portName;
1425 if (parser.parseKeywordOrString(&portName))
1427 portNames.push_back(StringAttr::get(context, portName));
1432 if (parser.parseColonType(portType))
1434 portTypes.push_back(TypeAttr::get(portType));
1435 if (isa<DomainType>(portType))
1436 domainIndex[portNames.back()] = portNames.size() - 1;
1438 if (hasSSAIdentifiers)
1439 entryArgs.back().type = portType;
1442 if (supportsSymbols) {
1443 hw::InnerSymAttr innerSymAttr;
1444 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
1445 NamedAttrList dummyAttrs;
1446 if (parser.parseCustomAttributeWithFallback(
1447 innerSymAttr, ::mlir::Type{},
1449 return ::mlir::failure();
1452 portSyms.push_back(innerSymAttr);
1456 Attribute domainsAttr;
1457 SmallVector<Attribute> portDomains;
1458 if (supportsDomains) {
1459 if (isa<DomainType>(portType)) {
1460 if (parser.parseKeyword(
"of"))
1462 StringAttr domainKind;
1463 if (parser.parseSymbolName(domainKind))
1465 domainsAttr = FlatSymbolRefAttr::get(context, domainKind);
1466 }
else if (succeeded(parser.parseOptionalKeyword(
"domains"))) {
1467 auto result = parser.parseCommaSeparatedList(
1468 OpAsmParser::Delimiter::Square, [&]() -> ParseResult {
1470 if (hasSSAIdentifiers) {
1471 OpAsmParser::Argument arg;
1472 if (parser.parseArgument(arg))
1475 StringAttr::get(context, arg.ssaName.name.drop_front());
1477 std::string portName;
1478 if (parser.parseKeywordOrString(&portName))
1480 argName = StringAttr::get(context, portName);
1483 auto index = domainIndex.find(argName);
1484 if (index == domainIndex.end()) {
1485 parser.emitError(irLoc)
1486 <<
"domain name '" << argName <<
"' not found";
1489 portDomains.push_back(IntegerAttr::get(
1490 IntegerType::get(context, 32, IntegerType::Unsigned),
1496 domainsAttr = parser.getBuilder().getArrayAttr(portDomains);
1500 domainsAttr = parser.getBuilder().getArrayAttr({});
1501 domains.push_back(domainsAttr);
1505 auto parseResult = parser.parseOptionalAttribute(annos);
1506 if (!parseResult.has_value())
1507 annos = parser.getBuilder().getArrayAttr({});
1508 else if (failed(*parseResult))
1510 portAnnotations.push_back(annos);
1513 std::optional<Location> maybeLoc;
1514 if (failed(parser.parseOptionalLocationSpecifier(maybeLoc)))
1516 Location loc = maybeLoc ? *maybeLoc : parser.getEncodedSourceLoc(irLoc);
1517 portLocs.push_back(loc);
1518 if (hasSSAIdentifiers)
1519 entryArgs.back().sourceLoc = loc;
1525 return parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
1531 ArrayAttr parameters) {
1532 if (!parameters || parameters.empty())
1536 llvm::interleaveComma(parameters, p, [&](Attribute param) {
1537 auto paramAttr = cast<ParamDeclAttr>(param);
1538 p << paramAttr.getName().getValue() <<
": " << paramAttr.getType();
1539 if (
auto value = paramAttr.getValue()) {
1541 p.printAttributeWithoutType(value);
1551 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
1552 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
1553 p << visibility.getValue() <<
' ';
1556 p.printSymbolName(op.getModuleName());
1563 Block *body =
nullptr;
1564 if (!op->getRegion(0).empty())
1565 body = &op->getRegion(0).front();
1568 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
1569 op.getPortAnnotations(), op.getPortSymbols(), op.getPortLocations(),
1570 op.getDomainInfo());
1572 SmallVector<StringRef, 13> omittedAttrs = {
1573 "sym_name",
"portDirections",
"portTypes",
1574 "portAnnotations",
"portSymbols",
"portLocations",
1575 "parameters", visibilityAttrName,
"domainInfo"};
1577 if (op.getConvention() == Convention::Internal)
1578 omittedAttrs.push_back(
"convention");
1582 if (!needPortNamesAttr)
1583 omittedAttrs.push_back(
"portNames");
1586 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
1587 omittedAttrs.push_back(
"annotations");
1590 if (
auto knownLayers = op->getAttrOfType<ArrayAttr>(
"knownLayers"))
1591 if (knownLayers.empty())
1592 omittedAttrs.push_back(
"knownLayers");
1595 if (
auto layers = op->getAttrOfType<ArrayAttr>(
"layers"))
1597 omittedAttrs.push_back(
"layers");
1599 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
1608void FModuleOp::print(OpAsmPrinter &p) {
1614 Region &fbody = getBody();
1615 if (!fbody.empty()) {
1617 p.printRegion(fbody,
false,
1629 SmallVectorImpl<Attribute> ¶meters) {
1631 return parser.parseCommaSeparatedList(
1632 OpAsmParser::Delimiter::OptionalLessGreater, [&]() {
1637 if (parser.parseKeywordOrString(&name) || parser.parseColonType(type))
1641 if (succeeded(parser.parseOptionalEqual())) {
1642 if (parser.parseAttribute(value, type))
1646 auto &builder = parser.getBuilder();
1647 parameters.push_back(ParamDeclAttr::get(
1648 builder.getContext(), builder.getStringAttr(name), type, value));
1655 ArrayAttr ¶meters) {
1656 SmallVector<Attribute> parseParameters;
1660 parameters = ArrayAttr::get(parser.getContext(), parseParameters);
1665template <
typename Properties,
typename =
void>
1668template <
typename Properties>
1670 Properties, std::void_t<decltype(std::declval<Properties>().parameters)>>
1671 : std::true_type {};
1673template <
typename OpTy>
1675 OperationState &result,
1676 bool hasSSAIdentifiers) {
1677 auto *context = result.getContext();
1678 auto &builder = parser.getBuilder();
1679 using Properties =
typename OpTy::Properties;
1680 auto &properties = result.getOrAddProperties<Properties>();
1684 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
1687 StringAttr nameAttr;
1688 if (parser.parseSymbolName(nameAttr))
1690 properties.setSymName(nameAttr);
1694 SmallVector<Attribute, 4> parameters;
1697 properties.setParameters(builder.getArrayAttr(parameters));
1701 SmallVector<OpAsmParser::Argument> entryArgs;
1702 SmallVector<Direction, 4> portDirections;
1703 SmallVector<Attribute, 4> portNames;
1704 SmallVector<Attribute, 4> portTypes;
1705 SmallVector<Attribute, 4> portAnnotations;
1706 SmallVector<Attribute, 4> portSyms;
1707 SmallVector<Attribute, 4> portLocs;
1708 SmallVector<Attribute, 4> domains;
1710 true, entryArgs, portDirections,
1711 portNames, portTypes, portAnnotations, portSyms,
1716 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
1719 assert(portNames.size() == portTypes.size());
1725 properties.setPortDirections(
1729 properties.setPortNames(builder.getArrayAttr(portNames));
1732 properties.setPortTypes(ArrayAttr::get(context, portTypes));
1736 if (llvm::any_of(portAnnotations, [&](Attribute anno) {
1737 return !cast<ArrayAttr>(anno).empty();
1739 properties.setPortAnnotations(ArrayAttr::get(context, portAnnotations));
1741 properties.setPortAnnotations(builder.getArrayAttr({}));
1744 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1745 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1748 properties.setPortLocations(ArrayAttr::get(context, portLocs));
1751 properties.setAnnotations(builder.getArrayAttr({}));
1754 properties.setDomainInfo(ArrayAttr::get(context, domains));
1757 auto *body = result.addRegion();
1759 if (hasSSAIdentifiers) {
1760 if (parser.parseRegion(*body, entryArgs))
1763 body->push_back(
new Block());
1768ParseResult FModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1769 if (parseFModuleLikeOp<FModuleOp>(parser, result,
1772 auto &properties = result.getOrAddProperties<Properties>();
1773 properties.setConvention(
1774 ConventionAttr::get(result.getContext(), Convention::Internal));
1775 properties.setLayers(ArrayAttr::get(parser.getContext(), {}));
1779ParseResult FExtModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1780 if (parseFModuleLikeOp<FExtModuleOp>(parser, result,
1783 auto &properties = result.getOrAddProperties<Properties>();
1784 properties.setConvention(
1785 ConventionAttr::get(result.getContext(), Convention::Internal));
1786 properties.setKnownLayers(ArrayAttr::get(result.getContext(), {}));
1790ParseResult FIntModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1791 return parseFModuleLikeOp<FIntModuleOp>(parser, result,
1795ParseResult FMemModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1796 return parseFModuleLikeOp<FMemModuleOp>(parser, result,
1800LogicalResult FModuleOp::verify() {
1803 auto portTypes = getPortTypes();
1804 auto portLocs = getPortLocations();
1805 auto numPorts = portTypes.size();
1808 if (body->getNumArguments() != numPorts)
1809 return emitOpError(
"entry block must have ")
1810 << numPorts <<
" arguments to match module signature";
1813 for (
auto [arg, type, loc] : zip(body->getArguments(), portTypes, portLocs)) {
1814 if (arg.getType() != cast<TypeAttr>(type).getValue())
1815 return emitOpError(
"block argument types should match signature types");
1816 if (arg.getLoc() != cast<LocationAttr>(loc))
1818 "block argument locations should match signature locations");
1826 std::optional<::mlir::ArrayAttr> internalPaths) {
1831 if (internalPaths->size() != op.getNumPorts())
1832 return op.emitError(
"module has inconsistent internal path array with ")
1833 << internalPaths->size() <<
" entries for " << op.getNumPorts()
1837 for (
auto [idx, path, typeattr] : llvm::enumerate(
1838 internalPaths->getAsRange<InternalPathAttr>(), op.getPortTypes())) {
1839 if (path.getPath() &&
1840 !type_isa<RefType>(cast<TypeAttr>(typeattr).getValue())) {
1842 op.emitError(
"module has internal path for non-ref-type port ")
1843 << op.getPortNameAttr(idx);
1844 return diag.attachNote(op.getPortLocation(idx)) <<
"this port";
1851LogicalResult FExtModuleOp::verify() {
1855 auto params = getParameters();
1857 auto checkParmValue = [&](Attribute elt) ->
bool {
1858 auto param = cast<ParamDeclAttr>(elt);
1859 auto value = param.getValue();
1860 if (isa<IntegerAttr, StringAttr, FloatAttr, hw::ParamVerbatimAttr>(value))
1862 emitError() <<
"has unknown extmodule parameter value '"
1863 << param.getName().getValue() <<
"' = " << value;
1867 if (!llvm::all_of(params, checkParmValue))
1872 known.insert_range(getKnownLayersAttr().getAsRange<SymbolRefAttr>());
1875 referenced.insert_range(getLayersAttr().getAsRange<SymbolRefAttr>());
1876 for (
auto attr : getPortTypes()) {
1877 auto type = cast<TypeAttr>(attr).getValue();
1878 if (
auto refType = type_dyn_cast<RefType>(type))
1879 if (
auto layer = refType.getLayer())
1880 referenced.insert(layer);
1884 "references unknown layers",
"unknown layers");
1887LogicalResult FIntModuleOp::verify() {
1891 auto params = getParameters();
1895 auto checkParmValue = [&](Attribute elt) ->
bool {
1896 auto param = cast<ParamDeclAttr>(elt);
1897 auto value = param.getValue();
1898 if (isa<IntegerAttr, StringAttr, FloatAttr>(value))
1900 emitError() <<
"has unknown intmodule parameter value '"
1901 << param.getName().getValue() <<
"' = " << value;
1905 if (!llvm::all_of(params, checkParmValue))
1912 CircuitOp circuitOp,
1913 SymbolTableCollection &symbolTable,
1915 auto layer = refType.getLayer();
1918 auto *layerOp = symbolTable.lookupSymbolIn(circuitOp, layer);
1920 return emitError(loc) << start <<
" associated with layer '" << layer
1921 <<
"', but this layer was not defined";
1922 if (!isa<LayerOp>(layerOp)) {
1923 auto diag = emitError(loc)
1924 << start <<
" associated with layer '" << layer
1925 <<
"', but symbol '" << layer <<
"' does not refer to a '"
1926 << LayerOp::getOperationName() <<
"' op";
1927 return diag.attachNote(layerOp->getLoc()) <<
"symbol refers to this op";
1933 SymbolTableCollection &symbolTable) {
1935 auto circuitOp =
module->getParentOfType<CircuitOp>();
1936 for (
size_t i = 0, e = module.getNumPorts(); i < e; ++i) {
1937 auto type =
module.getPortType(i);
1939 if (
auto refType = type_dyn_cast<RefType>(type)) {
1941 refType, module.getPortLocation(i), circuitOp, symbolTable,
1942 Twine(
"probe port '") + module.getPortName(i) +
"' is")))
1947 if (
auto classType = dyn_cast<ClassType>(type)) {
1948 auto className = classType.getNameAttr();
1949 auto classOp = dyn_cast_or_null<ClassLike>(
1950 symbolTable.lookupSymbolIn(circuitOp, className));
1952 return module.emitOpError() << "references unknown class " << className;
1955 if (failed(classOp.verifyType(classType,
1956 [&]() { return module.emitOpError(); })))
1961 if (isa<DomainType>(type)) {
1962 auto domainInfo =
module.getDomainInfoAttrForPort(i);
1963 if (
auto kind = dyn_cast<FlatSymbolRefAttr>(domainInfo))
1964 if (!dyn_cast_or_null<DomainOp>(
1965 symbolTable.lookupSymbolIn(circuitOp, kind)))
1966 return mlir::emitError(module.getPortLocation(i))
1967 <<
"domain port '" <<
module.getPortName(i)
1968 << "' has undefined domain kind '" << kind.getValue() << "'";
1975LogicalResult FModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1979 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
1980 for (
auto layer : getLayers()) {
1981 if (!symbolTable.lookupSymbolIn(circuitOp, cast<SymbolRefAttr>(layer)))
1982 return emitOpError() <<
"enables undefined layer '" << layer <<
"'";
1989FExtModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1993 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
1994 for (
auto layer : getKnownLayersAttr().getAsRange<SymbolRefAttr>()) {
1995 if (!symbolTable.lookupSymbolIn(circuitOp, layer))
1996 return emitOpError() <<
"knows undefined layer '" << layer <<
"'";
1998 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>()) {
1999 if (!symbolTable.lookupSymbolIn(circuitOp, layer))
2000 return emitOpError() <<
"enables undefined layer '" << layer <<
"'";
2007FIntModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2012FMemModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2016void FModuleOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2021void FExtModuleOp::getAsmBlockArgumentNames(
2026void FIntModuleOp::getAsmBlockArgumentNames(
2031void FMemModuleOp::getAsmBlockArgumentNames(
2036ArrayAttr FMemModuleOp::getParameters() {
return {}; }
2038ArrayAttr FModuleOp::getParameters() {
return {}; }
2040Convention FIntModuleOp::getConvention() {
return Convention::Internal; }
2042ConventionAttr FIntModuleOp::getConventionAttr() {
2043 return ConventionAttr::get(getContext(), getConvention());
2046Convention FMemModuleOp::getConvention() {
return Convention::Internal; }
2048ConventionAttr FMemModuleOp::getConventionAttr() {
2049 return ConventionAttr::get(getContext(), getConvention());
2057 ClassLike classOp, ClassType type,
2058 function_ref<InFlightDiagnostic()> emitError) {
2060 auto name = type.getNameAttr().getAttr();
2061 auto expectedName = classOp.getModuleNameAttr();
2062 if (name != expectedName)
2063 return emitError() <<
"type has wrong name, got " << name <<
", expected "
2066 auto elements = type.getElements();
2068 auto expectedNumElements = classOp.getNumPorts();
2070 return emitError() <<
"has wrong number of ports, got " <<
numElements
2071 <<
", expected " << expectedNumElements;
2073 auto portNames = classOp.getPortNames();
2074 auto portDirections = classOp.getPortDirections();
2075 auto portTypes = classOp.getPortTypes();
2078 auto element = elements[i];
2080 auto name = element.name;
2081 auto expectedName = portNames[i];
2082 if (name != expectedName)
2083 return emitError() <<
"port #" << i <<
" has wrong name, got " << name
2084 <<
", expected " << expectedName;
2086 auto direction = element.direction;
2087 auto expectedDirection =
Direction(portDirections[i]);
2088 if (direction != expectedDirection)
2089 return emitError() <<
"port " << name <<
" has wrong direction, got "
2093 auto type = element.type;
2094 auto expectedType = cast<TypeAttr>(portTypes[i]).getValue();
2095 if (type != expectedType)
2096 return emitError() <<
"port " << name <<
" has wrong type, got " << type
2097 <<
", expected " << expectedType;
2104 auto n = classOp.getNumPorts();
2105 SmallVector<ClassElement> elements;
2106 elements.reserve(n);
2107 for (
size_t i = 0; i < n; ++i)
2108 elements.push_back({classOp.getPortNameAttr(i), classOp.getPortType(i),
2109 classOp.getPortDirection(i)});
2110 auto name = FlatSymbolRefAttr::get(classOp.getNameAttr());
2111 return ClassType::get(name, elements);
2114template <
typename OpTy>
2116 bool hasSSAIdentifiers) {
2117 auto *context = result.getContext();
2118 auto &builder = parser.getBuilder();
2119 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
2123 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
2126 StringAttr nameAttr;
2127 if (parser.parseSymbolName(nameAttr))
2129 properties.setSymName(nameAttr);
2132 SmallVector<OpAsmParser::Argument> entryArgs;
2133 SmallVector<Direction, 4> portDirections;
2134 SmallVector<Attribute, 4> portNames;
2135 SmallVector<Attribute, 4> portTypes;
2136 SmallVector<Attribute, 4> portAnnotations;
2137 SmallVector<Attribute, 4> portSyms;
2138 SmallVector<Attribute, 4> portLocs;
2139 SmallVector<Attribute, 4> domains;
2142 entryArgs, portDirections, portNames, portTypes,
2143 portAnnotations, portSyms, portLocs, domains))
2147 for (
auto annos : portAnnotations)
2148 if (!cast<ArrayAttr>(annos).empty())
2152 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
2155 assert(portNames.size() == portTypes.size());
2161 properties.setPortDirections(
2165 properties.setPortNames(builder.getArrayAttr(portNames));
2168 properties.setPortTypes(builder.getArrayAttr(portTypes));
2171 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
2172 properties.setPortSymbols(builder.getArrayAttr(portSyms));
2175 properties.setPortLocations(ArrayAttr::get(context, portLocs));
2181 auto *bodyRegion = result.addRegion();
2183 if (hasSSAIdentifiers) {
2184 if (parser.parseRegion(*bodyRegion, entryArgs))
2186 if (bodyRegion->empty())
2187 bodyRegion->push_back(
new Block());
2197 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
2198 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
2199 p << visibility.getValue() <<
' ';
2202 p.printSymbolName(op.getName());
2206 Region ®ion = op->getRegion(0);
2207 Block *body =
nullptr;
2208 if (!region.empty())
2209 body = ®ion.front();
2212 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
2213 {}, op.getPortSymbols(), op.getPortLocations(), {});
2216 SmallVector<StringRef, 8> omittedAttrs = {
2217 "sym_name",
"portNames",
"portTypes",
"portDirections",
2218 "portSymbols",
"portLocations", visibilityAttrName,
"domainInfo"};
2222 if (!needPortNamesAttr)
2223 omittedAttrs.push_back(
"portNames");
2225 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
2228 if (!region.empty()) {
2230 auto printEntryBlockArgs =
false;
2231 auto printBlockTerminators =
false;
2232 p.printRegion(region, printEntryBlockArgs, printBlockTerminators);
2240void ClassOp::build(OpBuilder &builder, OperationState &result, StringAttr name,
2241 ArrayRef<PortInfo> ports) {
2244 [](
const auto &port) {
return port.annotations.empty(); }) &&
2245 "class ports may not have annotations");
2247 buildClass<ClassOp>(builder, result, name, ports);
2250 auto *bodyRegion = result.regions[0].get();
2252 bodyRegion->push_back(body);
2255 for (
auto &elt : ports)
2256 body->addArgument(elt.type, elt.loc);
2259void ClassOp::build(::mlir::OpBuilder &odsBuilder,
2260 ::mlir::OperationState &odsState, Twine name,
2261 mlir::ArrayRef<mlir::StringRef> fieldNames,
2262 mlir::ArrayRef<mlir::Type> fieldTypes) {
2264 SmallVector<PortInfo, 10> ports;
2265 for (
auto [fieldName, fieldType] :
llvm::zip(fieldNames, fieldTypes)) {
2266 ports.emplace_back(odsBuilder.getStringAttr(fieldName +
"_in"), fieldType,
2268 ports.emplace_back(odsBuilder.getStringAttr(fieldName), fieldType,
2271 build(odsBuilder, odsState, odsBuilder.getStringAttr(name), ports);
2273 auto &body = odsState.regions[0]->getBlocks().front();
2274 auto prevLoc = odsBuilder.saveInsertionPoint();
2275 odsBuilder.setInsertionPointToEnd(&body);
2276 auto args = body.getArguments();
2277 auto loc = odsState.location;
2278 for (
unsigned i = 0, e = ports.size(); i != e; i += 2)
2279 PropAssignOp::create(odsBuilder, loc, args[i + 1], args[i]);
2281 odsBuilder.restoreInsertionPoint(prevLoc);
2283void ClassOp::print(OpAsmPrinter &p) {
2287ParseResult ClassOp::parse(OpAsmParser &parser, OperationState &result) {
2288 auto hasSSAIdentifiers =
true;
2289 return parseClassLike<ClassOp>(parser, result, hasSSAIdentifiers);
2292LogicalResult ClassOp::verify() {
2294 auto type = operand.getType();
2295 if (!isa<PropertyType>(type)) {
2296 emitOpError(
"ports on a class must be properties");
2305ClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2309void ClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2314SmallVector<PortInfo> ClassOp::getPorts() {
2315 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2318void ClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2319 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2323void ClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2324 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2327Convention ClassOp::getConvention() {
return Convention::Internal; }
2329ConventionAttr ClassOp::getConventionAttr() {
2330 return ConventionAttr::get(getContext(), getConvention());
2333ArrayAttr ClassOp::getParameters() {
return {}; }
2335ArrayAttr ClassOp::getPortAnnotationsAttr() {
2336 return ArrayAttr::get(getContext(), {});
2339ArrayRef<Attribute> ClassOp::getPortAnnotations() {
return {}; }
2341void ClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2342 llvm_unreachable(
"classes do not support annotations");
2345ArrayAttr ClassOp::getLayersAttr() {
return ArrayAttr::get(getContext(), {}); }
2347ArrayRef<Attribute> ClassOp::getLayers() {
return {}; }
2349SmallVector<::circt::hw::PortInfo> ClassOp::getPortList() {
2350 return ::getPortListImpl(*
this);
2354 return ::getPortImpl(*
this, idx);
2357BlockArgument ClassOp::getArgument(
size_t portNumber) {
2361bool ClassOp::canDiscardOnUseEmpty() {
2372void ExtClassOp::build(OpBuilder &builder, OperationState &result,
2373 StringAttr name, ArrayRef<PortInfo> ports) {
2376 [](
const auto &port) {
return port.annotations.empty(); }) &&
2377 "class ports may not have annotations");
2378 buildClass<ClassOp>(builder, result, name, ports);
2381void ExtClassOp::print(OpAsmPrinter &p) {
2385ParseResult ExtClassOp::parse(OpAsmParser &parser, OperationState &result) {
2386 auto hasSSAIdentifiers =
false;
2387 return parseClassLike<ExtClassOp>(parser, result, hasSSAIdentifiers);
2391ExtClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2395void ExtClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2400SmallVector<PortInfo> ExtClassOp::getPorts() {
2401 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2404void ExtClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2405 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2408void ExtClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2409 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2412Convention ExtClassOp::getConvention() {
return Convention::Internal; }
2414ConventionAttr ExtClassOp::getConventionAttr() {
2415 return ConventionAttr::get(getContext(), getConvention());
2418ArrayAttr ExtClassOp::getLayersAttr() {
2419 return ArrayAttr::get(getContext(), {});
2422ArrayRef<Attribute> ExtClassOp::getLayers() {
return {}; }
2424ArrayAttr ExtClassOp::getParameters() {
return {}; }
2426ArrayAttr ExtClassOp::getPortAnnotationsAttr() {
2427 return ArrayAttr::get(getContext(), {});
2430ArrayRef<Attribute> ExtClassOp::getPortAnnotations() {
return {}; }
2432void ExtClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2433 llvm_unreachable(
"classes do not support annotations");
2436SmallVector<::circt::hw::PortInfo> ExtClassOp::getPortList() {
2437 return ::getPortListImpl(*
this);
2441 return ::getPortImpl(*
this, idx);
2444bool ExtClassOp::canDiscardOnUseEmpty() {
2455void InstanceOp::build(
2456 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2457 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2458 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2459 ArrayRef<Attribute> domainInfo, ArrayRef<Attribute> annotations,
2460 ArrayRef<Attribute> portAnnotations, ArrayRef<Attribute> layers,
2461 bool lowerToBind,
bool doNotPrint, StringAttr innerSym) {
2462 build(builder, result, resultTypes, moduleName, name, nameKind,
2463 portDirections, portNames, domainInfo, annotations, portAnnotations,
2464 layers, lowerToBind, doNotPrint,
2465 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr());
2468void InstanceOp::build(
2469 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2470 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2471 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2472 ArrayRef<Attribute> domainInfo, ArrayRef<Attribute> annotations,
2473 ArrayRef<Attribute> portAnnotations, ArrayRef<Attribute> layers,
2474 bool lowerToBind,
bool doNotPrint, hw::InnerSymAttr innerSym) {
2475 result.addTypes(resultTypes);
2476 result.getOrAddProperties<Properties>().setModuleName(
2477 SymbolRefAttr::get(builder.getContext(), moduleName));
2478 result.getOrAddProperties<Properties>().setName(builder.getStringAttr(name));
2479 result.getOrAddProperties<Properties>().setPortDirections(
2481 result.getOrAddProperties<Properties>().setPortNames(
2482 builder.getArrayAttr(portNames));
2484 if (domainInfo.empty()) {
2485 SmallVector<Attribute, 16> domainInfoVec(resultTypes.size(),
2486 builder.getArrayAttr({}));
2487 result.getOrAddProperties<Properties>().setDomainInfo(
2488 builder.getArrayAttr(domainInfoVec));
2490 assert(domainInfo.size() == resultTypes.size());
2491 result.getOrAddProperties<Properties>().setDomainInfo(
2492 builder.getArrayAttr(domainInfo));
2495 result.getOrAddProperties<Properties>().setAnnotations(
2496 builder.getArrayAttr(annotations));
2497 result.getOrAddProperties<Properties>().setLayers(
2498 builder.getArrayAttr(layers));
2500 result.getOrAddProperties<Properties>().setLowerToBind(
2501 builder.getUnitAttr());
2503 result.getOrAddProperties<Properties>().setDoNotPrint(
2504 builder.getUnitAttr());
2506 result.getOrAddProperties<Properties>().setInnerSym(innerSym);
2508 result.getOrAddProperties<Properties>().setNameKind(
2509 NameKindEnumAttr::get(builder.getContext(), nameKind));
2511 if (portAnnotations.empty()) {
2512 SmallVector<Attribute, 16> portAnnotationsVec(resultTypes.size(),
2513 builder.getArrayAttr({}));
2514 result.getOrAddProperties<Properties>().setPortAnnotations(
2515 builder.getArrayAttr(portAnnotationsVec));
2517 assert(portAnnotations.size() == resultTypes.size());
2518 result.getOrAddProperties<Properties>().setPortAnnotations(
2519 builder.getArrayAttr(portAnnotations));
2523void InstanceOp::build(OpBuilder &builder, OperationState &result,
2524 FModuleLike module, StringRef name,
2525 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2526 ArrayRef<Attribute> portAnnotations,
bool lowerToBind,
2527 bool doNotPrint, hw::InnerSymAttr innerSym) {
2530 SmallVector<Type> resultTypes;
2531 resultTypes.reserve(module.getNumPorts());
2533 module.getPortTypes(), std::back_inserter(resultTypes),
2534 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2539 ArrayAttr portAnnotationsAttr;
2540 if (portAnnotations.empty()) {
2541 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2542 resultTypes.size(), builder.getArrayAttr({})));
2544 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2546 ArrayAttr domainInfoAttr =
module.getDomainInfoAttr();
2547 if (domainInfoAttr.empty()) {
2548 domainInfoAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2549 resultTypes.size(), builder.getArrayAttr({})));
2553 builder, result, resultTypes,
2554 SymbolRefAttr::get(builder.getContext(), module.getModuleNameAttr()),
2555 builder.getStringAttr(name),
2556 NameKindEnumAttr::get(builder.getContext(), nameKind),
2557 module.getPortDirectionsAttr(), module.getPortNamesAttr(), domainInfoAttr,
2558 builder.getArrayAttr(annotations), portAnnotationsAttr,
2559 module.getLayersAttr(), lowerToBind ? builder.getUnitAttr() : UnitAttr(),
2560 doNotPrint ? builder.getUnitAttr() : UnitAttr(), innerSym);
2563void InstanceOp::build(OpBuilder &builder, OperationState &odsState,
2564 ArrayRef<PortInfo> ports, StringRef moduleName,
2565 StringRef name, NameKindEnum nameKind,
2566 ArrayRef<Attribute> annotations,
2567 ArrayRef<Attribute> layers,
bool lowerToBind,
2568 bool doNotPrint, hw::InnerSymAttr innerSym) {
2570 SmallVector<Type> newResultTypes;
2571 SmallVector<Direction> newPortDirections;
2572 SmallVector<Attribute> newPortNames;
2573 SmallVector<Attribute> newPortAnnotations;
2574 SmallVector<Attribute> newDomainInfo;
2575 for (
auto &p : ports) {
2576 newResultTypes.push_back(p.type);
2577 newPortDirections.push_back(p.direction);
2578 newPortNames.push_back(p.name);
2579 newPortAnnotations.push_back(p.annotations.getArrayAttr());
2581 newDomainInfo.push_back(p.domains);
2583 newDomainInfo.push_back(builder.getArrayAttr({}));
2586 return build(builder, odsState, newResultTypes, moduleName, name, nameKind,
2587 newPortDirections, newPortNames, newDomainInfo, annotations,
2588 newPortAnnotations, layers, lowerToBind, doNotPrint, innerSym);
2591LogicalResult InstanceOp::verify() {
2594 SmallVector<SymbolRefAttr> missingLayers;
2595 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
2597 missingLayers.push_back(layer);
2599 if (missingLayers.empty())
2603 emitOpError(
"ambient layers are insufficient to instantiate module");
2604 auto ¬e = diag.attachNote();
2605 note <<
"missing layer requirements: ";
2606 interleaveComma(missingLayers, note);
2612InstanceOp InstanceOp::erasePorts(OpBuilder &builder,
2613 const llvm::BitVector &portIndices) {
2614 assert(portIndices.size() >= getNumResults() &&
2615 "portIndices is not at least as large as getNumResults()");
2617 if (portIndices.none())
2620 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
2621 SmallVector<Type>(result_type_begin(), result_type_end()), portIndices);
2622 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
2624 SmallVector<Attribute> newPortNames =
2626 SmallVector<Attribute> newPortAnnotations =
2628 ArrayAttr newDomainInfo =
2632 auto newOp = InstanceOp::create(
2633 builder,
getLoc(), newResultTypes, getModuleName(),
getName(),
2634 getNameKind(), newPortDirections, newPortNames, newDomainInfo.getValue(),
2635 getAnnotations().getValue(), newPortAnnotations, getLayers(),
2636 getLowerToBind(), getDoNotPrint(), getInnerSymAttr());
2638 for (
unsigned oldIdx = 0, newIdx = 0, numOldPorts = getNumResults();
2639 oldIdx != numOldPorts; ++oldIdx) {
2640 if (portIndices.test(oldIdx)) {
2641 assert(getResult(oldIdx).use_empty() &&
"removed instance port has uses");
2644 getResult(oldIdx).replaceAllUsesWith(newOp.getResult(newIdx));
2652 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2653 newOp->setAttr(
"output_file", outputFile);
2658ArrayAttr InstanceOp::getPortAnnotation(
unsigned portIdx) {
2659 assert(portIdx < getNumResults() &&
2660 "index should be smaller than result number");
2661 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
2664void InstanceOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
2665 assert(annotations.size() == getNumResults() &&
2666 "number of annotations is not equal to result number");
2667 (*this)->setAttr(
"portAnnotations",
2668 ArrayAttr::get(getContext(), annotations));
2671ArrayAttr InstanceOp::getPortDomain(
unsigned portIdx) {
2672 assert(portIdx < getNumResults() &&
2673 "index should be smaller than result number");
2674 return cast<ArrayAttr>(getDomainInfo()[portIdx]);
2678InstanceOp::cloneAndInsertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2679 auto portSize = ports.size();
2680 auto newPortCount = getNumResults() + portSize;
2681 SmallVector<Direction> newPortDirections;
2682 newPortDirections.reserve(newPortCount);
2683 SmallVector<Attribute> newPortNames;
2684 newPortNames.reserve(newPortCount);
2685 SmallVector<Type> newPortTypes;
2686 newPortTypes.reserve(newPortCount);
2687 SmallVector<Attribute> newPortAnnos;
2688 newPortAnnos.reserve(newPortCount);
2689 SmallVector<Attribute> newDomainInfo;
2690 newDomainInfo.reserve(newPortCount);
2691 SmallVector<unsigned> numInserted;
2692 numInserted.resize(getNumResults());
2694 unsigned oldIndex = 0;
2695 unsigned newIndex = 0;
2696 while (oldIndex + newIndex < newPortCount) {
2698 if (newIndex < portSize && ports[newIndex].first == oldIndex) {
2699 auto &newPort = ports[newIndex].second;
2700 newPortDirections.push_back(newPort.direction);
2701 newPortNames.push_back(newPort.name);
2702 newPortTypes.push_back(newPort.type);
2703 newPortAnnos.push_back(newPort.annotations.getArrayAttr());
2706 newPort.domains ? newPort.domains : ArrayAttr::
get(getContext(), {}),
2708 if (oldIndex < getNumResults())
2709 numInserted[oldIndex] += 1;
2713 newPortDirections.push_back(getPortDirection(oldIndex));
2714 newPortNames.push_back(getPortName(oldIndex));
2715 newPortTypes.push_back(getType(oldIndex));
2716 newPortAnnos.push_back(getPortAnnotation(oldIndex));
2717 newDomainInfo.push_back(getDomainInfo()[oldIndex]);
2719 numInserted[oldIndex] = 0;
2721 numInserted[oldIndex] += numInserted[oldIndex - 1];
2727 OpBuilder builder(*
this);
2728 return InstanceOp::create(
2729 builder,
getLoc(), newPortTypes, getModuleName(),
getName(),
2730 getNameKind(), newPortDirections, newPortNames, newDomainInfo,
2731 getAnnotations().getValue(), newPortAnnos, getLayers(), getLowerToBind(),
2732 getDoNotPrint(), getInnerSymAttr());
2735LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2737 getModuleNameAttr());
2740StringRef InstanceOp::getInstanceName() {
return getName(); }
2742StringAttr InstanceOp::getInstanceNameAttr() {
return getNameAttr(); }
2744void InstanceOp::print(OpAsmPrinter &p) {
2747 p.printKeywordOrString(
getName());
2748 if (
auto attr = getInnerSymAttr()) {
2750 p.printSymbolName(attr.getSymName());
2752 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2753 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2756 SmallVector<StringRef, 10> omittedAttrs = {
2757 "moduleName",
"name",
"portDirections",
2758 "portNames",
"portTypes",
"portAnnotations",
2759 "inner_sym",
"nameKind",
"domainInfo"};
2760 if (getAnnotations().
empty())
2761 omittedAttrs.push_back(
"annotations");
2762 if (getLayers().
empty())
2763 omittedAttrs.push_back(
"layers");
2764 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2768 p.printSymbolName(getModuleName());
2771 SmallVector<Attribute> portTypes;
2772 portTypes.reserve(getNumResults());
2773 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2777 getPortNames().getValue(), portTypes,
2778 getPortAnnotations().getValue(), {}, {},
2779 getDomainInfo().getValue());
2782ParseResult InstanceOp::parse(OpAsmParser &parser, OperationState &result) {
2783 auto *context = parser.getContext();
2784 auto &properties = result.getOrAddProperties<Properties>();
2787 hw::InnerSymAttr innerSymAttr;
2788 FlatSymbolRefAttr moduleName;
2789 SmallVector<OpAsmParser::Argument> entryArgs;
2790 SmallVector<Direction, 4> portDirections;
2791 SmallVector<Attribute, 4> portNames;
2792 SmallVector<Attribute, 4> portTypes;
2793 SmallVector<Attribute, 4> portAnnotations;
2794 SmallVector<Attribute, 4> portSyms;
2795 SmallVector<Attribute, 4> portLocs;
2796 SmallVector<Attribute, 4> domains;
2797 NameKindEnumAttr nameKind;
2799 if (parser.parseKeywordOrString(&name))
2801 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
2802 if (parser.parseCustomAttributeWithFallback(
2803 innerSymAttr, ::mlir::Type{},
2805 result.attributes)) {
2806 return ::mlir::failure();
2810 parser.parseOptionalAttrDict(result.attributes) ||
2811 parser.parseAttribute(moduleName) ||
2814 entryArgs, portDirections, portNames, portTypes,
2815 portAnnotations, portSyms, portLocs, domains))
2821 properties.setModuleName(moduleName);
2822 properties.setName(StringAttr::get(context, name));
2823 properties.setNameKind(nameKind);
2824 properties.setPortDirections(
2826 properties.setPortNames(ArrayAttr::get(context, portNames));
2827 properties.setPortAnnotations(ArrayAttr::get(context, portAnnotations));
2831 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
2832 properties.setLayers(parser.getBuilder().getArrayAttr({}));
2835 properties.setDomainInfo(ArrayAttr::get(context, domains));
2838 result.types.reserve(portTypes.size());
2840 portTypes, std::back_inserter(result.types),
2841 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2846void InstanceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
2851 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
2852 setNameFn(getResult(i), (base +
"_" + getPortNameStr(i)).str());
2856std::optional<size_t> InstanceOp::getTargetResultIndex() {
2858 return std::nullopt;
2865void InstanceChoiceOp::build(
2866 OpBuilder &builder, OperationState &result, FModuleLike defaultModule,
2867 ArrayRef<std::pair<OptionCaseOp, FModuleLike>> cases, StringRef name,
2868 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2869 ArrayRef<Attribute> portAnnotations, StringAttr innerSym) {
2871 SmallVector<Type> resultTypes;
2872 for (Attribute portType : defaultModule.getPortTypes())
2873 resultTypes.push_back(cast<TypeAttr>(portType).getValue());
2876 ArrayAttr portAnnotationsAttr;
2877 if (portAnnotations.empty()) {
2878 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2879 resultTypes.size(), builder.getArrayAttr({})));
2881 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2885 SmallVector<Attribute> moduleNames, caseNames;
2886 moduleNames.push_back(SymbolRefAttr::get(defaultModule.getModuleNameAttr()));
2887 for (
auto [caseOption, caseModule] : cases) {
2888 auto caseGroup = caseOption->getParentOfType<OptionOp>();
2889 caseNames.push_back(SymbolRefAttr::get(caseGroup.getSymNameAttr(),
2890 {SymbolRefAttr::get(caseOption)}));
2891 moduleNames.push_back(SymbolRefAttr::get(caseModule.getModuleNameAttr()));
2895 builder, result, resultTypes, builder.getArrayAttr(moduleNames),
2896 builder.getArrayAttr(caseNames), builder.getStringAttr(name),
2897 NameKindEnumAttr::get(builder.getContext(), nameKind),
2898 defaultModule.getPortDirectionsAttr(), defaultModule.getPortNamesAttr(),
2899 defaultModule.getDomainInfoAttr(), builder.getArrayAttr(annotations),
2900 portAnnotationsAttr, defaultModule.getLayersAttr(),
2901 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr());
2904std::optional<size_t> InstanceChoiceOp::getTargetResultIndex() {
2905 return std::nullopt;
2908void InstanceChoiceOp::print(OpAsmPrinter &p) {
2911 p.printKeywordOrString(
getName());
2912 if (
auto attr = getInnerSymAttr()) {
2914 p.printSymbolName(attr.getSymName());
2916 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2917 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2920 SmallVector<StringRef, 11> omittedAttrs = {
2921 "moduleNames",
"caseNames",
"name",
2922 "portDirections",
"portNames",
"portTypes",
2923 "portAnnotations",
"inner_sym",
"nameKind",
2925 if (getAnnotations().
empty())
2926 omittedAttrs.push_back(
"annotations");
2927 if (getLayers().
empty())
2928 omittedAttrs.push_back(
"layers");
2929 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2934 auto moduleNames = getModuleNamesAttr();
2935 auto caseNames = getCaseNamesAttr();
2937 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[0]).getValue());
2939 p <<
" alternatives ";
2941 cast<SymbolRefAttr>(caseNames[0]).getRootReference().getValue());
2943 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
2947 auto symbol = cast<SymbolRefAttr>(caseNames[i]);
2948 p.printSymbolName(symbol.getNestedReferences()[0].getValue());
2950 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[i + 1]).getValue());
2956 SmallVector<Attribute> portTypes;
2957 portTypes.reserve(getNumResults());
2958 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2961 getPortNames().getValue(), portTypes,
2962 getPortAnnotations().getValue(), {}, {},
2963 getDomainInfo().getValue());
2966ParseResult InstanceChoiceOp::parse(OpAsmParser &parser,
2967 OperationState &result) {
2968 auto *context = parser.getContext();
2969 auto &properties = result.getOrAddProperties<Properties>();
2972 hw::InnerSymAttr innerSymAttr;
2973 SmallVector<Attribute> moduleNames;
2974 SmallVector<Attribute> caseNames;
2975 SmallVector<OpAsmParser::Argument> entryArgs;
2976 SmallVector<Direction, 4> portDirections;
2977 SmallVector<Attribute, 4> portNames;
2978 SmallVector<Attribute, 4> portTypes;
2979 SmallVector<Attribute, 4> portAnnotations;
2980 SmallVector<Attribute, 4> portSyms;
2981 SmallVector<Attribute, 4> portLocs;
2982 SmallVector<Attribute, 4> domains;
2983 NameKindEnumAttr nameKind;
2985 if (parser.parseKeywordOrString(&name))
2987 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
2988 if (parser.parseCustomAttributeWithFallback(
2989 innerSymAttr, Type{},
2991 result.attributes)) {
2996 parser.parseOptionalAttrDict(result.attributes))
2999 FlatSymbolRefAttr defaultModuleName;
3000 if (parser.parseAttribute(defaultModuleName))
3002 moduleNames.push_back(defaultModuleName);
3006 FlatSymbolRefAttr optionName;
3007 if (parser.parseKeyword(
"alternatives") ||
3008 parser.parseAttribute(optionName) || parser.parseLBrace())
3011 FlatSymbolRefAttr moduleName;
3012 StringAttr caseName;
3013 while (succeeded(parser.parseOptionalSymbolName(caseName))) {
3014 if (parser.parseArrow() || parser.parseAttribute(moduleName))
3016 moduleNames.push_back(moduleName);
3017 caseNames.push_back(SymbolRefAttr::get(
3018 optionName.getAttr(), {FlatSymbolRefAttr::get(caseName)}));
3019 if (failed(parser.parseOptionalComma()))
3022 if (parser.parseRBrace())
3028 entryArgs, portDirections, portNames, portTypes,
3029 portAnnotations, portSyms, portLocs, domains))
3034 properties.setModuleNames(ArrayAttr::get(context, moduleNames));
3035 properties.setCaseNames(ArrayAttr::get(context, caseNames));
3036 properties.setName(StringAttr::get(context, name));
3037 properties.setNameKind(nameKind);
3038 properties.setPortDirections(
3040 properties.setPortNames(ArrayAttr::get(context, portNames));
3041 properties.setDomainInfo(ArrayAttr::get(context, domains));
3042 properties.setPortAnnotations(ArrayAttr::get(context, portAnnotations));
3046 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
3047 properties.setLayers(parser.getBuilder().getArrayAttr({}));
3050 result.types.reserve(portTypes.size());
3052 portTypes, std::back_inserter(result.types),
3053 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
3058void InstanceChoiceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3060 for (
auto [result, name] :
llvm::zip(getResults(), getPortNames()))
3061 setNameFn(result, (base +
"_" + cast<StringAttr>(name).getValue()).str());
3064LogicalResult InstanceChoiceOp::verify() {
3065 if (getCaseNamesAttr().
empty())
3066 return emitOpError() <<
"must have at least one case";
3067 if (getModuleNamesAttr().size() != getCaseNamesAttr().size() + 1)
3068 return emitOpError() <<
"number of referenced modules does not match the "
3069 "number of options";
3074 SmallVector<SymbolRefAttr> missingLayers;
3075 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
3077 missingLayers.push_back(layer);
3079 if (missingLayers.empty())
3083 emitOpError(
"ambient layers are insufficient to instantiate module");
3084 auto ¬e = diag.attachNote();
3085 note <<
"missing layer requirements: ";
3086 interleaveComma(missingLayers, note);
3091InstanceChoiceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3092 auto caseNames = getCaseNamesAttr();
3093 for (
auto moduleName : getModuleNamesAttr()) {
3095 *
this, symbolTable, cast<FlatSymbolRefAttr>(moduleName))))
3099 auto root = cast<SymbolRefAttr>(caseNames[0]).getRootReference();
3100 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3101 auto ref = cast<SymbolRefAttr>(caseNames[i]);
3102 auto refRoot = ref.getRootReference();
3103 if (ref.getRootReference() != root)
3104 return emitOpError() <<
"case " << ref
3105 <<
" is not in the same option group as "
3108 if (!symbolTable.lookupNearestSymbolFrom<OptionOp>(*
this, refRoot))
3109 return emitOpError() <<
"option " << refRoot <<
" does not exist";
3111 if (!symbolTable.lookupNearestSymbolFrom<OptionCaseOp>(*
this, ref))
3112 return emitOpError() <<
"option " << refRoot
3113 <<
" does not contain option case " << ref;
3120InstanceChoiceOp::getTargetOrDefaultAttr(OptionCaseOp option) {
3121 auto caseNames = getCaseNamesAttr();
3122 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3123 StringAttr caseSym = cast<SymbolRefAttr>(caseNames[i]).getLeafReference();
3124 if (caseSym == option.getSymName())
3125 return cast<FlatSymbolRefAttr>(getModuleNamesAttr()[i + 1]);
3127 return getDefaultTargetAttr();
3130SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1>
3131InstanceChoiceOp::getTargetChoices() {
3132 auto caseNames = getCaseNamesAttr();
3133 auto moduleNames = getModuleNamesAttr();
3134 SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1> choices;
3135 for (
size_t i = 0; i < caseNames.size(); ++i) {
3136 choices.emplace_back(cast<SymbolRefAttr>(caseNames[i]),
3137 cast<FlatSymbolRefAttr>(moduleNames[i + 1]));
3144InstanceChoiceOp::erasePorts(OpBuilder &builder,
3145 const llvm::BitVector &portIndices) {
3146 assert(portIndices.size() >= getNumResults() &&
3147 "portIndices is not at least as large as getNumResults()");
3149 if (portIndices.none())
3152 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
3153 SmallVector<Type>(result_type_begin(), result_type_end()), portIndices);
3154 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
3156 SmallVector<Attribute> newPortNames =
3158 SmallVector<Attribute> newPortAnnotations =
3160 ArrayAttr newPortDomains =
3164 auto newOp = InstanceChoiceOp::create(
3165 builder,
getLoc(), newResultTypes, getModuleNames(), getCaseNames(),
3168 ArrayAttr::get(getContext(), newPortNames),
3169 ArrayAttr::get(getContext(), newPortDomains), getAnnotationsAttr(),
3170 ArrayAttr::get(getContext(), newPortAnnotations), getLayers(),
3173 for (
unsigned oldIdx = 0, newIdx = 0, numOldPorts = getNumResults();
3174 oldIdx != numOldPorts; ++oldIdx) {
3175 if (portIndices.test(oldIdx)) {
3176 assert(getResult(oldIdx).use_empty() &&
"removed instance port has uses");
3179 getResult(oldIdx).replaceAllUsesWith(newOp.getResult(newIdx));
3187 if (
auto outputFile = (*this)->getAttr(
"output_file"))
3188 newOp->setAttr(
"output_file", outputFile);
3197ArrayAttr MemOp::getPortAnnotation(
unsigned portIdx) {
3198 assert(portIdx < getNumResults() &&
3199 "index should be smaller than result number");
3200 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
3203void MemOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
3204 assert(annotations.size() == getNumResults() &&
3205 "number of annotations is not equal to result number");
3206 (*this)->setAttr(
"portAnnotations",
3207 ArrayAttr::get(getContext(), annotations));
3211void MemOp::getNumPorts(
size_t &numReadPorts,
size_t &numWritePorts,
3212 size_t &numReadWritePorts,
size_t &numDbgsPorts) {
3215 numReadWritePorts = 0;
3217 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3218 auto portKind = getPortKind(i);
3219 if (portKind == MemOp::PortKind::Debug)
3221 else if (portKind == MemOp::PortKind::Read)
3223 else if (portKind == MemOp::PortKind::Write) {
3226 ++numReadWritePorts;
3231LogicalResult MemOp::verify() {
3235 llvm::SmallDenseSet<Attribute, 8> portNamesSet;
3241 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3242 auto portName = getPortName(i);
3247 BundleType portBundleType =
3248 type_dyn_cast<BundleType>(getResult(i).getType());
3251 if (!portNamesSet.insert(portName).second) {
3252 emitOpError() <<
"has non-unique port name " << portName;
3260 auto elt = getPortNamed(portName);
3262 emitOpError() <<
"could not get port with name " << portName;
3265 auto firrtlType = type_cast<FIRRTLType>(elt.getType());
3268 if (portKind == MemOp::PortKind::Debug &&
3269 !type_isa<RefType>(getResult(i).getType()))
3270 return emitOpError() <<
"has an invalid type on port " << portName
3271 <<
" (expected Read/Write/ReadWrite/Debug)";
3272 if (type_isa<RefType>(firrtlType) && e == 1)
3273 return emitOpError()
3274 <<
"cannot have only one port of debug type. Debug port can only "
3275 "exist alongside other read/write/read-write port";
3280 if (portKind == MemOp::PortKind::Debug) {
3281 auto resType = type_cast<RefType>(getResult(i).getType());
3282 if (!(resType && type_isa<FVectorType>(resType.getType())))
3283 return emitOpError() <<
"debug ports must be a RefType of FVectorType";
3284 dataType = type_cast<FVectorType>(resType.getType()).getElementType();
3286 auto dataTypeOption = portBundleType.getElement(
"data");
3287 if (!dataTypeOption && portKind == MemOp::PortKind::ReadWrite)
3288 dataTypeOption = portBundleType.getElement(
"wdata");
3289 if (!dataTypeOption) {
3290 emitOpError() <<
"has no data field on port " << portName
3291 <<
" (expected to see \"data\" for a read or write "
3292 "port or \"rdata\" for a read/write port)";
3295 dataType = dataTypeOption->type;
3297 if (portKind == MemOp::PortKind::Read) {
3304 emitOpError() <<
"has non-passive data type on port " << portName
3305 <<
" (memory types must be passive)";
3310 if (dataType.containsAnalog()) {
3311 emitOpError() <<
"has a data type that contains an analog type on port "
3313 <<
" (memory types cannot contain analog types)";
3321 getTypeForPort(getDepth(), dataType, portKind,
3322 dataType.isGround() ? getMaskBits() : 0);
3325 auto originalType = getResult(i).getType();
3326 if (originalType != expectedType) {
3327 StringRef portKindName;
3329 case MemOp::PortKind::Read:
3330 portKindName =
"read";
3332 case MemOp::PortKind::Write:
3333 portKindName =
"write";
3335 case MemOp::PortKind::ReadWrite:
3336 portKindName =
"readwrite";
3338 case MemOp::PortKind::Debug:
3339 portKindName =
"dbg";
3342 emitOpError() <<
"has an invalid type for port " << portName
3343 <<
" of determined kind \"" << portKindName
3344 <<
"\" (expected " << expectedType <<
", but got "
3345 << originalType <<
")";
3351 if (oldDataType && oldDataType != dataType) {
3352 emitOpError() <<
"port " << getPortName(i)
3353 <<
" has a different type than port " << getPortName(i - 1)
3354 <<
" (expected " << oldDataType <<
", but got " << dataType
3359 oldDataType = dataType;
3362 auto maskWidth = getMaskBits();
3364 auto dataWidth = getDataType().getBitWidthOrSentinel();
3365 if (dataWidth > 0 && maskWidth > (
size_t)dataWidth)
3366 return emitOpError(
"the mask width cannot be greater than "
3369 if (getPortAnnotations().size() != getNumResults())
3370 return emitOpError(
"the number of result annotations should be "
3371 "equal to the number of results");
3377 return std::max(1U, llvm::Log2_64_Ceil(depth));
3383 PortKind portKind,
size_t maskBits) {
3385 auto *context = dataType.getContext();
3386 if (portKind == PortKind::Debug)
3387 return RefType::get(FVectorType::get(dataType, depth));
3393 maskType = UIntType::get(context, maskBits);
3395 auto getId = [&](StringRef name) -> StringAttr {
3396 return StringAttr::get(context, name);
3399 SmallVector<BundleType::BundleElement, 7> portFields;
3403 portFields.push_back({getId(
"addr"),
false, addressType});
3404 portFields.push_back({getId(
"en"),
false, UIntType::get(context, 1)});
3405 portFields.push_back({getId(
"clk"),
false, ClockType::get(context)});
3408 case PortKind::Read:
3409 portFields.push_back({getId(
"data"),
true, dataType});
3412 case PortKind::Write:
3413 portFields.push_back({getId(
"data"),
false, dataType});
3414 portFields.push_back({getId(
"mask"),
false, maskType});
3417 case PortKind::ReadWrite:
3418 portFields.push_back({getId(
"rdata"),
true, dataType});
3419 portFields.push_back({getId(
"wmode"),
false, UIntType::get(context, 1)});
3420 portFields.push_back({getId(
"wdata"),
false, dataType});
3421 portFields.push_back({getId(
"wmask"),
false, maskType});
3424 llvm::report_fatal_error(
"memory port kind not handled");
3428 return BundleType::get(context, portFields);
3432SmallVector<MemOp::NamedPort> MemOp::getPorts() {
3433 SmallVector<MemOp::NamedPort> result;
3435 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3437 auto portType = type_cast<FIRRTLType>(getResult(i).getType());
3444MemOp::PortKind MemOp::getPortKind(StringRef portName) {
3446 type_cast<FIRRTLType>(getPortNamed(portName).getType()));
3450MemOp::PortKind MemOp::getPortKind(
size_t resultNo) {
3452 type_cast<FIRRTLType>(getResult(resultNo).getType()));
3456size_t MemOp::getMaskBits() {
3458 for (
auto res : getResults()) {
3459 if (type_isa<RefType>(res.getType()))
3461 auto firstPortType = type_cast<FIRRTLBaseType>(res.getType());
3468 if (t.name.getValue().contains(
"mask"))
3471 if (type_isa<UIntType>(mType))
3481 assert(getNumResults() != 0 &&
"Mems with no read/write ports are illegal");
3483 if (
auto refType = type_dyn_cast<RefType>(getResult(0).getType()))
3484 return type_cast<FVectorType>(refType.getType()).getElementType();
3485 auto firstPortType = type_cast<FIRRTLBaseType>(getResult(0).getType());
3487 StringRef dataFieldName =
"data";
3489 dataFieldName =
"rdata";
3491 return type_cast<BundleType>(firstPortType.getPassiveType())
3492 .getElementType(dataFieldName);
3495StringAttr MemOp::getPortName(
size_t resultNo) {
3496 return cast<StringAttr>(getPortNames()[resultNo]);
3500 return type_cast<FIRRTLBaseType>(getResults()[resultNo].getType());
3503Value MemOp::getPortNamed(StringAttr name) {
3504 auto namesArray = getPortNames();
3505 for (
size_t i = 0, e = namesArray.size(); i != e; ++i) {
3506 if (namesArray[i] == name) {
3507 assert(i < getNumResults() &&
" names array out of sync with results");
3508 return getResult(i);
3517 size_t numReadPorts = 0;
3518 size_t numWritePorts = 0;
3519 size_t numReadWritePorts = 0;
3521 SmallVector<int32_t> writeClockIDs;
3523 for (
size_t i = 0, e = op.getNumResults(); i != e; ++i) {
3524 auto portKind = op.getPortKind(i);
3525 if (portKind == MemOp::PortKind::Read)
3527 else if (portKind == MemOp::PortKind::Write) {
3528 for (
auto *a : op.getResult(i).getUsers()) {
3529 auto subfield = dyn_cast<SubfieldOp>(a);
3530 if (!subfield || subfield.getFieldIndex() != 2)
3532 auto clockPort = a->getResult(0);
3533 for (
auto *b : clockPort.getUsers()) {
3534 if (
auto connect = dyn_cast<FConnectLike>(b)) {
3535 if (
connect.getDest() == clockPort) {
3538 connect.getSrc(),
true,
true,
true),
3540 if (result.second) {
3541 writeClockIDs.push_back(numWritePorts);
3543 writeClockIDs.push_back(result.first->second);
3552 ++numReadWritePorts;
3559 op.emitError(
"'firrtl.mem' should have simple type and known width");
3560 MemoryInitAttr init = op->getAttrOfType<MemoryInitAttr>(
"init");
3562 if (op->hasAttr(
"modName"))
3563 modName = op->getAttrOfType<StringAttr>(
"modName");
3565 SmallString<8> clocks;
3566 for (
auto a : writeClockIDs)
3567 clocks.
append(Twine((char)(a +
'a')).str());
3568 SmallString<32> initStr;
3573 for (
auto c : init.getFilename().getValue())
3574 if ((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') ||
3575 (c >=
'0' && c <=
'9'))
3576 initStr.push_back(c);
3577 initStr.push_back(
'_');
3578 initStr.push_back(init.getIsBinary() ?
't' :
'f');
3579 initStr.push_back(
'_');
3580 initStr.push_back(init.getIsInline() ?
't' :
'f');
3582 modName = StringAttr::get(
3585 "{0}FIRRTLMem_{1}_{2}_{3}_{4}_{5}_{6}_{7}_{8}_{9}_{10}{11}{12}",
3586 op.getPrefix().value_or(
""), numReadPorts, numWritePorts,
3587 numReadWritePorts, (
size_t)width, op.getDepth(),
3588 op.getReadLatency(), op.getWriteLatency(), op.getMaskBits(),
3589 (
unsigned)op.getRuw(), (
unsigned)seq::WUW::PortOrder,
3590 clocks.empty() ?
"" :
"_" + clocks, init ? initStr.str() :
""));
3592 return {numReadPorts,
3597 op.getReadLatency(),
3598 op.getWriteLatency(),
3600 *seq::symbolizeRUW(
unsigned(op.getRuw())),
3601 seq::WUW::PortOrder,
3604 op.getMaskBits() > 1,
3610void MemOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3615 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
3616 setNameFn(getResult(i), (base +
"_" + getPortNameStr(i)).str());
3620std::optional<size_t> MemOp::getTargetResultIndex() {
3622 return std::nullopt;
3630 OpAsmSetValueNameFn setNameFn) {
3633 setNameFn(op.getDataRaw(), name);
3634 if (op.isForceable())
3635 setNameFn(op.getDataRef(), (name +
"_ref").str());
3638void NodeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3642LogicalResult NodeOp::inferReturnTypes(
3643 mlir::MLIRContext *context, std::optional<mlir::Location> location,
3644 ::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes,
3645 ::mlir::OpaqueProperties properties, ::mlir::RegionRange regions,
3646 ::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
3647 if (operands.empty())
3649 Adaptor adaptor(operands, attributes, properties, regions);
3650 inferredReturnTypes.push_back(adaptor.getInput().getType());
3651 if (adaptor.getForceable()) {
3653 true, adaptor.getInput().getType());
3654 if (!forceableType) {
3656 ::mlir::emitError(*location,
"cannot force a node of type ")
3657 << operands[0].getType();
3660 inferredReturnTypes.push_back(forceableType);
3665std::optional<size_t> NodeOp::getTargetResultIndex() {
return 0; }
3667void RegOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3671std::optional<size_t> RegOp::getTargetResultIndex() {
return 0; }
3673SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3674RegOp::computeDataFlow() {
3679LogicalResult RegResetOp::verify() {
3680 auto reset = getResetValue();
3687 return emitError(
"type mismatch between register ")
3688 << regType <<
" and reset value " << resetType;
3693std::optional<size_t> RegResetOp::getTargetResultIndex() {
return 0; }
3695void RegResetOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3704FormalOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3705 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3707 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3709 if (!isa<FModuleLike>(op)) {
3710 auto d = emitOpError() <<
"target " << getModuleNameAttr()
3711 <<
" is not a module";
3712 d.attachNote(op->getLoc()) <<
"target defined here";
3724SimulationOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3725 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3727 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3729 auto complain = [&] {
3730 auto d = emitOpError() <<
"target " << getModuleNameAttr() <<
" ";
3731 d.attachNote(op->getLoc()) <<
"target defined here";
3735 auto module = dyn_cast<FModuleLike>(op);
3737 return complain() <<
"is not a module";
3739 auto numPorts =
module.getPortDirections().size();
3741 return complain() <<
"must have 4 ports, got " << numPorts <<
" instead";
3743 auto checkPort = [&](
unsigned idx, StringRef expName,
Direction expDir,
3744 llvm::function_ref<bool(Type)> checkType,
3745 StringRef expType) {
3746 auto name =
module.getPortNameAttr(idx);
3747 if (name != expName) {
3748 complain() <<
"port " << idx <<
" must be called \"" << expName
3749 <<
"\", got " << name <<
" instead";
3752 if (
auto dir = module.getPortDirection(idx); dir != expDir) {
3756 complain() <<
"port " << name <<
" must be " << stringify(expDir)
3757 <<
", got " << stringify(dir) <<
" instead";
3760 if (
auto type = module.getPortType(idx); !checkType(type)) {
3761 complain() <<
"port " << name <<
" must be a '!firrtl." << expType
3762 <<
"', got " << type <<
" instead";
3768 auto isClock = [](Type type) {
return isa<ClockType>(type); };
3769 auto isBool = [](Type type) {
3770 if (
auto uintType = dyn_cast<UIntType>(type))
3771 return uintType.getWidth() == 1;
3774 return success(checkPort(0,
"clock",
Direction::In, isClock,
"clock") &&
3784void WireOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3788SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3789RegResetOp::computeDataFlow() {
3794std::optional<size_t> WireOp::getTargetResultIndex() {
return 0; }
3796LogicalResult WireOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3797 auto refType = type_dyn_cast<RefType>(getType(0));
3802 refType,
getLoc(), getOperation()->getParentOfType<CircuitOp>(),
3803 symbolTable, Twine(
"'") + getOperationName() +
"' op is");
3810LogicalResult ContractOp::verify() {
3811 if (getBody().getArgumentTypes() != getInputs().getType())
3812 return emitOpError(
"result types and region argument types must match");
3820void ObjectOp::build(OpBuilder &builder, OperationState &state, ClassLike klass,
3822 build(builder, state, klass.getInstanceType(),
3823 StringAttr::get(builder.getContext(), name));
3826LogicalResult ObjectOp::verify() {
return success(); }
3828LogicalResult ObjectOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3829 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
3830 auto classType = getType();
3831 auto className = classType.getNameAttr();
3834 auto classOp = dyn_cast_or_null<ClassLike>(
3835 symbolTable.lookupSymbolIn(circuitOp, className));
3837 return emitOpError() <<
"references unknown class " << className;
3840 if (failed(classOp.verifyType(classType, [&]() { return emitOpError(); })))
3846StringAttr ObjectOp::getClassNameAttr() {
3847 return getType().getNameAttr().getAttr();
3850StringRef ObjectOp::getClassName() {
return getType().getName(); }
3852ClassLike ObjectOp::getReferencedClass(
const SymbolTable &symbolTable) {
3853 auto symRef = getType().getNameAttr();
3854 return symbolTable.lookup<ClassLike>(symRef.getLeafReference());
3857Operation *ObjectOp::getReferencedOperation(
const SymbolTable &symtbl) {
3858 return getReferencedClass(symtbl);
3861StringRef ObjectOp::getInstanceName() {
return getName(); }
3863StringAttr ObjectOp::getInstanceNameAttr() {
return getNameAttr(); }
3865StringRef ObjectOp::getReferencedModuleName() {
return getClassName(); }
3867StringAttr ObjectOp::getReferencedModuleNameAttr() {
3868 return getClassNameAttr();
3871void ObjectOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3872 setNameFn(getResult(),
getName());
3879LogicalResult AttachOp::verify() {
3881 std::optional<int32_t> commonWidth;
3882 for (
auto operand : getOperands()) {
3883 auto thisWidth = type_cast<AnalogType>(operand.getType()).getWidth();
3887 commonWidth = thisWidth;
3890 if (commonWidth != thisWidth)
3891 return emitOpError(
"is inavlid as not all known operand widths match");
3898 Value dst = connect->getOperand(0);
3899 Value src = connect->getOperand(1);
3908 if (isa<PropertyType>(src.getType()) ||
3912 auto diag = emitError(connect->getLoc());
3913 diag <<
"connect has invalid flow: the source expression ";
3915 diag <<
"\"" << srcName <<
"\" ";
3916 diag <<
"has " <<
toString(srcFlow) <<
", expected source or duplex flow";
3917 return diag.attachNote(srcRef.getLoc()) <<
"the source was defined here";
3925 auto diag = emitError(connect->getLoc());
3926 diag <<
"connect has invalid flow: the destination expression ";
3928 diag <<
"\"" << dstName <<
"\" ";
3929 diag <<
"has " <<
toString(dstFlow) <<
", expected sink or duplex flow";
3930 return diag.attachNote(dstRef.getLoc())
3931 <<
"the destination was defined here";
3940 bool outerTypeIsConst =
false) {
3941 auto typeIsConst = outerTypeIsConst || type.
isConst();
3946 if (
auto bundleType = type_dyn_cast<BundleType>(type))
3947 return llvm::any_of(bundleType.getElements(), [&](
auto &element) {
3948 return isConstFieldDriven(element.type, isFlip ^ element.isFlip,
3952 if (
auto vectorType = type_dyn_cast<FVectorType>(type))
3964 auto dest = connect.getDest();
3965 auto destType = type_dyn_cast<FIRRTLBaseType>(dest.getType());
3966 auto src = connect.getSrc();
3967 auto srcType = type_dyn_cast<FIRRTLBaseType>(src.getType());
3968 if (!destType || !srcType)
3971 auto destRefinedType = destType;
3972 auto srcRefinedType = srcType;
3977 auto findFieldDeclarationRefiningFieldType =
3979 while (
auto *definingOp = value.getDefiningOp()) {
3980 bool shouldContinue =
true;
3981 TypeSwitch<Operation *>(definingOp)
3982 .Case<SubfieldOp, SubindexOp>([&](
auto op) { value = op.getInput(); })
3983 .Case<SubaccessOp>([&](SubaccessOp op) {
3987 .getElementTypePreservingConst()
3989 originalFieldType = originalFieldType.getConstType(
true);
3990 value = op.getInput();
3992 .Default([&](Operation *) { shouldContinue =
false; });
3993 if (!shouldContinue)
3999 auto destDeclaration =
4000 findFieldDeclarationRefiningFieldType(dest, destRefinedType);
4001 auto srcDeclaration =
4002 findFieldDeclarationRefiningFieldType(src, srcRefinedType);
4004 auto checkConstConditionality = [&](Value value,
FIRRTLBaseType type,
4005 Value declaration) -> LogicalResult {
4006 auto *declarationBlock = declaration.getParentBlock();
4007 auto *block = connect->getBlock();
4008 while (block && block != declarationBlock) {
4009 auto *parentOp = block->getParentOp();
4011 if (
auto whenOp = dyn_cast<WhenOp>(parentOp);
4012 whenOp && !whenOp.getCondition().getType().isConst()) {
4014 return connect.emitOpError()
4015 <<
"assignment to 'const' type " << type
4016 <<
" is dependent on a non-'const' condition";
4017 return connect->emitOpError()
4018 <<
"assignment to nested 'const' member of type " << type
4019 <<
" is dependent on a non-'const' condition";
4022 block = parentOp->getBlock();
4027 auto emitSubaccessError = [&] {
4028 return connect.emitError(
4029 "assignment to non-'const' subaccess of 'const' type is disallowed");
4035 if (destType != destRefinedType)
4036 return emitSubaccessError();
4038 if (failed(checkConstConditionality(dest, destType, destDeclaration)))
4043 if (srcRefinedType.containsConst() &&
4046 if (srcType != srcRefinedType)
4047 return emitSubaccessError();
4048 if (failed(checkConstConditionality(src, srcType, srcDeclaration)))
4055LogicalResult ConnectOp::verify() {
4056 auto dstType = getDest().getType();
4057 auto srcType = getSrc().getType();
4058 auto dstBaseType = type_dyn_cast<FIRRTLBaseType>(dstType);
4059 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(srcType);
4060 if (!dstBaseType || !srcBaseType) {
4061 if (dstType != srcType)
4062 return emitError(
"may not connect different non-base types");
4065 if (dstBaseType.containsAnalog() || srcBaseType.containsAnalog())
4066 return emitError(
"analog types may not be connected");
4070 return emitError(
"type mismatch between destination ")
4071 << dstBaseType <<
" and source " << srcBaseType;
4076 return emitError(
"destination ")
4077 << dstBaseType <<
" is not as wide as the source " << srcBaseType;
4090LogicalResult MatchingConnectOp::verify() {
4091 if (
auto type = type_dyn_cast<FIRRTLType>(getDest().getType())) {
4092 auto baseType = type_cast<FIRRTLBaseType>(type);
4095 if (baseType && baseType.containsAnalog())
4096 return emitError(
"analog types may not be connected");
4101 "`SameAnonTypeOperands` trait should have already rejected "
4102 "structurally non-equivalent types");
4115LogicalResult RefDefineOp::verify() {
4125 for (
auto *user : getDest().getUsers()) {
4126 if (
auto conn = dyn_cast<FConnectLike>(user);
4127 conn && conn.getDest() == getDest() && conn != *
this)
4128 return emitError(
"destination reference cannot be reused by multiple "
4129 "operations, it can only capture a unique dataflow");
4133 if (
auto *op = getDest().getDefiningOp()) {
4135 if (isa<RefSubOp>(op))
4137 "destination reference cannot be a sub-element of a reference");
4138 if (isa<RefCastOp>(op))
4140 "destination reference cannot be a cast of another reference");
4148 SmallVector<SymbolRefAttr> missingLayers;
4151 "has more layer requirements than destination",
4152 "additional layers required");
4155LogicalResult PropAssignOp::verify() {
4161 for (
auto *user : getDest().getUsers()) {
4162 if (
auto conn = dyn_cast<FConnectLike>(user);
4163 conn && conn.getDest() == getDest() && conn != *
this)
4164 return emitError(
"destination property cannot be reused by multiple "
4165 "operations, it can only capture a unique dataflow");
4171void WhenOp::createElseRegion() {
4172 assert(!hasElseRegion() &&
"already has an else region");
4173 getElseRegion().push_back(
new Block());
4176void WhenOp::build(OpBuilder &builder, OperationState &result, Value condition,
4177 bool withElseRegion, std::function<
void()> thenCtor,
4178 std::function<
void()> elseCtor) {
4179 OpBuilder::InsertionGuard guard(builder);
4180 result.addOperands(condition);
4183 builder.createBlock(result.addRegion());
4188 Region *elseRegion = result.addRegion();
4189 if (withElseRegion) {
4190 builder.createBlock(elseRegion);
4200LogicalResult MatchOp::verify() {
4201 FEnumType type = getInput().getType();
4204 auto numCases = getTags().size();
4205 auto numRegions = getNumRegions();
4206 if (numRegions != numCases)
4207 return emitOpError(
"expected ")
4208 << numRegions <<
" tags but got " << numCases;
4210 auto numTags = type.getNumElements();
4212 SmallDenseSet<int64_t> seen;
4213 for (
const auto &[tag, region] :
llvm::zip(getTags(), getRegions())) {
4214 auto tagIndex = size_t(cast<IntegerAttr>(tag).
getInt());
4217 if (region.getNumArguments() != 1)
4218 return emitOpError(
"region should have exactly one argument");
4221 if (tagIndex >= numTags)
4222 return emitOpError(
"the tag index ")
4223 << tagIndex <<
" is out of the range of valid tags in " << type;
4226 auto [it, inserted] = seen.insert(tagIndex);
4228 return emitOpError(
"the tag ") << type.getElementNameAttr(tagIndex)
4229 <<
" is matched more than once";
4232 auto expectedType = type.getElementTypePreservingConst(tagIndex);
4233 auto regionType = region.getArgument(0).getType();
4234 if (regionType != expectedType)
4235 return emitOpError(
"region type ")
4236 << regionType <<
" does not match the expected type "
4241 for (
size_t i = 0, e = type.getNumElements(); i < e; ++i)
4242 if (!seen.contains(i))
4243 return emitOpError(
"missing case for tag ") << type.getElementNameAttr(i);
4248void MatchOp::print(OpAsmPrinter &p) {
4249 auto input = getInput();
4250 FEnumType type = input.getType();
4251 auto regions = getRegions();
4252 p <<
" " << input <<
" : " << type;
4253 SmallVector<StringRef> elided = {
"tags"};
4254 p.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elided);
4257 for (
const auto &[tag, region] :
llvm::zip(getTags(), regions)) {
4260 p.printKeywordOrString(
4261 type.getElementName(cast<IntegerAttr>(tag).getInt()));
4263 p.printRegionArgument(region.front().getArgument(0), {},
4266 p.printRegion(region,
false);
4273ParseResult MatchOp::parse(OpAsmParser &parser, OperationState &result) {
4274 auto *context = parser.getContext();
4275 auto &properties = result.getOrAddProperties<Properties>();
4276 OpAsmParser::UnresolvedOperand input;
4277 if (parser.parseOperand(input) || parser.parseColon())
4280 auto loc = parser.getCurrentLocation();
4282 if (parser.parseType(type))
4284 auto enumType = type_dyn_cast<FEnumType>(type);
4286 return parser.emitError(loc,
"expected enumeration type but got") << type;
4288 if (parser.resolveOperand(input, type, result.operands) ||
4289 parser.parseOptionalAttrDictWithKeyword(result.attributes) ||
4290 parser.parseLBrace())
4293 auto i32Type = IntegerType::get(context, 32);
4294 SmallVector<Attribute> tags;
4297 if (failed(parser.parseOptionalKeyword(
"case")))
4301 auto nameLoc = parser.getCurrentLocation();
4303 OpAsmParser::Argument arg;
4304 auto *region = result.addRegion();
4305 if (parser.parseKeywordOrString(&name) || parser.parseLParen() ||
4306 parser.parseArgument(arg) || parser.parseRParen())
4310 auto index = enumType.getElementIndex(name);
4312 return parser.emitError(nameLoc,
"the tag \"")
4313 << name <<
"\" is not a member of the enumeration " << enumType;
4314 tags.push_back(IntegerAttr::get(i32Type, *index));
4317 arg.type = enumType.getElementTypePreservingConst(*index);
4318 if (parser.parseRegion(*region, arg))
4321 properties.setTags(ArrayAttr::get(context, tags));
4323 return parser.parseRBrace();
4326void MatchOp::build(OpBuilder &builder, OperationState &result, Value input,
4328 MutableArrayRef<std::unique_ptr<Region>> regions) {
4329 auto &properties = result.getOrAddProperties<Properties>();
4330 result.addOperands(input);
4331 properties.setTags(tags);
4332 result.addRegions(regions);
4341 struct IsExprClassifier :
public ExprVisitor<IsExprClassifier, bool> {
4342 bool visitInvalidExpr(Operation *op) {
return false; }
4343 bool visitUnhandledExpr(Operation *op) {
return true; }
4349void InvalidValueOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4352 if (
auto ty = type_dyn_cast<IntType>(getType())) {
4353 const char *base = ty.isSigned() ?
"invalid_si" :
"invalid_ui";
4354 auto width = ty.getWidthOrSentinel();
4358 name = (Twine(base) + Twine(width)).str();
4359 }
else if (
auto ty = type_dyn_cast<AnalogType>(getType())) {
4360 auto width = ty.getWidthOrSentinel();
4362 name =
"invalid_analog";
4364 name = (
"invalid_analog" + Twine(width)).str();
4365 }
else if (type_isa<AsyncResetType>(getType()))
4366 name =
"invalid_asyncreset";
4367 else if (type_isa<ResetType>(getType()))
4368 name =
"invalid_reset";
4369 else if (type_isa<ClockType>(getType()))
4370 name =
"invalid_clock";
4374 setNameFn(getResult(), name);
4377void ConstantOp::print(OpAsmPrinter &p) {
4379 p.printAttributeWithoutType(getValueAttr());
4381 p.printType(getType());
4382 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4385ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
4386 auto &properties = result.getOrAddProperties<Properties>();
4389 auto loc = parser.getCurrentLocation();
4390 auto valueResult = parser.parseOptionalInteger(value);
4391 if (!valueResult.has_value())
4392 return parser.emitError(loc,
"expected integer value");
4396 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4397 parser.parseOptionalAttrDict(result.attributes))
4399 result.addTypes(resultType);
4405 if (width > value.getBitWidth()) {
4409 value = value.sext(width);
4410 }
else if (width < value.getBitWidth()) {
4413 unsigned neededBits = value.isNegative() ? value.getSignificantBits()
4414 : value.getActiveBits();
4415 if (width < neededBits)
4416 return parser.emitError(loc,
"constant out of range for result type ")
4418 value = value.trunc(width);
4422 auto intType = parser.getBuilder().getIntegerType(value.getBitWidth(),
4424 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4425 properties.setValue(valueAttr);
4429LogicalResult ConstantOp::verify() {
4433 if (width != -1 && (
int)getValue().
getBitWidth() != width)
4435 "firrtl.constant attribute bitwidth doesn't match return type");
4438 auto attrType = type_cast<IntegerType>(getValueAttr().getType());
4439 if (attrType.isSignless() || attrType.isSigned() != intType.
isSigned())
4440 return emitError(
"firrtl.constant attribute has wrong sign");
4447void ConstantOp::build(OpBuilder &builder, OperationState &result,
IntType type,
4448 const APInt &value) {
4451 assert((width == -1 || (int32_t)value.getBitWidth() == width) &&
4452 "incorrect attribute bitwidth for firrtl.constant");
4455 IntegerAttr::get(type.getContext(), APSInt(value, !type.
isSigned()));
4456 return build(builder, result, type, attr);
4461void ConstantOp::build(OpBuilder &builder, OperationState &result,
4462 const APSInt &value) {
4463 auto attr = IntegerAttr::get(builder.getContext(), value);
4465 IntType::get(builder.getContext(), value.isSigned(), value.getBitWidth());
4466 return build(builder, result, type, attr);
4469void ConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4476 SmallString<32> specialNameBuffer;
4477 llvm::raw_svector_ostream specialName(specialNameBuffer);
4479 getValue().print(specialName, intTy.
isSigned());
4481 specialName << (intTy.
isSigned() ?
"_si" :
"_ui");
4484 specialName << width;
4485 setNameFn(getResult(), specialName.str());
4488void SpecialConstantOp::print(OpAsmPrinter &p) {
4491 p << static_cast<unsigned>(getValue());
4493 p.printType(getType());
4494 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4497ParseResult SpecialConstantOp::parse(OpAsmParser &parser,
4498 OperationState &result) {
4499 auto &properties = result.getOrAddProperties<Properties>();
4503 auto loc = parser.getCurrentLocation();
4504 auto valueResult = parser.parseOptionalInteger(value);
4505 if (!valueResult.has_value())
4506 return parser.emitError(loc,
"expected integer value");
4509 if (value != 0 && value != 1)
4510 return parser.emitError(loc,
"special constants can only be 0 or 1.");
4514 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4515 parser.parseOptionalAttrDict(result.attributes))
4517 result.addTypes(resultType);
4520 auto valueAttr = parser.getBuilder().getBoolAttr(value == 1);
4521 properties.setValue(valueAttr);
4525void SpecialConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4526 SmallString<32> specialNameBuffer;
4527 llvm::raw_svector_ostream specialName(specialNameBuffer);
4529 specialName << static_cast<unsigned>(getValue());
4530 auto type = getType();
4531 if (type_isa<ClockType>(type)) {
4532 specialName <<
"_clock";
4533 }
else if (type_isa<ResetType>(type)) {
4534 specialName <<
"_reset";
4535 }
else if (type_isa<AsyncResetType>(type)) {
4536 specialName <<
"_asyncreset";
4538 setNameFn(getResult(), specialName.str());
4545 if (type.isGround()) {
4546 if (!isa<IntegerAttr>(attr)) {
4547 op->emitOpError(
"Ground type is not an integer attribute");
4552 auto attrlist = dyn_cast<ArrayAttr>(attr);
4554 op->emitOpError(
"expected array attribute for aggregate constant");
4557 if (
auto array = type_dyn_cast<FVectorType>(type)) {
4558 if (array.getNumElements() != attrlist.size()) {
4559 op->emitOpError(
"array attribute (")
4560 << attrlist.size() <<
") has wrong size for vector constant ("
4561 << array.getNumElements() <<
")";
4564 return llvm::all_of(attrlist, [&array, op](Attribute attr) {
4568 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4569 if (bundle.getNumElements() != attrlist.size()) {
4570 op->emitOpError(
"array attribute (")
4571 << attrlist.size() <<
") has wrong size for bundle constant ("
4572 << bundle.getNumElements() <<
")";
4575 for (
size_t i = 0; i < bundle.getNumElements(); ++i) {
4576 if (bundle.getElement(i).isFlip) {
4577 op->emitOpError(
"Cannot have constant bundle type with flip");
4585 op->emitOpError(
"Unknown aggregate type");
4589LogicalResult AggregateConstantOp::verify() {
4595Attribute AggregateConstantOp::getAttributeFromFieldID(uint64_t fieldID) {
4597 Attribute value = getFields();
4598 while (fieldID != 0) {
4599 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4600 auto index = bundle.getIndexForFieldID(fieldID);
4601 fieldID -= bundle.getFieldID(index);
4602 type = bundle.getElementType(index);
4603 value = cast<ArrayAttr>(value)[index];
4605 auto vector = type_cast<FVectorType>(type);
4606 auto index = vector.getIndexForFieldID(fieldID);
4607 fieldID -= vector.getFieldID(index);
4608 type = vector.getElementType();
4609 value = cast<ArrayAttr>(value)[index];
4615void FIntegerConstantOp::print(OpAsmPrinter &p) {
4617 p.printAttributeWithoutType(getValueAttr());
4618 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4621ParseResult FIntegerConstantOp::parse(OpAsmParser &parser,
4622 OperationState &result) {
4623 auto *context = parser.getContext();
4624 auto &properties = result.getOrAddProperties<Properties>();
4626 if (parser.parseInteger(value) ||
4627 parser.parseOptionalAttrDict(result.attributes))
4629 result.addTypes(FIntegerType::get(context));
4631 IntegerType::get(context, value.getBitWidth(), IntegerType::Signed);
4632 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4633 properties.setValue(valueAttr);
4637ParseResult ListCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4638 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
4641 if (parser.parseOperandList(operands) ||
4642 parser.parseOptionalAttrDict(result.attributes) ||
4643 parser.parseColonType(type))
4645 result.addTypes(type);
4647 return parser.resolveOperands(operands, type.getElementType(),
4651void ListCreateOp::print(OpAsmPrinter &p) {
4653 p.printOperands(getElements());
4654 p.printOptionalAttrDict((*this)->getAttrs());
4655 p <<
" : " << getType();
4658LogicalResult ListCreateOp::verify() {
4659 if (getElements().
empty())
4662 auto elementType = getElements().front().getType();
4663 auto listElementType = getType().getElementType();
4665 return emitOpError(
"has elements of type ")
4666 <<
elementType <<
" instead of " << listElementType;
4671LogicalResult BundleCreateOp::verify() {
4672 BundleType resultType = getType();
4673 if (resultType.getNumElements() != getFields().size())
4674 return emitOpError(
"number of fields doesn't match type");
4675 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4677 resultType.getElementTypePreservingConst(i),
4678 type_cast<FIRRTLBaseType>(getOperand(i).getType())))
4679 return emitOpError(
"type of element doesn't match bundle for field ")
4680 << resultType.getElement(i).name;
4685LogicalResult VectorCreateOp::verify() {
4686 FVectorType resultType = getType();
4687 if (resultType.getNumElements() != getFields().size())
4688 return emitOpError(
"number of fields doesn't match type");
4689 auto elemTy = resultType.getElementTypePreservingConst();
4690 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4692 elemTy, type_cast<FIRRTLBaseType>(getOperand(i).getType())))
4693 return emitOpError(
"type of element doesn't match vector element");
4702LogicalResult FEnumCreateOp::verify() {
4703 FEnumType resultType = getResult().getType();
4704 auto elementIndex = resultType.getElementIndex(
getFieldName());
4706 return emitOpError(
"label ")
4707 <<
getFieldName() <<
" is not a member of the enumeration type "
4710 resultType.getElementTypePreservingConst(*elementIndex),
4711 getInput().getType()))
4712 return emitOpError(
"type of element doesn't match enum element");
4716void FEnumCreateOp::print(OpAsmPrinter &printer) {
4719 printer <<
'(' << getInput() <<
')';
4720 SmallVector<StringRef> elidedAttrs = {
"fieldIndex"};
4721 printer.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elidedAttrs);
4723 printer.printFunctionalType(ArrayRef<Type>{getInput().getType()},
4724 ArrayRef<Type>{getResult().getType()});
4727ParseResult FEnumCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4728 auto *context = parser.getContext();
4729 auto &properties = result.getOrAddProperties<Properties>();
4731 OpAsmParser::UnresolvedOperand input;
4732 std::string fieldName;
4733 mlir::FunctionType functionType;
4734 if (parser.parseKeywordOrString(&fieldName) || parser.parseLParen() ||
4735 parser.parseOperand(input) || parser.parseRParen() ||
4736 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4737 parser.parseType(functionType))
4740 if (functionType.getNumInputs() != 1)
4741 return parser.emitError(parser.getNameLoc(),
"single input type required");
4742 if (functionType.getNumResults() != 1)
4743 return parser.emitError(parser.getNameLoc(),
"single result type required");
4745 auto inputType = functionType.getInput(0);
4746 if (parser.resolveOperand(input, inputType, result.operands))
4749 auto outputType = functionType.getResult(0);
4750 auto enumType = type_dyn_cast<FEnumType>(outputType);
4752 return parser.emitError(parser.getNameLoc(),
4753 "output must be enum type, got ")
4755 auto fieldIndex = enumType.getElementIndex(fieldName);
4757 return parser.emitError(parser.getNameLoc(),
4758 "unknown field " + fieldName +
" in enum type ")
4761 properties.setFieldIndex(
4762 IntegerAttr::get(IntegerType::get(context, 32), *fieldIndex));
4764 result.addTypes(enumType);
4773LogicalResult IsTagOp::verify() {
4774 if (getFieldIndex() >= getInput().getType().base().getNumElements())
4775 return emitOpError(
"element index is greater than the number of fields in "
4780void IsTagOp::print(::mlir::OpAsmPrinter &printer) {
4781 printer <<
' ' << getInput() <<
' ';
4783 SmallVector<::llvm::StringRef, 1> elidedAttrs = {
"fieldIndex"};
4784 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
4785 printer <<
" : " << getInput().getType();
4788ParseResult IsTagOp::parse(OpAsmParser &parser, OperationState &result) {
4789 auto *context = parser.getContext();
4790 auto &properties = result.getOrAddProperties<Properties>();
4792 OpAsmParser::UnresolvedOperand input;
4793 std::string fieldName;
4795 if (parser.parseOperand(input) || parser.parseKeywordOrString(&fieldName) ||
4796 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4797 parser.parseType(inputType))
4800 if (parser.resolveOperand(input, inputType, result.operands))
4803 auto enumType = type_dyn_cast<FEnumType>(inputType);
4805 return parser.emitError(parser.getNameLoc(),
4806 "input must be enum type, got ")
4808 auto fieldIndex = enumType.getElementIndex(fieldName);
4810 return parser.emitError(parser.getNameLoc(),
4811 "unknown field " + fieldName +
" in enum type ")
4814 properties.setFieldIndex(
4815 IntegerAttr::get(IntegerType::get(context, 32), *fieldIndex));
4817 result.addTypes(UIntType::get(context, 1,
false));
4822FIRRTLType IsTagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
4823 OpaqueProperties properties,
4824 mlir::RegionRange regions,
4825 std::optional<Location> loc) {
4826 Adaptor adaptor(operands, attrs, properties, regions);
4827 return UIntType::get(attrs.getContext(), 1,
4828 isConst(adaptor.getInput().getType()));
4831template <
typename OpTy>
4833 auto *context = parser.getContext();
4835 OpAsmParser::UnresolvedOperand input;
4836 std::string fieldName;
4838 if (parser.parseOperand(input) || parser.parseLSquare() ||
4839 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
4840 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4841 parser.parseType(inputType))
4844 if (parser.resolveOperand(input, inputType, result.operands))
4847 auto bundleType = type_dyn_cast<typename OpTy::InputType>(inputType);
4849 return parser.emitError(parser.getNameLoc(),
4850 "input must be bundle type, got ")
4852 auto fieldIndex = bundleType.getElementIndex(fieldName);
4854 return parser.emitError(parser.getNameLoc(),
4855 "unknown field " + fieldName +
" in bundle type ")
4858 result.getOrAddProperties<
typename OpTy::Properties>().setFieldIndex(
4859 IntegerAttr::get(IntegerType::get(context, 32), *fieldIndex));
4861 auto type = OpTy::inferReturnType(inputType, *fieldIndex, {});
4864 result.addTypes(type);
4869ParseResult SubtagOp::parse(OpAsmParser &parser, OperationState &result) {
4870 auto *context = parser.getContext();
4872 OpAsmParser::UnresolvedOperand input;
4873 std::string fieldName;
4875 if (parser.parseOperand(input) || parser.parseLSquare() ||
4876 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
4877 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4878 parser.parseType(inputType))
4881 if (parser.resolveOperand(input, inputType, result.operands))
4884 auto enumType = type_dyn_cast<FEnumType>(inputType);
4886 return parser.emitError(parser.getNameLoc(),
4887 "input must be enum type, got ")
4889 auto fieldIndex = enumType.getElementIndex(fieldName);
4891 return parser.emitError(parser.getNameLoc(),
4892 "unknown field " + fieldName +
" in enum type ")
4895 result.getOrAddProperties<Properties>().setFieldIndex(
4896 IntegerAttr::get(IntegerType::get(context, 32), *fieldIndex));
4898 SmallVector<Type> inferredReturnTypes;
4899 if (failed(SubtagOp::inferReturnTypes(
4900 context, result.location, result.operands,
4901 result.attributes.getDictionary(context), result.getRawProperties(),
4902 result.regions, inferredReturnTypes)))
4904 result.addTypes(inferredReturnTypes);
4909ParseResult SubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
4910 return parseSubfieldLikeOp<SubfieldOp>(parser, result);
4912ParseResult OpenSubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
4913 return parseSubfieldLikeOp<OpenSubfieldOp>(parser, result);
4916template <
typename OpTy>
4918 printer <<
' ' << op.getInput() <<
'[';
4919 printer.printKeywordOrString(op.getFieldName());
4921 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
4922 elidedAttrs.push_back(
"fieldIndex");
4923 printer.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
4924 printer <<
" : " << op.getInput().getType();
4926void SubfieldOp::print(::mlir::OpAsmPrinter &printer) {
4927 return printSubfieldLikeOp<SubfieldOp>(*
this, printer);
4929void OpenSubfieldOp::print(::mlir::OpAsmPrinter &printer) {
4930 return printSubfieldLikeOp<OpenSubfieldOp>(*
this, printer);
4933void SubtagOp::print(::mlir::OpAsmPrinter &printer) {
4934 printer <<
' ' << getInput() <<
'[';
4937 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
4938 elidedAttrs.push_back(
"fieldIndex");
4939 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
4940 printer <<
" : " << getInput().getType();
4943template <
typename OpTy>
4945 if (op.getFieldIndex() >=
4946 firrtl::type_cast<typename OpTy::InputType>(op.getInput().getType())
4948 return op.emitOpError(
"subfield element index is greater than the number "
4949 "of fields in the bundle type");
4952LogicalResult SubfieldOp::verify() {
4953 return verifySubfieldLike<SubfieldOp>(*
this);
4955LogicalResult OpenSubfieldOp::verify() {
4956 return verifySubfieldLike<OpenSubfieldOp>(*
this);
4959LogicalResult SubtagOp::verify() {
4960 if (getFieldIndex() >= getInput().getType().base().getNumElements())
4961 return emitOpError(
"subfield element index is greater than the number "
4962 "of fields in the bundle type");
4972 SmallVector<Operation *, 8> worklist({op});
4976 bool constant =
true;
4982 while (constant && !(worklist.empty()))
4983 TypeSwitch<Operation *>(worklist.pop_back_val())
4984 .Case<NodeOp, AsSIntPrimOp, AsUIntPrimOp>([&](
auto op) {
4985 if (
auto definingOp = op.getInput().getDefiningOp())
4986 worklist.push_back(definingOp);
4989 .Case<WireOp, SubindexOp, SubfieldOp>([&](
auto op) {
4990 for (
auto &use : op.getResult().getUses())
4991 worklist.push_back(use.getOwner());
4993 .Case<ConstantOp, SpecialConstantOp, AggregateConstantOp>([](
auto) {})
4994 .Default([&](
auto) { constant =
false; });
5003 if (
auto *op = value.getDefiningOp())
5008LogicalResult ConstCastOp::verify() {
5010 return emitOpError() << getInput().getType()
5011 <<
" is not 'const'-castable to "
5012 << getResult().getType();
5016FIRRTLType SubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
5017 std::optional<Location> loc) {
5018 auto inType = type_cast<BundleType>(type);
5020 if (fieldIndex >= inType.getNumElements())
5022 "subfield element index is greater than the "
5023 "number of fields in the bundle type");
5027 return inType.getElementTypePreservingConst(fieldIndex);
5030FIRRTLType OpenSubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
5031 std::optional<Location> loc) {
5032 auto inType = type_cast<OpenBundleType>(type);
5034 if (fieldIndex >= inType.getNumElements())
5036 "subfield element index is greater than the "
5037 "number of fields in the bundle type");
5041 return inType.getElementTypePreservingConst(fieldIndex);
5044bool SubfieldOp::isFieldFlipped() {
5045 BundleType bundle = getInput().getType();
5046 return bundle.getElement(getFieldIndex()).isFlip;
5048bool OpenSubfieldOp::isFieldFlipped() {
5049 auto bundle = getInput().getType();
5050 return bundle.getElement(getFieldIndex()).isFlip;
5053FIRRTLType SubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
5054 std::optional<Location> loc) {
5055 if (
auto vectorType = type_dyn_cast<FVectorType>(type)) {
5056 if (fieldIndex < vectorType.getNumElements())
5057 return vectorType.getElementTypePreservingConst();
5059 "' in vector type ", type);
5064FIRRTLType OpenSubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
5065 std::optional<Location> loc) {
5066 if (
auto vectorType = type_dyn_cast<OpenVectorType>(type)) {
5067 if (fieldIndex < vectorType.getNumElements())
5068 return vectorType.getElementTypePreservingConst();
5070 "' in vector type ", type);
5076FIRRTLType SubtagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5077 OpaqueProperties properties,
5078 mlir::RegionRange regions,
5079 std::optional<Location> loc) {
5080 Adaptor adaptor(operands, attrs, properties, regions);
5081 auto inType = type_cast<FEnumType>(adaptor.getInput().getType());
5082 auto fieldIndex = adaptor.getFieldIndex();
5084 if (fieldIndex >= inType.getNumElements())
5086 "subtag element index is greater than the "
5087 "number of fields in the enum type");
5091 auto elementType = inType.getElement(fieldIndex).type;
5095FIRRTLType SubaccessOp::inferReturnType(Type inType, Type indexType,
5096 std::optional<Location> loc) {
5097 if (!type_isa<UIntType>(indexType))
5101 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
5103 return vectorType.getElementTypePreservingConst();
5104 return vectorType.getElementType().getAllConstDroppedType();
5112 std::optional<Location> loc) {
5113 auto inType = type_cast<FEnumType>(input);
5114 return UIntType::get(inType.getContext(), inType.getTagWidth());
5117ParseResult MultibitMuxOp::parse(OpAsmParser &parser, OperationState &result) {
5118 OpAsmParser::UnresolvedOperand index;
5119 SmallVector<OpAsmParser::UnresolvedOperand, 16> inputs;
5120 Type indexType, elemType;
5122 if (parser.parseOperand(index) || parser.parseComma() ||
5123 parser.parseOperandList(inputs) ||
5124 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5125 parser.parseType(indexType) || parser.parseComma() ||
5126 parser.parseType(elemType))
5129 if (parser.resolveOperand(index, indexType, result.operands))
5132 result.addTypes(elemType);
5134 return parser.resolveOperands(inputs, elemType, result.operands);
5137void MultibitMuxOp::print(OpAsmPrinter &p) {
5138 p <<
" " << getIndex() <<
", ";
5139 p.printOperands(getInputs());
5140 p.printOptionalAttrDict((*this)->getAttrs());
5141 p <<
" : " << getIndex().getType() <<
", " << getType();
5144FIRRTLType MultibitMuxOp::inferReturnType(ValueRange operands,
5145 DictionaryAttr attrs,
5146 OpaqueProperties properties,
5147 mlir::RegionRange regions,
5148 std::optional<Location> loc) {
5149 if (operands.size() < 2)
5153 if (!llvm::all_of(operands.drop_front(2), [&](
auto op) {
5154 return operands[1].getType() == op.getType();
5158 return type_cast<FIRRTLType>(operands[1].getType());
5165LogicalResult ObjectSubfieldOp::inferReturnTypes(
5166 MLIRContext *context, std::optional<mlir::Location> location,
5167 ValueRange operands, DictionaryAttr attributes, OpaqueProperties properties,
5168 RegionRange regions, llvm::SmallVectorImpl<Type> &inferredReturnTypes) {
5170 inferReturnType(operands, attributes, properties, regions, location);
5173 inferredReturnTypes.push_back(type);
5177Type ObjectSubfieldOp::inferReturnType(Type inType, uint32_t fieldIndex,
5178 std::optional<Location> loc) {
5179 auto classType = dyn_cast<ClassType>(inType);
5183 if (classType.getNumElements() <= fieldIndex)
5185 "number of fields in the object");
5186 return classType.getElement(fieldIndex).type;
5189void ObjectSubfieldOp::print(OpAsmPrinter &p) {
5190 auto input = getInput();
5191 auto classType = input.getType();
5192 p <<
' ' << input <<
"[";
5193 p.printKeywordOrString(classType.getElement(getIndex()).name);
5195 p.printOptionalAttrDict((*this)->getAttrs(), std::array{StringRef(
"index")});
5196 p <<
" : " << classType;
5199ParseResult ObjectSubfieldOp::parse(OpAsmParser &parser,
5200 OperationState &result) {
5201 auto *context = parser.getContext();
5203 OpAsmParser::UnresolvedOperand input;
5204 std::string fieldName;
5205 ClassType inputType;
5206 if (parser.parseOperand(input) || parser.parseLSquare() ||
5207 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5208 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5209 parser.parseType(inputType) ||
5210 parser.resolveOperand(input, inputType, result.operands))
5213 auto index = inputType.getElementIndex(fieldName);
5215 return parser.emitError(parser.getNameLoc(),
5216 "unknown field " + fieldName +
" in class type ")
5218 result.getOrAddProperties<Properties>().setIndex(
5219 IntegerAttr::get(IntegerType::get(context, 32), *index));
5221 SmallVector<Type> inferredReturnTypes;
5222 if (failed(inferReturnTypes(context, result.location, result.operands,
5223 result.attributes.getDictionary(context),
5224 result.getRawProperties(), result.regions,
5225 inferredReturnTypes)))
5227 result.addTypes(inferredReturnTypes);
5244 int32_t &rhsWidth,
bool &isConstResult,
5245 std::optional<Location> loc) {
5247 auto lhsi = type_dyn_cast<IntType>(lhs);
5248 auto rhsi = type_dyn_cast<IntType>(rhs);
5249 if (!lhsi || !rhsi || lhsi.isSigned() != rhsi.isSigned()) {
5252 mlir::emitError(*loc,
"second operand must be an integer type, not ")
5254 else if (!lhsi && rhsi)
5255 mlir::emitError(*loc,
"first operand must be an integer type, not ")
5257 else if (!lhsi && !rhsi)
5258 mlir::emitError(*loc,
"operands must be integer types, not ")
5259 << lhs <<
" and " << rhs;
5261 mlir::emitError(*loc,
"operand signedness must match");
5266 lhsWidth = lhsi.getWidthOrSentinel();
5267 rhsWidth = rhsi.getWidthOrSentinel();
5268 isConstResult = lhsi.isConst() && rhsi.isConst();
5273 assert(op->getNumOperands() == 2 &&
5274 "SameOperandsIntTypeKind on non-binary op");
5275 int32_t lhsWidth, rhsWidth;
5278 op->getOperand(1).getType(), lhsWidth,
5279 rhsWidth, isConstResult, op->getLoc()));
5283 std::optional<Location> loc) {
5284 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5285 bool isConstResult =
false;
5289 if (lhsWidth != -1 && rhsWidth != -1)
5290 resultWidth = std::max(lhsWidth, rhsWidth) + 1;
5291 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5296 std::optional<Location> loc) {
5297 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5298 bool isConstResult =
false;
5302 if (lhsWidth != -1 && rhsWidth != -1)
5303 resultWidth = lhsWidth + rhsWidth;
5305 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5310 std::optional<Location> loc) {
5311 int32_t lhsWidth, rhsWidth;
5312 bool isConstResult =
false;
5317 if (type_isa<UIntType>(lhs))
5318 return UIntType::get(lhs.getContext(), lhsWidth, isConstResult);
5321 int32_t resultWidth = lhsWidth != -1 ? lhsWidth + 1 : -1;
5322 return SIntType::get(lhs.getContext(), resultWidth, isConstResult);
5326 std::optional<Location> loc) {
5327 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5328 bool isConstResult =
false;
5332 if (lhsWidth != -1 && rhsWidth != -1)
5333 resultWidth = std::min(lhsWidth, rhsWidth);
5334 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5339 std::optional<Location> loc) {
5340 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5341 bool isConstResult =
false;
5345 if (lhsWidth != -1 && rhsWidth != -1) {
5346 resultWidth = std::max(lhsWidth, rhsWidth);
5347 if (lhsWidth == resultWidth && lhs.
isConst() == isConstResult &&
5350 if (rhsWidth == resultWidth && rhs.
isConst() == isConstResult &&
5354 return UIntType::get(lhs.getContext(), resultWidth, isConstResult);
5358 std::optional<Location> loc) {
5359 if (!type_isa<FVectorType>(lhs) || !type_isa<FVectorType>(rhs))
5362 auto lhsVec = type_cast<FVectorType>(lhs);
5363 auto rhsVec = type_cast<FVectorType>(rhs);
5365 if (lhsVec.getNumElements() != rhsVec.getNumElements())
5370 rhsVec.getElementTypePreservingConst(), loc);
5373 auto elemBaseType = type_cast<FIRRTLBaseType>(elemType);
5374 return FVectorType::get(elemBaseType, lhsVec.getNumElements(),
5375 lhsVec.isConst() && rhsVec.isConst() &&
5376 elemBaseType.isConst());
5380 std::optional<Location> loc) {
5381 return UIntType::get(lhs.getContext(), 1,
isConst(lhs) &&
isConst(rhs));
5384FIRRTLType CatPrimOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5385 OpaqueProperties properties,
5386 mlir::RegionRange regions,
5387 std::optional<Location> loc) {
5389 if (operands.empty())
5390 return UIntType::get(attrs.getContext(), 0);
5393 bool isSigned = type_isa<SIntType>(operands[0].getType());
5394 for (
auto operand : operands) {
5395 auto type = type_dyn_cast<IntType>(operand.getType());
5398 if (type.isSigned() != isSigned)
5400 "all operands must have same signedness");
5404 int32_t resultWidth = 0;
5405 bool isConstResult =
true;
5407 for (
auto operand : operands) {
5408 auto type = type_cast<IntType>(operand.getType());
5409 int32_t width = type.getWidthOrSentinel();
5416 if (resultWidth != -1)
5417 resultWidth += width;
5420 isConstResult &= type.isConst();
5424 return UIntType::get(attrs.getContext(), resultWidth, isConstResult);
5428 std::optional<Location> loc) {
5429 auto lhsi = type_dyn_cast<IntType>(lhs);
5430 auto rhsui = type_dyn_cast<UIntType>(rhs);
5431 if (!rhsui || !lhsi)
5433 loc,
"first operand should be integer, second unsigned int");
5437 auto width = lhsi.getWidthOrSentinel();
5438 if (width == -1 || !rhsui.getWidth().has_value()) {
5441 auto amount = *rhsui.getWidth();
5444 "shift amount too large: second operand of "
5445 "dshl is wider than 31 bits");
5446 int64_t newWidth = (int64_t)width + ((int64_t)1 << amount) - 1;
5447 if (newWidth > INT32_MAX)
5449 loc,
"shift amount too large: first operand shifted by maximum "
5450 "amount exceeds maximum width");
5453 return IntType::get(lhs.getContext(), lhsi.isSigned(), width,
5454 lhsi.
isConst() && rhsui.isConst());
5458 std::optional<Location> loc) {
5459 auto lhsi = type_dyn_cast<IntType>(lhs);
5460 auto rhsu = type_dyn_cast<UIntType>(rhs);
5463 loc,
"first operand should be integer, second unsigned int");
5464 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5468 std::optional<Location> loc) {
5469 auto lhsi = type_dyn_cast<IntType>(lhs);
5470 auto rhsu = type_dyn_cast<UIntType>(rhs);
5473 loc,
"first operand should be integer, second unsigned int");
5474 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5482 std::optional<Location> loc) {
5483 return UIntType::get(input.getContext(), 32);
5487 std::optional<Location> loc) {
5488 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5491 int32_t width = base.getBitWidthOrSentinel();
5494 return SIntType::get(input.getContext(), width, base.
isConst());
5498 std::optional<Location> loc) {
5499 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5502 int32_t width = base.getBitWidthOrSentinel();
5505 return UIntType::get(input.getContext(), width, base.
isConst());
5509 std::optional<Location> loc) {
5510 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5513 "operand must be single bit scalar base type");
5514 int32_t width = base.getBitWidthOrSentinel();
5515 if (width == -2 || width == 0 || width > 1)
5517 return AsyncResetType::get(input.getContext(), base.
isConst());
5521 std::optional<Location> loc) {
5522 return ClockType::get(input.getContext(),
isConst(input));
5526 std::optional<Location> loc) {
5527 if (
auto uiType = type_dyn_cast<UIntType>(input)) {
5528 auto width = uiType.getWidthOrSentinel();
5531 return SIntType::get(input.getContext(), width, uiType.
isConst());
5534 if (type_isa<SIntType>(input))
5541 std::optional<Location> loc) {
5542 auto inputi = type_dyn_cast<IntType>(input);
5545 int32_t width = inputi.getWidthOrSentinel();
5548 return SIntType::get(input.getContext(), width, inputi.
isConst());
5552 std::optional<Location> loc) {
5553 auto inputi = type_dyn_cast<IntType>(input);
5556 if (isa<UIntType>(inputi))
5558 return UIntType::get(input.getContext(), inputi.getWidthOrSentinel(),
5563 std::optional<Location> loc) {
5564 return UIntType::get(input.getContext(), 1,
isConst(input));
5573 std::optional<Location> loc) {
5574 auto inputi = type_dyn_cast<IntType>(input);
5577 loc,
"input type should be the int type but got ", input);
5582 loc,
"high must be equal or greater than low, but got high = ", high,
5590 int32_t width = inputi.getWidthOrSentinel();
5591 if (width != -1 && high >= width)
5594 "high must be smaller than the width of input, but got high = ", high,
5595 ", width = ", width);
5597 return UIntType::get(input.getContext(), high - low + 1, inputi.
isConst());
5601 std::optional<Location> loc) {
5603 auto inputi = type_dyn_cast<IntType>(input);
5604 if (amount < 0 || !inputi)
5606 loc,
"operand must have integer type and amount must be >= 0");
5608 int32_t width = inputi.getWidthOrSentinel();
5609 if (width != -1 && amount > width)
5612 return UIntType::get(input.getContext(), amount, inputi.
isConst());
5627 bool isConstCondition,
5628 std::optional<Location> loc) {
5634 if (high.getTypeID() != low.getTypeID())
5635 return emitInferRetTypeError<FIRRTLBaseType>(
5636 loc,
"incompatible mux operand types, true value type: ", high,
5637 ", false value type: ", low);
5639 bool outerTypeIsConst = isConstCondition && low.
isConst() && high.
isConst();
5644 if (type_isa<IntType>(low)) {
5649 if (highWidth == -1)
5651 return (lowWidth > highWidth ? low : high).getConstType(outerTypeIsConst);
5656 auto highEnum = type_dyn_cast<FEnumType>(high);
5657 auto lowEnum = type_dyn_cast<FEnumType>(low);
5658 if (lowEnum && highEnum) {
5659 if (lowEnum.getNumElements() != highEnum.getNumElements())
5660 return emitInferRetTypeError<FIRRTLBaseType>(
5661 loc,
"incompatible mux operand types, true value type: ", high,
5662 ", false value type: ", low);
5663 SmallVector<FEnumType::EnumElement> elements;
5664 for (
auto [high, low] : llvm::zip_equal(highEnum, lowEnum)) {
5666 if (high.name != low.name || high.value != low.value)
5667 return emitInferRetTypeError<FIRRTLBaseType>(
5668 loc,
"incompatible mux operand types, true value type: ", highEnum,
5669 ", false value type: ", lowEnum);
5676 elements.emplace_back(high.name, high.value, inner);
5678 return FEnumType::get(high.getContext(), elements, outerTypeIsConst);
5682 auto highVector = type_dyn_cast<FVectorType>(high);
5683 auto lowVector = type_dyn_cast<FVectorType>(low);
5684 if (highVector && lowVector &&
5685 highVector.getNumElements() == lowVector.getNumElements()) {
5687 lowVector.getElementTypePreservingConst(),
5688 isConstCondition, loc);
5691 return FVectorType::get(inner, lowVector.getNumElements(),
5696 auto highBundle = type_dyn_cast<BundleType>(high);
5697 auto lowBundle = type_dyn_cast<BundleType>(low);
5698 if (highBundle && lowBundle) {
5699 auto highElements = highBundle.getElements();
5700 auto lowElements = lowBundle.getElements();
5703 SmallVector<BundleType::BundleElement> newElements;
5705 bool failed =
false;
5707 if (highElements[i].name != lowElements[i].name ||
5708 highElements[i].isFlip != lowElements[i].isFlip) {
5712 auto element = highElements[i];
5714 highBundle.getElementTypePreservingConst(i),
5715 lowBundle.getElementTypePreservingConst(i), isConstCondition, loc);
5718 newElements.push_back(element);
5721 return BundleType::get(low.getContext(), newElements, outerTypeIsConst);
5723 return emitInferRetTypeError<FIRRTLBaseType>(
5724 loc,
"incompatible mux operand bundle fields, true value type: ", high,
5725 ", false value type: ", low);
5730 return emitInferRetTypeError<FIRRTLBaseType>(
5731 loc,
"invalid mux operand types, true value type: ", high,
5732 ", false value type: ", low);
5737 std::optional<Location> loc) {
5738 auto highType = type_dyn_cast<FIRRTLBaseType>(high);
5739 auto lowType = type_dyn_cast<FIRRTLBaseType>(low);
5740 if (!highType || !lowType)
5745FIRRTLType Mux2CellIntrinsicOp::inferReturnType(ValueRange operands,
5746 DictionaryAttr attrs,
5747 OpaqueProperties properties,
5748 mlir::RegionRange regions,
5749 std::optional<Location> loc) {
5750 auto highType = type_dyn_cast<FIRRTLBaseType>(operands[1].getType());
5751 auto lowType = type_dyn_cast<FIRRTLBaseType>(operands[2].getType());
5752 if (!highType || !lowType)
5758FIRRTLType Mux4CellIntrinsicOp::inferReturnType(ValueRange operands,
5759 DictionaryAttr attrs,
5760 OpaqueProperties properties,
5761 mlir::RegionRange regions,
5762 std::optional<Location> loc) {
5763 SmallVector<FIRRTLBaseType> types;
5765 for (
unsigned i = 1; i < 5; i++) {
5766 types.push_back(type_dyn_cast<FIRRTLBaseType>(operands[i].getType()));
5771 isConst(operands[0].getType()), loc);
5775 result = types.back();
5782 std::optional<Location> loc) {
5783 auto inputi = type_dyn_cast<IntType>(input);
5784 if (amount < 0 || !inputi)
5786 loc,
"pad input must be integer and amount must be >= 0");
5788 int32_t width = inputi.getWidthOrSentinel();
5792 width = std::max<int32_t>(width, amount);
5793 return IntType::get(input.getContext(), inputi.isSigned(), width,
5798 std::optional<Location> loc) {
5799 auto inputi = type_dyn_cast<IntType>(input);
5800 if (amount < 0 || !inputi)
5802 loc,
"shl input must be integer and amount must be >= 0");
5804 int32_t width = inputi.getWidthOrSentinel();
5808 return IntType::get(input.getContext(), inputi.isSigned(), width,
5813 std::optional<Location> loc) {
5814 auto inputi = type_dyn_cast<IntType>(input);
5815 if (amount < 0 || !inputi)
5817 loc,
"shr input must be integer and amount must be >= 0");
5819 int32_t width = inputi.getWidthOrSentinel();
5822 int32_t minWidth = inputi.isUnsigned() ? 0 : 1;
5823 width = std::max<int32_t>(minWidth, width - amount);
5826 return IntType::get(input.getContext(), inputi.isSigned(), width,
5831 std::optional<Location> loc) {
5833 auto inputi = type_dyn_cast<IntType>(input);
5834 if (amount < 0 || !inputi)
5836 loc,
"tail input must be integer and amount must be >= 0");
5838 int32_t width = inputi.getWidthOrSentinel();
5842 loc,
"amount must be less than or equal operand width");
5853void VerbatimExprOp::getAsmResultNames(
5854 function_ref<
void(Value, StringRef)> setNameFn) {
5858 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
5859 auto name = getText();
5861 if (name.starts_with(
"`"))
5862 name = name.drop_front();
5863 name = name.take_while(isOkCharacter);
5865 setNameFn(getResult(), name);
5872void VerbatimWireOp::getAsmResultNames(
5873 function_ref<
void(Value, StringRef)> setNameFn) {
5877 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
5878 auto name = getText();
5880 if (name.starts_with(
"`"))
5881 name = name.drop_front();
5882 name = name.take_while(isOkCharacter);
5884 setNameFn(getResult(), name);
5895 op->emitError() <<
"unknown width is not allowed for DPI";
5896 return WalkResult::interrupt();
5898 if (width == 1 || width == 8 || width == 16 || width == 32 ||
5900 return WalkResult::advance();
5902 <<
"integer types used by DPI functions must have a "
5903 "specific bit width; "
5904 "it must be equal to 1(bit), 8(byte), 16(shortint), "
5905 "32(int), 64(longint) "
5906 "or greater than 64, but got "
5908 return WalkResult::interrupt();
5913LogicalResult DPICallIntrinsicOp::verify() {
5914 if (
auto inputNames = getInputNames()) {
5915 if (getInputs().size() != inputNames->size())
5916 return emitError() <<
"inputNames has " << inputNames->size()
5917 <<
" elements but there are " << getInputs().size()
5918 <<
" input arguments";
5920 if (
auto outputName = getOutputName())
5921 if (getNumResults() == 0)
5922 return emitError() <<
"output name is given but there is no result";
5924 auto checkType = [
this](Type type) {
5927 return success(llvm::all_of(this->getResultTypes(), checkType) &&
5928 llvm::all_of(this->getOperandTypes(), checkType));
5931SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
5932DPICallIntrinsicOp::computeDataFlow() {
5936 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
5938 for (
auto operand : getOperands()) {
5939 auto type = type_cast<FIRRTLBaseType>(operand.getType());
5941 SmallVector<circt::FieldRef> operandFields;
5944 operandFields.push_back(baseFieldRef.getSubField(dstIndex));
5948 for (
auto result : getResults())
5951 for (
auto field : operandFields)
5952 deps.emplace_back(
circt::
FieldRef(result, dstIndex), field);
5962LogicalResult HWStructCastOp::verify() {
5964 BundleType bundleType;
5965 hw::StructType structType;
5966 if ((bundleType = type_dyn_cast<BundleType>(getOperand().getType()))) {
5967 structType = dyn_cast<hw::StructType>(getType());
5969 return emitError(
"result type must be a struct");
5970 }
else if ((bundleType = type_dyn_cast<BundleType>(getType()))) {
5971 structType = dyn_cast<hw::StructType>(getOperand().getType());
5973 return emitError(
"operand type must be a struct");
5975 return emitError(
"either source or result type must be a bundle type");
5978 auto firFields = bundleType.getElements();
5979 auto hwFields = structType.getElements();
5980 if (firFields.size() != hwFields.size())
5981 return emitError(
"bundle and struct have different number of fields");
5983 for (
size_t findex = 0, fend = firFields.size(); findex < fend; ++findex) {
5984 if (firFields[findex].name.getValue() != hwFields[findex].name)
5985 return emitError(
"field names don't match '")
5986 << firFields[findex].name.getValue() <<
"', '"
5987 << hwFields[findex].name.getValue() <<
"'";
5991 if (firWidth > 0 && hwWidth > 0 && firWidth != hwWidth)
5992 return emitError(
"size of field '")
5993 << hwFields[findex].name.getValue() <<
"' don't match " << firWidth
6000LogicalResult BitCastOp::verify() {
6001 auto inTypeBits =
getBitWidth(getInput().getType(),
true);
6003 if (inTypeBits.has_value() && resTypeBits.has_value()) {
6005 if (*inTypeBits == *resTypeBits) {
6008 return emitError(
"cannot cast non-'const' input type ")
6009 << getOperand().getType() <<
" to 'const' result type "
6013 return emitError(
"the bitwidth of input (")
6014 << *inTypeBits <<
") and result (" << *resTypeBits
6017 if (!inTypeBits.has_value())
6018 return emitError(
"bitwidth cannot be determined for input operand type ")
6019 << getInput().getType();
6020 return emitError(
"bitwidth cannot be determined for result type ")
6031 NamedAttrList &resultAttrs) {
6032 auto result = parser.parseOptionalAttrDict(resultAttrs);
6033 if (!resultAttrs.get(
"annotations"))
6034 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
6040 DictionaryAttr attr,
6041 ArrayRef<StringRef> extraElides = {}) {
6042 SmallVector<StringRef> elidedAttrs(extraElides.begin(), extraElides.end());
6044 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
6045 elidedAttrs.push_back(
"annotations");
6047 elidedAttrs.push_back(
"nameKind");
6049 p.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
6055 NamedAttrList &resultAttrs) {
6058 if (!resultAttrs.get(
"portAnnotations")) {
6059 SmallVector<Attribute, 16> portAnnotations(
6060 parser.getNumResults(), parser.getBuilder().getArrayAttr({}));
6061 resultAttrs.append(
"portAnnotations",
6062 parser.getBuilder().getArrayAttr(portAnnotations));
6069 DictionaryAttr attr,
6070 ArrayRef<StringRef> extraElides = {}) {
6071 SmallVector<StringRef, 2> elidedAttrs(extraElides.begin(), extraElides.end());
6073 if (llvm::all_of(op->getAttrOfType<ArrayAttr>(
"portAnnotations"),
6074 [&](Attribute a) { return cast<ArrayAttr>(a).empty(); }))
6075 elidedAttrs.push_back(
"portAnnotations");
6084 firrtl::NameKindEnumAttr &result) {
6087 if (!parser.parseOptionalKeyword(&keyword,
6088 {
"interesting_name",
"droppable_name"})) {
6089 auto kind = symbolizeNameKindEnum(keyword);
6090 result = NameKindEnumAttr::get(parser.getContext(), kind.value());
6096 NameKindEnumAttr::get(parser.getContext(), NameKindEnum::DroppableName);
6101 firrtl::NameKindEnumAttr attr,
6102 ArrayRef<StringRef> extraElides = {}) {
6103 if (attr.getValue() != NameKindEnum::DroppableName)
6104 p <<
" " << stringifyNameKindEnum(attr.getValue());
6112 NamedAttrList &resultAttrs) {
6120 DictionaryAttr attrs) {
6121 SmallVector<StringRef, 4> elides;
6123 elides.push_back(Forceable::getForceableAttrName());
6132static ParseResult
parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs) {
6137static void printMemOp(OpAsmPrinter &p, Operation *op, DictionaryAttr attr) {
6148 if (ClassType::parseInterface(parser, type))
6155 type.printInterface(p);
6163 NamedAttrList &resultAttrs) {
6164 auto result = p.parseOptionalAttrDict(resultAttrs);
6165 if (!resultAttrs.get(
"name"))
6166 resultAttrs.append(
"name", p.getBuilder().getStringAttr(
""));
6172 DictionaryAttr attr,
6173 ArrayRef<StringRef> extraElides = {}) {
6174 SmallVector<StringRef> elides(extraElides.begin(), extraElides.end());
6175 if (op->getAttrOfType<StringAttr>(
"name").getValue().empty())
6176 elides.push_back(
"name");
6178 p.printOptionalAttrDict(op->getAttrs(), elides);
6182 NamedAttrList &resultAttrs) {
6187 DictionaryAttr attr) {
6192 NamedAttrList &resultAttrs) {
6197 DictionaryAttr attr) {
6199 {
"formatString",
"outputFile",
"operandSegmentSizes"});
6207 DictionaryAttr attr) {
6216 DictionaryAttr attr) {
6225 OpAsmSetValueNameFn setNameFn) {
6228 if (op->getNumResults() == 1)
6229 if (
auto nameAttr = op->getAttrOfType<StringAttr>(
"name"))
6230 setNameFn(op->getResult(0), nameAttr.getValue());
6233void AddPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6237void AndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6241void AndRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6245void SizeOfIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6248void AsAsyncResetPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6251void AsClockPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6254void AsSIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6257void AsUIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6260void BitsPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6263void CatPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6266void CvtPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6269void DShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6272void DShlwPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6275void DShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6278void DivPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6281void EQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6284void GEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6287void GTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6290void GenericIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6293void HeadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6296void IntegerAddOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6299void IntegerMulOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6302void IntegerShrOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6305void IntegerShlOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6308void IsTagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6311void IsXIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6314void PlusArgsValueIntrinsicOp::getAsmResultNames(
6315 OpAsmSetValueNameFn setNameFn) {
6318void PlusArgsTestIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6321void LEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6324void LTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6327void MulPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6330void MultibitMuxOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6333void MuxPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6336void Mux4CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6339void Mux2CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6342void NEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6345void NegPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6348void NotPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6351void OrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6354void OrRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6357void PadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6360void RemPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6363void ShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6366void ShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6370void SubPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6374void SubaccessOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6378void SubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6382void OpenSubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6386void SubtagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6390void SubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6394void OpenSubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6398void TagExtractOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6402void TailPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6406void XorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6410void XorRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6414void UninferredResetCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6418void ConstCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6422void ElementwiseXorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6426void ElementwiseOrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6430void ElementwiseAndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6438void RefCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6442void RefResolveOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6446void RefSendOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6450void RefSubOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6454void RWProbeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6458FIRRTLType RefResolveOp::inferReturnType(ValueRange operands,
6459 DictionaryAttr attrs,
6460 OpaqueProperties properties,
6461 mlir::RegionRange regions,
6462 std::optional<Location> loc) {
6463 Type inType = operands[0].getType();
6464 auto inRefType = type_dyn_cast<RefType>(inType);
6467 loc,
"ref.resolve operand must be ref type, not ", inType);
6468 return inRefType.getType();
6471FIRRTLType RefSendOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
6472 OpaqueProperties properties,
6473 mlir::RegionRange regions,
6474 std::optional<Location> loc) {
6475 Type inType = operands[0].getType();
6476 auto inBaseType = type_dyn_cast<FIRRTLBaseType>(inType);
6479 loc,
"ref.send operand must be base type, not ", inType);
6480 return RefType::get(inBaseType.getPassiveType());
6483FIRRTLType RefSubOp::inferReturnType(Type type, uint32_t fieldIndex,
6484 std::optional<Location> loc) {
6485 auto refType = type_dyn_cast<RefType>(type);
6488 auto inType = refType.getType();
6494 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
6495 if (fieldIndex < vectorType.getNumElements())
6496 return RefType::get(
6497 vectorType.getElementType().getConstType(
6498 vectorType.isConst() || vectorType.getElementType().isConst()),
6499 refType.getForceable(), refType.getLayer());
6501 "' in RefType of vector type ", refType);
6503 if (
auto bundleType = type_dyn_cast<BundleType>(inType)) {
6504 if (fieldIndex >= bundleType.getNumElements()) {
6506 "subfield element index is greater than "
6507 "the number of fields in the bundle type");
6509 return RefType::get(
6510 bundleType.getElement(fieldIndex)
6512 bundleType.isConst() ||
6513 bundleType.getElement(fieldIndex).type.isConst()),
6514 refType.getForceable(), refType.getLayer());
6518 loc,
"ref.sub op requires a RefType of vector or bundle base type");
6521LogicalResult RefCastOp::verify() {
6525 getOperation(), srcLayers, dstLayers,
6526 "cannot discard layer requirements of input reference",
6527 "discarding layer requirements");
6530LogicalResult RefResolveOp::verify() {
6534 getOperation(), srcLayers, dstLayers,
6535 "ambient layers are insufficient to resolve reference");
6539 auto targetRef = getTarget();
6540 if (targetRef.getModule() !=
6541 (*this)->getParentOfType<FModuleLike>().getModuleNameAttr())
6542 return emitOpError() <<
"has non-local target";
6544 auto target = ns.
lookup(targetRef);
6546 return emitOpError() <<
"has target that cannot be resolved: " << targetRef;
6548 auto checkFinalType = [&](
auto type, Location loc) -> LogicalResult {
6553 auto baseType = type_dyn_cast<FIRRTLBaseType>(fType);
6554 if (!baseType || baseType.getPassiveType() != getType().getType()) {
6555 auto diag = emitOpError(
"has type mismatch: target resolves to ")
6556 << fType <<
" instead of expected " << getType().getType();
6557 diag.attachNote(loc) <<
"target resolves here";
6562 if (target.isPort()) {
6563 auto mod = cast<FModuleLike>(target.getOp());
6564 return checkFinalType(mod.getPortType(target.getPort()),
6565 mod.getPortLocation(target.getPort()));
6567 hw::InnerSymbolOpInterface symOp =
6568 cast<hw::InnerSymbolOpInterface>(target.getOp());
6569 if (!symOp.getTargetResult())
6570 return emitOpError(
"has target that cannot be probed")
6571 .attachNote(symOp.getLoc())
6572 .append(
"target resolves here");
6574 symOp.getTargetResult().getParentBlock()->findAncestorOpInBlock(**
this);
6575 if (!ancestor || !symOp->isBeforeInBlock(ancestor))
6576 return emitOpError(
"is not dominated by target")
6577 .attachNote(symOp.getLoc())
6578 .append(
"target here");
6579 return checkFinalType(symOp.getTargetResult().getType(), symOp.getLoc());
6582LogicalResult RefForceOp::verify() {
6586 getOperation(), destLayers, ambientLayers,
6587 "has insufficient ambient layers to force its reference");
6590LogicalResult RefForceInitialOp::verify() {
6594 getOperation(), destLayers, ambientLayers,
6595 "has insufficient ambient layers to force its reference");
6598LogicalResult RefReleaseOp::verify() {
6602 getOperation(), destLayers, ambientLayers,
6603 "has insufficient ambient layers to release its reference");
6606LogicalResult RefReleaseInitialOp::verify() {
6610 getOperation(), destLayers, ambientLayers,
6611 "has insufficient ambient layers to release its reference");
6614LogicalResult XMRRefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6615 auto *target = symbolTable.lookupNearestSymbolFrom(*
this, getRefAttr());
6617 return emitOpError(
"has an invalid symbol reference");
6619 if (!isa<hw::HierPathOp>(target))
6620 return emitOpError(
"does not target a hierpath op");
6626LogicalResult XMRDerefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6627 auto *target = symbolTable.lookupNearestSymbolFrom(*
this, getRefAttr());
6629 return emitOpError(
"has an invalid symbol reference");
6631 if (!isa<hw::HierPathOp>(target))
6632 return emitOpError(
"does not target a hierpath op");
6642LogicalResult LayerBlockOp::verify() {
6643 auto layerName = getLayerName();
6644 auto *parentOp = (*this)->getParentOp();
6647 while (isa<WhenOp, MatchOp>(parentOp))
6648 parentOp = parentOp->getParentOp();
6652 auto nestedReferences = layerName.getNestedReferences();
6653 if (nestedReferences.empty()) {
6654 if (!isa<FModuleOp>(parentOp)) {
6655 auto diag = emitOpError() <<
"has an un-nested layer symbol, but does "
6656 "not have a 'firrtl.module' op as a parent";
6657 return diag.attachNote(parentOp->getLoc())
6658 <<
"illegal parent op defined here";
6661 auto parentLayerBlock = dyn_cast<LayerBlockOp>(parentOp);
6662 if (!parentLayerBlock) {
6663 auto diag = emitOpError()
6664 <<
"has a nested layer symbol, but does not have a '"
6665 << getOperationName() <<
"' op as a parent'";
6666 return diag.attachNote(parentOp->getLoc())
6667 <<
"illegal parent op defined here";
6669 auto parentLayerBlockName = parentLayerBlock.getLayerName();
6670 if (parentLayerBlockName.getRootReference() !=
6671 layerName.getRootReference() ||
6672 parentLayerBlockName.getNestedReferences() !=
6673 layerName.getNestedReferences().drop_back()) {
6674 auto diag = emitOpError() <<
"is nested under an illegal layer block";
6675 return diag.attachNote(parentLayerBlock->getLoc())
6676 <<
"illegal parent layer block defined here";
6682 auto result = getBody(0)->walk<mlir::WalkOrder::PreOrder>(
6683 [&](Operation *op) -> WalkResult {
6685 if (isa<LayerBlockOp>(op))
6686 return WalkResult::skip();
6690 for (
auto operand : op->getOperands()) {
6692 if (
auto *definingOp = operand.getDefiningOp())
6696 auto type = operand.getType();
6699 if (isa<PropertyType>(type)) {
6700 auto diag = emitOpError() <<
"captures a property operand";
6701 diag.attachNote(operand.getLoc()) <<
"operand is defined here";
6702 diag.attachNote(op->getLoc()) <<
"operand is used here";
6703 return WalkResult::interrupt();
6708 if (
auto connect = dyn_cast<FConnectLike>(op)) {
6710 if (isa<RefDefineOp>(connect))
6711 return WalkResult::advance();
6718 bool passive =
true;
6720 type_dyn_cast<FIRRTLBaseType>(
connect.getDest().getType()))
6721 passive = type.isPassive();
6730 return WalkResult::advance();
6733 return WalkResult::advance();
6737 <<
"connects to a destination which is defined outside its "
6738 "enclosing layer block";
6739 diag.attachNote(
getLoc()) <<
"enclosing layer block is defined here";
6740 diag.attachNote(dest.getLoc()) <<
"destination is defined here";
6741 return WalkResult::interrupt();
6744 return WalkResult::advance();
6747 return failure(result.wasInterrupted());
6751LayerBlockOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6753 symbolTable.lookupNearestSymbolFrom<LayerOp>(*
this, getLayerNameAttr());
6755 return emitOpError(
"invalid symbol reference");
6765void TimeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6766 setNameFn(getResult(),
"time");
6769void HierarchicalModuleNameOp::getAsmResultNames(
6770 OpAsmSetValueNameFn setNameFn) {
6771 setNameFn(getResult(),
"hierarchicalmodulename");
6774ParseResult FPrintFOp::parse(::mlir::OpAsmParser &parser,
6775 ::mlir::OperationState &result) {
6777 OpAsmParser::UnresolvedOperand clock, cond;
6778 if (parser.parseOperand(clock) || parser.parseComma() ||
6779 parser.parseOperand(cond) || parser.parseComma())
6782 auto parseFormatString =
6783 [&parser](llvm::SMLoc &loc, StringAttr &result,
6784 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &operands)
6786 loc = parser.getCurrentLocation();
6789 std::string resultStr;
6790 if (parser.parseString(&resultStr))
6792 result = parser.getBuilder().getStringAttr(resultStr);
6795 if (parser.parseOperandList(operands, AsmParser::Delimiter::OptionalParen))
6801 SmallVector<OpAsmParser::UnresolvedOperand> outputFileSubstitutions,
6803 llvm::SMLoc outputFileLoc, formatStringLoc;
6805 if (parseFormatString(
6807 result.getOrAddProperties<FPrintFOp::Properties>().outputFile,
6808 outputFileSubstitutions) ||
6809 parser.parseComma() ||
6812 result.getOrAddProperties<FPrintFOp::Properties>().formatString,
6820 Type clockType, condType;
6821 SmallVector<Type> restTypes;
6823 if (parser.parseColon() || parser.parseType(clockType) ||
6824 parser.parseComma() || parser.parseType(condType))
6827 if (succeeded(parser.parseOptionalComma())) {
6828 if (parser.parseTypeList(restTypes))
6833 result.getOrAddProperties<FPrintFOp::Properties>().operandSegmentSizes = {
6834 1, 1,
static_cast<int32_t
>(outputFileSubstitutions.size()),
6835 static_cast<int32_t
>(substitutions.size())};
6838 if (parser.resolveOperand(clock, clockType, result.operands) ||
6839 parser.resolveOperand(cond, condType, result.operands) ||
6840 parser.resolveOperands(
6841 outputFileSubstitutions,
6842 ArrayRef(restTypes).take_front(outputFileSubstitutions.size()),
6843 outputFileLoc, result.operands) ||
6844 parser.resolveOperands(
6846 ArrayRef(restTypes).drop_front(outputFileSubstitutions.size()),
6847 formatStringLoc, result.operands))
6853void FPrintFOp::print(OpAsmPrinter &p) {
6854 p <<
" " << getClock() <<
", " << getCond() <<
", ";
6855 p.printAttributeWithoutType(getOutputFileAttr());
6856 if (!getOutputFileSubstitutions().
empty()) {
6858 p.printOperands(getOutputFileSubstitutions());
6862 p.printAttributeWithoutType(getFormatStringAttr());
6863 if (!getSubstitutions().
empty()) {
6865 p.printOperands(getSubstitutions());
6869 p <<
" : " << getClock().getType() <<
", " << getCond().getType();
6870 if (!getOutputFileSubstitutions().
empty() || !getSubstitutions().
empty()) {
6871 for (
auto type : getOperands().drop_front(2).getTypes()) {
6882LogicalResult FFlushOp::verify() {
6883 if (!getOutputFileAttr() && !getOutputFileSubstitutions().
empty())
6884 return emitOpError(
"substitutions without output file are not allowed");
6893 auto ref = getInstanceAttr();
6894 auto target = ns.
lookup(ref);
6896 return emitError() <<
"target " << ref <<
" cannot be resolved";
6898 if (!target.isOpOnly())
6899 return emitError() <<
"target " << ref <<
" is not an operation";
6901 auto instance = dyn_cast<InstanceOp>(target.getOp());
6903 return emitError() <<
"target " << ref <<
" is not an instance";
6905 if (!instance.getDoNotPrint())
6906 return emitError() <<
"target " << ref <<
" is not marked doNotPrint";
6916#define GET_OP_CLASSES
6917#include "circt/Dialect/FIRRTL/FIRRTL.cpp.inc"
static void printNameKind(OpAsmPrinter &p, Operation *op, firrtl::NameKindEnumAttr attr, ArrayRef< StringRef > extraElides={})
static ParseResult parseNameKind(OpAsmParser &parser, firrtl::NameKindEnumAttr &result)
assert(baseType &&"element must be base type")
MlirType uint64_t numElements
static LogicalResult verifyProbeType(RefType refType, Location loc, CircuitOp circuitOp, SymbolTableCollection &symbolTable, Twine start)
static ArrayAttr fixDomainInfoDeletions(MLIRContext *context, ArrayAttr domainInfoAttr, const llvm::BitVector &portIndices, bool supportsEmptyAttr)
static SmallVector< PortInfo > getPortImpl(FModuleLike module)
static void buildClass(OpBuilder &builder, OperationState &result, StringAttr name, ArrayRef< PortInfo > ports)
static void printStopAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
static void buildModule(OpBuilder &builder, OperationState &result, StringAttr name, ArrayRef< PortInfo > ports, ArrayAttr annotations, ArrayAttr layers)
static LayerSet getLayersFor(Value value)
Get the effective layer requirements for the given value.
static SmallVector< hw::PortInfo > getPortListImpl(FModuleLike module)
ParseResult parseSubfieldLikeOp(OpAsmParser &parser, OperationState &result)
static bool isSameIntTypeKind(Type lhs, Type rhs, int32_t &lhsWidth, int32_t &rhsWidth, bool &isConstResult, std::optional< Location > loc)
If LHS and RHS are both UInt or SInt types, the return true and fill in the width of them if known.
static LogicalResult verifySubfieldLike(OpTy op)
static void eraseInternalPaths(T op, const llvm::BitVector &portIndices)
static void printFPrintfAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
static bool isConstFieldDriven(FIRRTLBaseType type, bool isFlip=false, bool outerTypeIsConst=false)
Checks if the type has any 'const' leaf elements .
static ParseResult parsePrintfAttrs(OpAsmParser &p, NamedAttrList &resultAttrs)
static ParseResult parseParameterList(OpAsmParser &parser, ArrayAttr ¶meters)
Shim to use with assemblyFormat, custom<ParameterList>.
static RetTy emitInferRetTypeError(std::optional< Location > loc, const Twine &message, Args &&...args)
Emit an error if optional location is non-null, return null of return type.
static SmallVector< T > removeElementsAtIndices(ArrayRef< T > input, const llvm::BitVector &indicesToDrop)
Remove elements from the input array corresponding to set bits in indicesToDrop, returning the elemen...
static LogicalResult checkLayerCompatibility(Operation *op, const LayerSet &src, const LayerSet &dst, const Twine &errorMsg, const Twine ¬eMsg=Twine("missing layer requirements"))
static ParseResult parseModulePorts(OpAsmParser &parser, bool hasSSAIdentifiers, bool supportsSymbols, bool supportsDomains, SmallVectorImpl< OpAsmParser::Argument > &entryArgs, SmallVectorImpl< Direction > &portDirections, SmallVectorImpl< Attribute > &portNames, SmallVectorImpl< Attribute > &portTypes, SmallVectorImpl< Attribute > &portAnnotations, SmallVectorImpl< Attribute > &portSyms, SmallVectorImpl< Attribute > &portLocs, SmallVectorImpl< Attribute > &domains)
Parse a list of module ports.
static LogicalResult checkConnectConditionality(FConnectLike connect)
Checks that connections to 'const' destinations are not dependent on non-'const' conditions in when b...
static void erasePorts(FModuleLike op, const llvm::BitVector &portIndices)
Erases the ports that have their corresponding bit set in portIndices.
static ParseResult parseClassInterface(OpAsmParser &parser, Type &result)
static void printElidePortAnnotations(OpAsmPrinter &p, Operation *op, DictionaryAttr attr, ArrayRef< StringRef > extraElides={})
static ParseResult parseStopAttrs(OpAsmParser &p, NamedAttrList &resultAttrs)
static ParseResult parseNameKind(OpAsmParser &parser, firrtl::NameKindEnumAttr &result)
A forward declaration for NameKind attribute parser.
static void insertPorts(FModuleLike op, ArrayRef< std::pair< unsigned, PortInfo > > ports, bool supportsInternalPaths=false)
Inserts the given ports.
static size_t getAddressWidth(size_t depth)
static void forceableAsmResultNames(Forceable op, StringRef name, OpAsmSetValueNameFn setNameFn)
Helper for naming forceable declarations (and their optional ref result).
static void printFModuleLikeOp(OpAsmPrinter &p, FModuleLike op)
static void printSubfieldLikeOp(OpTy op, ::mlir::OpAsmPrinter &printer)
static bool checkAggConstant(Operation *op, Attribute attr, FIRRTLBaseType type)
static void printClassLike(OpAsmPrinter &p, ClassLike op)
static hw::ModulePort::Direction dirFtoH(Direction dir)
static ParseResult parseOptionalParameters(OpAsmParser &parser, SmallVectorImpl< Attribute > ¶meters)
Parse an parameter list if present.
static MemOp::PortKind getMemPortKindFromType(FIRRTLType type)
Return the kind of port this is given the port type from a 'mem' decl.
static LogicalResult verifyInternalPaths(FModuleLike op, std::optional<::mlir::ArrayAttr > internalPaths)
static void genericAsmResultNames(Operation *op, OpAsmSetValueNameFn setNameFn)
static void printClassInterface(OpAsmPrinter &p, Operation *, ClassType type)
static void printPrintfAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
const char * toString(Flow flow)
static bool isLayerSetCompatibleWith(const LayerSet &src, const LayerSet &dst, SmallVectorImpl< SymbolRefAttr > &missing)
Check that the source layers are all present in the destination layers.
static bool isLayerCompatibleWith(mlir::SymbolRefAttr srcLayer, mlir::SymbolRefAttr dstLayer)
Check that the source layer is compatible with the destination layer.
static LayerSet getAmbientLayersFor(Value value)
Get the ambient layer requirements at the definition site of the value.
void buildModuleLike(OpBuilder &builder, OperationState &result, StringAttr name, ArrayRef< PortInfo > ports)
static LayerSet getAmbientLayersAt(Operation *op)
Get the ambient layers active at the given op.
static void printFIRRTLImplicitSSAName(OpAsmPrinter &p, Operation *op, DictionaryAttr attrs)
static ParseResult parseFIRRTLImplicitSSAName(OpAsmParser &parser, NamedAttrList &resultAttrs)
static FIRRTLBaseType inferMuxReturnType(FIRRTLBaseType high, FIRRTLBaseType low, bool isConstCondition, std::optional< Location > loc)
Infer the result type for a multiplexer given its two operand types, which may be aggregates.
static ParseResult parseCircuitOpAttrs(OpAsmParser &parser, NamedAttrList &resultAttrs)
void getAsmBlockArgumentNamesImpl(Operation *op, mlir::Region ®ion, OpAsmSetValueNameFn setNameFn)
Get a special name to use when printing the entry block arguments of the region contained by an opera...
static void printElideAnnotations(OpAsmPrinter &p, Operation *op, DictionaryAttr attr, ArrayRef< StringRef > extraElides={})
static ParseResult parseElidePortAnnotations(OpAsmParser &parser, NamedAttrList &resultAttrs)
Parse an optional attribute dictionary, adding empty 'annotations' and 'portAnnotations' attributes i...
static ParseResult parseFPrintfAttrs(OpAsmParser &p, NamedAttrList &resultAttrs)
static ParseResult parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs)
static Attribute fixDomainInfoInsertions(MLIRContext *context, Attribute domainInfoAttr, const SmallVectorImpl< unsigned > &numInserted)
Return an updated domain info Attribute with domain indices updated based on port insertions.
static LogicalResult checkConnectFlow(Operation *connect)
Check if the source and sink are of appropriate flow.
static void printParameterList(OpAsmPrinter &p, Operation *op, ArrayAttr parameters)
Print a paramter list for a module or instance.
static ParseResult parseVerifAttrs(OpAsmParser &p, NamedAttrList &resultAttrs)
static ParseResult parseElideAnnotations(OpAsmParser &parser, NamedAttrList &resultAttrs)
Parse an optional attribute dictionary, adding an empty 'annotations' attribute if not specified.
ParseResult parseClassLike(OpAsmParser &parser, OperationState &result, bool hasSSAIdentifiers)
static void printCircuitOpAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
static LogicalResult verifyPortSymbolUses(FModuleLike module, SymbolTableCollection &symbolTable)
static void printVerifAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
static void printMemOp(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
Always elide "ruw" and elide "annotations" if it exists or if it is empty.
static bool isTypeAllowedForDPI(Operation *op, Type type)
static ParseResult parseElideEmptyName(OpAsmParser &p, NamedAttrList &resultAttrs)
static bool printModulePorts(OpAsmPrinter &p, Block *block, ArrayRef< bool > portDirections, ArrayRef< Attribute > portNames, ArrayRef< Attribute > portTypes, ArrayRef< Attribute > portAnnotations, ArrayRef< Attribute > portSyms, ArrayRef< Attribute > portLocs, ArrayRef< Attribute > domainInfo)
Print a list of module ports in the following form: in x: !firrtl.uint<1> [{class = "DontTouch}],...
static void printElideEmptyName(OpAsmPrinter &p, Operation *op, DictionaryAttr attr, ArrayRef< StringRef > extraElides={})
static ParseResult parseFModuleLikeOp(OpAsmParser &parser, OperationState &result, bool hasSSAIdentifiers)
static bool isAncestor(Block *block, Block *other)
static Location getLoc(DefSlot slot)
static StringAttr append(StringAttr base, const Twine &suffix)
Return a attribute with the specified suffix appended.
static std::optional< APInt > getInt(Value value)
Helper to convert a value to a constant integer if it is one.
static Block * getBodyBlock(FModuleLike mod)
static InstancePath empty
This class represents a reference to a specific field or element of an aggregate value.
Value getValue() const
Get the Value which created this location.
This class provides a read-only projection over the MLIR attributes that represent a set of annotatio...
bool hasDontTouch() const
firrtl.transforms.DontTouchAnnotation
static AnnotationSet forPort(FModuleLike op, size_t portNo)
Get an annotation set for the specified port.
ExprVisitor is a visitor for FIRRTL expression nodes.
ResultType dispatchExprVisitor(Operation *op, ExtraArgs... args)
FIRRTLBaseType getConstType(bool isConst) const
Return a 'const' or non-'const' version of this type.
FIRRTLBaseType getMaskType()
Return this type with all ground types replaced with UInt<1>.
int32_t getBitWidthOrSentinel()
If this is an IntType, AnalogType, or sugar type for a single bit (Clock, Reset, etc) then return the...
FIRRTLBaseType getAllConstDroppedType()
Return this type with a 'const' modifiers dropped.
bool isPassive() const
Return true if this is a "passive" type - one that contains no "flip" types recursively within itself...
bool isConst() const
Returns true if this is a 'const' type that can only hold compile-time constant values.
bool isConst() const
Returns true if this is a 'const' type that can only hold compile-time constant values.
Caching version of getFieldRefFromValue.
FieldRef getFieldRefFromValue(Value value, bool lookThroughCasts=false)
Caching version of getFieldRefFromValue.
This is the common base class between SIntType and UIntType.
int32_t getWidthOrSentinel() const
Return the width of this type, or -1 if it has none specified.
static IntType get(MLIRContext *context, bool isSigned, int32_t widthOrSentinel=-1, bool isConst=false)
Return an SIntType or UIntType with the specified signedness, width, and constness.
bool hasWidth() const
Return true if this integer type has a known width.
std::optional< int32_t > getWidth() const
Return an optional containing the width, if the width is known (or empty if width is unknown).
static StringRef getInnerSymbolAttrName()
Return the name of the attribute used for inner symbol names.
int main(int argc, char **argv)
connect(destination, source)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
ClassType getInstanceTypeForClassLike(ClassLike classOp)
LogicalResult verifyTypeAgainstClassLike(ClassLike classOp, ClassType type, function_ref< InFlightDiagnostic()> emitError)
Assuming that the classOp is the source of truth, verify that the type accurately matches the signatu...
RefType getForceableResultType(bool forceable, Type type)
Return null or forceable reference result type.
mlir::DenseBoolArrayAttr packAttribute(MLIRContext *context, ArrayRef< Direction > directions)
Return a DenseBoolArrayAttr containing the packed representation of an array of directions.
static bool unGet(Direction dir)
Convert from Direction to bool. The opposite of get;.
SmallVector< Direction > unpackAttribute(mlir::DenseBoolArrayAttr directions)
Turn a packed representation of port attributes into a vector that can be worked with.
static Direction get(bool isOutput)
Return an output direction if isOutput is true, otherwise return an input direction.
static StringRef toString(Direction direction)
FIRRTLType inferElementwiseResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
FIRRTLType inferBitwiseResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
FIRRTLType inferAddSubResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
FIRRTLType inferComparisonResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
FIRRTLType inferReductionResult(FIRRTLType arg, std::optional< Location > loc)
LogicalResult verifySameOperandsIntTypeKind(Operation *op)
LogicalResult verifyReferencedModule(Operation *instanceOp, SymbolTableCollection &symbolTable, mlir::FlatSymbolRefAttr moduleName)
Verify that the instance refers to a valid FIRRTL module.
BaseTy type_cast(Type type)
Flow swapFlow(Flow flow)
Get a flow's reverse.
Direction
This represents the direction of a single port.
FieldRef getFieldRefFromValue(Value value, bool lookThroughCasts=false)
Get the FieldRef from a value.
void walkGroundTypes(FIRRTLType firrtlType, llvm::function_ref< void(uint64_t, FIRRTLBaseType, bool)> fn)
Walk leaf ground types in the firrtlType and apply the function fn.
bool isConstant(Operation *op)
Return true if the specified operation has a constant value.
bool areAnonymousTypesEquivalent(FIRRTLBaseType lhs, FIRRTLBaseType rhs)
Return true if anonymous types of given arguments are equivalent by pointer comparison.
constexpr bool isValidDst(Flow flow)
Flow foldFlow(Value val, Flow accumulatedFlow=Flow::Source)
Compute the flow for a Value, val, as determined by the FIRRTL specification.
constexpr const char * dutAnnoClass
bool areTypesEquivalent(FIRRTLType destType, FIRRTLType srcType, bool destOuterTypeIsConst=false, bool srcOuterTypeIsConst=false, bool requireSameWidths=false)
Returns whether the two types are equivalent.
bool hasDontTouch(Value value)
Check whether a block argument ("port") or the operation defining a value has a DontTouch annotation,...
size_t getNumPorts(Operation *op)
Return the number of ports in a module-like thing (modules, memories, etc)
mlir::Type getPassiveType(mlir::Type anyBaseFIRRTLType)
bool isTypeLarger(FIRRTLBaseType dstType, FIRRTLBaseType srcType)
Returns true if the destination is at least as wide as a source.
bool containsConst(Type type)
Returns true if the type is or contains a 'const' type whose value is guaranteed to be unchanging at ...
bool isDuplexValue(Value val)
Returns true if the value results from an expression with duplex flow.
SmallSet< SymbolRefAttr, 4, LayerSetCompare > LayerSet
constexpr bool isValidSrc(Flow flow)
Value getModuleScopedDriver(Value val, bool lookThroughWires, bool lookThroughNodes, bool lookThroughCasts)
Return the value that drives another FIRRTL value within module scope.
std::pair< std::string, bool > getFieldName(const FieldRef &fieldRef, bool nameSafe=false)
Get a string identifier representing the FieldRef.
BaseTy type_dyn_cast(Type type)
bool isConst(Type type)
Returns true if this is a 'const' type whose value is guaranteed to be unchanging at circuit executio...
bool areTypesConstCastable(FIRRTLType destType, FIRRTLType srcType, bool srcOuterTypeIsConst=false)
Returns whether the srcType can be const-casted to the destType.
bool isExpression(Operation *op)
Return true if the specified operation is a firrtl expression.
DeclKind getDeclarationKind(Value val)
std::optional< int64_t > getBitWidth(FIRRTLBaseType type, bool ignoreFlip=false)
::mlir::Type getFinalTypeByFieldID(Type type, uint64_t fieldID)
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
int64_t getBitWidth(mlir::Type type)
Return the hardware bit width of a type.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
void elideImplicitSSAName(OpAsmPrinter &printer, Operation *op, DictionaryAttr attrs, SmallVectorImpl< StringRef > &elides)
Check if the name attribute in attrs matches the SSA name of the operation's first result.
bool isAncestorOfValueOwner(Operation *op, Value value)
Return true if a Value is created "underneath" an operation.
bool inferImplicitSSAName(OpAsmParser &parser, NamedAttrList &attrs)
Ensure that attrs contains a name attribute by inferring its value from the SSA name of the operation...
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn
StringAttr getFirMemoryName() const
Compares two SymbolRefAttr lexicographically, returning true if LHS should be ordered before RHS.
This class represents the namespace in which InnerRef's can be resolved.
InnerSymTarget lookup(hw::InnerRefAttr inner) const
Resolve the InnerRef to its target within this namespace, returning empty target if no such name exis...
This holds the name, type, direction of a module's ports.