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 results.reserve(module.getNumPorts());
657 ArrayRef<Attribute> domains =
module.getDomainInfo();
658 for (
unsigned i = 0, e = module.getNumPorts(); i < e; ++i) {
659 results.push_back({
module.getPortNameAttr(i), module.getPortType(i),
660 module.getPortDirection(i), module.getPortSymbolAttr(i),
661 module.getPortLocation(i),
662 AnnotationSet::forPort(module, i),
663 domains.empty() ? Attribute{} : domains[i]});
668SmallVector<PortInfo> FModuleOp::getPorts() { return ::getPortImpl(*
this); }
670SmallVector<PortInfo> FExtModuleOp::getPorts() { return ::getPortImpl(*
this); }
672SmallVector<PortInfo> FIntModuleOp::getPorts() { return ::getPortImpl(*
this); }
674SmallVector<PortInfo> FMemModuleOp::getPorts() { return ::getPortImpl(*
this); }
677 if (dir == Direction::In)
678 return hw::ModulePort::Direction::Input;
679 if (dir == Direction::Out)
680 return hw::ModulePort::Direction::Output;
681 assert(0 &&
"invalid direction");
686 SmallVector<hw::PortInfo> results;
687 auto aname = StringAttr::get(module.getContext(),
688 hw::HWModuleLike::getPortSymbolAttrName());
689 auto emptyDict = DictionaryAttr::get(module.getContext());
690 for (
unsigned i = 0, e =
getNumPorts(module); i < e; ++i) {
691 auto sym =
module.getPortSymbolAttr(i);
693 {{
module.getPortNameAttr(i), module.getPortType(i),
694 dirFtoH(module.getPortDirection(i))},
696 sym ? DictionaryAttr::get(
698 ArrayRef<mlir::NamedAttribute>{NamedAttribute{aname, sym}})
700 module.getPortLocation(i)});
705SmallVector<::circt::hw::PortInfo> FModuleOp::getPortList() {
706 return ::getPortListImpl(*
this);
709SmallVector<::circt::hw::PortInfo> FExtModuleOp::getPortList() {
710 return ::getPortListImpl(*
this);
713SmallVector<::circt::hw::PortInfo> FIntModuleOp::getPortList() {
714 return ::getPortListImpl(*
this);
717SmallVector<::circt::hw::PortInfo> FMemModuleOp::getPortList() {
718 return ::getPortListImpl(*
this);
722 auto sym =
module.getPortSymbolAttr(idx);
723 auto attrs = sym ? DictionaryAttr::getWithSorted(
725 ArrayRef(mlir::NamedAttribute(
726 hw::HWModuleLike::getPortSymbolAttrName(), sym)))
727 : DictionaryAttr::get(module.getContext());
728 return {{
module.getPortNameAttr(idx), module.getPortType(idx),
729 dirFtoH(module.getPortDirection(idx))},
732 module.getPortLocation(idx)};
736 return ::getPortImpl(*
this, idx);
740 return ::getPortImpl(*
this, idx);
744 return ::getPortImpl(*
this, idx);
748 return ::getPortImpl(*
this, idx);
752BlockArgument FModuleOp::getArgument(
size_t portNumber) {
759 Attribute domainInfoAttr,
760 ArrayRef<unsigned> indexMap) {
762 auto di = dyn_cast_or_null<ArrayAttr>(domainInfoAttr);
763 if (!di || di.empty())
764 return domainInfoAttr;
767 SmallVector<Attribute> domainInfo;
768 for (
auto attr : di) {
769 auto oldIdx = cast<IntegerAttr>(attr).getUInt();
770 auto newIdx = indexMap[oldIdx];
771 if (oldIdx == newIdx)
772 domainInfo.push_back(attr);
774 domainInfo.push_back(IntegerAttr::get(
775 IntegerType::get(
context, 32, IntegerType::Unsigned), newIdx));
777 return ArrayAttr::get(
context, domainInfo);
784 ArrayRef<std::pair<unsigned, PortInfo>> ports) {
787 unsigned oldNumArgs = op.getNumPorts();
788 unsigned newNumArgs = oldNumArgs + ports.size();
791 SmallVector<unsigned> indexMap(oldNumArgs);
793 for (
size_t i = 0; i < oldNumArgs; ++i) {
794 while (inserted < ports.size() && ports[inserted].first == i)
796 indexMap[i] = i + inserted;
800 auto existingDirections = op.getPortDirectionsAttr();
801 ArrayRef<Attribute> existingNames = op.getPortNames();
802 ArrayRef<Attribute> existingTypes = op.getPortTypes();
803 ArrayRef<Attribute> existingLocs = op.getPortLocations();
804 assert(existingDirections.size() == oldNumArgs);
805 assert(existingNames.size() == oldNumArgs);
806 assert(existingTypes.size() == oldNumArgs);
807 assert(existingLocs.size() == oldNumArgs);
809 SmallVector<bool> newDirections;
810 SmallVector<Attribute> newNames, newTypes, newDomains, newAnnos, newSyms,
812 newDirections.reserve(newNumArgs);
813 newNames.reserve(newNumArgs);
814 newTypes.reserve(newNumArgs);
815 newDomains.reserve(newNumArgs);
816 newAnnos.reserve(newNumArgs);
817 newSyms.reserve(newNumArgs);
818 newLocs.reserve(newNumArgs);
820 auto emptyArray = ArrayAttr::get(op.getContext(), {});
823 auto migrateOldPorts = [&](
unsigned untilOldIdx) {
824 while (oldIdx < oldNumArgs && oldIdx < untilOldIdx) {
825 newDirections.push_back(existingDirections[oldIdx]);
826 newNames.push_back(existingNames[oldIdx]);
827 newTypes.push_back(existingTypes[oldIdx]);
829 op.getContext(), op.getDomainInfoAttrForPort(oldIdx), indexMap));
830 newAnnos.push_back(op.getAnnotationsAttrForPort(oldIdx));
831 newSyms.push_back(op.getPortSymbolAttr(oldIdx));
832 newLocs.push_back(existingLocs[oldIdx]);
837 for (
auto [idx, port] : ports) {
838 migrateOldPorts(idx);
840 newNames.push_back(port.name);
841 newTypes.push_back(TypeAttr::get(port.type));
844 port.domains ? port.domains : ArrayAttr::get(op.getContext(), {}),
846 auto annos = port.annotations.getArrayAttr();
847 newAnnos.push_back(annos ? annos : emptyArray);
848 newSyms.push_back(port.sym);
849 newLocs.push_back(port.loc);
852 migrateOldPorts(oldNumArgs);
856 if (llvm::all_of(newAnnos, [](Attribute attr) {
857 return cast<ArrayAttr>(attr).empty();
863 if (llvm::all_of(newDomains, [](Attribute attr) {
866 if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr))
867 return arrayAttr.empty();
873 op->setAttr(
"portDirections",
875 op->setAttr(
"portNames", ArrayAttr::get(op.getContext(), newNames));
876 op->setAttr(
"portTypes", ArrayAttr::get(op.getContext(), newTypes));
877 op->setAttr(
"domainInfo", ArrayAttr::get(op.getContext(), newDomains));
878 op->setAttr(
"portAnnotations", ArrayAttr::get(op.getContext(), newAnnos));
879 FModuleLike::fixupPortSymsArray(newSyms, op.getContext());
880 op.setPortSymbols(newSyms);
881 op->setAttr(
"portLocations", ArrayAttr::get(op.getContext(), newLocs));
892 ArrayAttr domainInfoAttr,
893 const llvm::BitVector &portIndices,
894 bool supportsEmptyAttr) {
895 if (supportsEmptyAttr && domainInfoAttr.empty())
896 return domainInfoAttr;
899 SmallVector<unsigned> indexMap(portIndices.size());
901 for (
size_t i = 0, e = portIndices.size(); i != e; ++i) {
902 indexMap[i] = i - deleted;
909 auto getEmpty = [&]() {
911 eEmpty = ArrayAttr::get(
context, {});
916 SmallVector<Attribute> newDomainInfo;
917 newDomainInfo.reserve(portIndices.size() - portIndices.count());
918 for (
size_t i = 0, e = portIndices.size(); i != e; ++i) {
920 if (portIndices.test(i))
923 if (domainInfoAttr.empty()) {
924 newDomainInfo.push_back(getEmpty());
927 auto attr = domainInfoAttr[i];
929 auto domains = dyn_cast<ArrayAttr>(attr);
930 if (!domains || domains.empty()) {
931 newDomainInfo.push_back(attr);
935 SmallVector<Attribute> newDomains;
936 for (
auto domain : domains) {
938 auto oldIdx = cast<IntegerAttr>(domain).getUInt();
939 if (portIndices.test(oldIdx))
942 auto newIdx = indexMap[oldIdx];
943 if (oldIdx == newIdx) {
944 newDomains.push_back(domain);
948 newDomains.push_back(IntegerAttr::get(
949 IntegerType::get(
context, 32, IntegerType::Unsigned), newIdx));
951 newDomainInfo.push_back(ArrayAttr::get(
context, newDomains));
954 return ArrayAttr::get(
context, newDomainInfo);
958static void erasePorts(FModuleLike op,
const llvm::BitVector &portIndices) {
959 if (portIndices.none())
963 ArrayRef<bool> portDirections = op.getPortDirectionsAttr().asArrayRef();
964 ArrayRef<Attribute> portNames = op.getPortNames();
965 ArrayRef<Attribute> portTypes = op.getPortTypes();
966 ArrayRef<Attribute> portAnnos = op.getPortAnnotations();
967 ArrayRef<Attribute> portSyms = op.getPortSymbols();
968 ArrayRef<Attribute> portLocs = op.getPortLocations();
969 ArrayRef<Attribute> portDomains = op.getDomainInfo();
970 auto numPorts = op.getNumPorts();
972 assert(portDirections.size() == numPorts);
973 assert(portNames.size() == numPorts);
974 assert(portAnnos.size() == numPorts || portAnnos.empty());
975 assert(portTypes.size() == numPorts);
976 assert(portSyms.size() == numPorts || portSyms.empty());
977 assert(portLocs.size() == numPorts);
978 assert(portDomains.size() == numPorts || portDomains.empty());
980 SmallVector<bool> newPortDirections =
981 removeElementsAtIndices<bool>(portDirections, portIndices);
982 SmallVector<Attribute> newPortNames, newPortTypes, newPortAnnos, newPortSyms,
990 op->setAttr(
"portDirections",
992 op->setAttr(
"portNames", ArrayAttr::get(op.getContext(), newPortNames));
993 op->setAttr(
"portAnnotations", ArrayAttr::get(op.getContext(), newPortAnnos));
994 op->setAttr(
"portTypes", ArrayAttr::get(op.getContext(), newPortTypes));
995 FModuleLike::fixupPortSymsArray(newPortSyms, op.getContext());
996 op->setAttr(
"portSymbols", ArrayAttr::get(op.getContext(), newPortSyms));
997 op->setAttr(
"portLocations", ArrayAttr::get(op.getContext(), newPortLocs));
998 op->setAttr(
"domainInfo",
1000 portIndices,
true));
1003void FExtModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1004 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1007void FIntModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1008 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1011void FMemModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1012 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1015void FModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1016 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1023void FModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1024 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1028 for (
size_t i = 0, e = ports.size(); i < e; ++i) {
1031 auto &[index, port] = ports[i];
1032 body->insertArgument(index + i, port.type, port.loc);
1036void FExtModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1037 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1040void FIntModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1041 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1047void FMemModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1048 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1051template <
typename OpTy>
1053 StringAttr name, ArrayRef<PortInfo> ports) {
1055 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
1056 properties.setSymName(name);
1059 SmallVector<Direction, 4> portDirections;
1060 SmallVector<Attribute, 4> portNames, portTypes, portSyms, portLocs,
1062 portDirections.reserve(ports.size());
1063 portNames.reserve(ports.size());
1064 portTypes.reserve(ports.size());
1065 portSyms.reserve(ports.size());
1066 portLocs.reserve(ports.size());
1067 portDomains.reserve(ports.size());
1069 for (
const auto &port : ports) {
1070 portDirections.push_back(port.direction);
1071 portNames.push_back(port.name);
1072 portTypes.push_back(TypeAttr::get(port.type));
1073 portSyms.push_back(port.sym);
1074 portLocs.push_back(port.loc);
1075 portDomains.push_back(port.domains);
1077 if (llvm::all_of(portDomains, [](Attribute attr) {
1080 if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr))
1081 return arrayAttr.empty();
1084 portDomains.clear();
1086 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1089 properties.setPortDirections(
1091 properties.setPortNames(builder.getArrayAttr(portNames));
1092 properties.setPortTypes(builder.getArrayAttr(portTypes));
1093 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1094 properties.setPortLocations(builder.getArrayAttr(portLocs));
1095 properties.setDomainInfo(builder.getArrayAttr(portDomains));
1100template <
typename OpTy>
1102 StringAttr name, ArrayRef<PortInfo> ports,
1103 ArrayAttr annotations, ArrayAttr layers) {
1104 buildModuleLike<OpTy>(builder, result, name, ports);
1105 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
1108 annotations = builder.getArrayAttr({});
1109 properties.setAnnotations(annotations);
1113 SmallVector<Attribute, 4> portAnnotations;
1114 for (
const auto &port : ports)
1115 portAnnotations.push_back(port.annotations.getArrayAttr());
1116 if (llvm::all_of(portAnnotations, [](Attribute attr) {
1117 return cast<ArrayAttr>(attr).empty();
1119 portAnnotations.clear();
1120 properties.setPortAnnotations(builder.getArrayAttr(portAnnotations));
1124 layers = builder.getArrayAttr({});
1125 properties.setLayers(layers);
1128template <
typename OpTy>
1129static void buildClass(OpBuilder &builder, OperationState &result,
1130 StringAttr name, ArrayRef<PortInfo> ports) {
1131 return buildModuleLike<OpTy>(builder, result, name, ports);
1134void FModuleOp::build(OpBuilder &builder, OperationState &result,
1135 StringAttr name, ConventionAttr convention,
1136 ArrayRef<PortInfo> ports, ArrayAttr annotations,
1138 buildModule<FModuleOp>(builder, result, name, ports, annotations, layers);
1139 auto &properties = result.getOrAddProperties<Properties>();
1140 properties.setConvention(convention);
1143 auto *bodyRegion = result.regions[0].get();
1145 bodyRegion->push_back(body);
1148 for (
auto &elt : ports)
1149 body->addArgument(elt.type, elt.loc);
1152void FExtModuleOp::build(OpBuilder &builder, OperationState &result,
1153 StringAttr name, ConventionAttr convention,
1154 ArrayRef<PortInfo> ports, ArrayAttr knownLayers,
1155 StringRef defnameAttr, ArrayAttr annotations,
1156 ArrayAttr parameters, ArrayAttr layers,
1157 ArrayAttr externalRequirements) {
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);
1169 if (externalRequirements)
1170 properties.setExternalRequirements(externalRequirements);
1173void FIntModuleOp::build(OpBuilder &builder, OperationState &result,
1174 StringAttr name, ArrayRef<PortInfo> ports,
1175 StringRef intrinsicNameStr, ArrayAttr annotations,
1176 ArrayAttr parameters, ArrayAttr layers) {
1177 buildModule<FIntModuleOp>(builder, result, name, ports, annotations, layers);
1178 auto &properties = result.getOrAddProperties<Properties>();
1179 properties.setIntrinsic(builder.getStringAttr(intrinsicNameStr));
1181 parameters = builder.getArrayAttr({});
1182 properties.setParameters(parameters);
1185void FMemModuleOp::build(OpBuilder &builder, OperationState &result,
1186 StringAttr name, ArrayRef<PortInfo> ports,
1187 uint32_t numReadPorts, uint32_t numWritePorts,
1188 uint32_t numReadWritePorts, uint32_t dataWidth,
1189 uint32_t maskBits, uint32_t readLatency,
1190 uint32_t writeLatency, uint64_t depth, RUWBehavior ruw,
1191 ArrayAttr annotations, ArrayAttr layers) {
1192 auto *
context = builder.getContext();
1193 buildModule<FMemModuleOp>(builder, result, name, ports, annotations, layers);
1194 auto ui32Type = IntegerType::get(
context, 32, IntegerType::Unsigned);
1195 auto ui64Type = IntegerType::get(
context, 64, IntegerType::Unsigned);
1196 auto &properties = result.getOrAddProperties<Properties>();
1197 properties.setNumReadPorts(IntegerAttr::get(ui32Type, numReadPorts));
1198 properties.setNumWritePorts(IntegerAttr::get(ui32Type, numWritePorts));
1199 properties.setNumReadWritePorts(
1200 IntegerAttr::get(ui32Type, numReadWritePorts));
1201 properties.setDataWidth(IntegerAttr::get(ui32Type, dataWidth));
1202 properties.setMaskBits(IntegerAttr::get(ui32Type, maskBits));
1203 properties.setReadLatency(IntegerAttr::get(ui32Type, readLatency));
1204 properties.setWriteLatency(IntegerAttr::get(ui32Type, writeLatency));
1205 properties.setDepth(IntegerAttr::get(ui64Type, depth));
1206 properties.setExtraPorts(ArrayAttr::get(
context, {}));
1207 properties.setRuw(RUWBehaviorAttr::get(
context, ruw));
1224 ArrayRef<Attribute> portNames, ArrayRef<Attribute> portTypes,
1225 ArrayRef<Attribute> portAnnotations,
1226 ArrayRef<Attribute> portSyms, ArrayRef<Attribute> portLocs,
1227 ArrayRef<Attribute> domainInfo) {
1230 bool printedNamesDontMatch =
false;
1232 mlir::OpPrintingFlags flags;
1235 DenseMap<unsigned, std::string> ssaNames;
1236 auto getSsaName = [&](
unsigned idx) -> StringRef {
1238 auto itr = ssaNames.find(idx);
1239 if (itr != ssaNames.end())
1240 return itr->getSecond();
1244 SmallString<32> resultNameStr;
1246 llvm::raw_svector_ostream tmpStream(resultNameStr);
1247 p.printOperand(block->getArgument(idx), tmpStream);
1250 auto portName = cast<StringAttr>(portNames[idx]).getValue();
1251 if (tmpStream.str().drop_front() != portName)
1252 printedNamesDontMatch =
true;
1253 return ssaNames.insert({idx, tmpStream.str().str()}).first->getSecond();
1256 auto name = cast<StringAttr>(portNames[idx]).getValue();
1257 return ssaNames.insert({idx, name.str()}).first->getSecond();
1263 for (
unsigned i = 0, e = portTypes.size(); i < e; ++i) {
1272 auto portType = cast<TypeAttr>(portTypes[i]).getValue();
1276 p.printKeywordOrString(getSsaName(i));
1281 p.printType(portType);
1284 if (!portSyms.empty()) {
1285 if (!cast<hw::InnerSymAttr>(portSyms[i]).
empty()) {
1287 cast<hw::InnerSymAttr>(portSyms[i]).print(p);
1292 if (!domainInfo.empty()) {
1293 if (
auto domainKind = dyn_cast<FlatSymbolRefAttr>(domainInfo[i])) {
1298 auto domains = cast<ArrayAttr>(domainInfo[i]);
1299 if (!domains.empty()) {
1301 llvm::interleaveComma(domains, p, [&](Attribute attr) {
1302 p << getSsaName(cast<IntegerAttr>(attr).getUInt());
1311 if (!portAnnotations.empty() &&
1312 !cast<ArrayAttr>(portAnnotations[i]).empty()) {
1314 p.printAttribute(portAnnotations[i]);
1321 if (flags.shouldPrintDebugInfo() && !portLocs.empty())
1322 p.printOptionalLocationSpecifier(cast<LocationAttr>(portLocs[i]));
1326 return printedNamesDontMatch;
1332 OpAsmParser &parser,
bool hasSSAIdentifiers,
bool supportsSymbols,
1333 bool supportsDomains, SmallVectorImpl<OpAsmParser::Argument> &entryArgs,
1334 SmallVectorImpl<Direction> &portDirections,
1335 SmallVectorImpl<Attribute> &portNames,
1336 SmallVectorImpl<Attribute> &portTypes,
1337 SmallVectorImpl<Attribute> &portAnnotations,
1338 SmallVectorImpl<Attribute> &portSyms, SmallVectorImpl<Attribute> &portLocs,
1339 SmallVectorImpl<Attribute> &domains) {
1340 auto *
context = parser.getContext();
1343 DenseMap<Attribute, size_t> domainIndex;
1346 using DomainAndLoc = std::pair<Attribute, llvm::SMLoc>;
1347 DenseMap<size_t, SmallVector<DomainAndLoc>> domainStrings;
1349 auto parseArgument = [&]() -> ParseResult {
1351 if (succeeded(parser.parseOptionalKeyword(
"out")))
1352 portDirections.push_back(Direction::Out);
1353 else if (succeeded(parser.parseKeyword(
"in",
" or 'out'")))
1354 portDirections.push_back(Direction::In);
1361 auto portIdx = portNames.size();
1363 if (hasSSAIdentifiers) {
1364 OpAsmParser::Argument arg;
1365 if (parser.parseArgument(arg))
1367 entryArgs.push_back(arg);
1371 assert(arg.ssaName.name.size() > 1 && arg.ssaName.name[0] ==
'%' &&
1372 "Unknown MLIR name");
1373 if (
isdigit(arg.ssaName.name[1]))
1374 portNames.push_back(StringAttr::get(
context,
""));
1376 portNames.push_back(
1377 StringAttr::get(
context, arg.ssaName.name.drop_front()));
1380 irLoc = arg.ssaName.location;
1384 irLoc = parser.getCurrentLocation();
1385 std::string portName;
1386 if (parser.parseKeywordOrString(&portName))
1388 portNames.push_back(StringAttr::get(
context, portName));
1393 if (parser.parseColonType(portType))
1395 portTypes.push_back(TypeAttr::get(portType));
1396 if (isa<DomainType>(portType))
1397 domainIndex[portNames.back()] = portIdx;
1399 if (hasSSAIdentifiers)
1400 entryArgs.back().type = portType;
1403 if (supportsSymbols) {
1404 hw::InnerSymAttr innerSymAttr;
1405 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
1406 NamedAttrList dummyAttrs;
1407 if (parser.parseCustomAttributeWithFallback(
1408 innerSymAttr, ::mlir::Type{},
1410 return ::mlir::failure();
1413 portSyms.push_back(innerSymAttr);
1421 Attribute domainInfo;
1422 if (supportsDomains) {
1423 if (
auto domainType = dyn_cast<DomainType>(portType)) {
1425 domainInfo = domainType.getName();
1426 }
else if (succeeded(parser.parseOptionalKeyword(
"domains"))) {
1427 auto result = parser.parseCommaSeparatedList(
1428 OpAsmParser::Delimiter::Square, [&]() -> ParseResult {
1430 if (hasSSAIdentifiers) {
1431 OpAsmParser::Argument arg;
1432 if (parser.parseArgument(arg))
1435 StringAttr::get(
context, arg.ssaName.name.drop_front());
1437 std::string portName;
1438 if (parser.parseKeywordOrString(&portName))
1440 argName = StringAttr::get(
context, portName);
1442 domainStrings[portIdx].push_back({argName, irLoc});
1449 domains.push_back(domainInfo);
1453 auto parseResult = parser.parseOptionalAttribute(annos);
1454 if (!parseResult.has_value())
1455 annos = parser.getBuilder().getArrayAttr({});
1456 else if (failed(*parseResult))
1458 portAnnotations.push_back(annos);
1461 std::optional<Location> maybeLoc;
1462 if (failed(parser.parseOptionalLocationSpecifier(maybeLoc)))
1464 Location loc = maybeLoc ? *maybeLoc : parser.getEncodedSourceLoc(irLoc);
1465 portLocs.push_back(loc);
1466 if (hasSSAIdentifiers)
1467 entryArgs.back().sourceLoc = loc;
1476 if (failed(parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
1482 for (
auto [portIdx, domainInfo] : llvm::enumerate(domains)) {
1487 SmallVector<Attribute> portDomains;
1488 for (
auto [domainName, loc] : domainStrings[portIdx]) {
1489 auto index = domainIndex.find(domainName);
1490 if (index == domainIndex.end()) {
1491 parser.emitError(loc) <<
"domain name '" << domainName <<
"' not found";
1494 portDomains.push_back(IntegerAttr::get(
1495 IntegerType::get(
context, 32, IntegerType::Unsigned), index->second));
1497 domains[portIdx] = parser.getBuilder().getArrayAttr(portDomains);
1505 ArrayAttr parameters) {
1506 if (!parameters || parameters.empty())
1510 llvm::interleaveComma(parameters, p, [&](Attribute param) {
1511 auto paramAttr = cast<ParamDeclAttr>(param);
1512 p << paramAttr.getName().getValue() <<
": " << paramAttr.getType();
1513 if (
auto value = paramAttr.getValue()) {
1515 p.printAttributeWithoutType(value);
1525 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
1526 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
1527 p << visibility.getValue() <<
' ';
1530 p.printSymbolName(op.getModuleName());
1537 Block *body =
nullptr;
1538 if (!op->getRegion(0).empty())
1539 body = &op->getRegion(0).front();
1542 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
1543 op.getPortAnnotations(), op.getPortSymbols(), op.getPortLocations(),
1544 op.getDomainInfo());
1546 SmallVector<StringRef, 13> omittedAttrs = {
1547 "sym_name",
"portDirections",
"portTypes",
1548 "portAnnotations",
"portSymbols",
"portLocations",
1549 "parameters", visibilityAttrName,
"domainInfo"};
1551 if (op.getConvention() == Convention::Internal)
1552 omittedAttrs.push_back(
"convention");
1556 if (!needPortNamesAttr)
1557 omittedAttrs.push_back(
"portNames");
1560 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
1561 omittedAttrs.push_back(
"annotations");
1564 if (
auto knownLayers = op->getAttrOfType<ArrayAttr>(
"knownLayers"))
1565 if (knownLayers.empty())
1566 omittedAttrs.push_back(
"knownLayers");
1569 if (
auto layers = op->getAttrOfType<ArrayAttr>(
"layers"))
1571 omittedAttrs.push_back(
"layers");
1574 if (
auto extReqs = op->getAttrOfType<ArrayAttr>(
"externalRequirements"))
1575 if (extReqs.empty())
1576 omittedAttrs.push_back(
"externalRequirements");
1578 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
1587void FModuleOp::print(OpAsmPrinter &p) {
1593 Region &fbody = getBody();
1594 if (!fbody.empty()) {
1596 p.printRegion(fbody,
false,
1608 SmallVectorImpl<Attribute> ¶meters) {
1610 return parser.parseCommaSeparatedList(
1611 OpAsmParser::Delimiter::OptionalLessGreater, [&]() {
1616 if (parser.parseKeywordOrString(&name) || parser.parseColonType(type))
1620 if (succeeded(parser.parseOptionalEqual())) {
1621 if (parser.parseAttribute(value, type))
1625 auto &builder = parser.getBuilder();
1626 parameters.push_back(ParamDeclAttr::get(
1627 builder.getContext(), builder.getStringAttr(name), type, value));
1634 ArrayAttr ¶meters) {
1635 SmallVector<Attribute> parseParameters;
1639 parameters = ArrayAttr::get(parser.getContext(), parseParameters);
1644template <
typename Properties,
typename =
void>
1647template <
typename Properties>
1649 Properties, std::void_t<decltype(std::declval<Properties>().parameters)>>
1650 : std::true_type {};
1652template <
typename OpTy>
1654 OperationState &result,
1655 bool hasSSAIdentifiers) {
1656 auto *
context = result.getContext();
1657 auto &builder = parser.getBuilder();
1658 using Properties =
typename OpTy::Properties;
1659 auto &properties = result.getOrAddProperties<Properties>();
1663 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
1666 StringAttr nameAttr;
1667 if (parser.parseSymbolName(nameAttr))
1669 properties.setSymName(nameAttr);
1673 SmallVector<Attribute, 4> parameters;
1676 properties.setParameters(builder.getArrayAttr(parameters));
1680 SmallVector<OpAsmParser::Argument> entryArgs;
1681 SmallVector<Direction, 4> portDirections;
1682 SmallVector<Attribute, 4> portNames;
1683 SmallVector<Attribute, 4> portTypes;
1684 SmallVector<Attribute, 4> portAnnotations;
1685 SmallVector<Attribute, 4> portSyms;
1686 SmallVector<Attribute, 4> portLocs;
1687 SmallVector<Attribute, 4> domains;
1689 true, entryArgs, portDirections,
1690 portNames, portTypes, portAnnotations, portSyms,
1695 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
1698 assert(portNames.size() == portTypes.size());
1704 properties.setPortDirections(
1708 properties.setPortNames(builder.getArrayAttr(portNames));
1711 properties.setPortTypes(ArrayAttr::get(
context, portTypes));
1715 if (llvm::any_of(portAnnotations, [&](Attribute anno) {
1716 return !cast<ArrayAttr>(anno).empty();
1718 properties.setPortAnnotations(ArrayAttr::get(
context, portAnnotations));
1720 properties.setPortAnnotations(builder.getArrayAttr({}));
1723 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1724 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1727 properties.setPortLocations(ArrayAttr::get(
context, portLocs));
1730 properties.setAnnotations(builder.getArrayAttr({}));
1733 if (llvm::all_of(domains, [&](Attribute attr) {
1734 auto arrayAttr = dyn_cast<ArrayAttr>(attr);
1735 return arrayAttr && arrayAttr.empty();
1737 properties.setDomainInfo(ArrayAttr::get(
context, {}));
1739 properties.setDomainInfo(ArrayAttr::get(
context, domains));
1742 auto *body = result.addRegion();
1744 if (hasSSAIdentifiers) {
1745 if (parser.parseRegion(*body, entryArgs))
1748 body->push_back(
new Block());
1753ParseResult FModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1754 if (parseFModuleLikeOp<FModuleOp>(parser, result,
1757 auto &properties = result.getOrAddProperties<Properties>();
1758 properties.setConvention(
1759 ConventionAttr::get(result.getContext(), Convention::Internal));
1760 properties.setLayers(ArrayAttr::get(parser.getContext(), {}));
1764ParseResult FExtModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1765 if (parseFModuleLikeOp<FExtModuleOp>(parser, result,
1768 auto &properties = result.getOrAddProperties<Properties>();
1769 properties.setConvention(
1770 ConventionAttr::get(result.getContext(), Convention::Internal));
1771 properties.setKnownLayers(ArrayAttr::get(result.getContext(), {}));
1775ParseResult FIntModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1776 return parseFModuleLikeOp<FIntModuleOp>(parser, result,
1780ParseResult FMemModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1781 return parseFModuleLikeOp<FMemModuleOp>(parser, result,
1785LogicalResult FModuleOp::verify() {
1788 auto portTypes = getPortTypes();
1789 auto portLocs = getPortLocations();
1790 auto numPorts = portTypes.size();
1793 if (body->getNumArguments() != numPorts)
1794 return emitOpError(
"entry block must have ")
1795 << numPorts <<
" arguments to match module signature";
1798 for (
auto [arg, type, loc] : zip(body->getArguments(), portTypes, portLocs)) {
1799 if (arg.getType() != cast<TypeAttr>(type).getValue())
1800 return emitOpError(
"block argument types should match signature types");
1801 if (arg.getLoc() != cast<LocationAttr>(loc))
1803 "block argument locations should match signature locations");
1809LogicalResult FExtModuleOp::verify() {
1810 auto params = getParameters();
1812 auto checkParmValue = [&](Attribute elt) ->
bool {
1813 auto param = cast<ParamDeclAttr>(elt);
1814 auto value = param.getValue();
1815 if (isa<IntegerAttr, StringAttr, FloatAttr, hw::ParamVerbatimAttr>(value))
1817 emitError() <<
"has unknown extmodule parameter value '"
1818 << param.getName().getValue() <<
"' = " << value;
1822 if (!llvm::all_of(params, checkParmValue))
1827 known.insert_range(getKnownLayersAttr().getAsRange<SymbolRefAttr>());
1830 referenced.insert_range(getLayersAttr().getAsRange<SymbolRefAttr>());
1831 for (
auto attr : getPortTypes()) {
1832 auto type = cast<TypeAttr>(attr).getValue();
1833 if (
auto refType = type_dyn_cast<RefType>(type))
1834 if (
auto layer = refType.getLayer())
1835 referenced.insert(layer);
1839 "references unknown layers",
"unknown layers");
1842LogicalResult FIntModuleOp::verify() {
1843 auto params = getParameters();
1847 auto checkParmValue = [&](Attribute elt) ->
bool {
1848 auto param = cast<ParamDeclAttr>(elt);
1849 auto value = param.getValue();
1850 if (isa<IntegerAttr, StringAttr, FloatAttr>(value))
1852 emitError() <<
"has unknown intmodule parameter value '"
1853 << param.getName().getValue() <<
"' = " << value;
1857 if (!llvm::all_of(params, checkParmValue))
1864 CircuitOp circuitOp,
1865 SymbolTableCollection &symbolTable,
1867 auto layer = refType.getLayer();
1870 auto *layerOp = symbolTable.lookupSymbolIn(circuitOp, layer);
1872 return emitError(loc) << start <<
" associated with layer '" << layer
1873 <<
"', but this layer was not defined";
1874 if (!isa<LayerOp>(layerOp)) {
1875 auto diag = emitError(loc)
1876 << start <<
" associated with layer '" << layer
1877 <<
"', but symbol '" << layer <<
"' does not refer to a '"
1878 << LayerOp::getOperationName() <<
"' op";
1879 return diag.attachNote(layerOp->getLoc()) <<
"symbol refers to this op";
1885 SymbolTableCollection &symbolTable) {
1887 auto circuitOp =
module->getParentOfType<CircuitOp>();
1888 for (
size_t i = 0, e = module.getNumPorts(); i < e; ++i) {
1889 auto type =
module.getPortType(i);
1891 if (
auto refType = type_dyn_cast<RefType>(type)) {
1893 refType, module.getPortLocation(i), circuitOp, symbolTable,
1894 Twine(
"probe port '") + module.getPortName(i) +
"' is")))
1899 if (
auto classType = dyn_cast<ClassType>(type)) {
1900 auto className = classType.getNameAttr();
1901 auto classOp = dyn_cast_or_null<ClassLike>(
1902 symbolTable.lookupSymbolIn(circuitOp, className));
1904 return module.emitOpError() << "references unknown class " << className;
1907 if (failed(classOp.verifyType(classType,
1908 [&]() { return module.emitOpError(); })))
1913 if (
auto domainType = dyn_cast<DomainType>(type)) {
1914 auto domainInfo =
module.getDomainInfoAttrForPort(i);
1915 if (
auto kind = dyn_cast<FlatSymbolRefAttr>(domainInfo)) {
1916 auto domainOp = dyn_cast_or_null<DomainOp>(
1917 symbolTable.lookupSymbolIn(circuitOp, kind));
1919 return mlir::emitError(module.getPortLocation(i))
1920 <<
"domain port '" <<
module.getPortName(i)
1921 << "' has undefined domain kind '" << kind.getValue() << "'";
1924 auto expectedType = DomainType::getFromDomainOp(domainOp);
1925 if (domainType != expectedType)
1926 return mlir::emitError(module.getPortLocation(i))
1927 <<
"domain port '" <<
module.getPortName(i) << "' has type "
1928 << domainType << " which does not match "
1929 << "the domain definition, expected " << expectedType;
1937LogicalResult FModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1941 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
1942 for (
auto layer : getLayers()) {
1943 if (!symbolTable.lookupSymbolIn(circuitOp, cast<SymbolRefAttr>(layer)))
1944 return emitOpError() <<
"enables undefined layer '" << layer <<
"'";
1951FExtModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1955 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
1956 for (
auto layer : getKnownLayersAttr().getAsRange<SymbolRefAttr>()) {
1957 if (!symbolTable.lookupSymbolIn(circuitOp, layer))
1958 return emitOpError() <<
"knows undefined layer '" << layer <<
"'";
1960 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>()) {
1961 if (!symbolTable.lookupSymbolIn(circuitOp, layer))
1962 return emitOpError() <<
"enables undefined layer '" << layer <<
"'";
1969FIntModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1974FMemModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1978void FModuleOp::getAsmBlockArgumentNames(mlir::Region ®ion,
1983void FExtModuleOp::getAsmBlockArgumentNames(
1988StringAttr FExtModuleOp::getExtModuleNameAttr() {
1989 if (
auto defnameAttr = getDefnameAttr(); defnameAttr && !defnameAttr.empty())
1991 return getNameAttr();
1994StringRef FExtModuleOp::getExtModuleName() {
1995 if (
auto defname = getDefname(); defname && !defname->empty())
2000void FIntModuleOp::getAsmBlockArgumentNames(
2005void FMemModuleOp::getAsmBlockArgumentNames(
2010ArrayAttr FMemModuleOp::getParameters() {
return {}; }
2012ArrayAttr FModuleOp::getParameters() {
return {}; }
2014Convention FIntModuleOp::getConvention() {
return Convention::Internal; }
2016ConventionAttr FIntModuleOp::getConventionAttr() {
2017 return ConventionAttr::get(getContext(), getConvention());
2020Convention FMemModuleOp::getConvention() {
return Convention::Internal; }
2022ConventionAttr FMemModuleOp::getConventionAttr() {
2023 return ConventionAttr::get(getContext(), getConvention());
2031 ClassLike classOp, ClassType type,
2032 function_ref<InFlightDiagnostic()> emitError) {
2034 auto name = type.getNameAttr().getAttr();
2035 auto expectedName = classOp.getModuleNameAttr();
2036 if (name != expectedName)
2037 return emitError() <<
"type has wrong name, got " << name <<
", expected "
2040 auto elements = type.getElements();
2042 auto expectedNumElements = classOp.getNumPorts();
2044 return emitError() <<
"has wrong number of ports, got " <<
numElements
2045 <<
", expected " << expectedNumElements;
2047 auto portNames = classOp.getPortNames();
2048 auto portDirections = classOp.getPortDirections();
2049 auto portTypes = classOp.getPortTypes();
2052 auto element = elements[i];
2054 auto name = element.name;
2055 auto expectedName = portNames[i];
2056 if (name != expectedName)
2057 return emitError() <<
"port #" << i <<
" has wrong name, got " << name
2058 <<
", expected " << expectedName;
2060 auto direction = element.direction;
2061 auto expectedDirection =
Direction(portDirections[i]);
2062 if (direction != expectedDirection)
2063 return emitError() <<
"port " << name <<
" has wrong direction, got "
2067 auto type = element.type;
2068 auto expectedType = cast<TypeAttr>(portTypes[i]).getValue();
2069 if (type != expectedType)
2070 return emitError() <<
"port " << name <<
" has wrong type, got " << type
2071 <<
", expected " << expectedType;
2078 auto n = classOp.getNumPorts();
2079 SmallVector<ClassElement> elements;
2080 elements.reserve(n);
2081 for (
size_t i = 0; i < n; ++i)
2082 elements.push_back({classOp.getPortNameAttr(i), classOp.getPortType(i),
2083 classOp.getPortDirection(i)});
2084 auto name = FlatSymbolRefAttr::get(classOp.getNameAttr());
2085 return ClassType::get(name, elements);
2088template <
typename OpTy>
2090 bool hasSSAIdentifiers) {
2091 auto *
context = result.getContext();
2092 auto &builder = parser.getBuilder();
2093 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
2097 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
2100 StringAttr nameAttr;
2101 if (parser.parseSymbolName(nameAttr))
2103 properties.setSymName(nameAttr);
2106 SmallVector<OpAsmParser::Argument> entryArgs;
2107 SmallVector<Direction, 4> portDirections;
2108 SmallVector<Attribute, 4> portNames;
2109 SmallVector<Attribute, 4> portTypes;
2110 SmallVector<Attribute, 4> portAnnotations;
2111 SmallVector<Attribute, 4> portSyms;
2112 SmallVector<Attribute, 4> portLocs;
2113 SmallVector<Attribute, 4> domains;
2116 entryArgs, portDirections, portNames, portTypes,
2117 portAnnotations, portSyms, portLocs, domains))
2121 for (
auto annos : portAnnotations)
2122 if (!cast<ArrayAttr>(annos).empty())
2126 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
2129 assert(portNames.size() == portTypes.size());
2135 properties.setPortDirections(
2139 properties.setPortNames(builder.getArrayAttr(portNames));
2142 properties.setPortTypes(builder.getArrayAttr(portTypes));
2145 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
2146 properties.setPortSymbols(builder.getArrayAttr(portSyms));
2149 properties.setPortLocations(ArrayAttr::get(
context, portLocs));
2155 auto *bodyRegion = result.addRegion();
2157 if (hasSSAIdentifiers) {
2158 if (parser.parseRegion(*bodyRegion, entryArgs))
2160 if (bodyRegion->empty())
2161 bodyRegion->push_back(
new Block());
2171 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
2172 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
2173 p << visibility.getValue() <<
' ';
2176 p.printSymbolName(op.getName());
2180 Region ®ion = op->getRegion(0);
2181 Block *body =
nullptr;
2182 if (!region.empty())
2183 body = ®ion.front();
2186 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
2187 {}, op.getPortSymbols(), op.getPortLocations(), {});
2190 SmallVector<StringRef, 8> omittedAttrs = {
2191 "sym_name",
"portNames",
"portTypes",
"portDirections",
2192 "portSymbols",
"portLocations", visibilityAttrName,
"domainInfo"};
2196 if (!needPortNamesAttr)
2197 omittedAttrs.push_back(
"portNames");
2199 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
2202 if (!region.empty()) {
2204 auto printEntryBlockArgs =
false;
2205 auto printBlockTerminators =
false;
2206 p.printRegion(region, printEntryBlockArgs, printBlockTerminators);
2214void ClassOp::build(OpBuilder &builder, OperationState &result, StringAttr name,
2215 ArrayRef<PortInfo> ports) {
2218 [](
const auto &port) {
return port.annotations.empty(); }) &&
2219 "class ports may not have annotations");
2221 buildClass<ClassOp>(builder, result, name, ports);
2224 auto *bodyRegion = result.regions[0].get();
2226 bodyRegion->push_back(body);
2229 for (
auto &elt : ports)
2230 body->addArgument(elt.type, elt.loc);
2233void ClassOp::build(::mlir::OpBuilder &odsBuilder,
2234 ::mlir::OperationState &odsState, Twine name,
2235 mlir::ArrayRef<mlir::StringRef> fieldNames,
2236 mlir::ArrayRef<mlir::Type> fieldTypes) {
2238 SmallVector<PortInfo, 10> ports;
2239 ports.reserve(fieldNames.size() * 2);
2240 for (
auto [fieldName, fieldType] :
llvm::zip(fieldNames, fieldTypes)) {
2241 ports.emplace_back(odsBuilder.getStringAttr(fieldName +
"_in"), fieldType,
2243 ports.emplace_back(odsBuilder.getStringAttr(fieldName), fieldType,
2246 build(odsBuilder, odsState, odsBuilder.getStringAttr(name), ports);
2248 auto &body = odsState.regions[0]->getBlocks().front();
2249 auto prevLoc = odsBuilder.saveInsertionPoint();
2250 odsBuilder.setInsertionPointToEnd(&body);
2251 auto args = body.getArguments();
2252 auto loc = odsState.location;
2253 for (
unsigned i = 0, e = ports.size(); i != e; i += 2)
2254 PropAssignOp::create(odsBuilder, loc, args[i + 1], args[i]);
2256 odsBuilder.restoreInsertionPoint(prevLoc);
2258void ClassOp::print(OpAsmPrinter &p) {
2262ParseResult ClassOp::parse(OpAsmParser &parser, OperationState &result) {
2263 auto hasSSAIdentifiers =
true;
2264 return parseClassLike<ClassOp>(parser, result, hasSSAIdentifiers);
2267LogicalResult ClassOp::verify() {
2269 auto type = operand.getType();
2270 if (!isa<PropertyType>(type)) {
2271 emitOpError(
"ports on a class must be properties");
2280ClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2284void ClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2289SmallVector<PortInfo> ClassOp::getPorts() {
2290 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2293void ClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2294 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2298void ClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2299 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2302Convention ClassOp::getConvention() {
return Convention::Internal; }
2304ConventionAttr ClassOp::getConventionAttr() {
2305 return ConventionAttr::get(getContext(), getConvention());
2308ArrayAttr ClassOp::getParameters() {
return {}; }
2310ArrayAttr ClassOp::getPortAnnotationsAttr() {
2311 return ArrayAttr::get(getContext(), {});
2314ArrayRef<Attribute> ClassOp::getPortAnnotations() {
return {}; }
2316void ClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2317 llvm_unreachable(
"classes do not support annotations");
2320ArrayAttr ClassOp::getLayersAttr() {
return ArrayAttr::get(getContext(), {}); }
2322ArrayRef<Attribute> ClassOp::getLayers() {
return {}; }
2324SmallVector<::circt::hw::PortInfo> ClassOp::getPortList() {
2325 return ::getPortListImpl(*
this);
2329 return ::getPortImpl(*
this, idx);
2332BlockArgument ClassOp::getArgument(
size_t portNumber) {
2336bool ClassOp::canDiscardOnUseEmpty() {
2347void ExtClassOp::build(OpBuilder &builder, OperationState &result,
2348 StringAttr name, ArrayRef<PortInfo> ports) {
2351 [](
const auto &port) {
return port.annotations.empty(); }) &&
2352 "class ports may not have annotations");
2353 buildClass<ClassOp>(builder, result, name, ports);
2356void ExtClassOp::print(OpAsmPrinter &p) {
2360ParseResult ExtClassOp::parse(OpAsmParser &parser, OperationState &result) {
2361 auto hasSSAIdentifiers =
false;
2362 return parseClassLike<ExtClassOp>(parser, result, hasSSAIdentifiers);
2366ExtClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2370void ExtClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2375SmallVector<PortInfo> ExtClassOp::getPorts() {
2376 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2379void ExtClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2380 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2383void ExtClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2384 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2387Convention ExtClassOp::getConvention() {
return Convention::Internal; }
2389ConventionAttr ExtClassOp::getConventionAttr() {
2390 return ConventionAttr::get(getContext(), getConvention());
2393ArrayAttr ExtClassOp::getLayersAttr() {
2394 return ArrayAttr::get(getContext(), {});
2397ArrayRef<Attribute> ExtClassOp::getLayers() {
return {}; }
2399ArrayAttr ExtClassOp::getParameters() {
return {}; }
2401ArrayAttr ExtClassOp::getPortAnnotationsAttr() {
2402 return ArrayAttr::get(getContext(), {});
2405ArrayRef<Attribute> ExtClassOp::getPortAnnotations() {
return {}; }
2407void ExtClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2408 llvm_unreachable(
"classes do not support annotations");
2411SmallVector<::circt::hw::PortInfo> ExtClassOp::getPortList() {
2412 return ::getPortListImpl(*
this);
2416 return ::getPortImpl(*
this, idx);
2419bool ExtClassOp::canDiscardOnUseEmpty() {
2430void InstanceOp::build(
2431 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2432 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2433 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2434 ArrayRef<Attribute> domainInfo, ArrayRef<Attribute> annotations,
2435 ArrayRef<Attribute> portAnnotations, ArrayRef<Attribute> layers,
2436 bool lowerToBind,
bool doNotPrint, StringAttr innerSym) {
2437 build(builder, result, resultTypes, moduleName, name, nameKind,
2438 portDirections, portNames, domainInfo, annotations, portAnnotations,
2439 layers, lowerToBind, doNotPrint,
2440 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr());
2443void InstanceOp::build(
2444 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2445 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2446 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2447 ArrayRef<Attribute> domainInfo, ArrayRef<Attribute> annotations,
2448 ArrayRef<Attribute> portAnnotations, ArrayRef<Attribute> layers,
2449 bool lowerToBind,
bool doNotPrint, hw::InnerSymAttr innerSym) {
2450 result.addTypes(resultTypes);
2451 result.getOrAddProperties<Properties>().setModuleName(
2452 SymbolRefAttr::get(builder.getContext(), moduleName));
2453 result.getOrAddProperties<Properties>().setName(builder.getStringAttr(name));
2454 result.getOrAddProperties<Properties>().setPortDirections(
2456 result.getOrAddProperties<Properties>().setPortNames(
2457 builder.getArrayAttr(portNames));
2459 if (domainInfo.empty()) {
2460 SmallVector<Attribute, 16> domainInfoVec(resultTypes.size(),
2461 builder.getArrayAttr({}));
2462 result.getOrAddProperties<Properties>().setDomainInfo(
2463 builder.getArrayAttr(domainInfoVec));
2465 assert(domainInfo.size() == resultTypes.size());
2466 result.getOrAddProperties<Properties>().setDomainInfo(
2467 builder.getArrayAttr(domainInfo));
2470 result.getOrAddProperties<Properties>().setAnnotations(
2471 builder.getArrayAttr(annotations));
2472 result.getOrAddProperties<Properties>().setLayers(
2473 builder.getArrayAttr(layers));
2475 result.getOrAddProperties<Properties>().setLowerToBind(
2476 builder.getUnitAttr());
2478 result.getOrAddProperties<Properties>().setDoNotPrint(
2479 builder.getUnitAttr());
2481 result.getOrAddProperties<Properties>().setInnerSym(innerSym);
2483 result.getOrAddProperties<Properties>().setNameKind(
2484 NameKindEnumAttr::get(builder.getContext(), nameKind));
2486 if (portAnnotations.empty()) {
2487 SmallVector<Attribute, 16> portAnnotationsVec(resultTypes.size(),
2488 builder.getArrayAttr({}));
2489 result.getOrAddProperties<Properties>().setPortAnnotations(
2490 builder.getArrayAttr(portAnnotationsVec));
2492 assert(portAnnotations.size() == resultTypes.size());
2493 result.getOrAddProperties<Properties>().setPortAnnotations(
2494 builder.getArrayAttr(portAnnotations));
2498void InstanceOp::build(OpBuilder &builder, OperationState &result,
2499 FModuleLike module, StringRef name,
2500 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2501 ArrayRef<Attribute> portAnnotations,
bool lowerToBind,
2502 bool doNotPrint, hw::InnerSymAttr innerSym) {
2505 SmallVector<Type> resultTypes;
2506 resultTypes.reserve(module.getNumPorts());
2508 module.getPortTypes(), std::back_inserter(resultTypes),
2509 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2514 ArrayAttr portAnnotationsAttr;
2515 if (portAnnotations.empty()) {
2516 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2517 resultTypes.size(), builder.getArrayAttr({})));
2519 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2521 ArrayAttr domainInfoAttr =
module.getDomainInfoAttr();
2522 if (domainInfoAttr.empty()) {
2523 domainInfoAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2524 resultTypes.size(), builder.getArrayAttr({})));
2528 builder, result, resultTypes,
2529 SymbolRefAttr::get(builder.getContext(), module.getModuleNameAttr()),
2530 builder.getStringAttr(name),
2531 NameKindEnumAttr::get(builder.getContext(), nameKind),
2532 module.getPortDirectionsAttr(), module.getPortNamesAttr(), domainInfoAttr,
2533 builder.getArrayAttr(annotations), portAnnotationsAttr,
2534 module.getLayersAttr(), lowerToBind ? builder.getUnitAttr() : UnitAttr(),
2535 doNotPrint ? builder.getUnitAttr() : UnitAttr(), innerSym);
2538void InstanceOp::build(OpBuilder &builder, OperationState &odsState,
2539 ArrayRef<PortInfo> ports, StringRef moduleName,
2540 StringRef name, NameKindEnum nameKind,
2541 ArrayRef<Attribute> annotations,
2542 ArrayRef<Attribute> layers,
bool lowerToBind,
2543 bool doNotPrint, hw::InnerSymAttr innerSym) {
2545 SmallVector<Type> newResultTypes;
2546 SmallVector<Direction> newPortDirections;
2547 SmallVector<Attribute> newPortNames, newPortAnnotations, newDomainInfo;
2548 newResultTypes.reserve(ports.size());
2549 newPortDirections.reserve(ports.size());
2550 newPortNames.reserve(ports.size());
2551 newPortAnnotations.reserve(ports.size());
2552 newDomainInfo.reserve(ports.size());
2554 for (
auto &p : ports) {
2555 newResultTypes.push_back(p.type);
2556 newPortDirections.push_back(p.direction);
2557 newPortNames.push_back(p.name);
2558 newPortAnnotations.push_back(p.annotations.getArrayAttr());
2560 newDomainInfo.push_back(p.domains);
2562 newDomainInfo.push_back(builder.getArrayAttr({}));
2565 return build(builder, odsState, newResultTypes, moduleName, name, nameKind,
2566 newPortDirections, newPortNames, newDomainInfo, annotations,
2567 newPortAnnotations, layers, lowerToBind, doNotPrint, innerSym);
2570LogicalResult InstanceOp::verify() {
2573 SmallVector<SymbolRefAttr> missingLayers;
2574 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
2576 missingLayers.push_back(layer);
2578 if (missingLayers.empty())
2582 emitOpError(
"ambient layers are insufficient to instantiate module");
2583 auto ¬e = diag.attachNote();
2584 note <<
"missing layer requirements: ";
2585 interleaveComma(missingLayers, note);
2590 Operation *op1, Operation *op2,
2591 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2593 size_t n = insertions.size();
2594 size_t inserted = 0;
2595 for (
size_t i = 0, e = op1->getNumResults(); i < e; ++i) {
2596 while (inserted < n) {
2597 auto &[index, portInfo] = insertions[inserted];
2602 auto r1 = op1->getResult(i);
2603 auto r2 = op2->getResult(i + inserted);
2604 r1.replaceAllUsesWith(r2);
2609 const llvm::BitVector &erasures) {
2612 for (
size_t i = 0, e = op1->getNumResults(); i < e; ++i) {
2613 auto r1 = op1->getResult(i);
2615 assert(r1.use_empty() &&
"removed instance port has uses");
2619 auto r2 = op2->getResult(i - erased);
2620 r1.replaceAllUsesWith(r2);
2624InstanceOp InstanceOp::cloneWithErasedPorts(
const llvm::BitVector &erasures) {
2625 assert(erasures.size() >= getNumResults() &&
2626 "erasures is not at least as large as getNumResults()");
2628 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
2629 SmallVector<Type>(result_type_begin(), result_type_end()), erasures);
2630 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
2632 SmallVector<Attribute> newPortNames =
2634 SmallVector<Attribute> newPortAnnotations =
2636 ArrayAttr newDomainInfo =
2640 OpBuilder builder(*
this);
2641 auto clone = InstanceOp::create(
2642 builder,
getLoc(), newResultTypes, getModuleName(),
getName(),
2643 getNameKind(), newPortDirections, newPortNames, newDomainInfo.getValue(),
2644 getAnnotations().getValue(), newPortAnnotations, getLayers(),
2645 getLowerToBind(), getDoNotPrint(), getInnerSymAttr());
2647 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2648 clone->setAttr(
"output_file", outputFile);
2653InstanceOp InstanceOp::cloneWithErasedPortsAndReplaceUses(
2654 const llvm::BitVector &erasures) {
2655 auto clone = cloneWithErasedPorts(erasures);
2660ArrayAttr InstanceOp::getPortAnnotation(
unsigned portIdx) {
2661 assert(portIdx < getNumResults() &&
2662 "index should be smaller than result number");
2663 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
2666void InstanceOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
2667 assert(annotations.size() == getNumResults() &&
2668 "number of annotations is not equal to result number");
2669 (*this)->setAttr(
"portAnnotations",
2670 ArrayAttr::get(getContext(), annotations));
2673Attribute InstanceOp::getPortDomain(
unsigned portIdx) {
2674 assert(portIdx < getNumResults() &&
2675 "index should be smaller than result number");
2676 return getDomainInfo()[portIdx];
2679InstanceOp InstanceOp::cloneWithInsertedPorts(
2680 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2684 auto oldPortCount = getNumResults();
2685 auto numInsertions = insertions.size();
2686 auto newPortCount = oldPortCount + numInsertions;
2688 SmallVector<Direction> newPortDirections;
2689 SmallVector<Attribute> newPortNames;
2690 SmallVector<Type> newPortTypes;
2691 SmallVector<Attribute> newPortAnnos;
2692 SmallVector<Attribute> newDomainInfo;
2694 newPortDirections.reserve(newPortCount);
2695 newPortNames.reserve(newPortCount);
2696 newPortTypes.reserve(newPortCount);
2697 newPortAnnos.reserve(newPortCount);
2698 newDomainInfo.reserve(newPortCount);
2704 SmallVector<unsigned> indexMap(oldPortCount);
2705 size_t inserted = 0;
2706 for (
size_t i = 0; i < oldPortCount; ++i) {
2707 while (inserted < numInsertions && insertions[inserted].first <= i)
2709 indexMap[i] = i + inserted;
2714 for (
size_t i = 0; i < oldPortCount; ++i) {
2715 while (inserted < numInsertions) {
2716 auto &[index,
info] = insertions[inserted];
2722 newPortDirections.push_back(
info.direction);
2723 newPortNames.push_back(
info.name);
2724 newPortTypes.push_back(
info.type);
2725 newPortAnnos.push_back(
info.annotations.getArrayAttr());
2726 newDomainInfo.push_back(domains);
2730 newPortDirections.push_back(getPortDirection(i));
2731 newPortNames.push_back(getPortNameAttr(i));
2732 newPortTypes.push_back(getType(i));
2733 newPortAnnos.push_back(getPortAnnotation(i));
2736 newDomainInfo.push_back(domains);
2739 while (inserted < numInsertions) {
2740 auto &[index,
info] = insertions[inserted];
2743 newPortDirections.push_back(
info.direction);
2744 newPortNames.push_back(
info.name);
2745 newPortTypes.push_back(
info.type);
2746 newPortAnnos.push_back(
info.annotations.getArrayAttr());
2747 newDomainInfo.push_back(domains);
2751 OpBuilder builder(*
this);
2752 auto clone = InstanceOp::create(
2753 builder,
getLoc(), newPortTypes, getModuleName(),
getName(),
2754 getNameKind(), newPortDirections, newPortNames, newDomainInfo,
2755 getAnnotations().getValue(), newPortAnnos, getLayers(), getLowerToBind(),
2756 getDoNotPrint(), getInnerSymAttr());
2758 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2759 clone->setAttr(
"output_file", outputFile);
2764InstanceOp InstanceOp::cloneWithInsertedPortsAndReplaceUses(
2765 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2766 auto clone = cloneWithInsertedPorts(insertions);
2771LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2773 getModuleNameAttr());
2776StringRef InstanceOp::getInstanceName() {
return getName(); }
2778StringAttr InstanceOp::getInstanceNameAttr() {
return getNameAttr(); }
2780void InstanceOp::print(OpAsmPrinter &p) {
2783 p.printKeywordOrString(
getName());
2784 if (
auto attr = getInnerSymAttr()) {
2786 p.printSymbolName(attr.getSymName());
2788 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2789 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2792 SmallVector<StringRef, 10> omittedAttrs = {
2793 "moduleName",
"name",
"portDirections",
2794 "portNames",
"portTypes",
"portAnnotations",
2795 "inner_sym",
"nameKind",
"domainInfo"};
2796 if (getAnnotations().
empty())
2797 omittedAttrs.push_back(
"annotations");
2798 if (getLayers().
empty())
2799 omittedAttrs.push_back(
"layers");
2800 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2804 p.printSymbolName(getModuleName());
2807 SmallVector<Attribute> portTypes;
2808 portTypes.reserve(getNumResults());
2809 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2813 getPortNames().getValue(), portTypes,
2814 getPortAnnotations().getValue(), {}, {},
2815 getDomainInfo().getValue());
2818ParseResult InstanceOp::parse(OpAsmParser &parser, OperationState &result) {
2819 auto *
context = parser.getContext();
2820 auto &properties = result.getOrAddProperties<Properties>();
2823 hw::InnerSymAttr innerSymAttr;
2824 FlatSymbolRefAttr moduleName;
2825 SmallVector<OpAsmParser::Argument> entryArgs;
2826 SmallVector<Direction, 4> portDirections;
2827 SmallVector<Attribute, 4> portNames;
2828 SmallVector<Attribute, 4> portTypes;
2829 SmallVector<Attribute, 4> portAnnotations;
2830 SmallVector<Attribute, 4> portSyms;
2831 SmallVector<Attribute, 4> portLocs;
2832 SmallVector<Attribute, 4> domains;
2833 NameKindEnumAttr nameKind;
2835 if (parser.parseKeywordOrString(&name))
2837 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
2838 if (parser.parseCustomAttributeWithFallback(
2839 innerSymAttr, ::mlir::Type{},
2841 result.attributes)) {
2842 return ::mlir::failure();
2846 parser.parseOptionalAttrDict(result.attributes) ||
2847 parser.parseAttribute(moduleName) ||
2850 entryArgs, portDirections, portNames, portTypes,
2851 portAnnotations, portSyms, portLocs, domains))
2857 properties.setModuleName(moduleName);
2858 properties.setName(StringAttr::get(
context, name));
2859 properties.setNameKind(nameKind);
2860 properties.setPortDirections(
2862 properties.setPortNames(ArrayAttr::get(
context, portNames));
2863 properties.setPortAnnotations(ArrayAttr::get(
context, portAnnotations));
2867 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
2868 properties.setLayers(parser.getBuilder().getArrayAttr({}));
2871 properties.setDomainInfo(ArrayAttr::get(
context, domains));
2874 result.types.reserve(portTypes.size());
2876 portTypes, std::back_inserter(result.types),
2877 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2882void InstanceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
2887 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
2888 setNameFn(getResult(i), (base +
"_" + getPortName(i)).str());
2892std::optional<size_t> InstanceOp::getTargetResultIndex() {
2894 return std::nullopt;
2901void InstanceChoiceOp::build(
2902 OpBuilder &builder, OperationState &result, FModuleLike defaultModule,
2903 ArrayRef<std::pair<OptionCaseOp, FModuleLike>> cases, StringRef name,
2904 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2905 ArrayRef<Attribute> portAnnotations, StringAttr innerSym,
2906 FlatSymbolRefAttr instanceMacro) {
2908 SmallVector<Type> resultTypes;
2909 for (Attribute portType : defaultModule.getPortTypes())
2910 resultTypes.push_back(cast<TypeAttr>(portType).getValue());
2913 ArrayAttr portAnnotationsAttr;
2914 if (portAnnotations.empty()) {
2915 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2916 resultTypes.size(), builder.getArrayAttr({})));
2918 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2922 ArrayAttr domainInfoAttr = defaultModule.getDomainInfoAttr();
2923 if (domainInfoAttr.empty()) {
2924 domainInfoAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2925 resultTypes.size(), builder.getArrayAttr({})));
2929 SmallVector<Attribute> moduleNames, caseNames;
2930 moduleNames.push_back(SymbolRefAttr::get(defaultModule.getModuleNameAttr()));
2931 for (
auto [caseOption, caseModule] : cases) {
2932 auto caseGroup = caseOption->getParentOfType<OptionOp>();
2933 caseNames.push_back(SymbolRefAttr::get(caseGroup.getSymNameAttr(),
2934 {SymbolRefAttr::get(caseOption)}));
2935 moduleNames.push_back(SymbolRefAttr::get(caseModule.getModuleNameAttr()));
2938 return build(builder, result, resultTypes, builder.getArrayAttr(moduleNames),
2939 builder.getArrayAttr(caseNames), builder.getStringAttr(name),
2940 NameKindEnumAttr::get(builder.getContext(), nameKind),
2941 defaultModule.getPortDirectionsAttr(),
2942 defaultModule.getPortNamesAttr(), domainInfoAttr,
2943 builder.getArrayAttr(annotations), portAnnotationsAttr,
2944 defaultModule.getLayersAttr(),
2945 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr(),
2949void InstanceChoiceOp::build(OpBuilder &builder, OperationState &odsState,
2950 ArrayRef<PortInfo> ports, ArrayAttr moduleNames,
2951 ArrayAttr caseNames, StringRef name,
2952 NameKindEnum nameKind, ArrayAttr annotations,
2953 ArrayAttr layers, hw::InnerSymAttr innerSym,
2954 FlatSymbolRefAttr instanceMacro) {
2956 SmallVector<Type> newResultTypes;
2957 SmallVector<bool> newPortDirections;
2958 SmallVector<Attribute> newPortNames, newPortAnnotations, newDomainInfo;
2959 newPortDirections.reserve(ports.size());
2960 newResultTypes.reserve(ports.size());
2961 newPortAnnotations.reserve(ports.size());
2962 newDomainInfo.reserve(ports.size());
2963 newPortNames.reserve(ports.size());
2964 for (
auto &p : ports) {
2965 newResultTypes.push_back(p.type);
2967 newPortDirections.push_back(p.direction == Direction::Out);
2968 newPortNames.push_back(p.name);
2969 newPortAnnotations.push_back(p.annotations.getArrayAttr());
2971 newDomainInfo.push_back(p.domains);
2973 newDomainInfo.push_back(builder.getArrayAttr({}));
2976 return build(builder, odsState, newResultTypes, moduleNames, caseNames, name,
2977 nameKind, newPortDirections, builder.getArrayAttr(newPortNames),
2978 builder.getArrayAttr(newDomainInfo), annotations,
2979 builder.getArrayAttr(newPortAnnotations), layers.getValue(),
2980 innerSym, instanceMacro);
2983std::optional<size_t> InstanceChoiceOp::getTargetResultIndex() {
2984 return std::nullopt;
2987StringRef InstanceChoiceOp::getInstanceName() {
return getName(); }
2989StringAttr InstanceChoiceOp::getInstanceNameAttr() {
return getNameAttr(); }
2991ArrayAttr InstanceChoiceOp::getReferencedModuleNamesAttr() {
2993 auto moduleNames = getModuleNamesAttr();
2994 SmallVector<Attribute> moduleNameStrings;
2995 moduleNameStrings.reserve(moduleNames.size());
2996 for (
auto moduleName : moduleNames)
2997 moduleNameStrings.push_back(cast<FlatSymbolRefAttr>(moduleName).getAttr());
2999 return ArrayAttr::get(getContext(), moduleNameStrings);
3002void InstanceChoiceOp::print(OpAsmPrinter &p) {
3005 p.printKeywordOrString(
getName());
3006 if (
auto attr = getInnerSymAttr()) {
3008 p.printSymbolName(attr.getSymName());
3010 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
3011 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
3014 SmallVector<StringRef, 11> omittedAttrs = {
3015 "moduleNames",
"caseNames",
"name",
3016 "portDirections",
"portNames",
"portTypes",
3017 "portAnnotations",
"inner_sym",
"nameKind",
3019 if (getAnnotations().
empty())
3020 omittedAttrs.push_back(
"annotations");
3021 if (getLayers().
empty())
3022 omittedAttrs.push_back(
"layers");
3023 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
3028 auto moduleNames = getModuleNamesAttr();
3029 auto caseNames = getCaseNamesAttr();
3031 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[0]).getValue());
3033 p <<
" alternatives ";
3035 cast<SymbolRefAttr>(caseNames[0]).getRootReference().getValue());
3037 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3041 auto symbol = cast<SymbolRefAttr>(caseNames[i]);
3042 p.printSymbolName(symbol.getNestedReferences()[0].getValue());
3044 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[i + 1]).getValue());
3050 SmallVector<Attribute> portTypes;
3051 portTypes.reserve(getNumResults());
3052 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
3055 getPortNames().getValue(), portTypes,
3056 getPortAnnotations().getValue(), {}, {},
3057 getDomainInfo().getValue());
3060ParseResult InstanceChoiceOp::parse(OpAsmParser &parser,
3061 OperationState &result) {
3062 auto *
context = parser.getContext();
3063 auto &properties = result.getOrAddProperties<Properties>();
3066 hw::InnerSymAttr innerSymAttr;
3067 SmallVector<Attribute> moduleNames;
3068 SmallVector<Attribute> caseNames;
3069 SmallVector<OpAsmParser::Argument> entryArgs;
3070 SmallVector<Direction, 4> portDirections;
3071 SmallVector<Attribute, 4> portNames;
3072 SmallVector<Attribute, 4> portTypes;
3073 SmallVector<Attribute, 4> portAnnotations;
3074 SmallVector<Attribute, 4> portSyms;
3075 SmallVector<Attribute, 4> portLocs;
3076 SmallVector<Attribute, 4> domains;
3077 NameKindEnumAttr nameKind;
3079 if (parser.parseKeywordOrString(&name))
3081 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
3082 if (parser.parseCustomAttributeWithFallback(
3083 innerSymAttr, Type{},
3085 result.attributes)) {
3090 parser.parseOptionalAttrDict(result.attributes))
3093 FlatSymbolRefAttr defaultModuleName;
3094 if (parser.parseAttribute(defaultModuleName))
3096 moduleNames.push_back(defaultModuleName);
3100 FlatSymbolRefAttr optionName;
3101 if (parser.parseKeyword(
"alternatives") ||
3102 parser.parseAttribute(optionName) || parser.parseLBrace())
3105 FlatSymbolRefAttr moduleName;
3106 StringAttr caseName;
3107 while (succeeded(parser.parseOptionalSymbolName(caseName))) {
3108 if (parser.parseArrow() || parser.parseAttribute(moduleName))
3110 moduleNames.push_back(moduleName);
3111 caseNames.push_back(SymbolRefAttr::get(
3112 optionName.getAttr(), {FlatSymbolRefAttr::get(caseName)}));
3113 if (failed(parser.parseOptionalComma()))
3116 if (parser.parseRBrace())
3122 entryArgs, portDirections, portNames, portTypes,
3123 portAnnotations, portSyms, portLocs, domains))
3128 properties.setModuleNames(ArrayAttr::get(
context, moduleNames));
3129 properties.setCaseNames(ArrayAttr::get(
context, caseNames));
3130 properties.setName(StringAttr::get(
context, name));
3131 properties.setNameKind(nameKind);
3132 properties.setPortDirections(
3134 properties.setPortNames(ArrayAttr::get(
context, portNames));
3135 properties.setDomainInfo(ArrayAttr::get(
context, domains));
3136 properties.setPortAnnotations(ArrayAttr::get(
context, portAnnotations));
3140 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
3141 properties.setLayers(parser.getBuilder().getArrayAttr({}));
3144 result.types.reserve(portTypes.size());
3146 portTypes, std::back_inserter(result.types),
3147 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
3152void InstanceChoiceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3154 for (
auto [result, name] :
llvm::zip(getResults(), getPortNames()))
3155 setNameFn(result, (base +
"_" + cast<StringAttr>(name).getValue()).str());
3158LogicalResult InstanceChoiceOp::verify() {
3159 if (getCaseNamesAttr().
empty())
3160 return emitOpError() <<
"must have at least one case";
3161 if (getModuleNamesAttr().size() != getCaseNamesAttr().size() + 1)
3162 return emitOpError() <<
"number of referenced modules does not match the "
3163 "number of options";
3168 SmallVector<SymbolRefAttr> missingLayers;
3169 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
3171 missingLayers.push_back(layer);
3173 if (missingLayers.empty())
3177 emitOpError(
"ambient layers are insufficient to instantiate module");
3178 auto ¬e = diag.attachNote();
3179 note <<
"missing layer requirements: ";
3180 interleaveComma(missingLayers, note);
3185InstanceChoiceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3186 auto caseNames = getCaseNamesAttr();
3187 for (
auto moduleName : getModuleNamesAttr()) {
3188 auto moduleNameRef = cast<FlatSymbolRefAttr>(moduleName);
3194 auto referencedModule =
3195 symbolTable.lookupNearestSymbolFrom<FModuleLike>(*
this, moduleNameRef);
3196 if (isa<FIntModuleOp>(referencedModule))
3197 return emitOpError(
"intmodule must be instantiated with instance op, "
3198 "not via 'firrtl.instance_choice'");
3201 auto root = cast<SymbolRefAttr>(caseNames[0]).getRootReference();
3202 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3203 auto ref = cast<SymbolRefAttr>(caseNames[i]);
3204 auto refRoot = ref.getRootReference();
3205 if (ref.getRootReference() != root)
3206 return emitOpError() <<
"case " << ref
3207 <<
" is not in the same option group as "
3210 if (!symbolTable.lookupNearestSymbolFrom<OptionOp>(*
this, refRoot))
3211 return emitOpError() <<
"option " << refRoot <<
" does not exist";
3213 if (!symbolTable.lookupNearestSymbolFrom<OptionCaseOp>(*
this, ref))
3214 return emitOpError() <<
"option " << refRoot
3215 <<
" does not contain option case " << ref;
3218 if (
auto instanceMacro = getInstanceMacroAttr())
3219 if (!symbolTable.lookupNearestSymbolFrom(*
this, instanceMacro))
3220 return emitOpError() <<
"instance_macro " << instanceMacro
3221 <<
" does not exist";
3227InstanceChoiceOp::getTargetOrDefaultAttr(OptionCaseOp option) {
3228 auto caseNames = getCaseNamesAttr();
3229 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3230 StringAttr caseSym = cast<SymbolRefAttr>(caseNames[i]).getLeafReference();
3231 if (caseSym == option.getSymName())
3232 return cast<FlatSymbolRefAttr>(getModuleNamesAttr()[i + 1]);
3234 return getDefaultTargetAttr();
3237SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1>
3238InstanceChoiceOp::getTargetChoices() {
3239 auto caseNames = getCaseNamesAttr();
3240 auto moduleNames = getModuleNamesAttr();
3241 SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1> choices;
3242 for (
size_t i = 0; i < caseNames.size(); ++i) {
3243 choices.emplace_back(cast<SymbolRefAttr>(caseNames[i]),
3244 cast<FlatSymbolRefAttr>(moduleNames[i + 1]));
3250InstanceChoiceOp InstanceChoiceOp::cloneWithInsertedPorts(
3251 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
3255 auto oldPortCount = getNumResults();
3256 auto numInsertions = insertions.size();
3257 auto newPortCount = oldPortCount + numInsertions;
3259 SmallVector<Direction> newPortDirections;
3260 SmallVector<Attribute> newPortNames;
3261 SmallVector<Type> newPortTypes;
3262 SmallVector<Attribute> newPortAnnos;
3263 SmallVector<Attribute> newDomainInfo;
3265 newPortDirections.reserve(newPortCount);
3266 newPortNames.reserve(newPortCount);
3267 newPortTypes.reserve(newPortCount);
3268 newPortAnnos.reserve(newPortCount);
3269 newDomainInfo.reserve(newPortCount);
3275 SmallVector<unsigned> indexMap(oldPortCount);
3276 size_t inserted = 0;
3277 for (
size_t i = 0; i < oldPortCount; ++i) {
3278 while (inserted < numInsertions && insertions[inserted].first <= i)
3280 indexMap[i] = i + inserted;
3285 for (
size_t i = 0; i < oldPortCount; ++i) {
3286 while (inserted < numInsertions) {
3287 auto &[index,
info] = insertions[inserted];
3293 newPortDirections.push_back(
info.direction);
3294 newPortNames.push_back(
info.name);
3295 newPortTypes.push_back(
info.type);
3296 newPortAnnos.push_back(
info.annotations.getArrayAttr());
3297 newDomainInfo.push_back(domains);
3301 newPortDirections.push_back(getPortDirection(i));
3302 newPortNames.push_back(getPortNameAttr(i));
3303 newPortTypes.push_back(getType(i));
3304 newPortAnnos.push_back(getPortAnnotations()[i]);
3307 newDomainInfo.push_back(domains);
3310 while (inserted < numInsertions) {
3311 auto &[index,
info] = insertions[inserted];
3314 newPortDirections.push_back(
info.direction);
3315 newPortNames.push_back(
info.name);
3316 newPortTypes.push_back(
info.type);
3317 newPortAnnos.push_back(
info.annotations.getArrayAttr());
3318 newDomainInfo.push_back(domains);
3322 OpBuilder builder(*
this);
3323 auto clone = InstanceChoiceOp::create(
3324 builder,
getLoc(), newPortTypes, getModuleNames(), getCaseNames(),
3327 ArrayAttr::get(
context, newPortNames),
3328 ArrayAttr::get(
context, newDomainInfo), getAnnotationsAttr(),
3329 ArrayAttr::get(
context, newPortAnnos), getLayers(), getInnerSymAttr(),
3330 getInstanceMacroAttr());
3332 if (
auto outputFile = (*this)->getAttr(
"output_file"))
3333 clone->setAttr(
"output_file", outputFile);
3338InstanceChoiceOp InstanceChoiceOp::cloneWithInsertedPortsAndReplaceUses(
3339 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
3340 auto clone = cloneWithInsertedPorts(insertions);
3346InstanceChoiceOp::cloneWithErasedPorts(
const llvm::BitVector &erasures) {
3347 assert(erasures.size() >= getNumResults() &&
3348 "erasures is not at least as large as getNumResults()");
3350 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
3351 SmallVector<Type>(result_type_begin(), result_type_end()), erasures);
3352 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
3354 SmallVector<Attribute> newPortNames =
3356 SmallVector<Attribute> newPortAnnotations =
3358 ArrayAttr newPortDomains =
3362 OpBuilder builder(*
this);
3363 auto clone = InstanceChoiceOp::create(
3364 builder,
getLoc(), newResultTypes, getModuleNames(), getCaseNames(),
3367 ArrayAttr::get(getContext(), newPortNames), newPortDomains,
3368 getAnnotationsAttr(), ArrayAttr::get(getContext(), newPortAnnotations),
3369 getLayers(), getInnerSymAttr(), getInstanceMacroAttr());
3371 if (
auto outputFile = (*this)->getAttr(
"output_file"))
3372 clone->setAttr(
"output_file", outputFile);
3377InstanceChoiceOp InstanceChoiceOp::cloneWithErasedPortsAndReplaceUses(
3378 const llvm::BitVector &erasures) {
3379 auto clone = cloneWithErasedPorts(erasures);
3388ArrayAttr MemOp::getPortAnnotation(
unsigned portIdx) {
3389 assert(portIdx < getNumResults() &&
3390 "index should be smaller than result number");
3391 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
3394void MemOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
3395 assert(annotations.size() == getNumResults() &&
3396 "number of annotations is not equal to result number");
3397 (*this)->setAttr(
"portAnnotations",
3398 ArrayAttr::get(getContext(), annotations));
3402void MemOp::getNumPorts(
size_t &numReadPorts,
size_t &numWritePorts,
3403 size_t &numReadWritePorts,
size_t &numDbgsPorts) {
3406 numReadWritePorts = 0;
3408 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3409 auto portKind = getPortKind(i);
3410 if (portKind == MemOp::PortKind::Debug)
3412 else if (portKind == MemOp::PortKind::Read)
3414 else if (portKind == MemOp::PortKind::Write) {
3417 ++numReadWritePorts;
3422LogicalResult MemOp::verify() {
3426 llvm::SmallDenseSet<Attribute, 8> portNamesSet;
3432 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3433 auto portName = getPortNameAttr(i);
3438 BundleType portBundleType =
3439 type_dyn_cast<BundleType>(getResult(i).getType());
3442 if (!portNamesSet.insert(portName).second) {
3443 emitOpError() <<
"has non-unique port name " << portName;
3451 auto elt = getPortNamed(portName);
3453 emitOpError() <<
"could not get port with name " << portName;
3456 auto firrtlType = type_cast<FIRRTLType>(elt.getType());
3459 if (portKind == MemOp::PortKind::Debug &&
3460 !type_isa<RefType>(getResult(i).getType()))
3461 return emitOpError() <<
"has an invalid type on port " << portName
3462 <<
" (expected Read/Write/ReadWrite/Debug)";
3463 if (type_isa<RefType>(firrtlType) && e == 1)
3464 return emitOpError()
3465 <<
"cannot have only one port of debug type. Debug port can only "
3466 "exist alongside other read/write/read-write port";
3471 if (portKind == MemOp::PortKind::Debug) {
3472 auto resType = type_cast<RefType>(getResult(i).getType());
3473 if (!(resType && type_isa<FVectorType>(resType.getType())))
3474 return emitOpError() <<
"debug ports must be a RefType of FVectorType";
3475 dataType = type_cast<FVectorType>(resType.getType()).getElementType();
3477 auto dataTypeOption = portBundleType.getElement(
"data");
3478 if (!dataTypeOption && portKind == MemOp::PortKind::ReadWrite)
3479 dataTypeOption = portBundleType.getElement(
"wdata");
3480 if (!dataTypeOption) {
3481 emitOpError() <<
"has no data field on port " << portName
3482 <<
" (expected to see \"data\" for a read or write "
3483 "port or \"rdata\" for a read/write port)";
3486 dataType = dataTypeOption->type;
3488 if (portKind == MemOp::PortKind::Read) {
3495 emitOpError() <<
"has non-passive data type on port " << portName
3496 <<
" (memory types must be passive)";
3501 if (dataType.containsAnalog()) {
3502 emitOpError() <<
"has a data type that contains an analog type on port "
3504 <<
" (memory types cannot contain analog types)";
3512 getTypeForPort(getDepth(), dataType, portKind,
3513 dataType.isGround() ? getMaskBits() : 0);
3516 auto originalType = getResult(i).getType();
3517 if (originalType != expectedType) {
3518 StringRef portKindName;
3520 case MemOp::PortKind::Read:
3521 portKindName =
"read";
3523 case MemOp::PortKind::Write:
3524 portKindName =
"write";
3526 case MemOp::PortKind::ReadWrite:
3527 portKindName =
"readwrite";
3529 case MemOp::PortKind::Debug:
3530 portKindName =
"dbg";
3533 emitOpError() <<
"has an invalid type for port " << portName
3534 <<
" of determined kind \"" << portKindName
3535 <<
"\" (expected " << expectedType <<
", but got "
3536 << originalType <<
")";
3542 if (oldDataType && oldDataType != dataType) {
3543 emitOpError() <<
"port " << getPortNameAttr(i)
3544 <<
" has a different type than port "
3545 << getPortNameAttr(i - 1) <<
" (expected " << oldDataType
3546 <<
", but got " << dataType <<
")";
3550 oldDataType = dataType;
3553 auto maskWidth = getMaskBits();
3555 auto dataWidth = getDataType().getBitWidthOrSentinel();
3556 if (dataWidth > 0 && maskWidth > (
size_t)dataWidth)
3557 return emitOpError(
"the mask width cannot be greater than "
3560 if (getPortAnnotations().size() != getNumResults())
3561 return emitOpError(
"the number of result annotations should be "
3562 "equal to the number of results");
3568 return std::max(1U, llvm::Log2_64_Ceil(depth));
3574 PortKind portKind,
size_t maskBits) {
3576 auto *
context = dataType.getContext();
3577 if (portKind == PortKind::Debug)
3578 return RefType::get(FVectorType::get(dataType, depth));
3584 maskType = UIntType::get(
context, maskBits);
3586 auto getId = [&](StringRef name) -> StringAttr {
3587 return StringAttr::get(
context, name);
3590 SmallVector<BundleType::BundleElement, 7> portFields;
3594 portFields.push_back({getId(
"addr"),
false, addressType});
3595 portFields.push_back({getId(
"en"),
false, UIntType::get(
context, 1)});
3596 portFields.push_back({getId(
"clk"),
false, ClockType::get(
context)});
3599 case PortKind::Read:
3600 portFields.push_back({getId(
"data"),
true, dataType});
3603 case PortKind::Write:
3604 portFields.push_back({getId(
"data"),
false, dataType});
3605 portFields.push_back({getId(
"mask"),
false, maskType});
3608 case PortKind::ReadWrite:
3609 portFields.push_back({getId(
"rdata"),
true, dataType});
3610 portFields.push_back({getId(
"wmode"),
false, UIntType::get(
context, 1)});
3611 portFields.push_back({getId(
"wdata"),
false, dataType});
3612 portFields.push_back({getId(
"wmask"),
false, maskType});
3615 llvm::report_fatal_error(
"memory port kind not handled");
3619 return BundleType::get(
context, portFields);
3623SmallVector<MemOp::NamedPort> MemOp::getPorts() {
3624 SmallVector<MemOp::NamedPort> result;
3626 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3628 auto portType = type_cast<FIRRTLType>(getResult(i).getType());
3635MemOp::PortKind MemOp::getPortKind(StringRef portName) {
3637 type_cast<FIRRTLType>(getPortNamed(portName).getType()));
3641MemOp::PortKind MemOp::getPortKind(
size_t resultNo) {
3643 type_cast<FIRRTLType>(getResult(resultNo).getType()));
3647size_t MemOp::getMaskBits() {
3649 for (
auto res : getResults()) {
3650 if (type_isa<RefType>(res.getType()))
3652 auto firstPortType = type_cast<FIRRTLBaseType>(res.getType());
3659 if (t.name.getValue().contains(
"mask"))
3662 if (type_isa<UIntType>(mType))
3672 assert(getNumResults() != 0 &&
"Mems with no read/write ports are illegal");
3674 if (
auto refType = type_dyn_cast<RefType>(getResult(0).getType()))
3675 return type_cast<FVectorType>(refType.getType()).getElementType();
3676 auto firstPortType = type_cast<FIRRTLBaseType>(getResult(0).getType());
3678 StringRef dataFieldName =
"data";
3680 dataFieldName =
"rdata";
3682 return type_cast<BundleType>(firstPortType.getPassiveType())
3683 .getElementType(dataFieldName);
3686StringAttr MemOp::getPortNameAttr(
size_t resultNo) {
3687 return cast<StringAttr>(getPortNames()[resultNo]);
3691 return type_cast<FIRRTLBaseType>(getResults()[resultNo].getType());
3694Value MemOp::getPortNamed(StringAttr name) {
3695 auto namesArray = getPortNames();
3696 for (
size_t i = 0, e = namesArray.size(); i != e; ++i) {
3697 if (namesArray[i] == name) {
3698 assert(i < getNumResults() &&
" names array out of sync with results");
3699 return getResult(i);
3708 size_t numReadPorts = 0;
3709 size_t numWritePorts = 0;
3710 size_t numReadWritePorts = 0;
3712 SmallVector<int32_t> writeClockIDs;
3714 for (
size_t i = 0, e = op.getNumResults(); i != e; ++i) {
3715 auto portKind = op.getPortKind(i);
3716 if (portKind == MemOp::PortKind::Read)
3718 else if (portKind == MemOp::PortKind::Write) {
3719 for (
auto *a : op.getResult(i).getUsers()) {
3720 auto subfield = dyn_cast<SubfieldOp>(a);
3721 if (!subfield || subfield.getFieldIndex() != 2)
3723 auto clockPort =
a->getResult(0);
3724 for (
auto *b : clockPort.getUsers()) {
3725 if (
auto connect = dyn_cast<FConnectLike>(b)) {
3726 if (
connect.getDest() == clockPort) {
3729 connect.getSrc(),
true,
true,
true),
3731 if (result.second) {
3732 writeClockIDs.push_back(numWritePorts);
3734 writeClockIDs.push_back(result.first->second);
3743 ++numReadWritePorts;
3750 op.emitError(
"'firrtl.mem' should have simple type and known width");
3751 MemoryInitAttr init = op->getAttrOfType<MemoryInitAttr>(
"init");
3753 if (op->hasAttr(
"modName"))
3754 modName = op->getAttrOfType<StringAttr>(
"modName");
3756 SmallString<8> clocks;
3757 for (
auto a : writeClockIDs)
3758 clocks.
append(Twine((char)(
a +
'a')).str());
3759 SmallString<32> initStr;
3764 for (
auto c : init.getFilename().getValue())
3765 if ((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') ||
3766 (c >=
'0' && c <=
'9'))
3767 initStr.push_back(c);
3768 initStr.push_back(
'_');
3769 initStr.push_back(init.getIsBinary() ?
't' :
'f');
3770 initStr.push_back(
'_');
3771 initStr.push_back(init.getIsInline() ?
't' :
'f');
3773 modName = StringAttr::get(
3776 "{0}FIRRTLMem_{1}_{2}_{3}_{4}_{5}_{6}_{7}_{8}_{9}_{10}{11}{12}",
3777 op.getPrefix().value_or(
""), numReadPorts, numWritePorts,
3778 numReadWritePorts, (
size_t)width, op.getDepth(),
3779 op.getReadLatency(), op.getWriteLatency(), op.getMaskBits(),
3780 (
unsigned)op.getRuw(), (
unsigned)seq::WUW::PortOrder,
3781 clocks.empty() ?
"" :
"_" + clocks, init ? initStr.str() :
""));
3783 return {numReadPorts,
3788 op.getReadLatency(),
3789 op.getWriteLatency(),
3791 *seq::symbolizeRUW(
unsigned(op.getRuw())),
3792 seq::WUW::PortOrder,
3795 op.getMaskBits() > 1,
3801void MemOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3806 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
3807 setNameFn(getResult(i), (base +
"_" + getPortName(i)).str());
3811std::optional<size_t> MemOp::getTargetResultIndex() {
3813 return std::nullopt;
3821 OpAsmSetValueNameFn setNameFn) {
3824 setNameFn(op.getDataRaw(), name);
3825 if (op.isForceable())
3826 setNameFn(op.getDataRef(), (name +
"_ref").str());
3829void NodeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3833LogicalResult NodeOp::inferReturnTypes(
3834 mlir::MLIRContext *
context, std::optional<mlir::Location> location,
3835 ::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes,
3836 ::mlir::OpaqueProperties properties, ::mlir::RegionRange regions,
3837 ::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
3838 if (operands.empty())
3840 Adaptor adaptor(operands, attributes, properties, regions);
3841 inferredReturnTypes.push_back(adaptor.getInput().getType());
3842 if (adaptor.getForceable()) {
3844 true, adaptor.getInput().getType());
3845 if (!forceableType) {
3847 ::mlir::emitError(*location,
"cannot force a node of type ")
3848 << operands[0].getType();
3851 inferredReturnTypes.push_back(forceableType);
3856std::optional<size_t> NodeOp::getTargetResultIndex() {
return 0; }
3858void RegOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3862std::optional<size_t> RegOp::getTargetResultIndex() {
return 0; }
3864SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3865RegOp::computeDataFlow() {
3870LogicalResult RegResetOp::verify() {
3871 auto reset = getResetValue();
3878 return emitError(
"type mismatch between register ")
3879 << regType <<
" and reset value " << resetType;
3884std::optional<size_t> RegResetOp::getTargetResultIndex() {
return 0; }
3886void RegResetOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3895FormalOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3896 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3898 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3900 if (!isa<FModuleLike>(op)) {
3901 auto d = emitOpError() <<
"target " << getModuleNameAttr()
3902 <<
" is not a module";
3903 d.attachNote(op->getLoc()) <<
"target defined here";
3915SimulationOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3916 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3918 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3920 auto complain = [&] {
3921 auto d = emitOpError() <<
"target " << getModuleNameAttr() <<
" ";
3922 d.attachNote(op->getLoc()) <<
"target defined here";
3926 auto module = dyn_cast<FModuleLike>(op);
3928 return complain() <<
"is not a module";
3930 auto numPorts =
module.getNumPorts();
3932 return complain() <<
"must have at least 4 ports, got " << numPorts
3936 auto checkPort = [&](
unsigned idx, StringRef expName,
Direction expDir,
3937 llvm::function_ref<bool(Type)> checkType,
3938 StringRef expType) {
3939 auto name =
module.getPortNameAttr(idx);
3940 if (name != expName) {
3941 complain() <<
"port " << idx <<
" must be called \"" << expName
3942 <<
"\", got " << name <<
" instead";
3945 if (
auto dir = module.getPortDirection(idx); dir != expDir) {
3949 complain() <<
"port " << name <<
" must be " << stringify(expDir)
3950 <<
", got " << stringify(dir) <<
" instead";
3953 if (
auto type = module.getPortType(idx); !checkType(type)) {
3954 complain() <<
"port " << name <<
" must be a '!firrtl." << expType
3955 <<
"', got " << type <<
" instead";
3961 auto isClock = [](Type type) {
return isa<ClockType>(type); };
3962 auto isBool = [](Type type) {
3963 if (
auto uintType = dyn_cast<UIntType>(type))
3964 return uintType.getWidth() == 1;
3968 if (!checkPort(0,
"clock",
Direction::In, isClock,
"clock") ||
3975 for (
unsigned i = 4; i < numPorts; ++i) {
3976 auto type =
module.getPortType(i);
3977 if (!isa<PropertyType>(type))
3978 return complain() <<
"port " << i <<
" may only be a property type, got "
3979 << type <<
" instead";
3989void WireOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3993SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3994RegResetOp::computeDataFlow() {
3999std::optional<size_t> WireOp::getTargetResultIndex() {
return 0; }
4001LogicalResult WireOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
4002 if (
auto refType = type_dyn_cast<RefType>(getType(0)))
4004 refType,
getLoc(), getOperation()->getParentOfType<CircuitOp>(),
4005 symbolTable, Twine(
"'") + getOperationName() +
"' op is");
4007 if (
auto domainType = type_dyn_cast<DomainType>(getType(0)))
4008 return domainType.verifySymbolUses(getOperation(), symbolTable);
4017LogicalResult ContractOp::verify() {
4018 if (getBody().getArgumentTypes() != getInputs().getType())
4019 return emitOpError(
"result types and region argument types must match");
4028OptionCaseOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
4029 auto caseMacro = getCaseMacroAttr();
4034 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
4035 auto *refOp = symbolTable.lookupSymbolIn(circuitOp, caseMacro);
4037 return emitOpError(
"case_macro references an undefined symbol: ")
4040 if (!isa<sv::MacroDeclOp>(refOp))
4041 return emitOpError(
"case_macro must reference a macro declaration");
4050void ObjectOp::build(OpBuilder &builder, OperationState &state, ClassLike klass,
4052 build(builder, state, klass.getInstanceType(),
4053 StringAttr::get(builder.getContext(), name));
4056LogicalResult ObjectOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
4057 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
4058 auto classType = getType();
4059 auto className = classType.getNameAttr();
4062 auto classOp = dyn_cast_or_null<ClassLike>(
4063 symbolTable.lookupSymbolIn(circuitOp, className));
4065 return emitOpError() <<
"references unknown class " << className;
4068 if (failed(classOp.verifyType(classType, [&]() { return emitOpError(); })))
4074StringAttr ObjectOp::getClassNameAttr() {
4075 return getType().getNameAttr().getAttr();
4078StringRef ObjectOp::getClassName() {
return getType().getName(); }
4080ClassLike ObjectOp::getReferencedClass(
const SymbolTable &symbolTable) {
4081 auto symRef = getType().getNameAttr();
4082 return symbolTable.lookup<ClassLike>(symRef.getLeafReference());
4085Operation *ObjectOp::getReferencedOperation(
const SymbolTable &symtbl) {
4086 return getReferencedClass(symtbl);
4089StringRef ObjectOp::getInstanceName() {
return getName(); }
4091StringAttr ObjectOp::getInstanceNameAttr() {
return getNameAttr(); }
4093StringAttr ObjectOp::getReferencedModuleNameAttr() {
4094 return getClassNameAttr();
4097void ObjectOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4098 setNameFn(getResult(),
getName());
4105LogicalResult AttachOp::verify() {
4107 std::optional<int32_t> commonWidth;
4108 for (
auto operand : getOperands()) {
4109 auto thisWidth = type_cast<AnalogType>(operand.getType()).getWidth();
4113 commonWidth = thisWidth;
4116 if (commonWidth != thisWidth)
4117 return emitOpError(
"is inavlid as not all known operand widths match");
4124 Value dst = connect->getOperand(0);
4125 Value src = connect->getOperand(1);
4134 if (isa<PropertyType>(src.getType()) ||
4138 auto diag = emitError(connect->getLoc());
4139 diag <<
"connect has invalid flow: the source expression ";
4141 diag <<
"\"" << srcName <<
"\" ";
4142 diag <<
"has " <<
toString(srcFlow) <<
", expected source or duplex flow";
4143 return diag.attachNote(srcRef.getLoc()) <<
"the source was defined here";
4151 auto diag = emitError(connect->getLoc());
4152 diag <<
"connect has invalid flow: the destination expression ";
4154 diag <<
"\"" << dstName <<
"\" ";
4155 diag <<
"has " <<
toString(dstFlow) <<
", expected sink or duplex flow";
4156 return diag.attachNote(dstRef.getLoc())
4157 <<
"the destination was defined here";
4166 bool outerTypeIsConst =
false) {
4167 auto typeIsConst = outerTypeIsConst || type.
isConst();
4172 if (
auto bundleType = type_dyn_cast<BundleType>(type))
4173 return llvm::any_of(bundleType.getElements(), [&](
auto &element) {
4174 return isConstFieldDriven(element.type, isFlip ^ element.isFlip,
4178 if (
auto vectorType = type_dyn_cast<FVectorType>(type))
4190 auto dest = connect.getDest();
4191 auto destType = type_dyn_cast<FIRRTLBaseType>(dest.getType());
4192 auto src = connect.getSrc();
4193 auto srcType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4194 if (!destType || !srcType)
4197 auto destRefinedType = destType;
4198 auto srcRefinedType = srcType;
4203 auto findFieldDeclarationRefiningFieldType =
4205 while (
auto *definingOp = value.getDefiningOp()) {
4206 bool shouldContinue =
true;
4207 TypeSwitch<Operation *>(definingOp)
4208 .Case<SubfieldOp, SubindexOp>([&](
auto op) { value = op.getInput(); })
4209 .Case<SubaccessOp>([&](SubaccessOp op) {
4213 .getElementTypePreservingConst()
4215 originalFieldType = originalFieldType.getConstType(
true);
4216 value = op.getInput();
4218 .Default([&](Operation *) { shouldContinue =
false; });
4219 if (!shouldContinue)
4225 auto destDeclaration =
4226 findFieldDeclarationRefiningFieldType(dest, destRefinedType);
4227 auto srcDeclaration =
4228 findFieldDeclarationRefiningFieldType(src, srcRefinedType);
4230 auto checkConstConditionality = [&](Value value,
FIRRTLBaseType type,
4231 Value declaration) -> LogicalResult {
4232 auto *declarationBlock = declaration.getParentBlock();
4233 auto *block = connect->getBlock();
4234 while (block && block != declarationBlock) {
4235 auto *parentOp = block->getParentOp();
4237 if (
auto whenOp = dyn_cast<WhenOp>(parentOp);
4238 whenOp && !whenOp.getCondition().getType().isConst()) {
4240 return connect.emitOpError()
4241 <<
"assignment to 'const' type " << type
4242 <<
" is dependent on a non-'const' condition";
4243 return connect->emitOpError()
4244 <<
"assignment to nested 'const' member of type " << type
4245 <<
" is dependent on a non-'const' condition";
4248 block = parentOp->getBlock();
4253 auto emitSubaccessError = [&] {
4254 return connect.emitError(
4255 "assignment to non-'const' subaccess of 'const' type is disallowed");
4261 if (destType != destRefinedType)
4262 return emitSubaccessError();
4264 if (failed(checkConstConditionality(dest, destType, destDeclaration)))
4269 if (srcRefinedType.containsConst() &&
4272 if (srcType != srcRefinedType)
4273 return emitSubaccessError();
4274 if (failed(checkConstConditionality(src, srcType, srcDeclaration)))
4291 auto dest = connect.getDest();
4292 for (
auto *user : dest.getUsers()) {
4293 if (
auto c = dyn_cast<FConnectLike>(user);
4294 c && c.getDest() == dest && c != connect) {
4295 auto diag = connect.emitError(
"destination cannot be driven by multiple "
4297 diag.attachNote(c->getLoc()) <<
"other driver is here";
4304LogicalResult ConnectOp::verify() {
4305 auto dstType = getDest().getType();
4306 auto srcType = getSrc().getType();
4307 auto dstBaseType = type_dyn_cast<FIRRTLBaseType>(dstType);
4308 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(srcType);
4309 if (!dstBaseType || !srcBaseType) {
4310 if (dstType != srcType)
4311 return emitError(
"may not connect different non-base types");
4314 if (dstBaseType.containsAnalog() || srcBaseType.containsAnalog())
4315 return emitError(
"analog types may not be connected");
4319 return emitError(
"type mismatch between destination ")
4320 << dstBaseType <<
" and source " << srcBaseType;
4325 return emitError(
"destination ")
4326 << dstBaseType <<
" is not as wide as the source " << srcBaseType;
4339LogicalResult MatchingConnectOp::verify() {
4340 if (
auto type = type_dyn_cast<FIRRTLType>(getDest().getType())) {
4341 auto baseType = type_cast<FIRRTLBaseType>(type);
4344 if (baseType && baseType.containsAnalog())
4345 return emitError(
"analog types may not be connected");
4350 "`SameAnonTypeOperands` trait should have already rejected "
4351 "structurally non-equivalent types");
4364LogicalResult RefDefineOp::verify() {
4371 if (
auto *op = getDest().getDefiningOp()) {
4373 if (isa<RefSubOp>(op))
4375 "destination reference cannot be a sub-element of a reference");
4376 if (isa<RefCastOp>(op))
4378 "destination reference cannot be a cast of another reference");
4386 SmallVector<SymbolRefAttr> missingLayers;
4389 "has more layer requirements than destination",
4390 "additional layers required");
4393LogicalResult PropAssignOp::verify() {
4403template <
typename T>
4405 auto info = op.getDomainInfo();
4408 return dyn_cast<FlatSymbolRefAttr>(info[i]);
4412 if (!isa<DomainType>(value.getType()))
4415 if (
auto arg = dyn_cast<BlockArgument>(value)) {
4416 auto *parent = arg.getOwner()->getParentOp();
4417 if (
auto module = dyn_cast<FModuleLike>(parent)) {
4418 auto info =
module.getDomainInfo();
4421 auto attr = info[arg.getArgNumber()];
4422 return dyn_cast<FlatSymbolRefAttr>(attr);
4428 if (
auto result = dyn_cast<OpResult>(value)) {
4429 auto *op = result.getDefiningOp();
4430 if (
auto instance = dyn_cast<InstanceOp>(op))
4432 if (
auto instance = dyn_cast<InstanceChoiceOp>(op))
4434 if (
auto anonDomain = dyn_cast<DomainCreateAnonOp>(op))
4435 return anonDomain.getDomainAttr();
4436 if (
auto domain = dyn_cast<DomainCreateOp>(op))
4437 return domain.getDomainAttr();
4444LogicalResult DomainDefineOp::verify() {
4451 auto dst = getDest();
4452 auto src = getSrc();
4460 if (
auto *srcDefOp = src.getDefiningOp())
4461 if (isa<WireOp>(srcDefOp))
4463 if (
auto *dstDefOp = dst.getDefiningOp())
4464 if (isa<WireOp>(dstDefOp))
4469 return emitError(
"could not determine domain-type of destination");
4473 return emitError(
"could not determine domain-type of source");
4475 if (dstDomain != srcDomain) {
4476 auto diag = emitError()
4477 <<
"source domain type " << srcDomain
4478 <<
" does not match destination domain type " << dstDomain;
4485void WhenOp::createElseRegion() {
4486 assert(!hasElseRegion() &&
"already has an else region");
4487 getElseRegion().push_back(
new Block());
4490void WhenOp::build(OpBuilder &builder, OperationState &result, Value condition,
4491 bool withElseRegion, std::function<
void()> thenCtor,
4492 std::function<
void()> elseCtor) {
4493 OpBuilder::InsertionGuard guard(builder);
4494 result.addOperands(condition);
4497 builder.createBlock(result.addRegion());
4502 Region *elseRegion = result.addRegion();
4503 if (withElseRegion) {
4504 builder.createBlock(elseRegion);
4514LogicalResult MatchOp::verify() {
4515 FEnumType type = getInput().getType();
4518 auto numCases = getTags().size();
4519 auto numRegions = getNumRegions();
4520 if (numRegions != numCases)
4521 return emitOpError(
"expected ")
4522 << numRegions <<
" tags but got " << numCases;
4524 auto numTags = type.getNumElements();
4526 SmallDenseSet<int64_t> seen;
4527 for (
const auto &[tag, region] :
llvm::zip(getTags(), getRegions())) {
4528 auto tagIndex = size_t(cast<IntegerAttr>(tag).
getInt());
4531 if (region.getNumArguments() != 1)
4532 return emitOpError(
"region should have exactly one argument");
4535 if (tagIndex >= numTags)
4536 return emitOpError(
"the tag index ")
4537 << tagIndex <<
" is out of the range of valid tags in " << type;
4540 auto [it, inserted] = seen.insert(tagIndex);
4542 return emitOpError(
"the tag ") << type.getElementNameAttr(tagIndex)
4543 <<
" is matched more than once";
4546 auto expectedType = type.getElementTypePreservingConst(tagIndex);
4547 auto regionType = region.getArgument(0).getType();
4548 if (regionType != expectedType)
4549 return emitOpError(
"region type ")
4550 << regionType <<
" does not match the expected type "
4555 for (
size_t i = 0, e = type.getNumElements(); i < e; ++i)
4556 if (!seen.contains(i))
4557 return emitOpError(
"missing case for tag ") << type.getElementNameAttr(i);
4562void MatchOp::print(OpAsmPrinter &p) {
4563 auto input = getInput();
4564 FEnumType type = input.getType();
4565 auto regions = getRegions();
4566 p <<
" " << input <<
" : " << type;
4567 SmallVector<StringRef> elided = {
"tags"};
4568 p.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elided);
4571 for (
const auto &[tag, region] :
llvm::zip(getTags(), regions)) {
4574 p.printKeywordOrString(
4575 type.getElementName(cast<IntegerAttr>(tag).getInt()));
4577 p.printRegionArgument(region.front().getArgument(0), {},
4580 p.printRegion(region,
false);
4587ParseResult MatchOp::parse(OpAsmParser &parser, OperationState &result) {
4588 auto *
context = parser.getContext();
4589 auto &properties = result.getOrAddProperties<Properties>();
4590 OpAsmParser::UnresolvedOperand input;
4591 if (parser.parseOperand(input) || parser.parseColon())
4594 auto loc = parser.getCurrentLocation();
4596 if (parser.parseType(type))
4598 auto enumType = type_dyn_cast<FEnumType>(type);
4600 return parser.emitError(loc,
"expected enumeration type but got") << type;
4602 if (parser.resolveOperand(input, type, result.operands) ||
4603 parser.parseOptionalAttrDictWithKeyword(result.attributes) ||
4604 parser.parseLBrace())
4607 auto i32Type = IntegerType::get(
context, 32);
4608 SmallVector<Attribute> tags;
4611 if (failed(parser.parseOptionalKeyword(
"case")))
4615 auto nameLoc = parser.getCurrentLocation();
4617 OpAsmParser::Argument arg;
4618 auto *region = result.addRegion();
4619 if (parser.parseKeywordOrString(&name) || parser.parseLParen() ||
4620 parser.parseArgument(arg) || parser.parseRParen())
4624 auto index = enumType.getElementIndex(name);
4626 return parser.emitError(nameLoc,
"the tag \"")
4627 << name <<
"\" is not a member of the enumeration " << enumType;
4628 tags.push_back(IntegerAttr::get(i32Type, *index));
4631 arg.type = enumType.getElementTypePreservingConst(*index);
4632 if (parser.parseRegion(*region, arg))
4635 properties.setTags(ArrayAttr::get(
context, tags));
4637 return parser.parseRBrace();
4640void MatchOp::build(OpBuilder &builder, OperationState &result, Value input,
4642 MutableArrayRef<std::unique_ptr<Region>> regions) {
4643 auto &properties = result.getOrAddProperties<Properties>();
4644 result.addOperands(input);
4645 properties.setTags(tags);
4646 result.addRegions(regions);
4655 struct IsExprClassifier :
public ExprVisitor<IsExprClassifier, bool> {
4656 bool visitInvalidExpr(Operation *op) {
return false; }
4657 bool visitUnhandledExpr(Operation *op) {
return true; }
4663void InvalidValueOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4666 if (
auto ty = type_dyn_cast<IntType>(getType())) {
4667 const char *base = ty.isSigned() ?
"invalid_si" :
"invalid_ui";
4668 auto width = ty.getWidthOrSentinel();
4672 name = (Twine(base) + Twine(width)).str();
4673 }
else if (
auto ty = type_dyn_cast<AnalogType>(getType())) {
4674 auto width = ty.getWidthOrSentinel();
4676 name =
"invalid_analog";
4678 name = (
"invalid_analog" + Twine(width)).str();
4679 }
else if (type_isa<AsyncResetType>(getType()))
4680 name =
"invalid_asyncreset";
4681 else if (type_isa<ResetType>(getType()))
4682 name =
"invalid_reset";
4683 else if (type_isa<ClockType>(getType()))
4684 name =
"invalid_clock";
4688 setNameFn(getResult(), name);
4691void ConstantOp::print(OpAsmPrinter &p) {
4693 p.printAttributeWithoutType(getValueAttr());
4695 p.printType(getType());
4696 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4699ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
4700 auto &properties = result.getOrAddProperties<Properties>();
4703 auto loc = parser.getCurrentLocation();
4704 auto valueResult = parser.parseOptionalInteger(value);
4705 if (!valueResult.has_value())
4706 return parser.emitError(loc,
"expected integer value");
4710 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4711 parser.parseOptionalAttrDict(result.attributes))
4713 result.addTypes(resultType);
4719 if (width > value.getBitWidth()) {
4723 value = value.sext(width);
4724 }
else if (width < value.getBitWidth()) {
4727 unsigned neededBits = value.isNegative() ? value.getSignificantBits()
4728 : value.getActiveBits();
4729 if (width < neededBits)
4730 return parser.emitError(loc,
"constant out of range for result type ")
4732 value = value.trunc(width);
4736 auto intType = parser.getBuilder().getIntegerType(value.getBitWidth(),
4738 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4739 properties.setValue(valueAttr);
4743LogicalResult ConstantOp::verify() {
4747 if (width != -1 && (
int)getValue().
getBitWidth() != width)
4749 "firrtl.constant attribute bitwidth doesn't match return type");
4752 auto attrType = type_cast<IntegerType>(getValueAttr().getType());
4753 if (attrType.isSignless() || attrType.isSigned() != intType.
isSigned())
4754 return emitError(
"firrtl.constant attribute has wrong sign");
4761void ConstantOp::build(OpBuilder &builder, OperationState &result,
IntType type,
4762 const APInt &value) {
4765 assert((width == -1 || (int32_t)value.getBitWidth() == width) &&
4766 "incorrect attribute bitwidth for firrtl.constant");
4769 IntegerAttr::get(type.getContext(), APSInt(value, !type.
isSigned()));
4770 return build(builder, result, type, attr);
4775void ConstantOp::build(OpBuilder &builder, OperationState &result,
4776 const APSInt &value) {
4777 auto attr = IntegerAttr::get(builder.getContext(), value);
4779 IntType::get(builder.getContext(), value.isSigned(), value.getBitWidth());
4780 return build(builder, result, type, attr);
4783void ConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4790 SmallString<32> specialNameBuffer;
4791 llvm::raw_svector_ostream specialName(specialNameBuffer);
4793 getValue().print(specialName, intTy.
isSigned());
4795 specialName << (intTy.
isSigned() ?
"_si" :
"_ui");
4798 specialName << width;
4799 setNameFn(getResult(), specialName.str());
4802void SpecialConstantOp::print(OpAsmPrinter &p) {
4805 p << static_cast<unsigned>(getValue());
4807 p.printType(getType());
4808 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4811ParseResult SpecialConstantOp::parse(OpAsmParser &parser,
4812 OperationState &result) {
4813 auto &properties = result.getOrAddProperties<Properties>();
4817 auto loc = parser.getCurrentLocation();
4818 auto valueResult = parser.parseOptionalInteger(value);
4819 if (!valueResult.has_value())
4820 return parser.emitError(loc,
"expected integer value");
4823 if (value != 0 && value != 1)
4824 return parser.emitError(loc,
"special constants can only be 0 or 1.");
4828 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4829 parser.parseOptionalAttrDict(result.attributes))
4831 result.addTypes(resultType);
4834 auto valueAttr = parser.getBuilder().getBoolAttr(value == 1);
4835 properties.setValue(valueAttr);
4839void SpecialConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4840 SmallString<32> specialNameBuffer;
4841 llvm::raw_svector_ostream specialName(specialNameBuffer);
4843 specialName << static_cast<unsigned>(getValue());
4844 auto type = getType();
4845 if (type_isa<ClockType>(type)) {
4846 specialName <<
"_clock";
4847 }
else if (type_isa<ResetType>(type)) {
4848 specialName <<
"_reset";
4849 }
else if (type_isa<AsyncResetType>(type)) {
4850 specialName <<
"_asyncreset";
4852 setNameFn(getResult(), specialName.str());
4859 if (type.isGround()) {
4860 if (!isa<IntegerAttr>(attr)) {
4861 op->emitOpError(
"Ground type is not an integer attribute");
4866 auto attrlist = dyn_cast<ArrayAttr>(attr);
4868 op->emitOpError(
"expected array attribute for aggregate constant");
4871 if (
auto array = type_dyn_cast<FVectorType>(type)) {
4872 if (array.getNumElements() != attrlist.size()) {
4873 op->emitOpError(
"array attribute (")
4874 << attrlist.size() <<
") has wrong size for vector constant ("
4875 << array.getNumElements() <<
")";
4878 return llvm::all_of(attrlist, [&array, op](Attribute attr) {
4882 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4883 if (bundle.getNumElements() != attrlist.size()) {
4884 op->emitOpError(
"array attribute (")
4885 << attrlist.size() <<
") has wrong size for bundle constant ("
4886 << bundle.getNumElements() <<
")";
4889 for (
size_t i = 0; i < bundle.getNumElements(); ++i) {
4890 if (bundle.getElement(i).isFlip) {
4891 op->emitOpError(
"Cannot have constant bundle type with flip");
4899 op->emitOpError(
"Unknown aggregate type");
4903LogicalResult AggregateConstantOp::verify() {
4909Attribute AggregateConstantOp::getAttributeFromFieldID(uint64_t fieldID) {
4911 Attribute value = getFields();
4912 while (fieldID != 0) {
4913 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4914 auto index = bundle.getIndexForFieldID(fieldID);
4915 fieldID -= bundle.getFieldID(index);
4916 type = bundle.getElementType(index);
4917 value = cast<ArrayAttr>(value)[index];
4919 auto vector = type_cast<FVectorType>(type);
4920 auto index = vector.getIndexForFieldID(fieldID);
4921 fieldID -= vector.getFieldID(index);
4922 type = vector.getElementType();
4923 value = cast<ArrayAttr>(value)[index];
4929LogicalResult FIntegerConstantOp::verify() {
4930 auto i = getValueAttr();
4931 if (!i.getType().isSignedInteger())
4932 return emitOpError(
"value must be signed");
4936void FIntegerConstantOp::print(OpAsmPrinter &p) {
4938 p.printAttributeWithoutType(getValueAttr());
4939 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4942ParseResult FIntegerConstantOp::parse(OpAsmParser &parser,
4943 OperationState &result) {
4944 auto *
context = parser.getContext();
4945 auto &properties = result.getOrAddProperties<Properties>();
4947 if (parser.parseInteger(value) ||
4948 parser.parseOptionalAttrDict(result.attributes))
4950 result.addTypes(FIntegerType::get(
context));
4952 IntegerType::get(
context, value.getBitWidth(), IntegerType::Signed);
4953 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4954 properties.setValue(valueAttr);
4958ParseResult ListCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4959 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
4962 if (parser.parseOperandList(operands) ||
4963 parser.parseOptionalAttrDict(result.attributes) ||
4964 parser.parseColonType(type))
4966 result.addTypes(type);
4968 return parser.resolveOperands(operands, type.getElementType(),
4972void ListCreateOp::print(OpAsmPrinter &p) {
4974 p.printOperands(getElements());
4975 p.printOptionalAttrDict((*this)->getAttrs());
4976 p <<
" : " << getType();
4979LogicalResult ListCreateOp::verify() {
4980 if (getElements().
empty())
4983 auto elementType = getElements().front().getType();
4984 auto listElementType = getType().getElementType();
4986 return emitOpError(
"has elements of type ")
4987 <<
elementType <<
" instead of " << listElementType;
4992LogicalResult BundleCreateOp::verify() {
4993 BundleType resultType = getType();
4994 if (resultType.getNumElements() != getFields().size())
4995 return emitOpError(
"number of fields doesn't match type");
4996 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4998 resultType.getElementTypePreservingConst(i),
4999 type_cast<FIRRTLBaseType>(getOperand(i).getType())))
5000 return emitOpError(
"type of element doesn't match bundle for field ")
5001 << resultType.getElement(i).name;
5006LogicalResult VectorCreateOp::verify() {
5007 FVectorType resultType = getType();
5008 if (resultType.getNumElements() != getFields().size())
5009 return emitOpError(
"number of fields doesn't match type");
5010 auto elemTy = resultType.getElementTypePreservingConst();
5011 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
5013 elemTy, type_cast<FIRRTLBaseType>(getOperand(i).getType())))
5014 return emitOpError(
"type of element doesn't match vector element");
5020UnknownValueOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
5022 auto classType = dyn_cast<ClassType>(getType());
5026 auto className = classType.getNameAttr();
5028 Operation *op = symbolTable.lookupNearestSymbolFrom(*
this, className);
5030 return emitOpError() <<
"refers to non-existent class ("
5031 << className.getAttr() <<
")";
5034 if (!isa<ClassLike>(op))
5035 return emitOpError() <<
"refers to a non-class type ("
5036 << className.getAttr() <<
")";
5045LogicalResult FEnumCreateOp::verify() {
5046 FEnumType resultType = getResult().getType();
5047 auto elementIndex = resultType.getElementIndex(
getFieldName());
5049 return emitOpError(
"label ")
5050 <<
getFieldName() <<
" is not a member of the enumeration type "
5053 resultType.getElementTypePreservingConst(*elementIndex),
5054 getInput().getType()))
5055 return emitOpError(
"type of element doesn't match enum element");
5059void FEnumCreateOp::print(OpAsmPrinter &printer) {
5062 printer <<
'(' << getInput() <<
')';
5063 SmallVector<StringRef> elidedAttrs = {
"fieldIndex"};
5064 printer.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elidedAttrs);
5066 printer.printFunctionalType(ArrayRef<Type>{getInput().getType()},
5067 ArrayRef<Type>{getResult().getType()});
5070ParseResult FEnumCreateOp::parse(OpAsmParser &parser, OperationState &result) {
5071 auto *
context = parser.getContext();
5072 auto &properties = result.getOrAddProperties<Properties>();
5074 OpAsmParser::UnresolvedOperand input;
5075 std::string fieldName;
5076 mlir::FunctionType functionType;
5077 if (parser.parseKeywordOrString(&fieldName) || parser.parseLParen() ||
5078 parser.parseOperand(input) || parser.parseRParen() ||
5079 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5080 parser.parseType(functionType))
5083 if (functionType.getNumInputs() != 1)
5084 return parser.emitError(parser.getNameLoc(),
"single input type required");
5085 if (functionType.getNumResults() != 1)
5086 return parser.emitError(parser.getNameLoc(),
"single result type required");
5088 auto inputType = functionType.getInput(0);
5089 if (parser.resolveOperand(input, inputType, result.operands))
5092 auto outputType = functionType.getResult(0);
5093 auto enumType = type_dyn_cast<FEnumType>(outputType);
5095 return parser.emitError(parser.getNameLoc(),
5096 "output must be enum type, got ")
5098 auto fieldIndex = enumType.getElementIndex(fieldName);
5100 return parser.emitError(parser.getNameLoc(),
5101 "unknown field " + fieldName +
" in enum type ")
5104 properties.setFieldIndex(
5105 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5107 result.addTypes(enumType);
5116LogicalResult IsTagOp::verify() {
5117 if (getFieldIndex() >= getInput().getType().base().getNumElements())
5118 return emitOpError(
"element index is greater than the number of fields in "
5123void IsTagOp::print(::mlir::OpAsmPrinter &printer) {
5124 printer <<
' ' << getInput() <<
' ';
5126 SmallVector<::llvm::StringRef, 1> elidedAttrs = {
"fieldIndex"};
5127 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
5128 printer <<
" : " << getInput().getType();
5131ParseResult IsTagOp::parse(OpAsmParser &parser, OperationState &result) {
5132 auto *
context = parser.getContext();
5133 auto &properties = result.getOrAddProperties<Properties>();
5135 OpAsmParser::UnresolvedOperand input;
5136 std::string fieldName;
5138 if (parser.parseOperand(input) || parser.parseKeywordOrString(&fieldName) ||
5139 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5140 parser.parseType(inputType))
5143 if (parser.resolveOperand(input, inputType, result.operands))
5146 auto enumType = type_dyn_cast<FEnumType>(inputType);
5148 return parser.emitError(parser.getNameLoc(),
5149 "input must be enum type, got ")
5151 auto fieldIndex = enumType.getElementIndex(fieldName);
5153 return parser.emitError(parser.getNameLoc(),
5154 "unknown field " + fieldName +
" in enum type ")
5157 properties.setFieldIndex(
5158 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5160 result.addTypes(UIntType::get(
context, 1,
false));
5165FIRRTLType IsTagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5166 OpaqueProperties properties,
5167 mlir::RegionRange regions,
5168 std::optional<Location> loc) {
5169 Adaptor adaptor(operands, attrs, properties, regions);
5170 return UIntType::get(attrs.getContext(), 1,
5171 isConst(adaptor.getInput().getType()));
5174template <
typename OpTy>
5176 auto *
context = parser.getContext();
5178 OpAsmParser::UnresolvedOperand input;
5179 std::string fieldName;
5181 if (parser.parseOperand(input) || parser.parseLSquare() ||
5182 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5183 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5184 parser.parseType(inputType))
5187 if (parser.resolveOperand(input, inputType, result.operands))
5190 auto bundleType = type_dyn_cast<typename OpTy::InputType>(inputType);
5192 return parser.emitError(parser.getNameLoc(),
5193 "input must be bundle type, got ")
5195 auto fieldIndex = bundleType.getElementIndex(fieldName);
5197 return parser.emitError(parser.getNameLoc(),
5198 "unknown field " + fieldName +
" in bundle type ")
5201 result.getOrAddProperties<
typename OpTy::Properties>().setFieldIndex(
5202 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5204 auto type = OpTy::inferReturnType(inputType, *fieldIndex, {});
5207 result.addTypes(type);
5212ParseResult SubtagOp::parse(OpAsmParser &parser, OperationState &result) {
5213 auto *
context = parser.getContext();
5215 OpAsmParser::UnresolvedOperand input;
5216 std::string fieldName;
5218 if (parser.parseOperand(input) || parser.parseLSquare() ||
5219 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5220 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5221 parser.parseType(inputType))
5224 if (parser.resolveOperand(input, inputType, result.operands))
5227 auto enumType = type_dyn_cast<FEnumType>(inputType);
5229 return parser.emitError(parser.getNameLoc(),
5230 "input must be enum type, got ")
5232 auto fieldIndex = enumType.getElementIndex(fieldName);
5234 return parser.emitError(parser.getNameLoc(),
5235 "unknown field " + fieldName +
" in enum type ")
5238 result.getOrAddProperties<Properties>().setFieldIndex(
5239 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5241 SmallVector<Type> inferredReturnTypes;
5242 if (failed(SubtagOp::inferReturnTypes(
5243 context, result.location, result.operands,
5244 result.attributes.getDictionary(
context), result.getRawProperties(),
5245 result.regions, inferredReturnTypes)))
5247 result.addTypes(inferredReturnTypes);
5252ParseResult SubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
5253 return parseSubfieldLikeOp<SubfieldOp>(parser, result);
5255ParseResult OpenSubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
5256 return parseSubfieldLikeOp<OpenSubfieldOp>(parser, result);
5259template <
typename OpTy>
5261 printer <<
' ' << op.getInput() <<
'[';
5262 printer.printKeywordOrString(op.getFieldName());
5264 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
5265 elidedAttrs.push_back(
"fieldIndex");
5266 printer.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
5267 printer <<
" : " << op.getInput().getType();
5269void SubfieldOp::print(::mlir::OpAsmPrinter &printer) {
5270 return printSubfieldLikeOp<SubfieldOp>(*
this, printer);
5272void OpenSubfieldOp::print(::mlir::OpAsmPrinter &printer) {
5273 return printSubfieldLikeOp<OpenSubfieldOp>(*
this, printer);
5276void SubtagOp::print(::mlir::OpAsmPrinter &printer) {
5277 printer <<
' ' << getInput() <<
'[';
5280 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
5281 elidedAttrs.push_back(
"fieldIndex");
5282 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
5283 printer <<
" : " << getInput().getType();
5286template <
typename OpTy>
5288 if (op.getFieldIndex() >=
5289 firrtl::type_cast<typename OpTy::InputType>(op.getInput().getType())
5291 return op.emitOpError(
"subfield element index is greater than the number "
5292 "of fields in the bundle type");
5295LogicalResult SubfieldOp::verify() {
5296 return verifySubfieldLike<SubfieldOp>(*
this);
5298LogicalResult OpenSubfieldOp::verify() {
5299 return verifySubfieldLike<OpenSubfieldOp>(*
this);
5302LogicalResult SubtagOp::verify() {
5303 if (getFieldIndex() >= getInput().getType().base().getNumElements())
5304 return emitOpError(
"subfield element index is greater than the number "
5305 "of fields in the bundle type");
5315 SmallVector<Operation *, 8> worklist({op});
5319 bool constant =
true;
5325 while (constant && !(worklist.empty()))
5326 TypeSwitch<Operation *>(worklist.pop_back_val())
5327 .Case<NodeOp, AsSIntPrimOp, AsUIntPrimOp>([&](
auto op) {
5328 if (
auto definingOp = op.getInput().getDefiningOp())
5329 worklist.push_back(definingOp);
5332 .Case<WireOp, SubindexOp, SubfieldOp>([&](
auto op) {
5333 for (
auto &use : op.getResult().getUses())
5334 worklist.push_back(use.getOwner());
5336 .Case<ConstantOp, SpecialConstantOp, AggregateConstantOp>([](
auto) {})
5337 .Default([&](
auto) { constant =
false; });
5346 if (
auto *op = value.getDefiningOp())
5351LogicalResult ConstCastOp::verify() {
5353 return emitOpError() << getInput().getType()
5354 <<
" is not 'const'-castable to "
5355 << getResult().getType();
5359FIRRTLType SubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
5360 std::optional<Location> loc) {
5361 auto inType = type_cast<BundleType>(type);
5363 if (fieldIndex >= inType.getNumElements())
5365 "subfield element index is greater than the "
5366 "number of fields in the bundle type");
5370 return inType.getElementTypePreservingConst(fieldIndex);
5373FIRRTLType OpenSubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
5374 std::optional<Location> loc) {
5375 auto inType = type_cast<OpenBundleType>(type);
5377 if (fieldIndex >= inType.getNumElements())
5379 "subfield element index is greater than the "
5380 "number of fields in the bundle type");
5384 return inType.getElementTypePreservingConst(fieldIndex);
5387bool SubfieldOp::isFieldFlipped() {
5388 BundleType bundle = getInput().getType();
5389 return bundle.getElement(getFieldIndex()).isFlip;
5391bool OpenSubfieldOp::isFieldFlipped() {
5392 auto bundle = getInput().getType();
5393 return bundle.getElement(getFieldIndex()).isFlip;
5396FIRRTLType SubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
5397 std::optional<Location> loc) {
5398 if (
auto vectorType = type_dyn_cast<FVectorType>(type)) {
5399 if (fieldIndex < vectorType.getNumElements())
5400 return vectorType.getElementTypePreservingConst();
5402 "' in vector type ", type);
5407FIRRTLType OpenSubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
5408 std::optional<Location> loc) {
5409 if (
auto vectorType = type_dyn_cast<OpenVectorType>(type)) {
5410 if (fieldIndex < vectorType.getNumElements())
5411 return vectorType.getElementTypePreservingConst();
5413 "' in vector type ", type);
5419FIRRTLType SubtagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5420 OpaqueProperties properties,
5421 mlir::RegionRange regions,
5422 std::optional<Location> loc) {
5423 Adaptor adaptor(operands, attrs, properties, regions);
5424 auto inType = type_cast<FEnumType>(adaptor.getInput().getType());
5425 auto fieldIndex = adaptor.getFieldIndex();
5427 if (fieldIndex >= inType.getNumElements())
5429 "subtag element index is greater than the "
5430 "number of fields in the enum type");
5434 auto elementType = inType.getElement(fieldIndex).type;
5438FIRRTLType SubaccessOp::inferReturnType(Type inType, Type indexType,
5439 std::optional<Location> loc) {
5440 if (!type_isa<UIntType>(indexType))
5444 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
5446 return vectorType.getElementTypePreservingConst();
5447 return vectorType.getElementType().getAllConstDroppedType();
5455 std::optional<Location> loc) {
5456 auto inType = type_cast<FEnumType>(input);
5457 return UIntType::get(inType.getContext(), inType.getTagWidth());
5460ParseResult MultibitMuxOp::parse(OpAsmParser &parser, OperationState &result) {
5461 OpAsmParser::UnresolvedOperand index;
5462 SmallVector<OpAsmParser::UnresolvedOperand, 16> inputs;
5463 Type indexType, elemType;
5465 if (parser.parseOperand(index) || parser.parseComma() ||
5466 parser.parseOperandList(inputs) ||
5467 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5468 parser.parseType(indexType) || parser.parseComma() ||
5469 parser.parseType(elemType))
5472 if (parser.resolveOperand(index, indexType, result.operands))
5475 result.addTypes(elemType);
5477 return parser.resolveOperands(inputs, elemType, result.operands);
5480void MultibitMuxOp::print(OpAsmPrinter &p) {
5481 p <<
" " << getIndex() <<
", ";
5482 p.printOperands(getInputs());
5483 p.printOptionalAttrDict((*this)->getAttrs());
5484 p <<
" : " << getIndex().getType() <<
", " << getType();
5487FIRRTLType MultibitMuxOp::inferReturnType(ValueRange operands,
5488 DictionaryAttr attrs,
5489 OpaqueProperties properties,
5490 mlir::RegionRange regions,
5491 std::optional<Location> loc) {
5492 if (operands.size() < 2)
5496 if (!llvm::all_of(operands.drop_front(2), [&](
auto op) {
5497 return operands[1].getType() == op.getType();
5501 return type_cast<FIRRTLType>(operands[1].getType());
5508LogicalResult ObjectSubfieldOp::inferReturnTypes(
5509 MLIRContext *
context, std::optional<mlir::Location> location,
5510 ValueRange operands, DictionaryAttr attributes, OpaqueProperties properties,
5511 RegionRange regions, llvm::SmallVectorImpl<Type> &inferredReturnTypes) {
5513 inferReturnType(operands, attributes, properties, regions, location);
5516 inferredReturnTypes.push_back(type);
5520Type ObjectSubfieldOp::inferReturnType(Type inType, uint32_t fieldIndex,
5521 std::optional<Location> loc) {
5522 auto classType = dyn_cast<ClassType>(inType);
5526 if (classType.getNumElements() <= fieldIndex)
5528 "number of fields in the object");
5529 return classType.getElement(fieldIndex).type;
5532void ObjectSubfieldOp::print(OpAsmPrinter &p) {
5533 auto input = getInput();
5534 auto classType = input.getType();
5535 p <<
' ' << input <<
"[";
5536 p.printKeywordOrString(classType.getElement(getIndex()).name);
5538 p.printOptionalAttrDict((*this)->getAttrs(), std::array{StringRef(
"index")});
5539 p <<
" : " << classType;
5542ParseResult ObjectSubfieldOp::parse(OpAsmParser &parser,
5543 OperationState &result) {
5544 auto *
context = parser.getContext();
5546 OpAsmParser::UnresolvedOperand input;
5547 std::string fieldName;
5548 ClassType inputType;
5549 if (parser.parseOperand(input) || parser.parseLSquare() ||
5550 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5551 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5552 parser.parseType(inputType) ||
5553 parser.resolveOperand(input, inputType, result.operands))
5556 auto index = inputType.getElementIndex(fieldName);
5558 return parser.emitError(parser.getNameLoc(),
5559 "unknown field " + fieldName +
" in class type ")
5561 result.getOrAddProperties<Properties>().setIndex(
5562 IntegerAttr::get(IntegerType::get(
context, 32), *index));
5564 SmallVector<Type> inferredReturnTypes;
5565 if (failed(inferReturnTypes(
context, result.location, result.operands,
5566 result.attributes.getDictionary(
context),
5567 result.getRawProperties(), result.regions,
5568 inferredReturnTypes)))
5570 result.addTypes(inferredReturnTypes);
5587 int32_t &rhsWidth,
bool &isConstResult,
5588 std::optional<Location> loc) {
5590 auto lhsi = type_dyn_cast<IntType>(lhs);
5591 auto rhsi = type_dyn_cast<IntType>(rhs);
5592 if (!lhsi || !rhsi || lhsi.isSigned() != rhsi.isSigned()) {
5595 mlir::emitError(*loc,
"second operand must be an integer type, not ")
5597 else if (!lhsi && rhsi)
5598 mlir::emitError(*loc,
"first operand must be an integer type, not ")
5600 else if (!lhsi && !rhsi)
5601 mlir::emitError(*loc,
"operands must be integer types, not ")
5602 << lhs <<
" and " << rhs;
5604 mlir::emitError(*loc,
"operand signedness must match");
5609 lhsWidth = lhsi.getWidthOrSentinel();
5610 rhsWidth = rhsi.getWidthOrSentinel();
5611 isConstResult = lhsi.isConst() && rhsi.isConst();
5616 assert(op->getNumOperands() == 2 &&
5617 "SameOperandsIntTypeKind on non-binary op");
5618 int32_t lhsWidth, rhsWidth;
5621 op->getOperand(1).getType(), lhsWidth,
5622 rhsWidth, isConstResult, op->getLoc()));
5626 std::optional<Location> loc) {
5627 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5628 bool isConstResult =
false;
5632 if (lhsWidth != -1 && rhsWidth != -1)
5633 resultWidth = std::max(lhsWidth, rhsWidth) + 1;
5634 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5639 std::optional<Location> loc) {
5640 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5641 bool isConstResult =
false;
5645 if (lhsWidth != -1 && rhsWidth != -1)
5646 resultWidth = lhsWidth + rhsWidth;
5648 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5653 std::optional<Location> loc) {
5654 int32_t lhsWidth, rhsWidth;
5655 bool isConstResult =
false;
5660 if (type_isa<UIntType>(lhs))
5661 return UIntType::get(lhs.getContext(), lhsWidth, isConstResult);
5664 int32_t resultWidth = lhsWidth != -1 ? lhsWidth + 1 : -1;
5665 return SIntType::get(lhs.getContext(), resultWidth, isConstResult);
5669 std::optional<Location> loc) {
5670 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5671 bool isConstResult =
false;
5675 if (lhsWidth != -1 && rhsWidth != -1)
5676 resultWidth = std::min(lhsWidth, rhsWidth);
5677 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5682 std::optional<Location> loc) {
5683 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5684 bool isConstResult =
false;
5688 if (lhsWidth != -1 && rhsWidth != -1) {
5689 resultWidth = std::max(lhsWidth, rhsWidth);
5690 if (lhsWidth == resultWidth && lhs.
isConst() == isConstResult &&
5693 if (rhsWidth == resultWidth && rhs.
isConst() == isConstResult &&
5697 return UIntType::get(lhs.getContext(), resultWidth, isConstResult);
5701 std::optional<Location> loc) {
5702 if (!type_isa<FVectorType>(lhs) || !type_isa<FVectorType>(rhs))
5705 auto lhsVec = type_cast<FVectorType>(lhs);
5706 auto rhsVec = type_cast<FVectorType>(rhs);
5708 if (lhsVec.getNumElements() != rhsVec.getNumElements())
5713 rhsVec.getElementTypePreservingConst(), loc);
5716 auto elemBaseType = type_cast<FIRRTLBaseType>(elemType);
5717 return FVectorType::get(elemBaseType, lhsVec.getNumElements(),
5718 lhsVec.isConst() && rhsVec.isConst() &&
5719 elemBaseType.isConst());
5723 std::optional<Location> loc) {
5724 return UIntType::get(lhs.getContext(), 1,
isConst(lhs) &&
isConst(rhs));
5727FIRRTLType CatPrimOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5728 OpaqueProperties properties,
5729 mlir::RegionRange regions,
5730 std::optional<Location> loc) {
5732 if (operands.empty())
5733 return UIntType::get(attrs.getContext(), 0);
5736 bool isSigned = type_isa<SIntType>(operands[0].getType());
5737 for (
auto operand : operands) {
5738 auto type = type_dyn_cast<IntType>(operand.getType());
5741 if (type.isSigned() != isSigned)
5743 "all operands must have same signedness");
5747 int32_t resultWidth = 0;
5748 bool isConstResult =
true;
5750 for (
auto operand : operands) {
5751 auto type = type_cast<IntType>(operand.getType());
5752 int32_t width = type.getWidthOrSentinel();
5759 if (resultWidth != -1)
5760 resultWidth += width;
5763 isConstResult &= type.isConst();
5767 return UIntType::get(attrs.getContext(), resultWidth, isConstResult);
5771 std::optional<Location> loc) {
5772 auto lhsi = type_dyn_cast<IntType>(lhs);
5773 auto rhsui = type_dyn_cast<UIntType>(rhs);
5774 if (!rhsui || !lhsi)
5776 loc,
"first operand should be integer, second unsigned int");
5780 auto width = lhsi.getWidthOrSentinel();
5781 if (width == -1 || !rhsui.getWidth().has_value()) {
5784 auto amount = *rhsui.getWidth();
5787 "shift amount too large: second operand of "
5788 "dshl is wider than 31 bits");
5789 int64_t newWidth = (int64_t)width + ((int64_t)1 << amount) - 1;
5790 if (newWidth > INT32_MAX)
5792 loc,
"shift amount too large: first operand shifted by maximum "
5793 "amount exceeds maximum width");
5796 return IntType::get(lhs.getContext(), lhsi.isSigned(), width,
5797 lhsi.
isConst() && rhsui.isConst());
5801 std::optional<Location> loc) {
5802 auto lhsi = type_dyn_cast<IntType>(lhs);
5803 auto rhsu = type_dyn_cast<UIntType>(rhs);
5806 loc,
"first operand should be integer, second unsigned int");
5807 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5811 std::optional<Location> loc) {
5812 auto lhsi = type_dyn_cast<IntType>(lhs);
5813 auto rhsu = type_dyn_cast<UIntType>(rhs);
5816 loc,
"first operand should be integer, second unsigned int");
5817 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5825 std::optional<Location> loc) {
5826 return UIntType::get(input.getContext(), 32);
5830 std::optional<Location> loc) {
5831 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5834 int32_t width = base.getBitWidthOrSentinel();
5837 return SIntType::get(input.getContext(), width, base.
isConst());
5841 std::optional<Location> loc) {
5842 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5845 int32_t width = base.getBitWidthOrSentinel();
5848 return UIntType::get(input.getContext(), width, base.
isConst());
5852 std::optional<Location> loc) {
5853 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5856 "operand must be single bit scalar base type");
5857 int32_t width = base.getBitWidthOrSentinel();
5858 if (width == -2 || width == 0 || width > 1)
5860 return AsyncResetType::get(input.getContext(), base.
isConst());
5864 std::optional<Location> loc) {
5865 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5868 return ResetType::get(input.getContext(), base.
isConst());
5872 std::optional<Location> loc) {
5873 return ClockType::get(input.getContext(),
isConst(input));
5877 std::optional<Location> loc) {
5878 if (
auto uiType = type_dyn_cast<UIntType>(input)) {
5879 auto width = uiType.getWidthOrSentinel();
5882 return SIntType::get(input.getContext(), width, uiType.
isConst());
5885 if (type_isa<SIntType>(input))
5892 std::optional<Location> loc) {
5893 auto inputi = type_dyn_cast<IntType>(input);
5896 int32_t width = inputi.getWidthOrSentinel();
5899 return SIntType::get(input.getContext(), width, inputi.
isConst());
5903 std::optional<Location> loc) {
5904 auto inputi = type_dyn_cast<IntType>(input);
5907 if (isa<UIntType>(inputi))
5909 return UIntType::get(input.getContext(), inputi.getWidthOrSentinel(),
5914 std::optional<Location> loc) {
5915 return UIntType::get(input.getContext(), 1,
isConst(input));
5924 std::optional<Location> loc) {
5925 auto inputi = type_dyn_cast<IntType>(input);
5928 loc,
"input type should be the int type but got ", input);
5933 loc,
"high must be equal or greater than low, but got high = ", high,
5941 int32_t width = inputi.getWidthOrSentinel();
5942 if (width != -1 && high >= width)
5945 "high must be smaller than the width of input, but got high = ", high,
5946 ", width = ", width);
5948 return UIntType::get(input.getContext(), high - low + 1, inputi.
isConst());
5952 std::optional<Location> loc) {
5954 auto inputi = type_dyn_cast<IntType>(input);
5955 if (amount < 0 || !inputi)
5957 loc,
"operand must have integer type and amount must be >= 0");
5959 int32_t width = inputi.getWidthOrSentinel();
5960 if (width != -1 && amount > width)
5963 return UIntType::get(input.getContext(), amount, inputi.
isConst());
5978 bool isConstCondition,
5979 std::optional<Location> loc) {
5985 if (high.getTypeID() != low.getTypeID())
5986 return emitInferRetTypeError<FIRRTLBaseType>(
5987 loc,
"incompatible mux operand types, true value type: ", high,
5988 ", false value type: ", low);
5990 bool outerTypeIsConst = isConstCondition && low.
isConst() && high.
isConst();
5995 if (type_isa<IntType>(low)) {
6000 if (highWidth == -1)
6002 return (lowWidth > highWidth ? low : high).getConstType(outerTypeIsConst);
6007 auto highEnum = type_dyn_cast<FEnumType>(high);
6008 auto lowEnum = type_dyn_cast<FEnumType>(low);
6009 if (lowEnum && highEnum) {
6010 if (lowEnum.getNumElements() != highEnum.getNumElements())
6011 return emitInferRetTypeError<FIRRTLBaseType>(
6012 loc,
"incompatible mux operand types, true value type: ", high,
6013 ", false value type: ", low);
6014 SmallVector<FEnumType::EnumElement> elements;
6015 for (
auto [high, low] : llvm::zip_equal(highEnum, lowEnum)) {
6017 if (high.name != low.name || high.value != low.value)
6018 return emitInferRetTypeError<FIRRTLBaseType>(
6019 loc,
"incompatible mux operand types, true value type: ", highEnum,
6020 ", false value type: ", lowEnum);
6027 elements.emplace_back(high.name, high.value, inner);
6029 return FEnumType::get(high.getContext(), elements, outerTypeIsConst);
6033 auto highVector = type_dyn_cast<FVectorType>(high);
6034 auto lowVector = type_dyn_cast<FVectorType>(low);
6035 if (highVector && lowVector &&
6036 highVector.getNumElements() == lowVector.getNumElements()) {
6038 lowVector.getElementTypePreservingConst(),
6039 isConstCondition, loc);
6042 return FVectorType::get(inner, lowVector.getNumElements(),
6047 auto highBundle = type_dyn_cast<BundleType>(high);
6048 auto lowBundle = type_dyn_cast<BundleType>(low);
6049 if (highBundle && lowBundle) {
6050 auto highElements = highBundle.getElements();
6051 auto lowElements = lowBundle.getElements();
6054 SmallVector<BundleType::BundleElement> newElements;
6056 bool failed =
false;
6058 if (highElements[i].name != lowElements[i].name ||
6059 highElements[i].isFlip != lowElements[i].isFlip) {
6063 auto element = highElements[i];
6065 highBundle.getElementTypePreservingConst(i),
6066 lowBundle.getElementTypePreservingConst(i), isConstCondition, loc);
6069 newElements.push_back(element);
6072 return BundleType::get(low.getContext(), newElements, outerTypeIsConst);
6074 return emitInferRetTypeError<FIRRTLBaseType>(
6075 loc,
"incompatible mux operand bundle fields, true value type: ", high,
6076 ", false value type: ", low);
6081 return emitInferRetTypeError<FIRRTLBaseType>(
6082 loc,
"invalid mux operand types, true value type: ", high,
6083 ", false value type: ", low);
6088 std::optional<Location> loc) {
6089 auto highType = type_dyn_cast<FIRRTLBaseType>(high);
6090 auto lowType = type_dyn_cast<FIRRTLBaseType>(low);
6091 if (!highType || !lowType)
6096FIRRTLType Mux2CellIntrinsicOp::inferReturnType(ValueRange operands,
6097 DictionaryAttr attrs,
6098 OpaqueProperties properties,
6099 mlir::RegionRange regions,
6100 std::optional<Location> loc) {
6101 auto highType = type_dyn_cast<FIRRTLBaseType>(operands[1].getType());
6102 auto lowType = type_dyn_cast<FIRRTLBaseType>(operands[2].getType());
6103 if (!highType || !lowType)
6109FIRRTLType Mux4CellIntrinsicOp::inferReturnType(ValueRange operands,
6110 DictionaryAttr attrs,
6111 OpaqueProperties properties,
6112 mlir::RegionRange regions,
6113 std::optional<Location> loc) {
6114 SmallVector<FIRRTLBaseType> types;
6116 for (
unsigned i = 1; i < 5; i++) {
6117 types.push_back(type_dyn_cast<FIRRTLBaseType>(operands[i].getType()));
6122 isConst(operands[0].getType()), loc);
6126 result = types.back();
6133 std::optional<Location> loc) {
6134 auto inputi = type_dyn_cast<IntType>(input);
6135 if (amount < 0 || !inputi)
6137 loc,
"pad input must be integer and amount must be >= 0");
6139 int32_t width = inputi.getWidthOrSentinel();
6143 width = std::max<int32_t>(width, amount);
6144 return IntType::get(input.getContext(), inputi.isSigned(), width,
6149 std::optional<Location> loc) {
6150 auto inputi = type_dyn_cast<IntType>(input);
6151 if (amount < 0 || !inputi)
6153 loc,
"shl input must be integer and amount must be >= 0");
6155 int32_t width = inputi.getWidthOrSentinel();
6159 return IntType::get(input.getContext(), inputi.isSigned(), width,
6164 std::optional<Location> loc) {
6165 auto inputi = type_dyn_cast<IntType>(input);
6166 if (amount < 0 || !inputi)
6168 loc,
"shr input must be integer and amount must be >= 0");
6170 int32_t width = inputi.getWidthOrSentinel();
6173 int32_t minWidth = inputi.isUnsigned() ? 0 : 1;
6174 width = std::max<int32_t>(minWidth, width - amount);
6177 return IntType::get(input.getContext(), inputi.isSigned(), width,
6182 std::optional<Location> loc) {
6184 auto inputi = type_dyn_cast<IntType>(input);
6185 if (amount < 0 || !inputi)
6187 loc,
"tail input must be integer and amount must be >= 0");
6189 int32_t width = inputi.getWidthOrSentinel();
6193 loc,
"amount must be less than or equal operand width");
6204void VerbatimExprOp::getAsmResultNames(
6205 function_ref<
void(Value, StringRef)> setNameFn) {
6209 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
6210 auto name = getText();
6212 if (name.starts_with(
"`"))
6213 name = name.drop_front();
6214 name = name.take_while(isOkCharacter);
6216 setNameFn(getResult(), name);
6223void VerbatimWireOp::getAsmResultNames(
6224 function_ref<
void(Value, StringRef)> setNameFn) {
6228 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
6229 auto name = getText();
6231 if (name.starts_with(
"`"))
6232 name = name.drop_front();
6233 name = name.take_while(isOkCharacter);
6235 setNameFn(getResult(), name);
6246 op->emitError() <<
"unknown width is not allowed for DPI";
6247 return WalkResult::interrupt();
6249 if (width == 1 || width == 8 || width == 16 || width == 32 ||
6251 return WalkResult::advance();
6253 <<
"integer types used by DPI functions must have a "
6254 "specific bit width; "
6255 "it must be equal to 1(bit), 8(byte), 16(shortint), "
6256 "32(int), 64(longint) "
6257 "or greater than 64, but got "
6259 return WalkResult::interrupt();
6264LogicalResult DPICallIntrinsicOp::verify() {
6265 if (
auto inputNames = getInputNames()) {
6266 if (getInputs().size() != inputNames->size())
6267 return emitError() <<
"inputNames has " << inputNames->size()
6268 <<
" elements but there are " << getInputs().size()
6269 <<
" input arguments";
6271 if (
auto outputName = getOutputName())
6272 if (getNumResults() == 0)
6273 return emitError() <<
"output name is given but there is no result";
6275 auto checkType = [
this](Type type) {
6278 return success(llvm::all_of(this->getResultTypes(), checkType) &&
6279 llvm::all_of(this->getOperandTypes(), checkType));
6282SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
6283DPICallIntrinsicOp::computeDataFlow() {
6287 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
6289 for (
auto operand : getOperands()) {
6290 auto type = type_cast<FIRRTLBaseType>(operand.getType());
6292 SmallVector<circt::FieldRef> operandFields;
6295 operandFields.push_back(baseFieldRef.getSubField(dstIndex));
6299 for (
auto result : getResults())
6302 for (
auto field : operandFields)
6303 deps.emplace_back(
circt::
FieldRef(result, dstIndex), field);
6313LogicalResult HWStructCastOp::verify() {
6315 BundleType bundleType;
6316 hw::StructType structType;
6317 if ((bundleType = type_dyn_cast<BundleType>(getOperand().getType()))) {
6318 structType = dyn_cast<hw::StructType>(getType());
6320 return emitError(
"result type must be a struct");
6321 }
else if ((bundleType = type_dyn_cast<BundleType>(getType()))) {
6322 structType = dyn_cast<hw::StructType>(getOperand().getType());
6324 return emitError(
"operand type must be a struct");
6326 return emitError(
"either source or result type must be a bundle type");
6329 auto firFields = bundleType.getElements();
6330 auto hwFields = structType.getElements();
6331 if (firFields.size() != hwFields.size())
6332 return emitError(
"bundle and struct have different number of fields");
6334 for (
size_t findex = 0, fend = firFields.size(); findex < fend; ++findex) {
6335 if (firFields[findex].name.getValue() != hwFields[findex].name)
6336 return emitError(
"field names don't match '")
6337 << firFields[findex].name.getValue() <<
"', '"
6338 << hwFields[findex].name.getValue() <<
"'";
6342 if (firWidth > 0 && hwWidth > 0 && firWidth != hwWidth)
6343 return emitError(
"size of field '")
6344 << hwFields[findex].name.getValue() <<
"' don't match " << firWidth
6351LogicalResult BitCastOp::verify() {
6352 auto inTypeBits =
getBitWidth(getInput().getType(),
true);
6354 if (inTypeBits.has_value() && resTypeBits.has_value()) {
6356 if (*inTypeBits == *resTypeBits) {
6359 return emitError(
"cannot cast non-'const' input type ")
6360 << getOperand().getType() <<
" to 'const' result type "
6364 return emitError(
"the bitwidth of input (")
6365 << *inTypeBits <<
") and result (" << *resTypeBits
6368 if (!inTypeBits.has_value())
6369 return emitError(
"bitwidth cannot be determined for input operand type ")
6370 << getInput().getType();
6371 return emitError(
"bitwidth cannot be determined for result type ")
6382 NamedAttrList &resultAttrs) {
6383 auto result = parser.parseOptionalAttrDict(resultAttrs);
6384 if (!resultAttrs.get(
"annotations"))
6385 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
6391 DictionaryAttr attr,
6392 ArrayRef<StringRef> extraElides = {}) {
6393 SmallVector<StringRef> elidedAttrs(extraElides.begin(), extraElides.end());
6395 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
6396 elidedAttrs.push_back(
"annotations");
6398 elidedAttrs.push_back(
"nameKind");
6400 p.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
6406 NamedAttrList &resultAttrs) {
6409 if (!resultAttrs.get(
"portAnnotations")) {
6410 SmallVector<Attribute, 16> portAnnotations(
6411 parser.getNumResults(), parser.getBuilder().getArrayAttr({}));
6412 resultAttrs.append(
"portAnnotations",
6413 parser.getBuilder().getArrayAttr(portAnnotations));
6420 DictionaryAttr attr,
6421 ArrayRef<StringRef> extraElides = {}) {
6422 SmallVector<StringRef, 2> elidedAttrs(extraElides.begin(), extraElides.end());
6424 if (llvm::all_of(op->getAttrOfType<ArrayAttr>(
"portAnnotations"),
6425 [&](Attribute a) { return cast<ArrayAttr>(a).empty(); }))
6426 elidedAttrs.push_back(
"portAnnotations");
6435 firrtl::NameKindEnumAttr &result) {
6438 if (!parser.parseOptionalKeyword(&keyword,
6439 {
"interesting_name",
"droppable_name"})) {
6440 auto kind = symbolizeNameKindEnum(keyword);
6441 result = NameKindEnumAttr::get(parser.getContext(), kind.value());
6447 NameKindEnumAttr::get(parser.getContext(), NameKindEnum::DroppableName);
6452 firrtl::NameKindEnumAttr attr,
6453 ArrayRef<StringRef> extraElides = {}) {
6454 if (attr.getValue() != NameKindEnum::DroppableName)
6455 p <<
" " << stringifyNameKindEnum(attr.getValue());
6463 NamedAttrList &resultAttrs) {
6471 DictionaryAttr attrs) {
6472 SmallVector<StringRef, 4> elides;
6474 elides.push_back(Forceable::getForceableAttrName());
6483static ParseResult
parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs) {
6488static void printMemOp(OpAsmPrinter &p, Operation *op, DictionaryAttr attr) {
6499 if (ClassType::parseInterface(parser, type))
6506 type.printInterface(p);
6514 NamedAttrList &resultAttrs) {
6515 auto result = p.parseOptionalAttrDict(resultAttrs);
6516 if (!resultAttrs.get(
"name"))
6517 resultAttrs.append(
"name", p.getBuilder().getStringAttr(
""));
6523 DictionaryAttr attr,
6524 ArrayRef<StringRef> extraElides = {}) {
6525 SmallVector<StringRef> elides(extraElides.begin(), extraElides.end());
6526 if (op->getAttrOfType<StringAttr>(
"name").getValue().empty())
6527 elides.push_back(
"name");
6529 p.printOptionalAttrDict(op->getAttrs(), elides);
6533 NamedAttrList &resultAttrs) {
6538 DictionaryAttr attr) {
6543 NamedAttrList &resultAttrs) {
6548 DictionaryAttr attr) {
6550 {
"formatString",
"outputFile",
"operandSegmentSizes"});
6558 DictionaryAttr attr) {
6567 DictionaryAttr attr) {
6576 OpAsmSetValueNameFn setNameFn) {
6579 if (op->getNumResults() == 1)
6580 if (
auto nameAttr = op->getAttrOfType<StringAttr>(
"name"))
6581 setNameFn(op->getResult(0), nameAttr.getValue());
6584void AddPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6588void AndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6592void AndRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6596void SizeOfIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6599void AsAsyncResetPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6602void AsResetPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6605void AsClockPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6608void AsSIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6611void AsUIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6614void BitsPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6617void CatPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6620void CvtPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6623void DShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6626void DShlwPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6629void DShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6632void DivPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6635void EQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6638void GEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6641void GTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6644void GenericIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6647void HeadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6650void IntegerAddOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6653void IntegerMulOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6656void IntegerShrOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6659void IntegerShlOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6662void IsTagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6665void IsXIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6668void PlusArgsValueIntrinsicOp::getAsmResultNames(
6669 OpAsmSetValueNameFn setNameFn) {
6672void PlusArgsTestIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6675void LEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6678void LTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6681void MulPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6684void MultibitMuxOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6687void MuxPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6690void Mux4CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6693void Mux2CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6696void NEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6699void NegPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6702void NotPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6705void OrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6708void OrRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6711void PadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6714void RemPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6717void ShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6720void ShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6724void SubPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6728void SubaccessOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6732void SubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6736void OpenSubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6740void SubtagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6744void SubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6748void OpenSubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6752void TagExtractOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6756void TailPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6760void XorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6764void XorRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6768void UninferredResetCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6772void ConstCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6776void ElementwiseXorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6780void ElementwiseOrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6784void ElementwiseAndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6792void RefCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6796void RefResolveOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6800void RefSendOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6804void RefSubOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6808void RWProbeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6812FIRRTLType RefResolveOp::inferReturnType(ValueRange operands,
6813 DictionaryAttr attrs,
6814 OpaqueProperties properties,
6815 mlir::RegionRange regions,
6816 std::optional<Location> loc) {
6817 Type inType = operands[0].getType();
6818 auto inRefType = type_dyn_cast<RefType>(inType);
6821 loc,
"ref.resolve operand must be ref type, not ", inType);
6822 return inRefType.getType();
6825FIRRTLType RefSendOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
6826 OpaqueProperties properties,
6827 mlir::RegionRange regions,
6828 std::optional<Location> loc) {
6829 Type inType = operands[0].getType();
6830 auto inBaseType = type_dyn_cast<FIRRTLBaseType>(inType);
6833 loc,
"ref.send operand must be base type, not ", inType);
6834 return RefType::get(inBaseType.getPassiveType());
6837FIRRTLType RefSubOp::inferReturnType(Type type, uint32_t fieldIndex,
6838 std::optional<Location> loc) {
6839 auto refType = type_dyn_cast<RefType>(type);
6842 auto inType = refType.getType();
6848 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
6849 if (fieldIndex < vectorType.getNumElements())
6850 return RefType::get(
6851 vectorType.getElementType().getConstType(
6852 vectorType.isConst() || vectorType.getElementType().isConst()),
6853 refType.getForceable(), refType.getLayer());
6855 "' in RefType of vector type ", refType);
6857 if (
auto bundleType = type_dyn_cast<BundleType>(inType)) {
6858 if (fieldIndex >= bundleType.getNumElements()) {
6860 "subfield element index is greater than "
6861 "the number of fields in the bundle type");
6863 return RefType::get(
6864 bundleType.getElement(fieldIndex)
6866 bundleType.isConst() ||
6867 bundleType.getElement(fieldIndex).type.isConst()),
6868 refType.getForceable(), refType.getLayer());
6872 loc,
"ref.sub op requires a RefType of vector or bundle base type");
6875LogicalResult RefCastOp::verify() {
6879 getOperation(), srcLayers, dstLayers,
6880 "cannot discard layer requirements of input reference",
6881 "discarding layer requirements");
6884LogicalResult RefResolveOp::verify() {
6888 getOperation(), srcLayers, dstLayers,
6889 "ambient layers are insufficient to resolve reference");
6893 auto targetRef = getTarget();
6894 if (targetRef.getModule() !=
6895 (*this)->getParentOfType<FModuleLike>().getModuleNameAttr())
6896 return emitOpError() <<
"has non-local target";
6898 auto target = ns.
lookup(targetRef);
6900 return emitOpError() <<
"has target that cannot be resolved: " << targetRef;
6902 auto checkFinalType = [&](
auto type, Location loc) -> LogicalResult {
6907 auto baseType = type_dyn_cast<FIRRTLBaseType>(fType);
6908 if (!baseType || baseType.getPassiveType() != getType().getType()) {
6909 auto diag = emitOpError(
"has type mismatch: target resolves to ")
6910 << fType <<
" instead of expected " << getType().getType();
6911 diag.attachNote(loc) <<
"target resolves here";
6916 if (target.isPort()) {
6917 auto mod = cast<FModuleLike>(target.getOp());
6918 return checkFinalType(mod.getPortType(target.getPort()),
6919 mod.getPortLocation(target.getPort()));
6921 hw::InnerSymbolOpInterface symOp =
6922 cast<hw::InnerSymbolOpInterface>(target.getOp());
6923 if (!symOp.getTargetResult())
6924 return emitOpError(
"has target that cannot be probed")
6925 .attachNote(symOp.getLoc())
6926 .append(
"target resolves here");
6928 symOp.getTargetResult().getParentBlock()->findAncestorOpInBlock(**
this);
6929 if (!ancestor || !symOp->isBeforeInBlock(ancestor))
6930 return emitOpError(
"is not dominated by target")
6931 .attachNote(symOp.getLoc())
6932 .append(
"target here");
6933 return checkFinalType(symOp.getTargetResult().getType(), symOp.getLoc());
6936LogicalResult RefForceOp::verify() {
6940 getOperation(), destLayers, ambientLayers,
6941 "has insufficient ambient layers to force its reference");
6944LogicalResult RefForceInitialOp::verify() {
6948 getOperation(), destLayers, ambientLayers,
6949 "has insufficient ambient layers to force its reference");
6952LogicalResult RefReleaseOp::verify() {
6956 getOperation(), destLayers, ambientLayers,
6957 "has insufficient ambient layers to release its reference");
6960LogicalResult RefReleaseInitialOp::verify() {
6964 getOperation(), destLayers, ambientLayers,
6965 "has insufficient ambient layers to release its reference");
6968LogicalResult XMRRefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6969 auto *target = symbolTable.lookupNearestSymbolFrom(*
this, getRefAttr());
6971 return emitOpError(
"has an invalid symbol reference");
6973 if (!isa<hw::HierPathOp>(target))
6974 return emitOpError(
"does not target a hierpath op");
6980LogicalResult XMRDerefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6981 auto *target = symbolTable.lookupNearestSymbolFrom(*
this, getRefAttr());
6983 return emitOpError(
"has an invalid symbol reference");
6985 if (!isa<hw::HierPathOp>(target))
6986 return emitOpError(
"does not target a hierpath op");
6996LogicalResult LayerBlockOp::verify() {
6997 auto layerName = getLayerName();
6998 auto *parentOp = (*this)->getParentOp();
7001 while (isa<WhenOp, MatchOp>(parentOp))
7002 parentOp = parentOp->getParentOp();
7006 auto nestedReferences = layerName.getNestedReferences();
7007 if (nestedReferences.empty()) {
7008 if (!isa<FModuleOp>(parentOp)) {
7009 auto diag = emitOpError() <<
"has an un-nested layer symbol, but does "
7010 "not have a 'firrtl.module' op as a parent";
7011 return diag.attachNote(parentOp->getLoc())
7012 <<
"illegal parent op defined here";
7015 auto parentLayerBlock = dyn_cast<LayerBlockOp>(parentOp);
7016 if (!parentLayerBlock) {
7017 auto diag = emitOpError()
7018 <<
"has a nested layer symbol, but does not have a '"
7019 << getOperationName() <<
"' op as a parent'";
7020 return diag.attachNote(parentOp->getLoc())
7021 <<
"illegal parent op defined here";
7023 auto parentLayerBlockName = parentLayerBlock.getLayerName();
7024 if (parentLayerBlockName.getRootReference() !=
7025 layerName.getRootReference() ||
7026 parentLayerBlockName.getNestedReferences() !=
7027 layerName.getNestedReferences().drop_back()) {
7028 auto diag = emitOpError() <<
"is nested under an illegal layer block";
7029 return diag.attachNote(parentLayerBlock->getLoc())
7030 <<
"illegal parent layer block defined here";
7036 auto result = getBody(0)->walk<mlir::WalkOrder::PreOrder>(
7037 [&](Operation *op) -> WalkResult {
7039 if (isa<LayerBlockOp>(op))
7040 return WalkResult::skip();
7044 for (
auto operand : op->getOperands()) {
7046 if (
auto *definingOp = operand.getDefiningOp())
7050 auto type = operand.getType();
7053 if (isa<PropertyType>(type)) {
7054 auto diag = emitOpError() <<
"captures a property operand";
7055 diag.attachNote(operand.getLoc()) <<
"operand is defined here";
7056 diag.attachNote(op->getLoc()) <<
"operand is used here";
7057 return WalkResult::interrupt();
7062 if (
auto connect = dyn_cast<FConnectLike>(op)) {
7064 if (isa<RefDefineOp>(connect))
7065 return WalkResult::advance();
7072 bool passive =
true;
7074 type_dyn_cast<FIRRTLBaseType>(
connect.getDest().getType()))
7075 passive = type.isPassive();
7084 return WalkResult::advance();
7087 return WalkResult::advance();
7091 <<
"connects to a destination which is defined outside its "
7092 "enclosing layer block";
7093 diag.attachNote(
getLoc()) <<
"enclosing layer block is defined here";
7094 diag.attachNote(dest.getLoc()) <<
"destination is defined here";
7095 return WalkResult::interrupt();
7098 return WalkResult::advance();
7101 return failure(result.wasInterrupted());
7105LayerBlockOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7107 symbolTable.lookupNearestSymbolFrom<LayerOp>(*
this, getLayerNameAttr());
7109 return emitOpError(
"invalid symbol reference");
7119void TimeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
7120 setNameFn(getResult(),
"time");
7123void HierarchicalModuleNameOp::getAsmResultNames(
7124 OpAsmSetValueNameFn setNameFn) {
7125 setNameFn(getResult(),
"hierarchicalmodulename");
7128ParseResult FPrintFOp::parse(::mlir::OpAsmParser &parser,
7129 ::mlir::OperationState &result) {
7131 OpAsmParser::UnresolvedOperand clock, cond;
7132 if (parser.parseOperand(clock) || parser.parseComma() ||
7133 parser.parseOperand(cond) || parser.parseComma())
7137 [&parser](llvm::SMLoc &loc, StringAttr &result,
7138 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &operands)
7140 loc = parser.getCurrentLocation();
7143 std::string resultStr;
7144 if (parser.parseString(&resultStr))
7146 result = parser.getBuilder().getStringAttr(resultStr);
7149 if (parser.parseOperandList(operands, AsmParser::Delimiter::OptionalParen))
7155 SmallVector<OpAsmParser::UnresolvedOperand> outputFileSubstitutions,
7157 llvm::SMLoc outputFileLoc, formatStringLoc;
7161 result.getOrAddProperties<FPrintFOp::Properties>().outputFile,
7162 outputFileSubstitutions) ||
7163 parser.parseComma() ||
7166 result.getOrAddProperties<FPrintFOp::Properties>().formatString,
7174 Type clockType, condType;
7175 SmallVector<Type> restTypes;
7177 if (parser.parseColon() || parser.parseType(clockType) ||
7178 parser.parseComma() || parser.parseType(condType))
7181 if (succeeded(parser.parseOptionalComma())) {
7182 if (parser.parseTypeList(restTypes))
7187 result.getOrAddProperties<FPrintFOp::Properties>().operandSegmentSizes = {
7188 1, 1,
static_cast<int32_t
>(outputFileSubstitutions.size()),
7189 static_cast<int32_t
>(substitutions.size())};
7192 if (parser.resolveOperand(clock, clockType, result.operands) ||
7193 parser.resolveOperand(cond, condType, result.operands) ||
7194 parser.resolveOperands(
7195 outputFileSubstitutions,
7196 ArrayRef(restTypes).take_front(outputFileSubstitutions.size()),
7197 outputFileLoc, result.operands) ||
7198 parser.resolveOperands(
7200 ArrayRef(restTypes).drop_front(outputFileSubstitutions.size()),
7201 formatStringLoc, result.operands))
7207void FPrintFOp::print(OpAsmPrinter &p) {
7208 p <<
" " << getClock() <<
", " << getCond() <<
", ";
7209 p.printAttributeWithoutType(getOutputFileAttr());
7210 if (!getOutputFileSubstitutions().
empty()) {
7212 p.printOperands(getOutputFileSubstitutions());
7216 p.printAttributeWithoutType(getFormatStringAttr());
7217 if (!getSubstitutions().
empty()) {
7219 p.printOperands(getSubstitutions());
7223 p <<
" : " << getClock().getType() <<
", " << getCond().getType();
7224 if (!getOutputFileSubstitutions().
empty() || !getSubstitutions().
empty()) {
7225 for (
auto type : getOperands().drop_front(2).getTypes()) {
7236LogicalResult FFlushOp::verify() {
7237 if (!getOutputFileAttr() && !getOutputFileSubstitutions().
empty())
7238 return emitOpError(
"substitutions without output file are not allowed");
7247 auto ref = getInstanceAttr();
7248 auto target = ns.
lookup(ref);
7250 return emitError() <<
"target " << ref <<
" cannot be resolved";
7252 if (!target.isOpOnly())
7253 return emitError() <<
"target " << ref <<
" is not an operation";
7255 auto instance = dyn_cast<InstanceOp>(target.getOp());
7257 return emitError() <<
"target " << ref <<
" is not an instance";
7259 if (!instance.getDoNotPrint())
7260 return emitError() <<
"target " << ref <<
" is not marked doNotPrint";
7269void DomainCreateAnonOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
7274DomainCreateAnonOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7275 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
7276 auto domainAttr = getDomainAttr();
7278 auto *symbol = symbolTable.lookupSymbolIn(circuitOp, domainAttr);
7280 return emitOpError() <<
"references undefined symbol '" << domainAttr
7283 if (!isa<DomainOp>(symbol))
7284 return emitOpError() <<
"references symbol '" << domainAttr
7285 <<
"' which is not a domain";
7288 auto domainType = getResult().getType();
7289 return domainType.verifySymbolUses(getOperation(), symbolTable);
7292void DomainCreateOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
7297DomainCreateOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7298 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
7299 auto domainAttr = getDomainAttr();
7301 auto *symbol = symbolTable.lookupSymbolIn(circuitOp, domainAttr);
7303 return emitOpError() <<
"references undefined symbol '" << domainAttr
7306 if (!isa<DomainOp>(symbol))
7307 return emitOpError() <<
"references symbol '" << domainAttr
7308 <<
"' which is not a domain";
7311 auto domainType = getResult().getType();
7312 return domainType.verifySymbolUses(getOperation(), symbolTable);
7320#define GET_OP_CLASSES
7321#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 std::unique_ptr< Context > context
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.
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.
mlir::ParseResult parseFormatString(mlir::OpBuilder &builder, mlir::Location loc, llvm::StringRef formatString, llvm::ArrayRef< mlir::Value > specOperands, mlir::StringAttr &formatStringResult, llvm::SmallVectorImpl< mlir::Value > &operands)
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.