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) {
757 Attribute domainInfoAttr,
758 ArrayRef<unsigned> indexMap) {
760 auto di = dyn_cast_or_null<ArrayAttr>(domainInfoAttr);
761 if (!di || di.empty())
762 return domainInfoAttr;
765 SmallVector<Attribute> domainInfo;
766 for (
auto attr : di) {
767 auto oldIdx = cast<IntegerAttr>(attr).getUInt();
768 auto newIdx = indexMap[oldIdx];
769 if (oldIdx == newIdx)
770 domainInfo.push_back(attr);
772 domainInfo.push_back(IntegerAttr::get(
773 IntegerType::get(context, 32, IntegerType::Unsigned), newIdx));
775 return ArrayAttr::get(context, domainInfo);
782 ArrayRef<std::pair<unsigned, PortInfo>> ports) {
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);
798 SmallVector<bool> newDirections;
799 SmallVector<Attribute> newNames, newTypes, newDomains, newAnnos, newSyms,
801 newDirections.reserve(newNumArgs);
802 newNames.reserve(newNumArgs);
803 newTypes.reserve(newNumArgs);
804 newDomains.reserve(newNumArgs);
805 newAnnos.reserve(newNumArgs);
806 newSyms.reserve(newNumArgs);
807 newLocs.reserve(newNumArgs);
809 SmallVector<unsigned> indexMap(oldNumArgs);
811 auto emptyArray = ArrayAttr::get(op.getContext(), {});
814 unsigned inserted = 0;
815 auto migrateOldPorts = [&](
unsigned untilOldIdx) {
816 while (oldIdx < oldNumArgs && oldIdx < untilOldIdx) {
817 newDirections.push_back(existingDirections[oldIdx]);
818 newNames.push_back(existingNames[oldIdx]);
819 newTypes.push_back(existingTypes[oldIdx]);
821 op.getContext(), op.getDomainInfoAttrForPort(oldIdx), indexMap));
822 newAnnos.push_back(op.getAnnotationsAttrForPort(oldIdx));
823 newSyms.push_back(op.getPortSymbolAttr(oldIdx));
824 newLocs.push_back(existingLocs[oldIdx]);
826 indexMap[oldIdx] = oldIdx + inserted;
831 for (
auto [idx, port] : ports) {
832 migrateOldPorts(idx);
834 newNames.push_back(port.name);
835 newTypes.push_back(TypeAttr::get(port.type));
838 port.domains ? port.domains : ArrayAttr::get(op.getContext(), {}),
840 auto annos = port.annotations.getArrayAttr();
841 newAnnos.push_back(annos ? annos : emptyArray);
842 newSyms.push_back(port.sym);
843 newLocs.push_back(port.loc);
846 migrateOldPorts(oldNumArgs);
850 if (llvm::all_of(newAnnos, [](Attribute attr) {
851 return cast<ArrayAttr>(attr).empty();
857 if (llvm::all_of(newDomains, [](Attribute attr) {
860 if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr))
861 return arrayAttr.empty();
867 op->setAttr(
"portDirections",
869 op->setAttr(
"portNames", ArrayAttr::get(op.getContext(), newNames));
870 op->setAttr(
"portTypes", ArrayAttr::get(op.getContext(), newTypes));
871 op->setAttr(
"domainInfo", ArrayAttr::get(op.getContext(), newDomains));
872 op->setAttr(
"portAnnotations", ArrayAttr::get(op.getContext(), newAnnos));
873 FModuleLike::fixupPortSymsArray(newSyms, op.getContext());
874 op.setPortSymbols(newSyms);
875 op->setAttr(
"portLocations", ArrayAttr::get(op.getContext(), newLocs));
886 ArrayAttr domainInfoAttr,
887 const llvm::BitVector &portIndices,
888 bool supportsEmptyAttr) {
889 if (supportsEmptyAttr && domainInfoAttr.empty())
890 return domainInfoAttr;
894 SmallVector<unsigned> numDeleted;
895 numDeleted.resize(portIndices.size());
896 size_t deletionIndex = portIndices.find_first();
897 for (
size_t i = 0, e = portIndices.size(); i != e; ++i) {
898 if (i == deletionIndex) {
902 numDeleted[i] = numDeleted[i - 1] + 1;
903 deletionIndex = portIndices.find_next(i);
909 numDeleted[i] = numDeleted[i - 1];
914 auto getEmpty = [&]() {
916 eEmpty = ArrayAttr::get(context, {});
921 SmallVector<Attribute> newDomainInfo;
922 newDomainInfo.reserve(portIndices.size() - portIndices.count());
923 for (
size_t i = 0, e = portIndices.size(); i != e; ++i) {
925 if (portIndices.test(i))
928 if (domainInfoAttr.empty()) {
929 newDomainInfo.push_back(getEmpty());
932 auto attr = domainInfoAttr[i];
934 auto domains = dyn_cast<ArrayAttr>(attr);
935 if (!domains || domains.empty()) {
936 newDomainInfo.push_back(attr);
940 SmallVector<Attribute> newDomains;
941 for (
auto domain : domains) {
943 auto oldIdx = cast<IntegerAttr>(domain).getUInt();
944 if (portIndices.test(oldIdx))
947 auto newIdx = oldIdx - numDeleted[oldIdx];
948 if (oldIdx == newIdx) {
949 newDomainInfo.push_back(attr);
953 newDomains.push_back(IntegerAttr::get(
954 IntegerType::get(context, 32, IntegerType::Unsigned), newIdx));
956 newDomainInfo.push_back(ArrayAttr::get(context, newDomains));
959 return ArrayAttr::get(context, newDomainInfo);
963static void erasePorts(FModuleLike op,
const llvm::BitVector &portIndices) {
964 if (portIndices.none())
968 ArrayRef<bool> portDirections = op.getPortDirectionsAttr().asArrayRef();
969 ArrayRef<Attribute> portNames = op.getPortNames();
970 ArrayRef<Attribute> portTypes = op.getPortTypes();
971 ArrayRef<Attribute> portAnnos = op.getPortAnnotations();
972 ArrayRef<Attribute> portSyms = op.getPortSymbols();
973 ArrayRef<Attribute> portLocs = op.getPortLocations();
974 ArrayRef<Attribute> portDomains = op.getDomainInfo();
975 auto numPorts = op.getNumPorts();
977 assert(portDirections.size() == numPorts);
978 assert(portNames.size() == numPorts);
979 assert(portAnnos.size() == numPorts || portAnnos.empty());
980 assert(portTypes.size() == numPorts);
981 assert(portSyms.size() == numPorts || portSyms.empty());
982 assert(portLocs.size() == numPorts);
983 assert(portDomains.size() == numPorts || portDomains.empty());
985 SmallVector<bool> newPortDirections =
986 removeElementsAtIndices<bool>(portDirections, portIndices);
987 SmallVector<Attribute> newPortNames, newPortTypes, newPortAnnos, newPortSyms,
995 op->setAttr(
"portDirections",
997 op->setAttr(
"portNames", ArrayAttr::get(op.getContext(), newPortNames));
998 op->setAttr(
"portAnnotations", ArrayAttr::get(op.getContext(), newPortAnnos));
999 op->setAttr(
"portTypes", ArrayAttr::get(op.getContext(), newPortTypes));
1000 FModuleLike::fixupPortSymsArray(newPortSyms, op.getContext());
1001 op->setAttr(
"portSymbols", ArrayAttr::get(op.getContext(), newPortSyms));
1002 op->setAttr(
"portLocations", ArrayAttr::get(op.getContext(), newPortLocs));
1003 op->setAttr(
"domainInfo",
1005 portIndices,
true));
1008void FExtModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1009 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1012void FIntModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1013 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1016void FMemModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1017 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1020void FModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1021 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1028void FModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1029 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1033 for (
size_t i = 0, e = ports.size(); i < e; ++i) {
1036 auto &[index, port] = ports[i];
1037 body->insertArgument(index + i, port.type, port.loc);
1041void FExtModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1042 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1045void FIntModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1046 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1052void FMemModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1053 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1056template <
typename OpTy>
1058 StringAttr name, ArrayRef<PortInfo> ports) {
1060 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
1061 properties.setSymName(name);
1064 SmallVector<Direction, 4> portDirections;
1065 SmallVector<Attribute, 4> portNames;
1066 SmallVector<Attribute, 4> portTypes;
1067 SmallVector<Attribute, 4> portSyms;
1068 SmallVector<Attribute, 4> portLocs;
1069 SmallVector<Attribute, 4> portDomains;
1070 for (
const auto &port : ports) {
1071 portDirections.push_back(port.direction);
1072 portNames.push_back(port.name);
1073 portTypes.push_back(TypeAttr::get(port.type));
1074 portSyms.push_back(port.sym);
1075 portLocs.push_back(port.loc);
1076 portDomains.push_back(port.domains);
1078 if (llvm::all_of(portDomains, [](Attribute attr) {
1081 if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr))
1082 return arrayAttr.empty();
1085 portDomains.clear();
1087 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1090 properties.setPortDirections(
1092 properties.setPortNames(builder.getArrayAttr(portNames));
1093 properties.setPortTypes(builder.getArrayAttr(portTypes));
1094 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1095 properties.setPortLocations(builder.getArrayAttr(portLocs));
1096 properties.setDomainInfo(builder.getArrayAttr(portDomains));
1101template <
typename OpTy>
1103 StringAttr name, ArrayRef<PortInfo> ports,
1104 ArrayAttr annotations, ArrayAttr layers) {
1105 buildModuleLike<OpTy>(builder, result, name, ports);
1106 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
1109 annotations = builder.getArrayAttr({});
1110 properties.setAnnotations(annotations);
1114 SmallVector<Attribute, 4> portAnnotations;
1115 for (
const auto &port : ports)
1116 portAnnotations.push_back(port.annotations.getArrayAttr());
1117 if (llvm::all_of(portAnnotations, [](Attribute attr) {
1118 return cast<ArrayAttr>(attr).empty();
1120 portAnnotations.clear();
1121 properties.setPortAnnotations(builder.getArrayAttr(portAnnotations));
1125 layers = builder.getArrayAttr({});
1126 properties.setLayers(layers);
1129template <
typename OpTy>
1130static void buildClass(OpBuilder &builder, OperationState &result,
1131 StringAttr name, ArrayRef<PortInfo> ports) {
1132 return buildModuleLike<OpTy>(builder, result, name, ports);
1135void FModuleOp::build(OpBuilder &builder, OperationState &result,
1136 StringAttr name, ConventionAttr convention,
1137 ArrayRef<PortInfo> ports, ArrayAttr annotations,
1139 buildModule<FModuleOp>(builder, result, name, ports, annotations, layers);
1140 auto &properties = result.getOrAddProperties<Properties>();
1141 properties.setConvention(convention);
1144 auto *bodyRegion = result.regions[0].get();
1146 bodyRegion->push_back(body);
1149 for (
auto &elt : ports)
1150 body->addArgument(elt.type, elt.loc);
1153void FExtModuleOp::build(OpBuilder &builder, OperationState &result,
1154 StringAttr name, ConventionAttr convention,
1155 ArrayRef<PortInfo> ports, ArrayAttr knownLayers,
1156 StringRef defnameAttr, ArrayAttr annotations,
1157 ArrayAttr parameters, ArrayAttr layers) {
1158 buildModule<FExtModuleOp>(builder, result, name, ports, annotations, layers);
1159 auto &properties = result.getOrAddProperties<Properties>();
1160 properties.setConvention(convention);
1162 knownLayers = builder.getArrayAttr({});
1163 properties.setKnownLayers(knownLayers);
1164 if (!defnameAttr.empty())
1165 properties.setDefname(builder.getStringAttr(defnameAttr));
1167 parameters = builder.getArrayAttr({});
1168 properties.setParameters(parameters);
1171void FIntModuleOp::build(OpBuilder &builder, OperationState &result,
1172 StringAttr name, ArrayRef<PortInfo> ports,
1173 StringRef intrinsicNameStr, ArrayAttr annotations,
1174 ArrayAttr parameters, ArrayAttr layers) {
1175 buildModule<FIntModuleOp>(builder, result, name, ports, annotations, layers);
1176 auto &properties = result.getOrAddProperties<Properties>();
1177 properties.setIntrinsic(builder.getStringAttr(intrinsicNameStr));
1179 parameters = builder.getArrayAttr({});
1180 properties.setParameters(parameters);
1183void FMemModuleOp::build(OpBuilder &builder, OperationState &result,
1184 StringAttr name, ArrayRef<PortInfo> ports,
1185 uint32_t numReadPorts, uint32_t numWritePorts,
1186 uint32_t numReadWritePorts, uint32_t dataWidth,
1187 uint32_t maskBits, uint32_t readLatency,
1188 uint32_t writeLatency, uint64_t depth, RUWBehavior ruw,
1189 ArrayAttr annotations, ArrayAttr layers) {
1190 auto *context = builder.getContext();
1191 buildModule<FMemModuleOp>(builder, result, name, ports, annotations, layers);
1192 auto ui32Type = IntegerType::get(context, 32, IntegerType::Unsigned);
1193 auto ui64Type = IntegerType::get(context, 64, IntegerType::Unsigned);
1194 auto &properties = result.getOrAddProperties<Properties>();
1195 properties.setNumReadPorts(IntegerAttr::get(ui32Type, numReadPorts));
1196 properties.setNumWritePorts(IntegerAttr::get(ui32Type, numWritePorts));
1197 properties.setNumReadWritePorts(
1198 IntegerAttr::get(ui32Type, numReadWritePorts));
1199 properties.setDataWidth(IntegerAttr::get(ui32Type, dataWidth));
1200 properties.setMaskBits(IntegerAttr::get(ui32Type, maskBits));
1201 properties.setReadLatency(IntegerAttr::get(ui32Type, readLatency));
1202 properties.setWriteLatency(IntegerAttr::get(ui32Type, writeLatency));
1203 properties.setDepth(IntegerAttr::get(ui64Type, depth));
1204 properties.setExtraPorts(ArrayAttr::get(context, {}));
1205 properties.setRuw(RUWBehaviorAttr::get(context, ruw));
1222 ArrayRef<Attribute> portNames, ArrayRef<Attribute> portTypes,
1223 ArrayRef<Attribute> portAnnotations,
1224 ArrayRef<Attribute> portSyms, ArrayRef<Attribute> portLocs,
1225 ArrayRef<Attribute> domainInfo) {
1228 bool printedNamesDontMatch =
false;
1230 mlir::OpPrintingFlags flags;
1234 SmallString<32> resultNameStr;
1235 DenseMap<unsigned, std::string> domainPortNames;
1237 for (
unsigned i = 0, e = portTypes.size(); i < e; ++i) {
1246 auto portType = cast<TypeAttr>(portTypes[i]).getValue();
1249 resultNameStr.clear();
1250 llvm::raw_svector_ostream tmpStream(resultNameStr);
1251 p.printOperand(block->getArgument(i), tmpStream);
1254 auto portName = cast<StringAttr>(portNames[i]).getValue();
1255 if (tmpStream.str().drop_front() != portName)
1256 printedNamesDontMatch =
true;
1257 p << tmpStream.str();
1258 if (isa<DomainType>(portType))
1259 domainPortNames[i] = tmpStream.str();
1261 auto name = cast<StringAttr>(portNames[i]).getValue();
1262 p.printKeywordOrString(name);
1263 if (isa<DomainType>(portType))
1264 domainPortNames[i] = name.str();
1269 p.printType(portType);
1272 if (!portSyms.empty()) {
1273 if (!cast<hw::InnerSymAttr>(portSyms[i]).
empty()) {
1275 cast<hw::InnerSymAttr>(portSyms[i]).print(p);
1280 if (!domainInfo.empty()) {
1281 if (
auto domainKind = dyn_cast<FlatSymbolRefAttr>(domainInfo[i])) {
1282 p <<
" of " << domainKind;
1284 auto domains = cast<ArrayAttr>(domainInfo[i]);
1285 if (!domains.empty()) {
1287 llvm::interleaveComma(domains, p, [&](Attribute attr) {
1288 p << domainPortNames[cast<IntegerAttr>(attr).getUInt()];
1297 if (!portAnnotations.empty() &&
1298 !cast<ArrayAttr>(portAnnotations[i]).empty()) {
1300 p.printAttribute(portAnnotations[i]);
1307 if (flags.shouldPrintDebugInfo() && !portLocs.empty())
1308 p.printOptionalLocationSpecifier(cast<LocationAttr>(portLocs[i]));
1312 return printedNamesDontMatch;
1318 OpAsmParser &parser,
bool hasSSAIdentifiers,
bool supportsSymbols,
1319 bool supportsDomains, SmallVectorImpl<OpAsmParser::Argument> &entryArgs,
1320 SmallVectorImpl<Direction> &portDirections,
1321 SmallVectorImpl<Attribute> &portNames,
1322 SmallVectorImpl<Attribute> &portTypes,
1323 SmallVectorImpl<Attribute> &portAnnotations,
1324 SmallVectorImpl<Attribute> &portSyms, SmallVectorImpl<Attribute> &portLocs,
1325 SmallVectorImpl<Attribute> &domains) {
1326 auto *context = parser.getContext();
1329 DenseMap<Attribute, size_t> domainIndex;
1331 auto parseArgument = [&]() -> ParseResult {
1333 if (succeeded(parser.parseOptionalKeyword(
"out")))
1334 portDirections.push_back(Direction::Out);
1335 else if (succeeded(parser.parseKeyword(
"in",
" or 'out'")))
1336 portDirections.push_back(Direction::In);
1344 if (hasSSAIdentifiers) {
1345 OpAsmParser::Argument arg;
1346 if (parser.parseArgument(arg))
1348 entryArgs.push_back(arg);
1352 assert(arg.ssaName.name.size() > 1 && arg.ssaName.name[0] ==
'%' &&
1353 "Unknown MLIR name");
1354 if (
isdigit(arg.ssaName.name[1]))
1355 portNames.push_back(StringAttr::get(context,
""));
1357 portNames.push_back(
1358 StringAttr::get(context, arg.ssaName.name.drop_front()));
1361 irLoc = arg.ssaName.location;
1365 irLoc = parser.getCurrentLocation();
1366 std::string portName;
1367 if (parser.parseKeywordOrString(&portName))
1369 portNames.push_back(StringAttr::get(context, portName));
1374 if (parser.parseColonType(portType))
1376 portTypes.push_back(TypeAttr::get(portType));
1377 if (isa<DomainType>(portType))
1378 domainIndex[portNames.back()] = portNames.size() - 1;
1380 if (hasSSAIdentifiers)
1381 entryArgs.back().type = portType;
1384 if (supportsSymbols) {
1385 hw::InnerSymAttr innerSymAttr;
1386 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
1387 NamedAttrList dummyAttrs;
1388 if (parser.parseCustomAttributeWithFallback(
1389 innerSymAttr, ::mlir::Type{},
1391 return ::mlir::failure();
1394 portSyms.push_back(innerSymAttr);
1398 Attribute domainsAttr;
1399 SmallVector<Attribute> portDomains;
1400 if (supportsDomains) {
1401 if (isa<DomainType>(portType)) {
1402 if (parser.parseKeyword(
"of"))
1404 StringAttr domainKind;
1405 if (parser.parseSymbolName(domainKind))
1407 domainsAttr = FlatSymbolRefAttr::get(context, domainKind);
1408 }
else if (succeeded(parser.parseOptionalKeyword(
"domains"))) {
1409 auto result = parser.parseCommaSeparatedList(
1410 OpAsmParser::Delimiter::Square, [&]() -> ParseResult {
1412 if (hasSSAIdentifiers) {
1413 OpAsmParser::Argument arg;
1414 if (parser.parseArgument(arg))
1417 StringAttr::get(context, arg.ssaName.name.drop_front());
1419 std::string portName;
1420 if (parser.parseKeywordOrString(&portName))
1422 argName = StringAttr::get(context, portName);
1425 auto index = domainIndex.find(argName);
1426 if (index == domainIndex.end()) {
1427 parser.emitError(irLoc)
1428 <<
"domain name '" << argName <<
"' not found";
1431 portDomains.push_back(IntegerAttr::get(
1432 IntegerType::get(context, 32, IntegerType::Unsigned),
1438 domainsAttr = parser.getBuilder().getArrayAttr(portDomains);
1442 domainsAttr = parser.getBuilder().getArrayAttr({});
1443 domains.push_back(domainsAttr);
1447 auto parseResult = parser.parseOptionalAttribute(annos);
1448 if (!parseResult.has_value())
1449 annos = parser.getBuilder().getArrayAttr({});
1450 else if (failed(*parseResult))
1452 portAnnotations.push_back(annos);
1455 std::optional<Location> maybeLoc;
1456 if (failed(parser.parseOptionalLocationSpecifier(maybeLoc)))
1458 Location loc = maybeLoc ? *maybeLoc : parser.getEncodedSourceLoc(irLoc);
1459 portLocs.push_back(loc);
1460 if (hasSSAIdentifiers)
1461 entryArgs.back().sourceLoc = loc;
1467 return parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
1473 ArrayAttr parameters) {
1474 if (!parameters || parameters.empty())
1478 llvm::interleaveComma(parameters, p, [&](Attribute param) {
1479 auto paramAttr = cast<ParamDeclAttr>(param);
1480 p << paramAttr.getName().getValue() <<
": " << paramAttr.getType();
1481 if (
auto value = paramAttr.getValue()) {
1483 p.printAttributeWithoutType(value);
1493 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
1494 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
1495 p << visibility.getValue() <<
' ';
1498 p.printSymbolName(op.getModuleName());
1505 Block *body =
nullptr;
1506 if (!op->getRegion(0).empty())
1507 body = &op->getRegion(0).front();
1510 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
1511 op.getPortAnnotations(), op.getPortSymbols(), op.getPortLocations(),
1512 op.getDomainInfo());
1514 SmallVector<StringRef, 13> omittedAttrs = {
1515 "sym_name",
"portDirections",
"portTypes",
1516 "portAnnotations",
"portSymbols",
"portLocations",
1517 "parameters", visibilityAttrName,
"domainInfo"};
1519 if (op.getConvention() == Convention::Internal)
1520 omittedAttrs.push_back(
"convention");
1524 if (!needPortNamesAttr)
1525 omittedAttrs.push_back(
"portNames");
1528 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
1529 omittedAttrs.push_back(
"annotations");
1532 if (
auto knownLayers = op->getAttrOfType<ArrayAttr>(
"knownLayers"))
1533 if (knownLayers.empty())
1534 omittedAttrs.push_back(
"knownLayers");
1537 if (
auto layers = op->getAttrOfType<ArrayAttr>(
"layers"))
1539 omittedAttrs.push_back(
"layers");
1541 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
1550void FModuleOp::print(OpAsmPrinter &p) {
1556 Region &fbody = getBody();
1557 if (!fbody.empty()) {
1559 p.printRegion(fbody,
false,
1571 SmallVectorImpl<Attribute> ¶meters) {
1573 return parser.parseCommaSeparatedList(
1574 OpAsmParser::Delimiter::OptionalLessGreater, [&]() {
1579 if (parser.parseKeywordOrString(&name) || parser.parseColonType(type))
1583 if (succeeded(parser.parseOptionalEqual())) {
1584 if (parser.parseAttribute(value, type))
1588 auto &builder = parser.getBuilder();
1589 parameters.push_back(ParamDeclAttr::get(
1590 builder.getContext(), builder.getStringAttr(name), type, value));
1597 ArrayAttr ¶meters) {
1598 SmallVector<Attribute> parseParameters;
1602 parameters = ArrayAttr::get(parser.getContext(), parseParameters);
1607template <
typename Properties,
typename =
void>
1610template <
typename Properties>
1612 Properties, std::void_t<decltype(std::declval<Properties>().parameters)>>
1613 : std::true_type {};
1615template <
typename OpTy>
1617 OperationState &result,
1618 bool hasSSAIdentifiers) {
1619 auto *context = result.getContext();
1620 auto &builder = parser.getBuilder();
1621 using Properties =
typename OpTy::Properties;
1622 auto &properties = result.getOrAddProperties<Properties>();
1626 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
1629 StringAttr nameAttr;
1630 if (parser.parseSymbolName(nameAttr))
1632 properties.setSymName(nameAttr);
1636 SmallVector<Attribute, 4> parameters;
1639 properties.setParameters(builder.getArrayAttr(parameters));
1643 SmallVector<OpAsmParser::Argument> entryArgs;
1644 SmallVector<Direction, 4> portDirections;
1645 SmallVector<Attribute, 4> portNames;
1646 SmallVector<Attribute, 4> portTypes;
1647 SmallVector<Attribute, 4> portAnnotations;
1648 SmallVector<Attribute, 4> portSyms;
1649 SmallVector<Attribute, 4> portLocs;
1650 SmallVector<Attribute, 4> domains;
1652 true, entryArgs, portDirections,
1653 portNames, portTypes, portAnnotations, portSyms,
1658 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
1661 assert(portNames.size() == portTypes.size());
1667 properties.setPortDirections(
1671 properties.setPortNames(builder.getArrayAttr(portNames));
1674 properties.setPortTypes(ArrayAttr::get(context, portTypes));
1678 if (llvm::any_of(portAnnotations, [&](Attribute anno) {
1679 return !cast<ArrayAttr>(anno).empty();
1681 properties.setPortAnnotations(ArrayAttr::get(context, portAnnotations));
1683 properties.setPortAnnotations(builder.getArrayAttr({}));
1686 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1687 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1690 properties.setPortLocations(ArrayAttr::get(context, portLocs));
1693 properties.setAnnotations(builder.getArrayAttr({}));
1696 if (llvm::all_of(domains, [&](Attribute attr) {
1697 auto arrayAttr = dyn_cast<ArrayAttr>(attr);
1698 return arrayAttr && arrayAttr.empty();
1700 properties.setDomainInfo(ArrayAttr::get(context, {}));
1702 properties.setDomainInfo(ArrayAttr::get(context, domains));
1705 auto *body = result.addRegion();
1707 if (hasSSAIdentifiers) {
1708 if (parser.parseRegion(*body, entryArgs))
1711 body->push_back(
new Block());
1716ParseResult FModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1717 if (parseFModuleLikeOp<FModuleOp>(parser, result,
1720 auto &properties = result.getOrAddProperties<Properties>();
1721 properties.setConvention(
1722 ConventionAttr::get(result.getContext(), Convention::Internal));
1723 properties.setLayers(ArrayAttr::get(parser.getContext(), {}));
1727ParseResult FExtModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1728 if (parseFModuleLikeOp<FExtModuleOp>(parser, result,
1731 auto &properties = result.getOrAddProperties<Properties>();
1732 properties.setConvention(
1733 ConventionAttr::get(result.getContext(), Convention::Internal));
1734 properties.setKnownLayers(ArrayAttr::get(result.getContext(), {}));
1738ParseResult FIntModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1739 return parseFModuleLikeOp<FIntModuleOp>(parser, result,
1743ParseResult FMemModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1744 return parseFModuleLikeOp<FMemModuleOp>(parser, result,
1748LogicalResult FModuleOp::verify() {
1751 auto portTypes = getPortTypes();
1752 auto portLocs = getPortLocations();
1753 auto numPorts = portTypes.size();
1756 if (body->getNumArguments() != numPorts)
1757 return emitOpError(
"entry block must have ")
1758 << numPorts <<
" arguments to match module signature";
1761 for (
auto [arg, type, loc] : zip(body->getArguments(), portTypes, portLocs)) {
1762 if (arg.getType() != cast<TypeAttr>(type).getValue())
1763 return emitOpError(
"block argument types should match signature types");
1764 if (arg.getLoc() != cast<LocationAttr>(loc))
1766 "block argument locations should match signature locations");
1772LogicalResult FExtModuleOp::verify() {
1773 auto params = getParameters();
1775 auto checkParmValue = [&](Attribute elt) ->
bool {
1776 auto param = cast<ParamDeclAttr>(elt);
1777 auto value = param.getValue();
1778 if (isa<IntegerAttr, StringAttr, FloatAttr, hw::ParamVerbatimAttr>(value))
1780 emitError() <<
"has unknown extmodule parameter value '"
1781 << param.getName().getValue() <<
"' = " << value;
1785 if (!llvm::all_of(params, checkParmValue))
1790 known.insert_range(getKnownLayersAttr().getAsRange<SymbolRefAttr>());
1793 referenced.insert_range(getLayersAttr().getAsRange<SymbolRefAttr>());
1794 for (
auto attr : getPortTypes()) {
1795 auto type = cast<TypeAttr>(attr).getValue();
1796 if (
auto refType = type_dyn_cast<RefType>(type))
1797 if (
auto layer = refType.getLayer())
1798 referenced.insert(layer);
1802 "references unknown layers",
"unknown layers");
1805LogicalResult FIntModuleOp::verify() {
1806 auto params = getParameters();
1810 auto checkParmValue = [&](Attribute elt) ->
bool {
1811 auto param = cast<ParamDeclAttr>(elt);
1812 auto value = param.getValue();
1813 if (isa<IntegerAttr, StringAttr, FloatAttr>(value))
1815 emitError() <<
"has unknown intmodule parameter value '"
1816 << param.getName().getValue() <<
"' = " << value;
1820 if (!llvm::all_of(params, checkParmValue))
1827 CircuitOp circuitOp,
1828 SymbolTableCollection &symbolTable,
1830 auto layer = refType.getLayer();
1833 auto *layerOp = symbolTable.lookupSymbolIn(circuitOp, layer);
1835 return emitError(loc) << start <<
" associated with layer '" << layer
1836 <<
"', but this layer was not defined";
1837 if (!isa<LayerOp>(layerOp)) {
1838 auto diag = emitError(loc)
1839 << start <<
" associated with layer '" << layer
1840 <<
"', but symbol '" << layer <<
"' does not refer to a '"
1841 << LayerOp::getOperationName() <<
"' op";
1842 return diag.attachNote(layerOp->getLoc()) <<
"symbol refers to this op";
1848 SymbolTableCollection &symbolTable) {
1850 auto circuitOp =
module->getParentOfType<CircuitOp>();
1851 for (
size_t i = 0, e = module.getNumPorts(); i < e; ++i) {
1852 auto type =
module.getPortType(i);
1854 if (
auto refType = type_dyn_cast<RefType>(type)) {
1856 refType, module.getPortLocation(i), circuitOp, symbolTable,
1857 Twine(
"probe port '") + module.getPortName(i) +
"' is")))
1862 if (
auto classType = dyn_cast<ClassType>(type)) {
1863 auto className = classType.getNameAttr();
1864 auto classOp = dyn_cast_or_null<ClassLike>(
1865 symbolTable.lookupSymbolIn(circuitOp, className));
1867 return module.emitOpError() << "references unknown class " << className;
1870 if (failed(classOp.verifyType(classType,
1871 [&]() { return module.emitOpError(); })))
1876 if (isa<DomainType>(type)) {
1877 auto domainInfo =
module.getDomainInfoAttrForPort(i);
1878 if (
auto kind = dyn_cast<FlatSymbolRefAttr>(domainInfo))
1879 if (!dyn_cast_or_null<DomainOp>(
1880 symbolTable.lookupSymbolIn(circuitOp, kind)))
1881 return mlir::emitError(module.getPortLocation(i))
1882 <<
"domain port '" <<
module.getPortName(i)
1883 << "' has undefined domain kind '" << kind.getValue() << "'";
1890LogicalResult FModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1894 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
1895 for (
auto layer : getLayers()) {
1896 if (!symbolTable.lookupSymbolIn(circuitOp, cast<SymbolRefAttr>(layer)))
1897 return emitOpError() <<
"enables undefined layer '" << layer <<
"'";
1904FExtModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1908 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
1909 for (
auto layer : getKnownLayersAttr().getAsRange<SymbolRefAttr>()) {
1910 if (!symbolTable.lookupSymbolIn(circuitOp, layer))
1911 return emitOpError() <<
"knows undefined layer '" << layer <<
"'";
1913 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>()) {
1914 if (!symbolTable.lookupSymbolIn(circuitOp, layer))
1915 return emitOpError() <<
"enables undefined layer '" << layer <<
"'";
1922FIntModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1927FMemModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1931void FModuleOp::getAsmBlockArgumentNames(mlir::Region ®ion,
1936void FExtModuleOp::getAsmBlockArgumentNames(
1941StringRef FExtModuleOp::getExtModuleName() {
1942 if (
auto defname = getDefname(); defname && !defname->empty())
1947void FIntModuleOp::getAsmBlockArgumentNames(
1952void FMemModuleOp::getAsmBlockArgumentNames(
1957ArrayAttr FMemModuleOp::getParameters() {
return {}; }
1959ArrayAttr FModuleOp::getParameters() {
return {}; }
1961Convention FIntModuleOp::getConvention() {
return Convention::Internal; }
1963ConventionAttr FIntModuleOp::getConventionAttr() {
1964 return ConventionAttr::get(getContext(), getConvention());
1967Convention FMemModuleOp::getConvention() {
return Convention::Internal; }
1969ConventionAttr FMemModuleOp::getConventionAttr() {
1970 return ConventionAttr::get(getContext(), getConvention());
1978 ClassLike classOp, ClassType type,
1979 function_ref<InFlightDiagnostic()> emitError) {
1981 auto name = type.getNameAttr().getAttr();
1982 auto expectedName = classOp.getModuleNameAttr();
1983 if (name != expectedName)
1984 return emitError() <<
"type has wrong name, got " << name <<
", expected "
1987 auto elements = type.getElements();
1989 auto expectedNumElements = classOp.getNumPorts();
1991 return emitError() <<
"has wrong number of ports, got " <<
numElements
1992 <<
", expected " << expectedNumElements;
1994 auto portNames = classOp.getPortNames();
1995 auto portDirections = classOp.getPortDirections();
1996 auto portTypes = classOp.getPortTypes();
1999 auto element = elements[i];
2001 auto name = element.name;
2002 auto expectedName = portNames[i];
2003 if (name != expectedName)
2004 return emitError() <<
"port #" << i <<
" has wrong name, got " << name
2005 <<
", expected " << expectedName;
2007 auto direction = element.direction;
2008 auto expectedDirection =
Direction(portDirections[i]);
2009 if (direction != expectedDirection)
2010 return emitError() <<
"port " << name <<
" has wrong direction, got "
2014 auto type = element.type;
2015 auto expectedType = cast<TypeAttr>(portTypes[i]).getValue();
2016 if (type != expectedType)
2017 return emitError() <<
"port " << name <<
" has wrong type, got " << type
2018 <<
", expected " << expectedType;
2025 auto n = classOp.getNumPorts();
2026 SmallVector<ClassElement> elements;
2027 elements.reserve(n);
2028 for (
size_t i = 0; i < n; ++i)
2029 elements.push_back({classOp.getPortNameAttr(i), classOp.getPortType(i),
2030 classOp.getPortDirection(i)});
2031 auto name = FlatSymbolRefAttr::get(classOp.getNameAttr());
2032 return ClassType::get(name, elements);
2035template <
typename OpTy>
2037 bool hasSSAIdentifiers) {
2038 auto *context = result.getContext();
2039 auto &builder = parser.getBuilder();
2040 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
2044 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
2047 StringAttr nameAttr;
2048 if (parser.parseSymbolName(nameAttr))
2050 properties.setSymName(nameAttr);
2053 SmallVector<OpAsmParser::Argument> entryArgs;
2054 SmallVector<Direction, 4> portDirections;
2055 SmallVector<Attribute, 4> portNames;
2056 SmallVector<Attribute, 4> portTypes;
2057 SmallVector<Attribute, 4> portAnnotations;
2058 SmallVector<Attribute, 4> portSyms;
2059 SmallVector<Attribute, 4> portLocs;
2060 SmallVector<Attribute, 4> domains;
2063 entryArgs, portDirections, portNames, portTypes,
2064 portAnnotations, portSyms, portLocs, domains))
2068 for (
auto annos : portAnnotations)
2069 if (!cast<ArrayAttr>(annos).empty())
2073 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
2076 assert(portNames.size() == portTypes.size());
2082 properties.setPortDirections(
2086 properties.setPortNames(builder.getArrayAttr(portNames));
2089 properties.setPortTypes(builder.getArrayAttr(portTypes));
2092 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
2093 properties.setPortSymbols(builder.getArrayAttr(portSyms));
2096 properties.setPortLocations(ArrayAttr::get(context, portLocs));
2102 auto *bodyRegion = result.addRegion();
2104 if (hasSSAIdentifiers) {
2105 if (parser.parseRegion(*bodyRegion, entryArgs))
2107 if (bodyRegion->empty())
2108 bodyRegion->push_back(
new Block());
2118 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
2119 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
2120 p << visibility.getValue() <<
' ';
2123 p.printSymbolName(op.getName());
2127 Region ®ion = op->getRegion(0);
2128 Block *body =
nullptr;
2129 if (!region.empty())
2130 body = ®ion.front();
2133 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
2134 {}, op.getPortSymbols(), op.getPortLocations(), {});
2137 SmallVector<StringRef, 8> omittedAttrs = {
2138 "sym_name",
"portNames",
"portTypes",
"portDirections",
2139 "portSymbols",
"portLocations", visibilityAttrName,
"domainInfo"};
2143 if (!needPortNamesAttr)
2144 omittedAttrs.push_back(
"portNames");
2146 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
2149 if (!region.empty()) {
2151 auto printEntryBlockArgs =
false;
2152 auto printBlockTerminators =
false;
2153 p.printRegion(region, printEntryBlockArgs, printBlockTerminators);
2161void ClassOp::build(OpBuilder &builder, OperationState &result, StringAttr name,
2162 ArrayRef<PortInfo> ports) {
2165 [](
const auto &port) {
return port.annotations.empty(); }) &&
2166 "class ports may not have annotations");
2168 buildClass<ClassOp>(builder, result, name, ports);
2171 auto *bodyRegion = result.regions[0].get();
2173 bodyRegion->push_back(body);
2176 for (
auto &elt : ports)
2177 body->addArgument(elt.type, elt.loc);
2180void ClassOp::build(::mlir::OpBuilder &odsBuilder,
2181 ::mlir::OperationState &odsState, Twine name,
2182 mlir::ArrayRef<mlir::StringRef> fieldNames,
2183 mlir::ArrayRef<mlir::Type> fieldTypes) {
2185 SmallVector<PortInfo, 10> ports;
2186 for (
auto [fieldName, fieldType] :
llvm::zip(fieldNames, fieldTypes)) {
2187 ports.emplace_back(odsBuilder.getStringAttr(fieldName +
"_in"), fieldType,
2189 ports.emplace_back(odsBuilder.getStringAttr(fieldName), fieldType,
2192 build(odsBuilder, odsState, odsBuilder.getStringAttr(name), ports);
2194 auto &body = odsState.regions[0]->getBlocks().front();
2195 auto prevLoc = odsBuilder.saveInsertionPoint();
2196 odsBuilder.setInsertionPointToEnd(&body);
2197 auto args = body.getArguments();
2198 auto loc = odsState.location;
2199 for (
unsigned i = 0, e = ports.size(); i != e; i += 2)
2200 PropAssignOp::create(odsBuilder, loc, args[i + 1], args[i]);
2202 odsBuilder.restoreInsertionPoint(prevLoc);
2204void ClassOp::print(OpAsmPrinter &p) {
2208ParseResult ClassOp::parse(OpAsmParser &parser, OperationState &result) {
2209 auto hasSSAIdentifiers =
true;
2210 return parseClassLike<ClassOp>(parser, result, hasSSAIdentifiers);
2213LogicalResult ClassOp::verify() {
2215 auto type = operand.getType();
2216 if (!isa<PropertyType>(type)) {
2217 emitOpError(
"ports on a class must be properties");
2226ClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2230void ClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2235SmallVector<PortInfo> ClassOp::getPorts() {
2236 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2239void ClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2240 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2244void ClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2245 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2248Convention ClassOp::getConvention() {
return Convention::Internal; }
2250ConventionAttr ClassOp::getConventionAttr() {
2251 return ConventionAttr::get(getContext(), getConvention());
2254ArrayAttr ClassOp::getParameters() {
return {}; }
2256ArrayAttr ClassOp::getPortAnnotationsAttr() {
2257 return ArrayAttr::get(getContext(), {});
2260ArrayRef<Attribute> ClassOp::getPortAnnotations() {
return {}; }
2262void ClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2263 llvm_unreachable(
"classes do not support annotations");
2266ArrayAttr ClassOp::getLayersAttr() {
return ArrayAttr::get(getContext(), {}); }
2268ArrayRef<Attribute> ClassOp::getLayers() {
return {}; }
2270SmallVector<::circt::hw::PortInfo> ClassOp::getPortList() {
2271 return ::getPortListImpl(*
this);
2275 return ::getPortImpl(*
this, idx);
2278BlockArgument ClassOp::getArgument(
size_t portNumber) {
2282bool ClassOp::canDiscardOnUseEmpty() {
2293void ExtClassOp::build(OpBuilder &builder, OperationState &result,
2294 StringAttr name, ArrayRef<PortInfo> ports) {
2297 [](
const auto &port) {
return port.annotations.empty(); }) &&
2298 "class ports may not have annotations");
2299 buildClass<ClassOp>(builder, result, name, ports);
2302void ExtClassOp::print(OpAsmPrinter &p) {
2306ParseResult ExtClassOp::parse(OpAsmParser &parser, OperationState &result) {
2307 auto hasSSAIdentifiers =
false;
2308 return parseClassLike<ExtClassOp>(parser, result, hasSSAIdentifiers);
2312ExtClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2316void ExtClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2321SmallVector<PortInfo> ExtClassOp::getPorts() {
2322 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2325void ExtClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2326 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2329void ExtClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2330 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2333Convention ExtClassOp::getConvention() {
return Convention::Internal; }
2335ConventionAttr ExtClassOp::getConventionAttr() {
2336 return ConventionAttr::get(getContext(), getConvention());
2339ArrayAttr ExtClassOp::getLayersAttr() {
2340 return ArrayAttr::get(getContext(), {});
2343ArrayRef<Attribute> ExtClassOp::getLayers() {
return {}; }
2345ArrayAttr ExtClassOp::getParameters() {
return {}; }
2347ArrayAttr ExtClassOp::getPortAnnotationsAttr() {
2348 return ArrayAttr::get(getContext(), {});
2351ArrayRef<Attribute> ExtClassOp::getPortAnnotations() {
return {}; }
2353void ExtClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2354 llvm_unreachable(
"classes do not support annotations");
2357SmallVector<::circt::hw::PortInfo> ExtClassOp::getPortList() {
2358 return ::getPortListImpl(*
this);
2362 return ::getPortImpl(*
this, idx);
2365bool ExtClassOp::canDiscardOnUseEmpty() {
2376void InstanceOp::build(
2377 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2378 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2379 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2380 ArrayRef<Attribute> domainInfo, ArrayRef<Attribute> annotations,
2381 ArrayRef<Attribute> portAnnotations, ArrayRef<Attribute> layers,
2382 bool lowerToBind,
bool doNotPrint, StringAttr innerSym) {
2383 build(builder, result, resultTypes, moduleName, name, nameKind,
2384 portDirections, portNames, domainInfo, annotations, portAnnotations,
2385 layers, lowerToBind, doNotPrint,
2386 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr());
2389void InstanceOp::build(
2390 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2391 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2392 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2393 ArrayRef<Attribute> domainInfo, ArrayRef<Attribute> annotations,
2394 ArrayRef<Attribute> portAnnotations, ArrayRef<Attribute> layers,
2395 bool lowerToBind,
bool doNotPrint, hw::InnerSymAttr innerSym) {
2396 result.addTypes(resultTypes);
2397 result.getOrAddProperties<Properties>().setModuleName(
2398 SymbolRefAttr::get(builder.getContext(), moduleName));
2399 result.getOrAddProperties<Properties>().setName(builder.getStringAttr(name));
2400 result.getOrAddProperties<Properties>().setPortDirections(
2402 result.getOrAddProperties<Properties>().setPortNames(
2403 builder.getArrayAttr(portNames));
2405 if (domainInfo.empty()) {
2406 SmallVector<Attribute, 16> domainInfoVec(resultTypes.size(),
2407 builder.getArrayAttr({}));
2408 result.getOrAddProperties<Properties>().setDomainInfo(
2409 builder.getArrayAttr(domainInfoVec));
2411 assert(domainInfo.size() == resultTypes.size());
2412 result.getOrAddProperties<Properties>().setDomainInfo(
2413 builder.getArrayAttr(domainInfo));
2416 result.getOrAddProperties<Properties>().setAnnotations(
2417 builder.getArrayAttr(annotations));
2418 result.getOrAddProperties<Properties>().setLayers(
2419 builder.getArrayAttr(layers));
2421 result.getOrAddProperties<Properties>().setLowerToBind(
2422 builder.getUnitAttr());
2424 result.getOrAddProperties<Properties>().setDoNotPrint(
2425 builder.getUnitAttr());
2427 result.getOrAddProperties<Properties>().setInnerSym(innerSym);
2429 result.getOrAddProperties<Properties>().setNameKind(
2430 NameKindEnumAttr::get(builder.getContext(), nameKind));
2432 if (portAnnotations.empty()) {
2433 SmallVector<Attribute, 16> portAnnotationsVec(resultTypes.size(),
2434 builder.getArrayAttr({}));
2435 result.getOrAddProperties<Properties>().setPortAnnotations(
2436 builder.getArrayAttr(portAnnotationsVec));
2438 assert(portAnnotations.size() == resultTypes.size());
2439 result.getOrAddProperties<Properties>().setPortAnnotations(
2440 builder.getArrayAttr(portAnnotations));
2444void InstanceOp::build(OpBuilder &builder, OperationState &result,
2445 FModuleLike module, StringRef name,
2446 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2447 ArrayRef<Attribute> portAnnotations,
bool lowerToBind,
2448 bool doNotPrint, hw::InnerSymAttr innerSym) {
2451 SmallVector<Type> resultTypes;
2452 resultTypes.reserve(module.getNumPorts());
2454 module.getPortTypes(), std::back_inserter(resultTypes),
2455 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2460 ArrayAttr portAnnotationsAttr;
2461 if (portAnnotations.empty()) {
2462 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2463 resultTypes.size(), builder.getArrayAttr({})));
2465 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2467 ArrayAttr domainInfoAttr =
module.getDomainInfoAttr();
2468 if (domainInfoAttr.empty()) {
2469 domainInfoAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2470 resultTypes.size(), builder.getArrayAttr({})));
2474 builder, result, resultTypes,
2475 SymbolRefAttr::get(builder.getContext(), module.getModuleNameAttr()),
2476 builder.getStringAttr(name),
2477 NameKindEnumAttr::get(builder.getContext(), nameKind),
2478 module.getPortDirectionsAttr(), module.getPortNamesAttr(), domainInfoAttr,
2479 builder.getArrayAttr(annotations), portAnnotationsAttr,
2480 module.getLayersAttr(), lowerToBind ? builder.getUnitAttr() : UnitAttr(),
2481 doNotPrint ? builder.getUnitAttr() : UnitAttr(), innerSym);
2484void InstanceOp::build(OpBuilder &builder, OperationState &odsState,
2485 ArrayRef<PortInfo> ports, StringRef moduleName,
2486 StringRef name, NameKindEnum nameKind,
2487 ArrayRef<Attribute> annotations,
2488 ArrayRef<Attribute> layers,
bool lowerToBind,
2489 bool doNotPrint, hw::InnerSymAttr innerSym) {
2491 SmallVector<Type> newResultTypes;
2492 SmallVector<Direction> newPortDirections;
2493 SmallVector<Attribute> newPortNames;
2494 SmallVector<Attribute> newPortAnnotations;
2495 SmallVector<Attribute> newDomainInfo;
2496 for (
auto &p : ports) {
2497 newResultTypes.push_back(p.type);
2498 newPortDirections.push_back(p.direction);
2499 newPortNames.push_back(p.name);
2500 newPortAnnotations.push_back(p.annotations.getArrayAttr());
2502 newDomainInfo.push_back(p.domains);
2504 newDomainInfo.push_back(builder.getArrayAttr({}));
2507 return build(builder, odsState, newResultTypes, moduleName, name, nameKind,
2508 newPortDirections, newPortNames, newDomainInfo, annotations,
2509 newPortAnnotations, layers, lowerToBind, doNotPrint, innerSym);
2512LogicalResult InstanceOp::verify() {
2515 SmallVector<SymbolRefAttr> missingLayers;
2516 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
2518 missingLayers.push_back(layer);
2520 if (missingLayers.empty())
2524 emitOpError(
"ambient layers are insufficient to instantiate module");
2525 auto ¬e = diag.attachNote();
2526 note <<
"missing layer requirements: ";
2527 interleaveComma(missingLayers, note);
2532 Operation *op1, Operation *op2,
2533 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2535 size_t n = insertions.size();
2536 size_t inserted = 0;
2537 for (
size_t i = 0, e = op1->getNumResults(); i < e; ++i) {
2538 while (inserted < n) {
2539 auto &[index, portInfo] = insertions[inserted];
2544 auto r1 = op1->getResult(i);
2545 auto r2 = op2->getResult(i + inserted);
2546 r1.replaceAllUsesWith(r2);
2551 const llvm::BitVector &erasures) {
2554 for (
size_t i = 0, e = op1->getNumResults(); i < e; ++i) {
2555 auto r1 = op1->getResult(i);
2557 assert(r1.use_empty() &&
"removed instance port has uses");
2561 auto r2 = op2->getResult(i - erased);
2562 r1.replaceAllUsesWith(r2);
2566InstanceOp InstanceOp::cloneWithErasedPorts(
const llvm::BitVector &erasures) {
2567 assert(erasures.size() >= getNumResults() &&
2568 "erasures is not at least as large as getNumResults()");
2570 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
2571 SmallVector<Type>(result_type_begin(), result_type_end()), erasures);
2572 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
2574 SmallVector<Attribute> newPortNames =
2576 SmallVector<Attribute> newPortAnnotations =
2578 ArrayAttr newDomainInfo =
2582 OpBuilder builder(*
this);
2583 auto clone = InstanceOp::create(
2584 builder,
getLoc(), newResultTypes, getModuleName(),
getName(),
2585 getNameKind(), newPortDirections, newPortNames, newDomainInfo.getValue(),
2586 getAnnotations().getValue(), newPortAnnotations, getLayers(),
2587 getLowerToBind(), getDoNotPrint(), getInnerSymAttr());
2589 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2590 clone->setAttr(
"output_file", outputFile);
2595InstanceOp InstanceOp::cloneWithErasedPortsAndReplaceUses(
2596 const llvm::BitVector &erasures) {
2597 auto clone = cloneWithErasedPorts(erasures);
2602ArrayAttr InstanceOp::getPortAnnotation(
unsigned portIdx) {
2603 assert(portIdx < getNumResults() &&
2604 "index should be smaller than result number");
2605 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
2608void InstanceOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
2609 assert(annotations.size() == getNumResults() &&
2610 "number of annotations is not equal to result number");
2611 (*this)->setAttr(
"portAnnotations",
2612 ArrayAttr::get(getContext(), annotations));
2615ArrayAttr InstanceOp::getPortDomain(
unsigned portIdx) {
2616 assert(portIdx < getNumResults() &&
2617 "index should be smaller than result number");
2618 return cast<ArrayAttr>(getDomainInfo()[portIdx]);
2621InstanceOp InstanceOp::cloneWithInsertedPorts(
2622 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2623 auto *context = getContext();
2624 auto empty = ArrayAttr::get(context, {});
2626 auto oldPortCount = getNumResults();
2627 auto numInsertions = insertions.size();
2628 auto newPortCount = oldPortCount + numInsertions;
2630 SmallVector<Direction> newPortDirections;
2631 SmallVector<Attribute> newPortNames;
2632 SmallVector<Type> newPortTypes;
2633 SmallVector<Attribute> newPortAnnos;
2634 SmallVector<Attribute> newDomainInfo;
2636 newPortDirections.reserve(newPortCount);
2637 newPortNames.reserve(newPortCount);
2638 newPortTypes.reserve(newPortCount);
2639 newPortAnnos.reserve(newPortCount);
2640 newDomainInfo.reserve(newPortCount);
2642 SmallVector<unsigned> indexMap(oldPortCount);
2644 size_t inserted = 0;
2645 for (
size_t i = 0; i < oldPortCount; ++i) {
2646 while (inserted < numInsertions) {
2647 auto &[index,
info] = insertions[inserted];
2653 newPortDirections.push_back(
info.direction);
2654 newPortNames.push_back(
info.name);
2655 newPortTypes.push_back(
info.type);
2656 newPortAnnos.push_back(
info.annotations.getArrayAttr());
2657 newDomainInfo.push_back(domains);
2661 newPortDirections.push_back(getPortDirection(i));
2662 newPortNames.push_back(getPortNameAttr(i));
2663 newPortTypes.push_back(getType(i));
2664 newPortAnnos.push_back(getPortAnnotation(i));
2665 newDomainInfo.push_back(getDomainInfo()[i]);
2666 indexMap[i] = i + inserted;
2669 while (inserted < numInsertions) {
2670 auto &[index,
info] = insertions[inserted];
2673 newPortDirections.push_back(
info.direction);
2674 newPortNames.push_back(
info.name);
2675 newPortTypes.push_back(
info.type);
2676 newPortAnnos.push_back(
info.annotations.getArrayAttr());
2677 newDomainInfo.push_back(domains);
2681 OpBuilder builder(*
this);
2682 auto clone = InstanceOp::create(
2683 builder,
getLoc(), newPortTypes, getModuleName(),
getName(),
2684 getNameKind(), newPortDirections, newPortNames, newDomainInfo,
2685 getAnnotations().getValue(), newPortAnnos, getLayers(), getLowerToBind(),
2686 getDoNotPrint(), getInnerSymAttr());
2688 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2689 clone->setAttr(
"output_file", outputFile);
2694InstanceOp InstanceOp::cloneWithInsertedPortsAndReplaceUses(
2695 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2696 auto clone = cloneWithInsertedPorts(insertions);
2701LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2703 getModuleNameAttr());
2706StringRef InstanceOp::getInstanceName() {
return getName(); }
2708StringAttr InstanceOp::getInstanceNameAttr() {
return getNameAttr(); }
2710void InstanceOp::print(OpAsmPrinter &p) {
2713 p.printKeywordOrString(
getName());
2714 if (
auto attr = getInnerSymAttr()) {
2716 p.printSymbolName(attr.getSymName());
2718 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2719 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2722 SmallVector<StringRef, 10> omittedAttrs = {
2723 "moduleName",
"name",
"portDirections",
2724 "portNames",
"portTypes",
"portAnnotations",
2725 "inner_sym",
"nameKind",
"domainInfo"};
2726 if (getAnnotations().
empty())
2727 omittedAttrs.push_back(
"annotations");
2728 if (getLayers().
empty())
2729 omittedAttrs.push_back(
"layers");
2730 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2734 p.printSymbolName(getModuleName());
2737 SmallVector<Attribute> portTypes;
2738 portTypes.reserve(getNumResults());
2739 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2743 getPortNames().getValue(), portTypes,
2744 getPortAnnotations().getValue(), {}, {},
2745 getDomainInfo().getValue());
2748ParseResult InstanceOp::parse(OpAsmParser &parser, OperationState &result) {
2749 auto *context = parser.getContext();
2750 auto &properties = result.getOrAddProperties<Properties>();
2753 hw::InnerSymAttr innerSymAttr;
2754 FlatSymbolRefAttr moduleName;
2755 SmallVector<OpAsmParser::Argument> entryArgs;
2756 SmallVector<Direction, 4> portDirections;
2757 SmallVector<Attribute, 4> portNames;
2758 SmallVector<Attribute, 4> portTypes;
2759 SmallVector<Attribute, 4> portAnnotations;
2760 SmallVector<Attribute, 4> portSyms;
2761 SmallVector<Attribute, 4> portLocs;
2762 SmallVector<Attribute, 4> domains;
2763 NameKindEnumAttr nameKind;
2765 if (parser.parseKeywordOrString(&name))
2767 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
2768 if (parser.parseCustomAttributeWithFallback(
2769 innerSymAttr, ::mlir::Type{},
2771 result.attributes)) {
2772 return ::mlir::failure();
2776 parser.parseOptionalAttrDict(result.attributes) ||
2777 parser.parseAttribute(moduleName) ||
2780 entryArgs, portDirections, portNames, portTypes,
2781 portAnnotations, portSyms, portLocs, domains))
2787 properties.setModuleName(moduleName);
2788 properties.setName(StringAttr::get(context, name));
2789 properties.setNameKind(nameKind);
2790 properties.setPortDirections(
2792 properties.setPortNames(ArrayAttr::get(context, portNames));
2793 properties.setPortAnnotations(ArrayAttr::get(context, portAnnotations));
2797 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
2798 properties.setLayers(parser.getBuilder().getArrayAttr({}));
2801 properties.setDomainInfo(ArrayAttr::get(context, domains));
2804 result.types.reserve(portTypes.size());
2806 portTypes, std::back_inserter(result.types),
2807 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2812void InstanceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
2817 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
2818 setNameFn(getResult(i), (base +
"_" + getPortName(i)).str());
2822std::optional<size_t> InstanceOp::getTargetResultIndex() {
2824 return std::nullopt;
2831void InstanceChoiceOp::build(
2832 OpBuilder &builder, OperationState &result, FModuleLike defaultModule,
2833 ArrayRef<std::pair<OptionCaseOp, FModuleLike>> cases, StringRef name,
2834 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2835 ArrayRef<Attribute> portAnnotations, StringAttr innerSym) {
2837 SmallVector<Type> resultTypes;
2838 for (Attribute portType : defaultModule.getPortTypes())
2839 resultTypes.push_back(cast<TypeAttr>(portType).getValue());
2842 ArrayAttr portAnnotationsAttr;
2843 if (portAnnotations.empty()) {
2844 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2845 resultTypes.size(), builder.getArrayAttr({})));
2847 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2851 ArrayAttr domainInfoAttr = defaultModule.getDomainInfoAttr();
2852 if (domainInfoAttr.empty()) {
2853 domainInfoAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2854 resultTypes.size(), builder.getArrayAttr({})));
2858 SmallVector<Attribute> moduleNames, caseNames;
2859 moduleNames.push_back(SymbolRefAttr::get(defaultModule.getModuleNameAttr()));
2860 for (
auto [caseOption, caseModule] : cases) {
2861 auto caseGroup = caseOption->getParentOfType<OptionOp>();
2862 caseNames.push_back(SymbolRefAttr::get(caseGroup.getSymNameAttr(),
2863 {SymbolRefAttr::get(caseOption)}));
2864 moduleNames.push_back(SymbolRefAttr::get(caseModule.getModuleNameAttr()));
2867 return build(builder, result, resultTypes, builder.getArrayAttr(moduleNames),
2868 builder.getArrayAttr(caseNames), builder.getStringAttr(name),
2869 NameKindEnumAttr::get(builder.getContext(), nameKind),
2870 defaultModule.getPortDirectionsAttr(),
2871 defaultModule.getPortNamesAttr(), domainInfoAttr,
2872 builder.getArrayAttr(annotations), portAnnotationsAttr,
2873 defaultModule.getLayersAttr(),
2874 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr());
2877std::optional<size_t> InstanceChoiceOp::getTargetResultIndex() {
2878 return std::nullopt;
2881void InstanceChoiceOp::print(OpAsmPrinter &p) {
2884 p.printKeywordOrString(
getName());
2885 if (
auto attr = getInnerSymAttr()) {
2887 p.printSymbolName(attr.getSymName());
2889 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2890 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2893 SmallVector<StringRef, 11> omittedAttrs = {
2894 "moduleNames",
"caseNames",
"name",
2895 "portDirections",
"portNames",
"portTypes",
2896 "portAnnotations",
"inner_sym",
"nameKind",
2898 if (getAnnotations().
empty())
2899 omittedAttrs.push_back(
"annotations");
2900 if (getLayers().
empty())
2901 omittedAttrs.push_back(
"layers");
2902 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2907 auto moduleNames = getModuleNamesAttr();
2908 auto caseNames = getCaseNamesAttr();
2910 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[0]).getValue());
2912 p <<
" alternatives ";
2914 cast<SymbolRefAttr>(caseNames[0]).getRootReference().getValue());
2916 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
2920 auto symbol = cast<SymbolRefAttr>(caseNames[i]);
2921 p.printSymbolName(symbol.getNestedReferences()[0].getValue());
2923 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[i + 1]).getValue());
2929 SmallVector<Attribute> portTypes;
2930 portTypes.reserve(getNumResults());
2931 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2934 getPortNames().getValue(), portTypes,
2935 getPortAnnotations().getValue(), {}, {},
2936 getDomainInfo().getValue());
2939ParseResult InstanceChoiceOp::parse(OpAsmParser &parser,
2940 OperationState &result) {
2941 auto *context = parser.getContext();
2942 auto &properties = result.getOrAddProperties<Properties>();
2945 hw::InnerSymAttr innerSymAttr;
2946 SmallVector<Attribute> moduleNames;
2947 SmallVector<Attribute> caseNames;
2948 SmallVector<OpAsmParser::Argument> entryArgs;
2949 SmallVector<Direction, 4> portDirections;
2950 SmallVector<Attribute, 4> portNames;
2951 SmallVector<Attribute, 4> portTypes;
2952 SmallVector<Attribute, 4> portAnnotations;
2953 SmallVector<Attribute, 4> portSyms;
2954 SmallVector<Attribute, 4> portLocs;
2955 SmallVector<Attribute, 4> domains;
2956 NameKindEnumAttr nameKind;
2958 if (parser.parseKeywordOrString(&name))
2960 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
2961 if (parser.parseCustomAttributeWithFallback(
2962 innerSymAttr, Type{},
2964 result.attributes)) {
2969 parser.parseOptionalAttrDict(result.attributes))
2972 FlatSymbolRefAttr defaultModuleName;
2973 if (parser.parseAttribute(defaultModuleName))
2975 moduleNames.push_back(defaultModuleName);
2979 FlatSymbolRefAttr optionName;
2980 if (parser.parseKeyword(
"alternatives") ||
2981 parser.parseAttribute(optionName) || parser.parseLBrace())
2984 FlatSymbolRefAttr moduleName;
2985 StringAttr caseName;
2986 while (succeeded(parser.parseOptionalSymbolName(caseName))) {
2987 if (parser.parseArrow() || parser.parseAttribute(moduleName))
2989 moduleNames.push_back(moduleName);
2990 caseNames.push_back(SymbolRefAttr::get(
2991 optionName.getAttr(), {FlatSymbolRefAttr::get(caseName)}));
2992 if (failed(parser.parseOptionalComma()))
2995 if (parser.parseRBrace())
3001 entryArgs, portDirections, portNames, portTypes,
3002 portAnnotations, portSyms, portLocs, domains))
3007 properties.setModuleNames(ArrayAttr::get(context, moduleNames));
3008 properties.setCaseNames(ArrayAttr::get(context, caseNames));
3009 properties.setName(StringAttr::get(context, name));
3010 properties.setNameKind(nameKind);
3011 properties.setPortDirections(
3013 properties.setPortNames(ArrayAttr::get(context, portNames));
3014 properties.setDomainInfo(ArrayAttr::get(context, domains));
3015 properties.setPortAnnotations(ArrayAttr::get(context, portAnnotations));
3019 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
3020 properties.setLayers(parser.getBuilder().getArrayAttr({}));
3023 result.types.reserve(portTypes.size());
3025 portTypes, std::back_inserter(result.types),
3026 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
3031void InstanceChoiceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3033 for (
auto [result, name] :
llvm::zip(getResults(), getPortNames()))
3034 setNameFn(result, (base +
"_" + cast<StringAttr>(name).getValue()).str());
3037LogicalResult InstanceChoiceOp::verify() {
3038 if (getCaseNamesAttr().
empty())
3039 return emitOpError() <<
"must have at least one case";
3040 if (getModuleNamesAttr().size() != getCaseNamesAttr().size() + 1)
3041 return emitOpError() <<
"number of referenced modules does not match the "
3042 "number of options";
3047 SmallVector<SymbolRefAttr> missingLayers;
3048 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
3050 missingLayers.push_back(layer);
3052 if (missingLayers.empty())
3056 emitOpError(
"ambient layers are insufficient to instantiate module");
3057 auto ¬e = diag.attachNote();
3058 note <<
"missing layer requirements: ";
3059 interleaveComma(missingLayers, note);
3064InstanceChoiceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3065 auto caseNames = getCaseNamesAttr();
3066 for (
auto moduleName : getModuleNamesAttr()) {
3068 *
this, symbolTable, cast<FlatSymbolRefAttr>(moduleName))))
3072 auto root = cast<SymbolRefAttr>(caseNames[0]).getRootReference();
3073 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3074 auto ref = cast<SymbolRefAttr>(caseNames[i]);
3075 auto refRoot = ref.getRootReference();
3076 if (ref.getRootReference() != root)
3077 return emitOpError() <<
"case " << ref
3078 <<
" is not in the same option group as "
3081 if (!symbolTable.lookupNearestSymbolFrom<OptionOp>(*
this, refRoot))
3082 return emitOpError() <<
"option " << refRoot <<
" does not exist";
3084 if (!symbolTable.lookupNearestSymbolFrom<OptionCaseOp>(*
this, ref))
3085 return emitOpError() <<
"option " << refRoot
3086 <<
" does not contain option case " << ref;
3093InstanceChoiceOp::getTargetOrDefaultAttr(OptionCaseOp option) {
3094 auto caseNames = getCaseNamesAttr();
3095 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3096 StringAttr caseSym = cast<SymbolRefAttr>(caseNames[i]).getLeafReference();
3097 if (caseSym == option.getSymName())
3098 return cast<FlatSymbolRefAttr>(getModuleNamesAttr()[i + 1]);
3100 return getDefaultTargetAttr();
3103SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1>
3104InstanceChoiceOp::getTargetChoices() {
3105 auto caseNames = getCaseNamesAttr();
3106 auto moduleNames = getModuleNamesAttr();
3107 SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1> choices;
3108 for (
size_t i = 0; i < caseNames.size(); ++i) {
3109 choices.emplace_back(cast<SymbolRefAttr>(caseNames[i]),
3110 cast<FlatSymbolRefAttr>(moduleNames[i + 1]));
3116InstanceChoiceOp InstanceChoiceOp::cloneWithInsertedPorts(
3117 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
3118 auto *context = getContext();
3119 auto empty = ArrayAttr::get(context, {});
3121 auto oldPortCount = getNumResults();
3122 auto numInsertions = insertions.size();
3123 auto newPortCount = oldPortCount + numInsertions;
3125 SmallVector<Direction> newPortDirections;
3126 SmallVector<Attribute> newPortNames;
3127 SmallVector<Type> newPortTypes;
3128 SmallVector<Attribute> newPortAnnos;
3129 SmallVector<Attribute> newDomainInfo;
3131 newPortDirections.reserve(newPortCount);
3132 newPortNames.reserve(newPortCount);
3133 newPortTypes.reserve(newPortCount);
3134 newPortAnnos.reserve(newPortCount);
3135 newDomainInfo.reserve(newPortCount);
3137 SmallVector<unsigned> indexMap(oldPortCount);
3139 size_t inserted = 0;
3140 for (
size_t i = 0; i < oldPortCount; ++i) {
3141 while (inserted < numInsertions) {
3142 auto &[index,
info] = insertions[inserted];
3148 newPortDirections.push_back(
info.direction);
3149 newPortNames.push_back(
info.name);
3150 newPortTypes.push_back(
info.type);
3151 newPortAnnos.push_back(
info.annotations.getArrayAttr());
3152 newDomainInfo.push_back(domains);
3156 newPortDirections.push_back(getPortDirection(i));
3157 newPortNames.push_back(getPortNameAttr(i));
3158 newPortTypes.push_back(getType(i));
3159 newPortAnnos.push_back(getPortAnnotations()[i]);
3160 newDomainInfo.push_back(getDomainInfo()[i]);
3161 indexMap[i] = i + inserted;
3164 while (inserted < numInsertions) {
3165 auto &[index,
info] = insertions[inserted];
3168 newPortDirections.push_back(
info.direction);
3169 newPortNames.push_back(
info.name);
3170 newPortTypes.push_back(
info.type);
3171 newPortAnnos.push_back(
info.annotations.getArrayAttr());
3172 newDomainInfo.push_back(domains);
3176 OpBuilder builder(*
this);
3177 auto clone = InstanceChoiceOp::create(
3178 builder,
getLoc(), newPortTypes, getModuleNames(), getCaseNames(),
3181 ArrayAttr::get(context, newPortNames),
3182 ArrayAttr::get(context, newDomainInfo), getAnnotationsAttr(),
3183 ArrayAttr::get(context, newPortAnnos), getLayers(), getInnerSymAttr());
3185 if (
auto outputFile = (*this)->getAttr(
"output_file"))
3186 clone->setAttr(
"output_file", outputFile);
3191InstanceChoiceOp InstanceChoiceOp::cloneWithInsertedPortsAndReplaceUses(
3192 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
3193 auto clone = cloneWithInsertedPorts(insertions);
3199InstanceChoiceOp::cloneWithErasedPorts(
const llvm::BitVector &erasures) {
3200 assert(erasures.size() >= getNumResults() &&
3201 "erasures is not at least as large as getNumResults()");
3203 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
3204 SmallVector<Type>(result_type_begin(), result_type_end()), erasures);
3205 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
3207 SmallVector<Attribute> newPortNames =
3209 SmallVector<Attribute> newPortAnnotations =
3211 ArrayAttr newPortDomains =
3215 OpBuilder builder(*
this);
3216 auto clone = InstanceChoiceOp::create(
3217 builder,
getLoc(), newResultTypes, getModuleNames(), getCaseNames(),
3220 ArrayAttr::get(getContext(), newPortNames), newPortDomains,
3221 getAnnotationsAttr(), ArrayAttr::get(getContext(), newPortAnnotations),
3222 getLayers(), getInnerSymAttr());
3224 if (
auto outputFile = (*this)->getAttr(
"output_file"))
3225 clone->setAttr(
"output_file", outputFile);
3230InstanceChoiceOp InstanceChoiceOp::cloneWithErasedPortsAndReplaceUses(
3231 const llvm::BitVector &erasures) {
3232 auto clone = cloneWithErasedPorts(erasures);
3241ArrayAttr MemOp::getPortAnnotation(
unsigned portIdx) {
3242 assert(portIdx < getNumResults() &&
3243 "index should be smaller than result number");
3244 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
3247void MemOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
3248 assert(annotations.size() == getNumResults() &&
3249 "number of annotations is not equal to result number");
3250 (*this)->setAttr(
"portAnnotations",
3251 ArrayAttr::get(getContext(), annotations));
3255void MemOp::getNumPorts(
size_t &numReadPorts,
size_t &numWritePorts,
3256 size_t &numReadWritePorts,
size_t &numDbgsPorts) {
3259 numReadWritePorts = 0;
3261 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3262 auto portKind = getPortKind(i);
3263 if (portKind == MemOp::PortKind::Debug)
3265 else if (portKind == MemOp::PortKind::Read)
3267 else if (portKind == MemOp::PortKind::Write) {
3270 ++numReadWritePorts;
3275LogicalResult MemOp::verify() {
3279 llvm::SmallDenseSet<Attribute, 8> portNamesSet;
3285 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3286 auto portName = getPortNameAttr(i);
3291 BundleType portBundleType =
3292 type_dyn_cast<BundleType>(getResult(i).getType());
3295 if (!portNamesSet.insert(portName).second) {
3296 emitOpError() <<
"has non-unique port name " << portName;
3304 auto elt = getPortNamed(portName);
3306 emitOpError() <<
"could not get port with name " << portName;
3309 auto firrtlType = type_cast<FIRRTLType>(elt.getType());
3312 if (portKind == MemOp::PortKind::Debug &&
3313 !type_isa<RefType>(getResult(i).getType()))
3314 return emitOpError() <<
"has an invalid type on port " << portName
3315 <<
" (expected Read/Write/ReadWrite/Debug)";
3316 if (type_isa<RefType>(firrtlType) && e == 1)
3317 return emitOpError()
3318 <<
"cannot have only one port of debug type. Debug port can only "
3319 "exist alongside other read/write/read-write port";
3324 if (portKind == MemOp::PortKind::Debug) {
3325 auto resType = type_cast<RefType>(getResult(i).getType());
3326 if (!(resType && type_isa<FVectorType>(resType.getType())))
3327 return emitOpError() <<
"debug ports must be a RefType of FVectorType";
3328 dataType = type_cast<FVectorType>(resType.getType()).getElementType();
3330 auto dataTypeOption = portBundleType.getElement(
"data");
3331 if (!dataTypeOption && portKind == MemOp::PortKind::ReadWrite)
3332 dataTypeOption = portBundleType.getElement(
"wdata");
3333 if (!dataTypeOption) {
3334 emitOpError() <<
"has no data field on port " << portName
3335 <<
" (expected to see \"data\" for a read or write "
3336 "port or \"rdata\" for a read/write port)";
3339 dataType = dataTypeOption->type;
3341 if (portKind == MemOp::PortKind::Read) {
3348 emitOpError() <<
"has non-passive data type on port " << portName
3349 <<
" (memory types must be passive)";
3354 if (dataType.containsAnalog()) {
3355 emitOpError() <<
"has a data type that contains an analog type on port "
3357 <<
" (memory types cannot contain analog types)";
3365 getTypeForPort(getDepth(), dataType, portKind,
3366 dataType.isGround() ? getMaskBits() : 0);
3369 auto originalType = getResult(i).getType();
3370 if (originalType != expectedType) {
3371 StringRef portKindName;
3373 case MemOp::PortKind::Read:
3374 portKindName =
"read";
3376 case MemOp::PortKind::Write:
3377 portKindName =
"write";
3379 case MemOp::PortKind::ReadWrite:
3380 portKindName =
"readwrite";
3382 case MemOp::PortKind::Debug:
3383 portKindName =
"dbg";
3386 emitOpError() <<
"has an invalid type for port " << portName
3387 <<
" of determined kind \"" << portKindName
3388 <<
"\" (expected " << expectedType <<
", but got "
3389 << originalType <<
")";
3395 if (oldDataType && oldDataType != dataType) {
3396 emitOpError() <<
"port " << getPortNameAttr(i)
3397 <<
" has a different type than port "
3398 << getPortNameAttr(i - 1) <<
" (expected " << oldDataType
3399 <<
", but got " << dataType <<
")";
3403 oldDataType = dataType;
3406 auto maskWidth = getMaskBits();
3408 auto dataWidth = getDataType().getBitWidthOrSentinel();
3409 if (dataWidth > 0 && maskWidth > (
size_t)dataWidth)
3410 return emitOpError(
"the mask width cannot be greater than "
3413 if (getPortAnnotations().size() != getNumResults())
3414 return emitOpError(
"the number of result annotations should be "
3415 "equal to the number of results");
3421 return std::max(1U, llvm::Log2_64_Ceil(depth));
3427 PortKind portKind,
size_t maskBits) {
3429 auto *context = dataType.getContext();
3430 if (portKind == PortKind::Debug)
3431 return RefType::get(FVectorType::get(dataType, depth));
3437 maskType = UIntType::get(context, maskBits);
3439 auto getId = [&](StringRef name) -> StringAttr {
3440 return StringAttr::get(context, name);
3443 SmallVector<BundleType::BundleElement, 7> portFields;
3447 portFields.push_back({getId(
"addr"),
false, addressType});
3448 portFields.push_back({getId(
"en"),
false, UIntType::get(context, 1)});
3449 portFields.push_back({getId(
"clk"),
false, ClockType::get(context)});
3452 case PortKind::Read:
3453 portFields.push_back({getId(
"data"),
true, dataType});
3456 case PortKind::Write:
3457 portFields.push_back({getId(
"data"),
false, dataType});
3458 portFields.push_back({getId(
"mask"),
false, maskType});
3461 case PortKind::ReadWrite:
3462 portFields.push_back({getId(
"rdata"),
true, dataType});
3463 portFields.push_back({getId(
"wmode"),
false, UIntType::get(context, 1)});
3464 portFields.push_back({getId(
"wdata"),
false, dataType});
3465 portFields.push_back({getId(
"wmask"),
false, maskType});
3468 llvm::report_fatal_error(
"memory port kind not handled");
3472 return BundleType::get(context, portFields);
3476SmallVector<MemOp::NamedPort> MemOp::getPorts() {
3477 SmallVector<MemOp::NamedPort> result;
3479 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3481 auto portType = type_cast<FIRRTLType>(getResult(i).getType());
3488MemOp::PortKind MemOp::getPortKind(StringRef portName) {
3490 type_cast<FIRRTLType>(getPortNamed(portName).getType()));
3494MemOp::PortKind MemOp::getPortKind(
size_t resultNo) {
3496 type_cast<FIRRTLType>(getResult(resultNo).getType()));
3500size_t MemOp::getMaskBits() {
3502 for (
auto res : getResults()) {
3503 if (type_isa<RefType>(res.getType()))
3505 auto firstPortType = type_cast<FIRRTLBaseType>(res.getType());
3512 if (t.name.getValue().contains(
"mask"))
3515 if (type_isa<UIntType>(mType))
3525 assert(getNumResults() != 0 &&
"Mems with no read/write ports are illegal");
3527 if (
auto refType = type_dyn_cast<RefType>(getResult(0).getType()))
3528 return type_cast<FVectorType>(refType.getType()).getElementType();
3529 auto firstPortType = type_cast<FIRRTLBaseType>(getResult(0).getType());
3531 StringRef dataFieldName =
"data";
3533 dataFieldName =
"rdata";
3535 return type_cast<BundleType>(firstPortType.getPassiveType())
3536 .getElementType(dataFieldName);
3539StringAttr MemOp::getPortNameAttr(
size_t resultNo) {
3540 return cast<StringAttr>(getPortNames()[resultNo]);
3544 return type_cast<FIRRTLBaseType>(getResults()[resultNo].getType());
3547Value MemOp::getPortNamed(StringAttr name) {
3548 auto namesArray = getPortNames();
3549 for (
size_t i = 0, e = namesArray.size(); i != e; ++i) {
3550 if (namesArray[i] == name) {
3551 assert(i < getNumResults() &&
" names array out of sync with results");
3552 return getResult(i);
3561 size_t numReadPorts = 0;
3562 size_t numWritePorts = 0;
3563 size_t numReadWritePorts = 0;
3565 SmallVector<int32_t> writeClockIDs;
3567 for (
size_t i = 0, e = op.getNumResults(); i != e; ++i) {
3568 auto portKind = op.getPortKind(i);
3569 if (portKind == MemOp::PortKind::Read)
3571 else if (portKind == MemOp::PortKind::Write) {
3572 for (
auto *a : op.getResult(i).getUsers()) {
3573 auto subfield = dyn_cast<SubfieldOp>(a);
3574 if (!subfield || subfield.getFieldIndex() != 2)
3576 auto clockPort = a->getResult(0);
3577 for (
auto *b : clockPort.getUsers()) {
3578 if (
auto connect = dyn_cast<FConnectLike>(b)) {
3579 if (
connect.getDest() == clockPort) {
3582 connect.getSrc(),
true,
true,
true),
3584 if (result.second) {
3585 writeClockIDs.push_back(numWritePorts);
3587 writeClockIDs.push_back(result.first->second);
3596 ++numReadWritePorts;
3603 op.emitError(
"'firrtl.mem' should have simple type and known width");
3604 MemoryInitAttr init = op->getAttrOfType<MemoryInitAttr>(
"init");
3606 if (op->hasAttr(
"modName"))
3607 modName = op->getAttrOfType<StringAttr>(
"modName");
3609 SmallString<8> clocks;
3610 for (
auto a : writeClockIDs)
3611 clocks.
append(Twine((char)(a +
'a')).str());
3612 SmallString<32> initStr;
3617 for (
auto c : init.getFilename().getValue())
3618 if ((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') ||
3619 (c >=
'0' && c <=
'9'))
3620 initStr.push_back(c);
3621 initStr.push_back(
'_');
3622 initStr.push_back(init.getIsBinary() ?
't' :
'f');
3623 initStr.push_back(
'_');
3624 initStr.push_back(init.getIsInline() ?
't' :
'f');
3626 modName = StringAttr::get(
3629 "{0}FIRRTLMem_{1}_{2}_{3}_{4}_{5}_{6}_{7}_{8}_{9}_{10}{11}{12}",
3630 op.getPrefix().value_or(
""), numReadPorts, numWritePorts,
3631 numReadWritePorts, (
size_t)width, op.getDepth(),
3632 op.getReadLatency(), op.getWriteLatency(), op.getMaskBits(),
3633 (
unsigned)op.getRuw(), (
unsigned)seq::WUW::PortOrder,
3634 clocks.empty() ?
"" :
"_" + clocks, init ? initStr.str() :
""));
3636 return {numReadPorts,
3641 op.getReadLatency(),
3642 op.getWriteLatency(),
3644 *seq::symbolizeRUW(
unsigned(op.getRuw())),
3645 seq::WUW::PortOrder,
3648 op.getMaskBits() > 1,
3654void MemOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3659 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
3660 setNameFn(getResult(i), (base +
"_" + getPortName(i)).str());
3664std::optional<size_t> MemOp::getTargetResultIndex() {
3666 return std::nullopt;
3674 OpAsmSetValueNameFn setNameFn) {
3677 setNameFn(op.getDataRaw(), name);
3678 if (op.isForceable())
3679 setNameFn(op.getDataRef(), (name +
"_ref").str());
3682void NodeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3686LogicalResult NodeOp::inferReturnTypes(
3687 mlir::MLIRContext *context, std::optional<mlir::Location> location,
3688 ::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes,
3689 ::mlir::OpaqueProperties properties, ::mlir::RegionRange regions,
3690 ::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
3691 if (operands.empty())
3693 Adaptor adaptor(operands, attributes, properties, regions);
3694 inferredReturnTypes.push_back(adaptor.getInput().getType());
3695 if (adaptor.getForceable()) {
3697 true, adaptor.getInput().getType());
3698 if (!forceableType) {
3700 ::mlir::emitError(*location,
"cannot force a node of type ")
3701 << operands[0].getType();
3704 inferredReturnTypes.push_back(forceableType);
3709std::optional<size_t> NodeOp::getTargetResultIndex() {
return 0; }
3711void RegOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3715std::optional<size_t> RegOp::getTargetResultIndex() {
return 0; }
3717SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3718RegOp::computeDataFlow() {
3723LogicalResult RegResetOp::verify() {
3724 auto reset = getResetValue();
3731 return emitError(
"type mismatch between register ")
3732 << regType <<
" and reset value " << resetType;
3737std::optional<size_t> RegResetOp::getTargetResultIndex() {
return 0; }
3739void RegResetOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3748FormalOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3749 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3751 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3753 if (!isa<FModuleLike>(op)) {
3754 auto d = emitOpError() <<
"target " << getModuleNameAttr()
3755 <<
" is not a module";
3756 d.attachNote(op->getLoc()) <<
"target defined here";
3768SimulationOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3769 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3771 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3773 auto complain = [&] {
3774 auto d = emitOpError() <<
"target " << getModuleNameAttr() <<
" ";
3775 d.attachNote(op->getLoc()) <<
"target defined here";
3779 auto module = dyn_cast<FModuleLike>(op);
3781 return complain() <<
"is not a module";
3783 auto numPorts =
module.getPortDirections().size();
3785 return complain() <<
"must have 4 ports, got " << numPorts <<
" instead";
3787 auto checkPort = [&](
unsigned idx, StringRef expName,
Direction expDir,
3788 llvm::function_ref<bool(Type)> checkType,
3789 StringRef expType) {
3790 auto name =
module.getPortNameAttr(idx);
3791 if (name != expName) {
3792 complain() <<
"port " << idx <<
" must be called \"" << expName
3793 <<
"\", got " << name <<
" instead";
3796 if (
auto dir = module.getPortDirection(idx); dir != expDir) {
3800 complain() <<
"port " << name <<
" must be " << stringify(expDir)
3801 <<
", got " << stringify(dir) <<
" instead";
3804 if (
auto type = module.getPortType(idx); !checkType(type)) {
3805 complain() <<
"port " << name <<
" must be a '!firrtl." << expType
3806 <<
"', got " << type <<
" instead";
3812 auto isClock = [](Type type) {
return isa<ClockType>(type); };
3813 auto isBool = [](Type type) {
3814 if (
auto uintType = dyn_cast<UIntType>(type))
3815 return uintType.getWidth() == 1;
3818 return success(checkPort(0,
"clock",
Direction::In, isClock,
"clock") &&
3828void WireOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3832SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3833RegResetOp::computeDataFlow() {
3838std::optional<size_t> WireOp::getTargetResultIndex() {
return 0; }
3840LogicalResult WireOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3841 auto refType = type_dyn_cast<RefType>(getType(0));
3846 refType,
getLoc(), getOperation()->getParentOfType<CircuitOp>(),
3847 symbolTable, Twine(
"'") + getOperationName() +
"' op is");
3854LogicalResult ContractOp::verify() {
3855 if (getBody().getArgumentTypes() != getInputs().getType())
3856 return emitOpError(
"result types and region argument types must match");
3864void ObjectOp::build(OpBuilder &builder, OperationState &state, ClassLike klass,
3866 build(builder, state, klass.getInstanceType(),
3867 StringAttr::get(builder.getContext(), name));
3870LogicalResult ObjectOp::verify() {
return success(); }
3872LogicalResult ObjectOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3873 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
3874 auto classType = getType();
3875 auto className = classType.getNameAttr();
3878 auto classOp = dyn_cast_or_null<ClassLike>(
3879 symbolTable.lookupSymbolIn(circuitOp, className));
3881 return emitOpError() <<
"references unknown class " << className;
3884 if (failed(classOp.verifyType(classType, [&]() { return emitOpError(); })))
3890StringAttr ObjectOp::getClassNameAttr() {
3891 return getType().getNameAttr().getAttr();
3894StringRef ObjectOp::getClassName() {
return getType().getName(); }
3896ClassLike ObjectOp::getReferencedClass(
const SymbolTable &symbolTable) {
3897 auto symRef = getType().getNameAttr();
3898 return symbolTable.lookup<ClassLike>(symRef.getLeafReference());
3901Operation *ObjectOp::getReferencedOperation(
const SymbolTable &symtbl) {
3902 return getReferencedClass(symtbl);
3905StringRef ObjectOp::getInstanceName() {
return getName(); }
3907StringAttr ObjectOp::getInstanceNameAttr() {
return getNameAttr(); }
3909StringRef ObjectOp::getReferencedModuleName() {
return getClassName(); }
3911StringAttr ObjectOp::getReferencedModuleNameAttr() {
3912 return getClassNameAttr();
3915void ObjectOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3916 setNameFn(getResult(),
getName());
3923LogicalResult AttachOp::verify() {
3925 std::optional<int32_t> commonWidth;
3926 for (
auto operand : getOperands()) {
3927 auto thisWidth = type_cast<AnalogType>(operand.getType()).getWidth();
3931 commonWidth = thisWidth;
3934 if (commonWidth != thisWidth)
3935 return emitOpError(
"is inavlid as not all known operand widths match");
3942 Value dst = connect->getOperand(0);
3943 Value src = connect->getOperand(1);
3952 if (isa<PropertyType>(src.getType()) ||
3956 auto diag = emitError(connect->getLoc());
3957 diag <<
"connect has invalid flow: the source expression ";
3959 diag <<
"\"" << srcName <<
"\" ";
3960 diag <<
"has " <<
toString(srcFlow) <<
", expected source or duplex flow";
3961 return diag.attachNote(srcRef.getLoc()) <<
"the source was defined here";
3969 auto diag = emitError(connect->getLoc());
3970 diag <<
"connect has invalid flow: the destination expression ";
3972 diag <<
"\"" << dstName <<
"\" ";
3973 diag <<
"has " <<
toString(dstFlow) <<
", expected sink or duplex flow";
3974 return diag.attachNote(dstRef.getLoc())
3975 <<
"the destination was defined here";
3984 bool outerTypeIsConst =
false) {
3985 auto typeIsConst = outerTypeIsConst || type.
isConst();
3990 if (
auto bundleType = type_dyn_cast<BundleType>(type))
3991 return llvm::any_of(bundleType.getElements(), [&](
auto &element) {
3992 return isConstFieldDriven(element.type, isFlip ^ element.isFlip,
3996 if (
auto vectorType = type_dyn_cast<FVectorType>(type))
4008 auto dest = connect.getDest();
4009 auto destType = type_dyn_cast<FIRRTLBaseType>(dest.getType());
4010 auto src = connect.getSrc();
4011 auto srcType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4012 if (!destType || !srcType)
4015 auto destRefinedType = destType;
4016 auto srcRefinedType = srcType;
4021 auto findFieldDeclarationRefiningFieldType =
4023 while (
auto *definingOp = value.getDefiningOp()) {
4024 bool shouldContinue =
true;
4025 TypeSwitch<Operation *>(definingOp)
4026 .Case<SubfieldOp, SubindexOp>([&](
auto op) { value = op.getInput(); })
4027 .Case<SubaccessOp>([&](SubaccessOp op) {
4031 .getElementTypePreservingConst()
4033 originalFieldType = originalFieldType.getConstType(
true);
4034 value = op.getInput();
4036 .Default([&](Operation *) { shouldContinue =
false; });
4037 if (!shouldContinue)
4043 auto destDeclaration =
4044 findFieldDeclarationRefiningFieldType(dest, destRefinedType);
4045 auto srcDeclaration =
4046 findFieldDeclarationRefiningFieldType(src, srcRefinedType);
4048 auto checkConstConditionality = [&](Value value,
FIRRTLBaseType type,
4049 Value declaration) -> LogicalResult {
4050 auto *declarationBlock = declaration.getParentBlock();
4051 auto *block = connect->getBlock();
4052 while (block && block != declarationBlock) {
4053 auto *parentOp = block->getParentOp();
4055 if (
auto whenOp = dyn_cast<WhenOp>(parentOp);
4056 whenOp && !whenOp.getCondition().getType().isConst()) {
4058 return connect.emitOpError()
4059 <<
"assignment to 'const' type " << type
4060 <<
" is dependent on a non-'const' condition";
4061 return connect->emitOpError()
4062 <<
"assignment to nested 'const' member of type " << type
4063 <<
" is dependent on a non-'const' condition";
4066 block = parentOp->getBlock();
4071 auto emitSubaccessError = [&] {
4072 return connect.emitError(
4073 "assignment to non-'const' subaccess of 'const' type is disallowed");
4079 if (destType != destRefinedType)
4080 return emitSubaccessError();
4082 if (failed(checkConstConditionality(dest, destType, destDeclaration)))
4087 if (srcRefinedType.containsConst() &&
4090 if (srcType != srcRefinedType)
4091 return emitSubaccessError();
4092 if (failed(checkConstConditionality(src, srcType, srcDeclaration)))
4109 auto dest = connect.getDest();
4110 for (
auto *user : dest.getUsers()) {
4111 if (
auto c = dyn_cast<FConnectLike>(user);
4112 c && c.getDest() == dest && c != connect) {
4113 auto diag = connect.emitError(
"destination cannot be driven by multiple "
4115 diag.attachNote(c->getLoc()) <<
"other driver is here";
4122LogicalResult ConnectOp::verify() {
4123 auto dstType = getDest().getType();
4124 auto srcType = getSrc().getType();
4125 auto dstBaseType = type_dyn_cast<FIRRTLBaseType>(dstType);
4126 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(srcType);
4127 if (!dstBaseType || !srcBaseType) {
4128 if (dstType != srcType)
4129 return emitError(
"may not connect different non-base types");
4132 if (dstBaseType.containsAnalog() || srcBaseType.containsAnalog())
4133 return emitError(
"analog types may not be connected");
4137 return emitError(
"type mismatch between destination ")
4138 << dstBaseType <<
" and source " << srcBaseType;
4143 return emitError(
"destination ")
4144 << dstBaseType <<
" is not as wide as the source " << srcBaseType;
4157LogicalResult MatchingConnectOp::verify() {
4158 if (
auto type = type_dyn_cast<FIRRTLType>(getDest().getType())) {
4159 auto baseType = type_cast<FIRRTLBaseType>(type);
4162 if (baseType && baseType.containsAnalog())
4163 return emitError(
"analog types may not be connected");
4168 "`SameAnonTypeOperands` trait should have already rejected "
4169 "structurally non-equivalent types");
4182LogicalResult RefDefineOp::verify() {
4189 if (
auto *op = getDest().getDefiningOp()) {
4191 if (isa<RefSubOp>(op))
4193 "destination reference cannot be a sub-element of a reference");
4194 if (isa<RefCastOp>(op))
4196 "destination reference cannot be a cast of another reference");
4204 SmallVector<SymbolRefAttr> missingLayers;
4207 "has more layer requirements than destination",
4208 "additional layers required");
4211LogicalResult PropAssignOp::verify() {
4221template <
typename T>
4223 auto info = op.getDomainInfo();
4226 return dyn_cast<FlatSymbolRefAttr>(info[i]);
4230 if (!isa<DomainType>(value.getType()))
4233 if (
auto arg = dyn_cast<BlockArgument>(value)) {
4234 auto *parent = arg.getOwner()->getParentOp();
4235 if (
auto module = dyn_cast<FModuleLike>(parent)) {
4236 auto info =
module.getDomainInfo();
4239 auto attr = info[arg.getArgNumber()];
4240 return dyn_cast<FlatSymbolRefAttr>(attr);
4246 if (
auto result = dyn_cast<OpResult>(value)) {
4247 auto *op = result.getDefiningOp();
4248 if (
auto instance = dyn_cast<InstanceOp>(op))
4250 if (
auto instance = dyn_cast<InstanceChoiceOp>(op))
4258LogicalResult DomainDefineOp::verify() {
4265 auto dst = getDest();
4266 auto src = getSrc();
4270 return emitError(
"could not determine domain-type of destination");
4274 return emitError(
"could not determine domain-type of source");
4276 if (dstDomain != srcDomain) {
4277 auto diag = emitError()
4278 <<
"source domain type " << srcDomain
4279 <<
" does not match destination domain type " << dstDomain;
4286void WhenOp::createElseRegion() {
4287 assert(!hasElseRegion() &&
"already has an else region");
4288 getElseRegion().push_back(
new Block());
4291void WhenOp::build(OpBuilder &builder, OperationState &result, Value condition,
4292 bool withElseRegion, std::function<
void()> thenCtor,
4293 std::function<
void()> elseCtor) {
4294 OpBuilder::InsertionGuard guard(builder);
4295 result.addOperands(condition);
4298 builder.createBlock(result.addRegion());
4303 Region *elseRegion = result.addRegion();
4304 if (withElseRegion) {
4305 builder.createBlock(elseRegion);
4315LogicalResult MatchOp::verify() {
4316 FEnumType type = getInput().getType();
4319 auto numCases = getTags().size();
4320 auto numRegions = getNumRegions();
4321 if (numRegions != numCases)
4322 return emitOpError(
"expected ")
4323 << numRegions <<
" tags but got " << numCases;
4325 auto numTags = type.getNumElements();
4327 SmallDenseSet<int64_t> seen;
4328 for (
const auto &[tag, region] :
llvm::zip(getTags(), getRegions())) {
4329 auto tagIndex = size_t(cast<IntegerAttr>(tag).
getInt());
4332 if (region.getNumArguments() != 1)
4333 return emitOpError(
"region should have exactly one argument");
4336 if (tagIndex >= numTags)
4337 return emitOpError(
"the tag index ")
4338 << tagIndex <<
" is out of the range of valid tags in " << type;
4341 auto [it, inserted] = seen.insert(tagIndex);
4343 return emitOpError(
"the tag ") << type.getElementNameAttr(tagIndex)
4344 <<
" is matched more than once";
4347 auto expectedType = type.getElementTypePreservingConst(tagIndex);
4348 auto regionType = region.getArgument(0).getType();
4349 if (regionType != expectedType)
4350 return emitOpError(
"region type ")
4351 << regionType <<
" does not match the expected type "
4356 for (
size_t i = 0, e = type.getNumElements(); i < e; ++i)
4357 if (!seen.contains(i))
4358 return emitOpError(
"missing case for tag ") << type.getElementNameAttr(i);
4363void MatchOp::print(OpAsmPrinter &p) {
4364 auto input = getInput();
4365 FEnumType type = input.getType();
4366 auto regions = getRegions();
4367 p <<
" " << input <<
" : " << type;
4368 SmallVector<StringRef> elided = {
"tags"};
4369 p.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elided);
4372 for (
const auto &[tag, region] :
llvm::zip(getTags(), regions)) {
4375 p.printKeywordOrString(
4376 type.getElementName(cast<IntegerAttr>(tag).getInt()));
4378 p.printRegionArgument(region.front().getArgument(0), {},
4381 p.printRegion(region,
false);
4388ParseResult MatchOp::parse(OpAsmParser &parser, OperationState &result) {
4389 auto *context = parser.getContext();
4390 auto &properties = result.getOrAddProperties<Properties>();
4391 OpAsmParser::UnresolvedOperand input;
4392 if (parser.parseOperand(input) || parser.parseColon())
4395 auto loc = parser.getCurrentLocation();
4397 if (parser.parseType(type))
4399 auto enumType = type_dyn_cast<FEnumType>(type);
4401 return parser.emitError(loc,
"expected enumeration type but got") << type;
4403 if (parser.resolveOperand(input, type, result.operands) ||
4404 parser.parseOptionalAttrDictWithKeyword(result.attributes) ||
4405 parser.parseLBrace())
4408 auto i32Type = IntegerType::get(context, 32);
4409 SmallVector<Attribute> tags;
4412 if (failed(parser.parseOptionalKeyword(
"case")))
4416 auto nameLoc = parser.getCurrentLocation();
4418 OpAsmParser::Argument arg;
4419 auto *region = result.addRegion();
4420 if (parser.parseKeywordOrString(&name) || parser.parseLParen() ||
4421 parser.parseArgument(arg) || parser.parseRParen())
4425 auto index = enumType.getElementIndex(name);
4427 return parser.emitError(nameLoc,
"the tag \"")
4428 << name <<
"\" is not a member of the enumeration " << enumType;
4429 tags.push_back(IntegerAttr::get(i32Type, *index));
4432 arg.type = enumType.getElementTypePreservingConst(*index);
4433 if (parser.parseRegion(*region, arg))
4436 properties.setTags(ArrayAttr::get(context, tags));
4438 return parser.parseRBrace();
4441void MatchOp::build(OpBuilder &builder, OperationState &result, Value input,
4443 MutableArrayRef<std::unique_ptr<Region>> regions) {
4444 auto &properties = result.getOrAddProperties<Properties>();
4445 result.addOperands(input);
4446 properties.setTags(tags);
4447 result.addRegions(regions);
4456 struct IsExprClassifier :
public ExprVisitor<IsExprClassifier, bool> {
4457 bool visitInvalidExpr(Operation *op) {
return false; }
4458 bool visitUnhandledExpr(Operation *op) {
return true; }
4464void InvalidValueOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4467 if (
auto ty = type_dyn_cast<IntType>(getType())) {
4468 const char *base = ty.isSigned() ?
"invalid_si" :
"invalid_ui";
4469 auto width = ty.getWidthOrSentinel();
4473 name = (Twine(base) + Twine(width)).str();
4474 }
else if (
auto ty = type_dyn_cast<AnalogType>(getType())) {
4475 auto width = ty.getWidthOrSentinel();
4477 name =
"invalid_analog";
4479 name = (
"invalid_analog" + Twine(width)).str();
4480 }
else if (type_isa<AsyncResetType>(getType()))
4481 name =
"invalid_asyncreset";
4482 else if (type_isa<ResetType>(getType()))
4483 name =
"invalid_reset";
4484 else if (type_isa<ClockType>(getType()))
4485 name =
"invalid_clock";
4489 setNameFn(getResult(), name);
4492void ConstantOp::print(OpAsmPrinter &p) {
4494 p.printAttributeWithoutType(getValueAttr());
4496 p.printType(getType());
4497 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4500ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
4501 auto &properties = result.getOrAddProperties<Properties>();
4504 auto loc = parser.getCurrentLocation();
4505 auto valueResult = parser.parseOptionalInteger(value);
4506 if (!valueResult.has_value())
4507 return parser.emitError(loc,
"expected integer value");
4511 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4512 parser.parseOptionalAttrDict(result.attributes))
4514 result.addTypes(resultType);
4520 if (width > value.getBitWidth()) {
4524 value = value.sext(width);
4525 }
else if (width < value.getBitWidth()) {
4528 unsigned neededBits = value.isNegative() ? value.getSignificantBits()
4529 : value.getActiveBits();
4530 if (width < neededBits)
4531 return parser.emitError(loc,
"constant out of range for result type ")
4533 value = value.trunc(width);
4537 auto intType = parser.getBuilder().getIntegerType(value.getBitWidth(),
4539 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4540 properties.setValue(valueAttr);
4544LogicalResult ConstantOp::verify() {
4548 if (width != -1 && (
int)getValue().
getBitWidth() != width)
4550 "firrtl.constant attribute bitwidth doesn't match return type");
4553 auto attrType = type_cast<IntegerType>(getValueAttr().getType());
4554 if (attrType.isSignless() || attrType.isSigned() != intType.
isSigned())
4555 return emitError(
"firrtl.constant attribute has wrong sign");
4562void ConstantOp::build(OpBuilder &builder, OperationState &result,
IntType type,
4563 const APInt &value) {
4566 assert((width == -1 || (int32_t)value.getBitWidth() == width) &&
4567 "incorrect attribute bitwidth for firrtl.constant");
4570 IntegerAttr::get(type.getContext(), APSInt(value, !type.
isSigned()));
4571 return build(builder, result, type, attr);
4576void ConstantOp::build(OpBuilder &builder, OperationState &result,
4577 const APSInt &value) {
4578 auto attr = IntegerAttr::get(builder.getContext(), value);
4580 IntType::get(builder.getContext(), value.isSigned(), value.getBitWidth());
4581 return build(builder, result, type, attr);
4584void ConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4591 SmallString<32> specialNameBuffer;
4592 llvm::raw_svector_ostream specialName(specialNameBuffer);
4594 getValue().print(specialName, intTy.
isSigned());
4596 specialName << (intTy.
isSigned() ?
"_si" :
"_ui");
4599 specialName << width;
4600 setNameFn(getResult(), specialName.str());
4603void SpecialConstantOp::print(OpAsmPrinter &p) {
4606 p << static_cast<unsigned>(getValue());
4608 p.printType(getType());
4609 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4612ParseResult SpecialConstantOp::parse(OpAsmParser &parser,
4613 OperationState &result) {
4614 auto &properties = result.getOrAddProperties<Properties>();
4618 auto loc = parser.getCurrentLocation();
4619 auto valueResult = parser.parseOptionalInteger(value);
4620 if (!valueResult.has_value())
4621 return parser.emitError(loc,
"expected integer value");
4624 if (value != 0 && value != 1)
4625 return parser.emitError(loc,
"special constants can only be 0 or 1.");
4629 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4630 parser.parseOptionalAttrDict(result.attributes))
4632 result.addTypes(resultType);
4635 auto valueAttr = parser.getBuilder().getBoolAttr(value == 1);
4636 properties.setValue(valueAttr);
4640void SpecialConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4641 SmallString<32> specialNameBuffer;
4642 llvm::raw_svector_ostream specialName(specialNameBuffer);
4644 specialName << static_cast<unsigned>(getValue());
4645 auto type = getType();
4646 if (type_isa<ClockType>(type)) {
4647 specialName <<
"_clock";
4648 }
else if (type_isa<ResetType>(type)) {
4649 specialName <<
"_reset";
4650 }
else if (type_isa<AsyncResetType>(type)) {
4651 specialName <<
"_asyncreset";
4653 setNameFn(getResult(), specialName.str());
4660 if (type.isGround()) {
4661 if (!isa<IntegerAttr>(attr)) {
4662 op->emitOpError(
"Ground type is not an integer attribute");
4667 auto attrlist = dyn_cast<ArrayAttr>(attr);
4669 op->emitOpError(
"expected array attribute for aggregate constant");
4672 if (
auto array = type_dyn_cast<FVectorType>(type)) {
4673 if (array.getNumElements() != attrlist.size()) {
4674 op->emitOpError(
"array attribute (")
4675 << attrlist.size() <<
") has wrong size for vector constant ("
4676 << array.getNumElements() <<
")";
4679 return llvm::all_of(attrlist, [&array, op](Attribute attr) {
4683 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4684 if (bundle.getNumElements() != attrlist.size()) {
4685 op->emitOpError(
"array attribute (")
4686 << attrlist.size() <<
") has wrong size for bundle constant ("
4687 << bundle.getNumElements() <<
")";
4690 for (
size_t i = 0; i < bundle.getNumElements(); ++i) {
4691 if (bundle.getElement(i).isFlip) {
4692 op->emitOpError(
"Cannot have constant bundle type with flip");
4700 op->emitOpError(
"Unknown aggregate type");
4704LogicalResult AggregateConstantOp::verify() {
4710Attribute AggregateConstantOp::getAttributeFromFieldID(uint64_t fieldID) {
4712 Attribute value = getFields();
4713 while (fieldID != 0) {
4714 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4715 auto index = bundle.getIndexForFieldID(fieldID);
4716 fieldID -= bundle.getFieldID(index);
4717 type = bundle.getElementType(index);
4718 value = cast<ArrayAttr>(value)[index];
4720 auto vector = type_cast<FVectorType>(type);
4721 auto index = vector.getIndexForFieldID(fieldID);
4722 fieldID -= vector.getFieldID(index);
4723 type = vector.getElementType();
4724 value = cast<ArrayAttr>(value)[index];
4730void FIntegerConstantOp::print(OpAsmPrinter &p) {
4732 p.printAttributeWithoutType(getValueAttr());
4733 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4736ParseResult FIntegerConstantOp::parse(OpAsmParser &parser,
4737 OperationState &result) {
4738 auto *context = parser.getContext();
4739 auto &properties = result.getOrAddProperties<Properties>();
4741 if (parser.parseInteger(value) ||
4742 parser.parseOptionalAttrDict(result.attributes))
4744 result.addTypes(FIntegerType::get(context));
4746 IntegerType::get(context, value.getBitWidth(), IntegerType::Signed);
4747 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4748 properties.setValue(valueAttr);
4752ParseResult ListCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4753 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
4756 if (parser.parseOperandList(operands) ||
4757 parser.parseOptionalAttrDict(result.attributes) ||
4758 parser.parseColonType(type))
4760 result.addTypes(type);
4762 return parser.resolveOperands(operands, type.getElementType(),
4766void ListCreateOp::print(OpAsmPrinter &p) {
4768 p.printOperands(getElements());
4769 p.printOptionalAttrDict((*this)->getAttrs());
4770 p <<
" : " << getType();
4773LogicalResult ListCreateOp::verify() {
4774 if (getElements().
empty())
4777 auto elementType = getElements().front().getType();
4778 auto listElementType = getType().getElementType();
4780 return emitOpError(
"has elements of type ")
4781 <<
elementType <<
" instead of " << listElementType;
4786LogicalResult BundleCreateOp::verify() {
4787 BundleType resultType = getType();
4788 if (resultType.getNumElements() != getFields().size())
4789 return emitOpError(
"number of fields doesn't match type");
4790 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4792 resultType.getElementTypePreservingConst(i),
4793 type_cast<FIRRTLBaseType>(getOperand(i).getType())))
4794 return emitOpError(
"type of element doesn't match bundle for field ")
4795 << resultType.getElement(i).name;
4800LogicalResult VectorCreateOp::verify() {
4801 FVectorType resultType = getType();
4802 if (resultType.getNumElements() != getFields().size())
4803 return emitOpError(
"number of fields doesn't match type");
4804 auto elemTy = resultType.getElementTypePreservingConst();
4805 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4807 elemTy, type_cast<FIRRTLBaseType>(getOperand(i).getType())))
4808 return emitOpError(
"type of element doesn't match vector element");
4817LogicalResult FEnumCreateOp::verify() {
4818 FEnumType resultType = getResult().getType();
4819 auto elementIndex = resultType.getElementIndex(
getFieldName());
4821 return emitOpError(
"label ")
4822 <<
getFieldName() <<
" is not a member of the enumeration type "
4825 resultType.getElementTypePreservingConst(*elementIndex),
4826 getInput().getType()))
4827 return emitOpError(
"type of element doesn't match enum element");
4831void FEnumCreateOp::print(OpAsmPrinter &printer) {
4834 printer <<
'(' << getInput() <<
')';
4835 SmallVector<StringRef> elidedAttrs = {
"fieldIndex"};
4836 printer.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elidedAttrs);
4838 printer.printFunctionalType(ArrayRef<Type>{getInput().getType()},
4839 ArrayRef<Type>{getResult().getType()});
4842ParseResult FEnumCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4843 auto *context = parser.getContext();
4844 auto &properties = result.getOrAddProperties<Properties>();
4846 OpAsmParser::UnresolvedOperand input;
4847 std::string fieldName;
4848 mlir::FunctionType functionType;
4849 if (parser.parseKeywordOrString(&fieldName) || parser.parseLParen() ||
4850 parser.parseOperand(input) || parser.parseRParen() ||
4851 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4852 parser.parseType(functionType))
4855 if (functionType.getNumInputs() != 1)
4856 return parser.emitError(parser.getNameLoc(),
"single input type required");
4857 if (functionType.getNumResults() != 1)
4858 return parser.emitError(parser.getNameLoc(),
"single result type required");
4860 auto inputType = functionType.getInput(0);
4861 if (parser.resolveOperand(input, inputType, result.operands))
4864 auto outputType = functionType.getResult(0);
4865 auto enumType = type_dyn_cast<FEnumType>(outputType);
4867 return parser.emitError(parser.getNameLoc(),
4868 "output must be enum type, got ")
4870 auto fieldIndex = enumType.getElementIndex(fieldName);
4872 return parser.emitError(parser.getNameLoc(),
4873 "unknown field " + fieldName +
" in enum type ")
4876 properties.setFieldIndex(
4877 IntegerAttr::get(IntegerType::get(context, 32), *fieldIndex));
4879 result.addTypes(enumType);
4888LogicalResult IsTagOp::verify() {
4889 if (getFieldIndex() >= getInput().getType().base().getNumElements())
4890 return emitOpError(
"element index is greater than the number of fields in "
4895void IsTagOp::print(::mlir::OpAsmPrinter &printer) {
4896 printer <<
' ' << getInput() <<
' ';
4898 SmallVector<::llvm::StringRef, 1> elidedAttrs = {
"fieldIndex"};
4899 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
4900 printer <<
" : " << getInput().getType();
4903ParseResult IsTagOp::parse(OpAsmParser &parser, OperationState &result) {
4904 auto *context = parser.getContext();
4905 auto &properties = result.getOrAddProperties<Properties>();
4907 OpAsmParser::UnresolvedOperand input;
4908 std::string fieldName;
4910 if (parser.parseOperand(input) || parser.parseKeywordOrString(&fieldName) ||
4911 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4912 parser.parseType(inputType))
4915 if (parser.resolveOperand(input, inputType, result.operands))
4918 auto enumType = type_dyn_cast<FEnumType>(inputType);
4920 return parser.emitError(parser.getNameLoc(),
4921 "input must be enum type, got ")
4923 auto fieldIndex = enumType.getElementIndex(fieldName);
4925 return parser.emitError(parser.getNameLoc(),
4926 "unknown field " + fieldName +
" in enum type ")
4929 properties.setFieldIndex(
4930 IntegerAttr::get(IntegerType::get(context, 32), *fieldIndex));
4932 result.addTypes(UIntType::get(context, 1,
false));
4937FIRRTLType IsTagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
4938 OpaqueProperties properties,
4939 mlir::RegionRange regions,
4940 std::optional<Location> loc) {
4941 Adaptor adaptor(operands, attrs, properties, regions);
4942 return UIntType::get(attrs.getContext(), 1,
4943 isConst(adaptor.getInput().getType()));
4946template <
typename OpTy>
4948 auto *context = parser.getContext();
4950 OpAsmParser::UnresolvedOperand input;
4951 std::string fieldName;
4953 if (parser.parseOperand(input) || parser.parseLSquare() ||
4954 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
4955 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4956 parser.parseType(inputType))
4959 if (parser.resolveOperand(input, inputType, result.operands))
4962 auto bundleType = type_dyn_cast<typename OpTy::InputType>(inputType);
4964 return parser.emitError(parser.getNameLoc(),
4965 "input must be bundle type, got ")
4967 auto fieldIndex = bundleType.getElementIndex(fieldName);
4969 return parser.emitError(parser.getNameLoc(),
4970 "unknown field " + fieldName +
" in bundle type ")
4973 result.getOrAddProperties<
typename OpTy::Properties>().setFieldIndex(
4974 IntegerAttr::get(IntegerType::get(context, 32), *fieldIndex));
4976 auto type = OpTy::inferReturnType(inputType, *fieldIndex, {});
4979 result.addTypes(type);
4984ParseResult SubtagOp::parse(OpAsmParser &parser, OperationState &result) {
4985 auto *context = parser.getContext();
4987 OpAsmParser::UnresolvedOperand input;
4988 std::string fieldName;
4990 if (parser.parseOperand(input) || parser.parseLSquare() ||
4991 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
4992 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4993 parser.parseType(inputType))
4996 if (parser.resolveOperand(input, inputType, result.operands))
4999 auto enumType = type_dyn_cast<FEnumType>(inputType);
5001 return parser.emitError(parser.getNameLoc(),
5002 "input must be enum type, got ")
5004 auto fieldIndex = enumType.getElementIndex(fieldName);
5006 return parser.emitError(parser.getNameLoc(),
5007 "unknown field " + fieldName +
" in enum type ")
5010 result.getOrAddProperties<Properties>().setFieldIndex(
5011 IntegerAttr::get(IntegerType::get(context, 32), *fieldIndex));
5013 SmallVector<Type> inferredReturnTypes;
5014 if (failed(SubtagOp::inferReturnTypes(
5015 context, result.location, result.operands,
5016 result.attributes.getDictionary(context), result.getRawProperties(),
5017 result.regions, inferredReturnTypes)))
5019 result.addTypes(inferredReturnTypes);
5024ParseResult SubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
5025 return parseSubfieldLikeOp<SubfieldOp>(parser, result);
5027ParseResult OpenSubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
5028 return parseSubfieldLikeOp<OpenSubfieldOp>(parser, result);
5031template <
typename OpTy>
5033 printer <<
' ' << op.getInput() <<
'[';
5034 printer.printKeywordOrString(op.getFieldName());
5036 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
5037 elidedAttrs.push_back(
"fieldIndex");
5038 printer.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
5039 printer <<
" : " << op.getInput().getType();
5041void SubfieldOp::print(::mlir::OpAsmPrinter &printer) {
5042 return printSubfieldLikeOp<SubfieldOp>(*
this, printer);
5044void OpenSubfieldOp::print(::mlir::OpAsmPrinter &printer) {
5045 return printSubfieldLikeOp<OpenSubfieldOp>(*
this, printer);
5048void SubtagOp::print(::mlir::OpAsmPrinter &printer) {
5049 printer <<
' ' << getInput() <<
'[';
5052 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
5053 elidedAttrs.push_back(
"fieldIndex");
5054 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
5055 printer <<
" : " << getInput().getType();
5058template <
typename OpTy>
5060 if (op.getFieldIndex() >=
5061 firrtl::type_cast<typename OpTy::InputType>(op.getInput().getType())
5063 return op.emitOpError(
"subfield element index is greater than the number "
5064 "of fields in the bundle type");
5067LogicalResult SubfieldOp::verify() {
5068 return verifySubfieldLike<SubfieldOp>(*
this);
5070LogicalResult OpenSubfieldOp::verify() {
5071 return verifySubfieldLike<OpenSubfieldOp>(*
this);
5074LogicalResult SubtagOp::verify() {
5075 if (getFieldIndex() >= getInput().getType().base().getNumElements())
5076 return emitOpError(
"subfield element index is greater than the number "
5077 "of fields in the bundle type");
5087 SmallVector<Operation *, 8> worklist({op});
5091 bool constant =
true;
5097 while (constant && !(worklist.empty()))
5098 TypeSwitch<Operation *>(worklist.pop_back_val())
5099 .Case<NodeOp, AsSIntPrimOp, AsUIntPrimOp>([&](
auto op) {
5100 if (
auto definingOp = op.getInput().getDefiningOp())
5101 worklist.push_back(definingOp);
5104 .Case<WireOp, SubindexOp, SubfieldOp>([&](
auto op) {
5105 for (
auto &use : op.getResult().getUses())
5106 worklist.push_back(use.getOwner());
5108 .Case<ConstantOp, SpecialConstantOp, AggregateConstantOp>([](
auto) {})
5109 .Default([&](
auto) { constant =
false; });
5118 if (
auto *op = value.getDefiningOp())
5123LogicalResult ConstCastOp::verify() {
5125 return emitOpError() << getInput().getType()
5126 <<
" is not 'const'-castable to "
5127 << getResult().getType();
5131FIRRTLType SubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
5132 std::optional<Location> loc) {
5133 auto inType = type_cast<BundleType>(type);
5135 if (fieldIndex >= inType.getNumElements())
5137 "subfield element index is greater than the "
5138 "number of fields in the bundle type");
5142 return inType.getElementTypePreservingConst(fieldIndex);
5145FIRRTLType OpenSubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
5146 std::optional<Location> loc) {
5147 auto inType = type_cast<OpenBundleType>(type);
5149 if (fieldIndex >= inType.getNumElements())
5151 "subfield element index is greater than the "
5152 "number of fields in the bundle type");
5156 return inType.getElementTypePreservingConst(fieldIndex);
5159bool SubfieldOp::isFieldFlipped() {
5160 BundleType bundle = getInput().getType();
5161 return bundle.getElement(getFieldIndex()).isFlip;
5163bool OpenSubfieldOp::isFieldFlipped() {
5164 auto bundle = getInput().getType();
5165 return bundle.getElement(getFieldIndex()).isFlip;
5168FIRRTLType SubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
5169 std::optional<Location> loc) {
5170 if (
auto vectorType = type_dyn_cast<FVectorType>(type)) {
5171 if (fieldIndex < vectorType.getNumElements())
5172 return vectorType.getElementTypePreservingConst();
5174 "' in vector type ", type);
5179FIRRTLType OpenSubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
5180 std::optional<Location> loc) {
5181 if (
auto vectorType = type_dyn_cast<OpenVectorType>(type)) {
5182 if (fieldIndex < vectorType.getNumElements())
5183 return vectorType.getElementTypePreservingConst();
5185 "' in vector type ", type);
5191FIRRTLType SubtagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5192 OpaqueProperties properties,
5193 mlir::RegionRange regions,
5194 std::optional<Location> loc) {
5195 Adaptor adaptor(operands, attrs, properties, regions);
5196 auto inType = type_cast<FEnumType>(adaptor.getInput().getType());
5197 auto fieldIndex = adaptor.getFieldIndex();
5199 if (fieldIndex >= inType.getNumElements())
5201 "subtag element index is greater than the "
5202 "number of fields in the enum type");
5206 auto elementType = inType.getElement(fieldIndex).type;
5210FIRRTLType SubaccessOp::inferReturnType(Type inType, Type indexType,
5211 std::optional<Location> loc) {
5212 if (!type_isa<UIntType>(indexType))
5216 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
5218 return vectorType.getElementTypePreservingConst();
5219 return vectorType.getElementType().getAllConstDroppedType();
5227 std::optional<Location> loc) {
5228 auto inType = type_cast<FEnumType>(input);
5229 return UIntType::get(inType.getContext(), inType.getTagWidth());
5232ParseResult MultibitMuxOp::parse(OpAsmParser &parser, OperationState &result) {
5233 OpAsmParser::UnresolvedOperand index;
5234 SmallVector<OpAsmParser::UnresolvedOperand, 16> inputs;
5235 Type indexType, elemType;
5237 if (parser.parseOperand(index) || parser.parseComma() ||
5238 parser.parseOperandList(inputs) ||
5239 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5240 parser.parseType(indexType) || parser.parseComma() ||
5241 parser.parseType(elemType))
5244 if (parser.resolveOperand(index, indexType, result.operands))
5247 result.addTypes(elemType);
5249 return parser.resolveOperands(inputs, elemType, result.operands);
5252void MultibitMuxOp::print(OpAsmPrinter &p) {
5253 p <<
" " << getIndex() <<
", ";
5254 p.printOperands(getInputs());
5255 p.printOptionalAttrDict((*this)->getAttrs());
5256 p <<
" : " << getIndex().getType() <<
", " << getType();
5259FIRRTLType MultibitMuxOp::inferReturnType(ValueRange operands,
5260 DictionaryAttr attrs,
5261 OpaqueProperties properties,
5262 mlir::RegionRange regions,
5263 std::optional<Location> loc) {
5264 if (operands.size() < 2)
5268 if (!llvm::all_of(operands.drop_front(2), [&](
auto op) {
5269 return operands[1].getType() == op.getType();
5273 return type_cast<FIRRTLType>(operands[1].getType());
5280LogicalResult ObjectSubfieldOp::inferReturnTypes(
5281 MLIRContext *context, std::optional<mlir::Location> location,
5282 ValueRange operands, DictionaryAttr attributes, OpaqueProperties properties,
5283 RegionRange regions, llvm::SmallVectorImpl<Type> &inferredReturnTypes) {
5285 inferReturnType(operands, attributes, properties, regions, location);
5288 inferredReturnTypes.push_back(type);
5292Type ObjectSubfieldOp::inferReturnType(Type inType, uint32_t fieldIndex,
5293 std::optional<Location> loc) {
5294 auto classType = dyn_cast<ClassType>(inType);
5298 if (classType.getNumElements() <= fieldIndex)
5300 "number of fields in the object");
5301 return classType.getElement(fieldIndex).type;
5304void ObjectSubfieldOp::print(OpAsmPrinter &p) {
5305 auto input = getInput();
5306 auto classType = input.getType();
5307 p <<
' ' << input <<
"[";
5308 p.printKeywordOrString(classType.getElement(getIndex()).name);
5310 p.printOptionalAttrDict((*this)->getAttrs(), std::array{StringRef(
"index")});
5311 p <<
" : " << classType;
5314ParseResult ObjectSubfieldOp::parse(OpAsmParser &parser,
5315 OperationState &result) {
5316 auto *context = parser.getContext();
5318 OpAsmParser::UnresolvedOperand input;
5319 std::string fieldName;
5320 ClassType inputType;
5321 if (parser.parseOperand(input) || parser.parseLSquare() ||
5322 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5323 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5324 parser.parseType(inputType) ||
5325 parser.resolveOperand(input, inputType, result.operands))
5328 auto index = inputType.getElementIndex(fieldName);
5330 return parser.emitError(parser.getNameLoc(),
5331 "unknown field " + fieldName +
" in class type ")
5333 result.getOrAddProperties<Properties>().setIndex(
5334 IntegerAttr::get(IntegerType::get(context, 32), *index));
5336 SmallVector<Type> inferredReturnTypes;
5337 if (failed(inferReturnTypes(context, result.location, result.operands,
5338 result.attributes.getDictionary(context),
5339 result.getRawProperties(), result.regions,
5340 inferredReturnTypes)))
5342 result.addTypes(inferredReturnTypes);
5359 int32_t &rhsWidth,
bool &isConstResult,
5360 std::optional<Location> loc) {
5362 auto lhsi = type_dyn_cast<IntType>(lhs);
5363 auto rhsi = type_dyn_cast<IntType>(rhs);
5364 if (!lhsi || !rhsi || lhsi.isSigned() != rhsi.isSigned()) {
5367 mlir::emitError(*loc,
"second operand must be an integer type, not ")
5369 else if (!lhsi && rhsi)
5370 mlir::emitError(*loc,
"first operand must be an integer type, not ")
5372 else if (!lhsi && !rhsi)
5373 mlir::emitError(*loc,
"operands must be integer types, not ")
5374 << lhs <<
" and " << rhs;
5376 mlir::emitError(*loc,
"operand signedness must match");
5381 lhsWidth = lhsi.getWidthOrSentinel();
5382 rhsWidth = rhsi.getWidthOrSentinel();
5383 isConstResult = lhsi.isConst() && rhsi.isConst();
5388 assert(op->getNumOperands() == 2 &&
5389 "SameOperandsIntTypeKind on non-binary op");
5390 int32_t lhsWidth, rhsWidth;
5393 op->getOperand(1).getType(), lhsWidth,
5394 rhsWidth, isConstResult, op->getLoc()));
5398 std::optional<Location> loc) {
5399 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5400 bool isConstResult =
false;
5404 if (lhsWidth != -1 && rhsWidth != -1)
5405 resultWidth = std::max(lhsWidth, rhsWidth) + 1;
5406 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5411 std::optional<Location> loc) {
5412 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5413 bool isConstResult =
false;
5417 if (lhsWidth != -1 && rhsWidth != -1)
5418 resultWidth = lhsWidth + rhsWidth;
5420 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5425 std::optional<Location> loc) {
5426 int32_t lhsWidth, rhsWidth;
5427 bool isConstResult =
false;
5432 if (type_isa<UIntType>(lhs))
5433 return UIntType::get(lhs.getContext(), lhsWidth, isConstResult);
5436 int32_t resultWidth = lhsWidth != -1 ? lhsWidth + 1 : -1;
5437 return SIntType::get(lhs.getContext(), resultWidth, isConstResult);
5441 std::optional<Location> loc) {
5442 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5443 bool isConstResult =
false;
5447 if (lhsWidth != -1 && rhsWidth != -1)
5448 resultWidth = std::min(lhsWidth, rhsWidth);
5449 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5454 std::optional<Location> loc) {
5455 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5456 bool isConstResult =
false;
5460 if (lhsWidth != -1 && rhsWidth != -1) {
5461 resultWidth = std::max(lhsWidth, rhsWidth);
5462 if (lhsWidth == resultWidth && lhs.
isConst() == isConstResult &&
5465 if (rhsWidth == resultWidth && rhs.
isConst() == isConstResult &&
5469 return UIntType::get(lhs.getContext(), resultWidth, isConstResult);
5473 std::optional<Location> loc) {
5474 if (!type_isa<FVectorType>(lhs) || !type_isa<FVectorType>(rhs))
5477 auto lhsVec = type_cast<FVectorType>(lhs);
5478 auto rhsVec = type_cast<FVectorType>(rhs);
5480 if (lhsVec.getNumElements() != rhsVec.getNumElements())
5485 rhsVec.getElementTypePreservingConst(), loc);
5488 auto elemBaseType = type_cast<FIRRTLBaseType>(elemType);
5489 return FVectorType::get(elemBaseType, lhsVec.getNumElements(),
5490 lhsVec.isConst() && rhsVec.isConst() &&
5491 elemBaseType.isConst());
5495 std::optional<Location> loc) {
5496 return UIntType::get(lhs.getContext(), 1,
isConst(lhs) &&
isConst(rhs));
5499FIRRTLType CatPrimOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5500 OpaqueProperties properties,
5501 mlir::RegionRange regions,
5502 std::optional<Location> loc) {
5504 if (operands.empty())
5505 return UIntType::get(attrs.getContext(), 0);
5508 bool isSigned = type_isa<SIntType>(operands[0].getType());
5509 for (
auto operand : operands) {
5510 auto type = type_dyn_cast<IntType>(operand.getType());
5513 if (type.isSigned() != isSigned)
5515 "all operands must have same signedness");
5519 int32_t resultWidth = 0;
5520 bool isConstResult =
true;
5522 for (
auto operand : operands) {
5523 auto type = type_cast<IntType>(operand.getType());
5524 int32_t width = type.getWidthOrSentinel();
5531 if (resultWidth != -1)
5532 resultWidth += width;
5535 isConstResult &= type.isConst();
5539 return UIntType::get(attrs.getContext(), resultWidth, isConstResult);
5543 std::optional<Location> loc) {
5544 auto lhsi = type_dyn_cast<IntType>(lhs);
5545 auto rhsui = type_dyn_cast<UIntType>(rhs);
5546 if (!rhsui || !lhsi)
5548 loc,
"first operand should be integer, second unsigned int");
5552 auto width = lhsi.getWidthOrSentinel();
5553 if (width == -1 || !rhsui.getWidth().has_value()) {
5556 auto amount = *rhsui.getWidth();
5559 "shift amount too large: second operand of "
5560 "dshl is wider than 31 bits");
5561 int64_t newWidth = (int64_t)width + ((int64_t)1 << amount) - 1;
5562 if (newWidth > INT32_MAX)
5564 loc,
"shift amount too large: first operand shifted by maximum "
5565 "amount exceeds maximum width");
5568 return IntType::get(lhs.getContext(), lhsi.isSigned(), width,
5569 lhsi.
isConst() && rhsui.isConst());
5573 std::optional<Location> loc) {
5574 auto lhsi = type_dyn_cast<IntType>(lhs);
5575 auto rhsu = type_dyn_cast<UIntType>(rhs);
5578 loc,
"first operand should be integer, second unsigned int");
5579 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5583 std::optional<Location> loc) {
5584 auto lhsi = type_dyn_cast<IntType>(lhs);
5585 auto rhsu = type_dyn_cast<UIntType>(rhs);
5588 loc,
"first operand should be integer, second unsigned int");
5589 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5597 std::optional<Location> loc) {
5598 return UIntType::get(input.getContext(), 32);
5602 std::optional<Location> loc) {
5603 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5606 int32_t width = base.getBitWidthOrSentinel();
5609 return SIntType::get(input.getContext(), width, base.
isConst());
5613 std::optional<Location> loc) {
5614 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5617 int32_t width = base.getBitWidthOrSentinel();
5620 return UIntType::get(input.getContext(), width, base.
isConst());
5624 std::optional<Location> loc) {
5625 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5628 "operand must be single bit scalar base type");
5629 int32_t width = base.getBitWidthOrSentinel();
5630 if (width == -2 || width == 0 || width > 1)
5632 return AsyncResetType::get(input.getContext(), base.
isConst());
5636 std::optional<Location> loc) {
5637 return ClockType::get(input.getContext(),
isConst(input));
5641 std::optional<Location> loc) {
5642 if (
auto uiType = type_dyn_cast<UIntType>(input)) {
5643 auto width = uiType.getWidthOrSentinel();
5646 return SIntType::get(input.getContext(), width, uiType.
isConst());
5649 if (type_isa<SIntType>(input))
5656 std::optional<Location> loc) {
5657 auto inputi = type_dyn_cast<IntType>(input);
5660 int32_t width = inputi.getWidthOrSentinel();
5663 return SIntType::get(input.getContext(), width, inputi.
isConst());
5667 std::optional<Location> loc) {
5668 auto inputi = type_dyn_cast<IntType>(input);
5671 if (isa<UIntType>(inputi))
5673 return UIntType::get(input.getContext(), inputi.getWidthOrSentinel(),
5678 std::optional<Location> loc) {
5679 return UIntType::get(input.getContext(), 1,
isConst(input));
5688 std::optional<Location> loc) {
5689 auto inputi = type_dyn_cast<IntType>(input);
5692 loc,
"input type should be the int type but got ", input);
5697 loc,
"high must be equal or greater than low, but got high = ", high,
5705 int32_t width = inputi.getWidthOrSentinel();
5706 if (width != -1 && high >= width)
5709 "high must be smaller than the width of input, but got high = ", high,
5710 ", width = ", width);
5712 return UIntType::get(input.getContext(), high - low + 1, inputi.
isConst());
5716 std::optional<Location> loc) {
5718 auto inputi = type_dyn_cast<IntType>(input);
5719 if (amount < 0 || !inputi)
5721 loc,
"operand must have integer type and amount must be >= 0");
5723 int32_t width = inputi.getWidthOrSentinel();
5724 if (width != -1 && amount > width)
5727 return UIntType::get(input.getContext(), amount, inputi.
isConst());
5742 bool isConstCondition,
5743 std::optional<Location> loc) {
5749 if (high.getTypeID() != low.getTypeID())
5750 return emitInferRetTypeError<FIRRTLBaseType>(
5751 loc,
"incompatible mux operand types, true value type: ", high,
5752 ", false value type: ", low);
5754 bool outerTypeIsConst = isConstCondition && low.
isConst() && high.
isConst();
5759 if (type_isa<IntType>(low)) {
5764 if (highWidth == -1)
5766 return (lowWidth > highWidth ? low : high).getConstType(outerTypeIsConst);
5771 auto highEnum = type_dyn_cast<FEnumType>(high);
5772 auto lowEnum = type_dyn_cast<FEnumType>(low);
5773 if (lowEnum && highEnum) {
5774 if (lowEnum.getNumElements() != highEnum.getNumElements())
5775 return emitInferRetTypeError<FIRRTLBaseType>(
5776 loc,
"incompatible mux operand types, true value type: ", high,
5777 ", false value type: ", low);
5778 SmallVector<FEnumType::EnumElement> elements;
5779 for (
auto [high, low] : llvm::zip_equal(highEnum, lowEnum)) {
5781 if (high.name != low.name || high.value != low.value)
5782 return emitInferRetTypeError<FIRRTLBaseType>(
5783 loc,
"incompatible mux operand types, true value type: ", highEnum,
5784 ", false value type: ", lowEnum);
5791 elements.emplace_back(high.name, high.value, inner);
5793 return FEnumType::get(high.getContext(), elements, outerTypeIsConst);
5797 auto highVector = type_dyn_cast<FVectorType>(high);
5798 auto lowVector = type_dyn_cast<FVectorType>(low);
5799 if (highVector && lowVector &&
5800 highVector.getNumElements() == lowVector.getNumElements()) {
5802 lowVector.getElementTypePreservingConst(),
5803 isConstCondition, loc);
5806 return FVectorType::get(inner, lowVector.getNumElements(),
5811 auto highBundle = type_dyn_cast<BundleType>(high);
5812 auto lowBundle = type_dyn_cast<BundleType>(low);
5813 if (highBundle && lowBundle) {
5814 auto highElements = highBundle.getElements();
5815 auto lowElements = lowBundle.getElements();
5818 SmallVector<BundleType::BundleElement> newElements;
5820 bool failed =
false;
5822 if (highElements[i].name != lowElements[i].name ||
5823 highElements[i].isFlip != lowElements[i].isFlip) {
5827 auto element = highElements[i];
5829 highBundle.getElementTypePreservingConst(i),
5830 lowBundle.getElementTypePreservingConst(i), isConstCondition, loc);
5833 newElements.push_back(element);
5836 return BundleType::get(low.getContext(), newElements, outerTypeIsConst);
5838 return emitInferRetTypeError<FIRRTLBaseType>(
5839 loc,
"incompatible mux operand bundle fields, true value type: ", high,
5840 ", false value type: ", low);
5845 return emitInferRetTypeError<FIRRTLBaseType>(
5846 loc,
"invalid mux operand types, true value type: ", high,
5847 ", false value type: ", low);
5852 std::optional<Location> loc) {
5853 auto highType = type_dyn_cast<FIRRTLBaseType>(high);
5854 auto lowType = type_dyn_cast<FIRRTLBaseType>(low);
5855 if (!highType || !lowType)
5860FIRRTLType Mux2CellIntrinsicOp::inferReturnType(ValueRange operands,
5861 DictionaryAttr attrs,
5862 OpaqueProperties properties,
5863 mlir::RegionRange regions,
5864 std::optional<Location> loc) {
5865 auto highType = type_dyn_cast<FIRRTLBaseType>(operands[1].getType());
5866 auto lowType = type_dyn_cast<FIRRTLBaseType>(operands[2].getType());
5867 if (!highType || !lowType)
5873FIRRTLType Mux4CellIntrinsicOp::inferReturnType(ValueRange operands,
5874 DictionaryAttr attrs,
5875 OpaqueProperties properties,
5876 mlir::RegionRange regions,
5877 std::optional<Location> loc) {
5878 SmallVector<FIRRTLBaseType> types;
5880 for (
unsigned i = 1; i < 5; i++) {
5881 types.push_back(type_dyn_cast<FIRRTLBaseType>(operands[i].getType()));
5886 isConst(operands[0].getType()), loc);
5890 result = types.back();
5897 std::optional<Location> loc) {
5898 auto inputi = type_dyn_cast<IntType>(input);
5899 if (amount < 0 || !inputi)
5901 loc,
"pad input must be integer and amount must be >= 0");
5903 int32_t width = inputi.getWidthOrSentinel();
5907 width = std::max<int32_t>(width, amount);
5908 return IntType::get(input.getContext(), inputi.isSigned(), width,
5913 std::optional<Location> loc) {
5914 auto inputi = type_dyn_cast<IntType>(input);
5915 if (amount < 0 || !inputi)
5917 loc,
"shl input must be integer and amount must be >= 0");
5919 int32_t width = inputi.getWidthOrSentinel();
5923 return IntType::get(input.getContext(), inputi.isSigned(), width,
5928 std::optional<Location> loc) {
5929 auto inputi = type_dyn_cast<IntType>(input);
5930 if (amount < 0 || !inputi)
5932 loc,
"shr input must be integer and amount must be >= 0");
5934 int32_t width = inputi.getWidthOrSentinel();
5937 int32_t minWidth = inputi.isUnsigned() ? 0 : 1;
5938 width = std::max<int32_t>(minWidth, width - amount);
5941 return IntType::get(input.getContext(), inputi.isSigned(), width,
5946 std::optional<Location> loc) {
5948 auto inputi = type_dyn_cast<IntType>(input);
5949 if (amount < 0 || !inputi)
5951 loc,
"tail input must be integer and amount must be >= 0");
5953 int32_t width = inputi.getWidthOrSentinel();
5957 loc,
"amount must be less than or equal operand width");
5968void VerbatimExprOp::getAsmResultNames(
5969 function_ref<
void(Value, StringRef)> setNameFn) {
5973 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
5974 auto name = getText();
5976 if (name.starts_with(
"`"))
5977 name = name.drop_front();
5978 name = name.take_while(isOkCharacter);
5980 setNameFn(getResult(), name);
5987void VerbatimWireOp::getAsmResultNames(
5988 function_ref<
void(Value, StringRef)> setNameFn) {
5992 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
5993 auto name = getText();
5995 if (name.starts_with(
"`"))
5996 name = name.drop_front();
5997 name = name.take_while(isOkCharacter);
5999 setNameFn(getResult(), name);
6010 op->emitError() <<
"unknown width is not allowed for DPI";
6011 return WalkResult::interrupt();
6013 if (width == 1 || width == 8 || width == 16 || width == 32 ||
6015 return WalkResult::advance();
6017 <<
"integer types used by DPI functions must have a "
6018 "specific bit width; "
6019 "it must be equal to 1(bit), 8(byte), 16(shortint), "
6020 "32(int), 64(longint) "
6021 "or greater than 64, but got "
6023 return WalkResult::interrupt();
6028LogicalResult DPICallIntrinsicOp::verify() {
6029 if (
auto inputNames = getInputNames()) {
6030 if (getInputs().size() != inputNames->size())
6031 return emitError() <<
"inputNames has " << inputNames->size()
6032 <<
" elements but there are " << getInputs().size()
6033 <<
" input arguments";
6035 if (
auto outputName = getOutputName())
6036 if (getNumResults() == 0)
6037 return emitError() <<
"output name is given but there is no result";
6039 auto checkType = [
this](Type type) {
6042 return success(llvm::all_of(this->getResultTypes(), checkType) &&
6043 llvm::all_of(this->getOperandTypes(), checkType));
6046SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
6047DPICallIntrinsicOp::computeDataFlow() {
6051 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
6053 for (
auto operand : getOperands()) {
6054 auto type = type_cast<FIRRTLBaseType>(operand.getType());
6056 SmallVector<circt::FieldRef> operandFields;
6059 operandFields.push_back(baseFieldRef.getSubField(dstIndex));
6063 for (
auto result : getResults())
6066 for (
auto field : operandFields)
6067 deps.emplace_back(
circt::
FieldRef(result, dstIndex), field);
6077LogicalResult HWStructCastOp::verify() {
6079 BundleType bundleType;
6080 hw::StructType structType;
6081 if ((bundleType = type_dyn_cast<BundleType>(getOperand().getType()))) {
6082 structType = dyn_cast<hw::StructType>(getType());
6084 return emitError(
"result type must be a struct");
6085 }
else if ((bundleType = type_dyn_cast<BundleType>(getType()))) {
6086 structType = dyn_cast<hw::StructType>(getOperand().getType());
6088 return emitError(
"operand type must be a struct");
6090 return emitError(
"either source or result type must be a bundle type");
6093 auto firFields = bundleType.getElements();
6094 auto hwFields = structType.getElements();
6095 if (firFields.size() != hwFields.size())
6096 return emitError(
"bundle and struct have different number of fields");
6098 for (
size_t findex = 0, fend = firFields.size(); findex < fend; ++findex) {
6099 if (firFields[findex].name.getValue() != hwFields[findex].name)
6100 return emitError(
"field names don't match '")
6101 << firFields[findex].name.getValue() <<
"', '"
6102 << hwFields[findex].name.getValue() <<
"'";
6106 if (firWidth > 0 && hwWidth > 0 && firWidth != hwWidth)
6107 return emitError(
"size of field '")
6108 << hwFields[findex].name.getValue() <<
"' don't match " << firWidth
6115LogicalResult BitCastOp::verify() {
6116 auto inTypeBits =
getBitWidth(getInput().getType(),
true);
6118 if (inTypeBits.has_value() && resTypeBits.has_value()) {
6120 if (*inTypeBits == *resTypeBits) {
6123 return emitError(
"cannot cast non-'const' input type ")
6124 << getOperand().getType() <<
" to 'const' result type "
6128 return emitError(
"the bitwidth of input (")
6129 << *inTypeBits <<
") and result (" << *resTypeBits
6132 if (!inTypeBits.has_value())
6133 return emitError(
"bitwidth cannot be determined for input operand type ")
6134 << getInput().getType();
6135 return emitError(
"bitwidth cannot be determined for result type ")
6146 NamedAttrList &resultAttrs) {
6147 auto result = parser.parseOptionalAttrDict(resultAttrs);
6148 if (!resultAttrs.get(
"annotations"))
6149 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
6155 DictionaryAttr attr,
6156 ArrayRef<StringRef> extraElides = {}) {
6157 SmallVector<StringRef> elidedAttrs(extraElides.begin(), extraElides.end());
6159 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
6160 elidedAttrs.push_back(
"annotations");
6162 elidedAttrs.push_back(
"nameKind");
6164 p.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
6170 NamedAttrList &resultAttrs) {
6173 if (!resultAttrs.get(
"portAnnotations")) {
6174 SmallVector<Attribute, 16> portAnnotations(
6175 parser.getNumResults(), parser.getBuilder().getArrayAttr({}));
6176 resultAttrs.append(
"portAnnotations",
6177 parser.getBuilder().getArrayAttr(portAnnotations));
6184 DictionaryAttr attr,
6185 ArrayRef<StringRef> extraElides = {}) {
6186 SmallVector<StringRef, 2> elidedAttrs(extraElides.begin(), extraElides.end());
6188 if (llvm::all_of(op->getAttrOfType<ArrayAttr>(
"portAnnotations"),
6189 [&](Attribute a) { return cast<ArrayAttr>(a).empty(); }))
6190 elidedAttrs.push_back(
"portAnnotations");
6199 firrtl::NameKindEnumAttr &result) {
6202 if (!parser.parseOptionalKeyword(&keyword,
6203 {
"interesting_name",
"droppable_name"})) {
6204 auto kind = symbolizeNameKindEnum(keyword);
6205 result = NameKindEnumAttr::get(parser.getContext(), kind.value());
6211 NameKindEnumAttr::get(parser.getContext(), NameKindEnum::DroppableName);
6216 firrtl::NameKindEnumAttr attr,
6217 ArrayRef<StringRef> extraElides = {}) {
6218 if (attr.getValue() != NameKindEnum::DroppableName)
6219 p <<
" " << stringifyNameKindEnum(attr.getValue());
6227 NamedAttrList &resultAttrs) {
6235 DictionaryAttr attrs) {
6236 SmallVector<StringRef, 4> elides;
6238 elides.push_back(Forceable::getForceableAttrName());
6247static ParseResult
parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs) {
6252static void printMemOp(OpAsmPrinter &p, Operation *op, DictionaryAttr attr) {
6263 if (ClassType::parseInterface(parser, type))
6270 type.printInterface(p);
6278 NamedAttrList &resultAttrs) {
6279 auto result = p.parseOptionalAttrDict(resultAttrs);
6280 if (!resultAttrs.get(
"name"))
6281 resultAttrs.append(
"name", p.getBuilder().getStringAttr(
""));
6287 DictionaryAttr attr,
6288 ArrayRef<StringRef> extraElides = {}) {
6289 SmallVector<StringRef> elides(extraElides.begin(), extraElides.end());
6290 if (op->getAttrOfType<StringAttr>(
"name").getValue().empty())
6291 elides.push_back(
"name");
6293 p.printOptionalAttrDict(op->getAttrs(), elides);
6297 NamedAttrList &resultAttrs) {
6302 DictionaryAttr attr) {
6307 NamedAttrList &resultAttrs) {
6312 DictionaryAttr attr) {
6314 {
"formatString",
"outputFile",
"operandSegmentSizes"});
6322 DictionaryAttr attr) {
6331 DictionaryAttr attr) {
6340 OpAsmSetValueNameFn setNameFn) {
6343 if (op->getNumResults() == 1)
6344 if (
auto nameAttr = op->getAttrOfType<StringAttr>(
"name"))
6345 setNameFn(op->getResult(0), nameAttr.getValue());
6348void AddPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6352void AndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6356void AndRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6360void SizeOfIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6363void AsAsyncResetPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6366void AsClockPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6369void AsSIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6372void AsUIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6375void BitsPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6378void CatPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6381void CvtPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6384void DShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6387void DShlwPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6390void DShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6393void DivPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6396void EQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6399void GEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6402void GTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6405void GenericIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6408void HeadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6411void IntegerAddOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6414void IntegerMulOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6417void IntegerShrOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6420void IntegerShlOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6423void IsTagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6426void IsXIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6429void PlusArgsValueIntrinsicOp::getAsmResultNames(
6430 OpAsmSetValueNameFn setNameFn) {
6433void PlusArgsTestIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6436void LEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6439void LTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6442void MulPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6445void MultibitMuxOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6448void MuxPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6451void Mux4CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6454void Mux2CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6457void NEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6460void NegPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6463void NotPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6466void OrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6469void OrRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6472void PadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6475void RemPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6478void ShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6481void ShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6485void SubPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6489void SubaccessOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6493void SubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6497void OpenSubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6501void SubtagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6505void SubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6509void OpenSubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6513void TagExtractOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6517void TailPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6521void XorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6525void XorRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6529void UninferredResetCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6533void ConstCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6537void ElementwiseXorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6541void ElementwiseOrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6545void ElementwiseAndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6553void RefCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6557void RefResolveOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6561void RefSendOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6565void RefSubOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6569void RWProbeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6573FIRRTLType RefResolveOp::inferReturnType(ValueRange operands,
6574 DictionaryAttr attrs,
6575 OpaqueProperties properties,
6576 mlir::RegionRange regions,
6577 std::optional<Location> loc) {
6578 Type inType = operands[0].getType();
6579 auto inRefType = type_dyn_cast<RefType>(inType);
6582 loc,
"ref.resolve operand must be ref type, not ", inType);
6583 return inRefType.getType();
6586FIRRTLType RefSendOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
6587 OpaqueProperties properties,
6588 mlir::RegionRange regions,
6589 std::optional<Location> loc) {
6590 Type inType = operands[0].getType();
6591 auto inBaseType = type_dyn_cast<FIRRTLBaseType>(inType);
6594 loc,
"ref.send operand must be base type, not ", inType);
6595 return RefType::get(inBaseType.getPassiveType());
6598FIRRTLType RefSubOp::inferReturnType(Type type, uint32_t fieldIndex,
6599 std::optional<Location> loc) {
6600 auto refType = type_dyn_cast<RefType>(type);
6603 auto inType = refType.getType();
6609 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
6610 if (fieldIndex < vectorType.getNumElements())
6611 return RefType::get(
6612 vectorType.getElementType().getConstType(
6613 vectorType.isConst() || vectorType.getElementType().isConst()),
6614 refType.getForceable(), refType.getLayer());
6616 "' in RefType of vector type ", refType);
6618 if (
auto bundleType = type_dyn_cast<BundleType>(inType)) {
6619 if (fieldIndex >= bundleType.getNumElements()) {
6621 "subfield element index is greater than "
6622 "the number of fields in the bundle type");
6624 return RefType::get(
6625 bundleType.getElement(fieldIndex)
6627 bundleType.isConst() ||
6628 bundleType.getElement(fieldIndex).type.isConst()),
6629 refType.getForceable(), refType.getLayer());
6633 loc,
"ref.sub op requires a RefType of vector or bundle base type");
6636LogicalResult RefCastOp::verify() {
6640 getOperation(), srcLayers, dstLayers,
6641 "cannot discard layer requirements of input reference",
6642 "discarding layer requirements");
6645LogicalResult RefResolveOp::verify() {
6649 getOperation(), srcLayers, dstLayers,
6650 "ambient layers are insufficient to resolve reference");
6654 auto targetRef = getTarget();
6655 if (targetRef.getModule() !=
6656 (*this)->getParentOfType<FModuleLike>().getModuleNameAttr())
6657 return emitOpError() <<
"has non-local target";
6659 auto target = ns.
lookup(targetRef);
6661 return emitOpError() <<
"has target that cannot be resolved: " << targetRef;
6663 auto checkFinalType = [&](
auto type, Location loc) -> LogicalResult {
6668 auto baseType = type_dyn_cast<FIRRTLBaseType>(fType);
6669 if (!baseType || baseType.getPassiveType() != getType().getType()) {
6670 auto diag = emitOpError(
"has type mismatch: target resolves to ")
6671 << fType <<
" instead of expected " << getType().getType();
6672 diag.attachNote(loc) <<
"target resolves here";
6677 if (target.isPort()) {
6678 auto mod = cast<FModuleLike>(target.getOp());
6679 return checkFinalType(mod.getPortType(target.getPort()),
6680 mod.getPortLocation(target.getPort()));
6682 hw::InnerSymbolOpInterface symOp =
6683 cast<hw::InnerSymbolOpInterface>(target.getOp());
6684 if (!symOp.getTargetResult())
6685 return emitOpError(
"has target that cannot be probed")
6686 .attachNote(symOp.getLoc())
6687 .append(
"target resolves here");
6689 symOp.getTargetResult().getParentBlock()->findAncestorOpInBlock(**
this);
6690 if (!ancestor || !symOp->isBeforeInBlock(ancestor))
6691 return emitOpError(
"is not dominated by target")
6692 .attachNote(symOp.getLoc())
6693 .append(
"target here");
6694 return checkFinalType(symOp.getTargetResult().getType(), symOp.getLoc());
6697LogicalResult RefForceOp::verify() {
6701 getOperation(), destLayers, ambientLayers,
6702 "has insufficient ambient layers to force its reference");
6705LogicalResult RefForceInitialOp::verify() {
6709 getOperation(), destLayers, ambientLayers,
6710 "has insufficient ambient layers to force its reference");
6713LogicalResult RefReleaseOp::verify() {
6717 getOperation(), destLayers, ambientLayers,
6718 "has insufficient ambient layers to release its reference");
6721LogicalResult RefReleaseInitialOp::verify() {
6725 getOperation(), destLayers, ambientLayers,
6726 "has insufficient ambient layers to release its reference");
6729LogicalResult XMRRefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6730 auto *target = symbolTable.lookupNearestSymbolFrom(*
this, getRefAttr());
6732 return emitOpError(
"has an invalid symbol reference");
6734 if (!isa<hw::HierPathOp>(target))
6735 return emitOpError(
"does not target a hierpath op");
6741LogicalResult XMRDerefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6742 auto *target = symbolTable.lookupNearestSymbolFrom(*
this, getRefAttr());
6744 return emitOpError(
"has an invalid symbol reference");
6746 if (!isa<hw::HierPathOp>(target))
6747 return emitOpError(
"does not target a hierpath op");
6757LogicalResult LayerBlockOp::verify() {
6758 auto layerName = getLayerName();
6759 auto *parentOp = (*this)->getParentOp();
6762 while (isa<WhenOp, MatchOp>(parentOp))
6763 parentOp = parentOp->getParentOp();
6767 auto nestedReferences = layerName.getNestedReferences();
6768 if (nestedReferences.empty()) {
6769 if (!isa<FModuleOp>(parentOp)) {
6770 auto diag = emitOpError() <<
"has an un-nested layer symbol, but does "
6771 "not have a 'firrtl.module' op as a parent";
6772 return diag.attachNote(parentOp->getLoc())
6773 <<
"illegal parent op defined here";
6776 auto parentLayerBlock = dyn_cast<LayerBlockOp>(parentOp);
6777 if (!parentLayerBlock) {
6778 auto diag = emitOpError()
6779 <<
"has a nested layer symbol, but does not have a '"
6780 << getOperationName() <<
"' op as a parent'";
6781 return diag.attachNote(parentOp->getLoc())
6782 <<
"illegal parent op defined here";
6784 auto parentLayerBlockName = parentLayerBlock.getLayerName();
6785 if (parentLayerBlockName.getRootReference() !=
6786 layerName.getRootReference() ||
6787 parentLayerBlockName.getNestedReferences() !=
6788 layerName.getNestedReferences().drop_back()) {
6789 auto diag = emitOpError() <<
"is nested under an illegal layer block";
6790 return diag.attachNote(parentLayerBlock->getLoc())
6791 <<
"illegal parent layer block defined here";
6797 auto result = getBody(0)->walk<mlir::WalkOrder::PreOrder>(
6798 [&](Operation *op) -> WalkResult {
6800 if (isa<LayerBlockOp>(op))
6801 return WalkResult::skip();
6805 for (
auto operand : op->getOperands()) {
6807 if (
auto *definingOp = operand.getDefiningOp())
6811 auto type = operand.getType();
6814 if (isa<PropertyType>(type)) {
6815 auto diag = emitOpError() <<
"captures a property operand";
6816 diag.attachNote(operand.getLoc()) <<
"operand is defined here";
6817 diag.attachNote(op->getLoc()) <<
"operand is used here";
6818 return WalkResult::interrupt();
6823 if (
auto connect = dyn_cast<FConnectLike>(op)) {
6825 if (isa<RefDefineOp>(connect))
6826 return WalkResult::advance();
6833 bool passive =
true;
6835 type_dyn_cast<FIRRTLBaseType>(
connect.getDest().getType()))
6836 passive = type.isPassive();
6845 return WalkResult::advance();
6848 return WalkResult::advance();
6852 <<
"connects to a destination which is defined outside its "
6853 "enclosing layer block";
6854 diag.attachNote(
getLoc()) <<
"enclosing layer block is defined here";
6855 diag.attachNote(dest.getLoc()) <<
"destination is defined here";
6856 return WalkResult::interrupt();
6859 return WalkResult::advance();
6862 return failure(result.wasInterrupted());
6866LayerBlockOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6868 symbolTable.lookupNearestSymbolFrom<LayerOp>(*
this, getLayerNameAttr());
6870 return emitOpError(
"invalid symbol reference");
6880void TimeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6881 setNameFn(getResult(),
"time");
6884void HierarchicalModuleNameOp::getAsmResultNames(
6885 OpAsmSetValueNameFn setNameFn) {
6886 setNameFn(getResult(),
"hierarchicalmodulename");
6889ParseResult FPrintFOp::parse(::mlir::OpAsmParser &parser,
6890 ::mlir::OperationState &result) {
6892 OpAsmParser::UnresolvedOperand clock, cond;
6893 if (parser.parseOperand(clock) || parser.parseComma() ||
6894 parser.parseOperand(cond) || parser.parseComma())
6897 auto parseFormatString =
6898 [&parser](llvm::SMLoc &loc, StringAttr &result,
6899 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &operands)
6901 loc = parser.getCurrentLocation();
6904 std::string resultStr;
6905 if (parser.parseString(&resultStr))
6907 result = parser.getBuilder().getStringAttr(resultStr);
6910 if (parser.parseOperandList(operands, AsmParser::Delimiter::OptionalParen))
6916 SmallVector<OpAsmParser::UnresolvedOperand> outputFileSubstitutions,
6918 llvm::SMLoc outputFileLoc, formatStringLoc;
6920 if (parseFormatString(
6922 result.getOrAddProperties<FPrintFOp::Properties>().outputFile,
6923 outputFileSubstitutions) ||
6924 parser.parseComma() ||
6927 result.getOrAddProperties<FPrintFOp::Properties>().formatString,
6935 Type clockType, condType;
6936 SmallVector<Type> restTypes;
6938 if (parser.parseColon() || parser.parseType(clockType) ||
6939 parser.parseComma() || parser.parseType(condType))
6942 if (succeeded(parser.parseOptionalComma())) {
6943 if (parser.parseTypeList(restTypes))
6948 result.getOrAddProperties<FPrintFOp::Properties>().operandSegmentSizes = {
6949 1, 1,
static_cast<int32_t
>(outputFileSubstitutions.size()),
6950 static_cast<int32_t
>(substitutions.size())};
6953 if (parser.resolveOperand(clock, clockType, result.operands) ||
6954 parser.resolveOperand(cond, condType, result.operands) ||
6955 parser.resolveOperands(
6956 outputFileSubstitutions,
6957 ArrayRef(restTypes).take_front(outputFileSubstitutions.size()),
6958 outputFileLoc, result.operands) ||
6959 parser.resolveOperands(
6961 ArrayRef(restTypes).drop_front(outputFileSubstitutions.size()),
6962 formatStringLoc, result.operands))
6968void FPrintFOp::print(OpAsmPrinter &p) {
6969 p <<
" " << getClock() <<
", " << getCond() <<
", ";
6970 p.printAttributeWithoutType(getOutputFileAttr());
6971 if (!getOutputFileSubstitutions().
empty()) {
6973 p.printOperands(getOutputFileSubstitutions());
6977 p.printAttributeWithoutType(getFormatStringAttr());
6978 if (!getSubstitutions().
empty()) {
6980 p.printOperands(getSubstitutions());
6984 p <<
" : " << getClock().getType() <<
", " << getCond().getType();
6985 if (!getOutputFileSubstitutions().
empty() || !getSubstitutions().
empty()) {
6986 for (
auto type : getOperands().drop_front(2).getTypes()) {
6997LogicalResult FFlushOp::verify() {
6998 if (!getOutputFileAttr() && !getOutputFileSubstitutions().
empty())
6999 return emitOpError(
"substitutions without output file are not allowed");
7008 auto ref = getInstanceAttr();
7009 auto target = ns.
lookup(ref);
7011 return emitError() <<
"target " << ref <<
" cannot be resolved";
7013 if (!target.isOpOnly())
7014 return emitError() <<
"target " << ref <<
" is not an operation";
7016 auto instance = dyn_cast<InstanceOp>(target.getOp());
7018 return emitError() <<
"target " << ref <<
" is not an instance";
7020 if (!instance.getDoNotPrint())
7021 return emitError() <<
"target " << ref <<
" is not marked doNotPrint";
7031#define GET_OP_CLASSES
7032#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 Attribute fixDomainInfoInsertions(MLIRContext *context, Attribute domainInfoAttr, ArrayRef< unsigned > indexMap)
Return an updated domain info Attribute with domain indices updated based on port insertions.
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 FlatSymbolRefAttr getDomainTypeName(Value value)
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 printFPrintfAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
static LogicalResult checkSingleConnect(FConnectLike connect)
Returns success if the given connect is the sole driver of its dest operand.
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 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 FlatSymbolRefAttr getDomainTypeNameOfResult(T op, size_t i)
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 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 void replaceUsesRespectingInsertedPorts(Operation *op1, Operation *op2, ArrayRef< std::pair< unsigned, PortInfo > > insertions)
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 void insertPorts(FModuleLike op, ArrayRef< std::pair< unsigned, PortInfo > > ports)
Inserts the given ports.
static ParseResult parseFPrintfAttrs(OpAsmParser &p, NamedAttrList &resultAttrs)
static ParseResult parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs)
static void replaceUsesRespectingErasedPorts(Operation *op1, Operation *op2, const llvm::BitVector &erasures)
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)
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.