29#include "mlir/IR/BuiltinTypes.h"
30#include "mlir/IR/Diagnostics.h"
31#include "mlir/IR/DialectImplementation.h"
32#include "mlir/IR/PatternMatch.h"
33#include "mlir/IR/SymbolTable.h"
34#include "mlir/Interfaces/FunctionImplementation.h"
35#include "llvm/ADT/BitVector.h"
36#include "llvm/ADT/DenseMap.h"
37#include "llvm/ADT/DenseSet.h"
38#include "llvm/ADT/STLExtras.h"
39#include "llvm/ADT/SmallSet.h"
40#include "llvm/ADT/StringExtras.h"
41#include "llvm/ADT/TypeSwitch.h"
42#include "llvm/Support/Casting.h"
43#include "llvm/Support/FormatVariadic.h"
45using llvm::SmallDenseSet;
46using mlir::RegionRange;
56template <
typename RetTy =
FIRRTLType,
typename... Args>
58 const Twine &message, Args &&...args) {
60 (mlir::emitError(*loc, message) << ... << std::forward<Args>(args));
66 while (Operation *op = val.getDefiningOp()) {
68 TypeSwitch<Operation *, std::optional<bool>>(op)
69 .Case<SubfieldOp, SubindexOp, SubaccessOp>([&val](
auto op) {
73 .Case<RegOp, RegResetOp, WireOp>([](
auto) {
return true; })
74 .Default([](
auto) {
return false; });
81SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
82MemOp::computeDataFlow() {
85 if (getReadLatency() > 0)
87 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
89 for (
auto memPort : getResults())
91 auto enableFieldId = type.getFieldID((
unsigned)ReadPortSubfield::en);
92 auto addressFieldId = type.getFieldID((
unsigned)ReadPortSubfield::addr);
93 auto dataFieldId = type.getFieldID((
unsigned)ReadPortSubfield::data);
95 FieldRef(memPort,
static_cast<unsigned>(dataFieldId)),
96 FieldRef(memPort,
static_cast<unsigned>(enableFieldId)));
98 FieldRef(memPort,
static_cast<unsigned>(dataFieldId)),
99 FieldRef(memPort,
static_cast<unsigned>(addressFieldId)));
106 constexpr unsigned int addr = 1 << 0;
107 constexpr unsigned int en = 1 << 1;
108 constexpr unsigned int clk = 1 << 2;
109 constexpr unsigned int data = 1 << 3;
110 constexpr unsigned int mask = 1 << 4;
111 constexpr unsigned int rdata = 1 << 5;
112 constexpr unsigned int wdata = 1 << 6;
113 constexpr unsigned int wmask = 1 << 7;
114 constexpr unsigned int wmode = 1 << 8;
115 constexpr unsigned int def = 1 << 9;
119 return MemOp::PortKind::Debug;
122 for (
auto elem : portType.getElements()) {
123 fields |= llvm::StringSwitch<unsigned>(elem.name.getValue())
129 .Case(
"rdata",
rdata)
130 .Case(
"wdata",
wdata)
131 .Case(
"wmask",
wmask)
132 .Case(
"wmode",
wmode)
136 return MemOp::PortKind::Read;
138 return MemOp::PortKind::Write;
140 return MemOp::PortKind::ReadWrite;
141 return MemOp::PortKind::Debug;
156 llvm_unreachable(
"Unsupported Flow type.");
164 return "source flow";
168 return "duplex flow";
171 llvm_unreachable(
"Unsupported Flow type.");
176 if (
auto blockArg = dyn_cast<BlockArgument>(val)) {
177 auto *op = val.getParentBlock()->getParentOp();
178 if (
auto moduleLike = dyn_cast<FModuleLike>(op)) {
179 auto direction = moduleLike.getPortDirection(blockArg.getArgNumber());
183 return accumulatedFlow;
186 Operation *op = val.getDefiningOp();
188 return TypeSwitch<Operation *, Flow>(op)
189 .Case<SubfieldOp, OpenSubfieldOp>([&](
auto op) {
190 return foldFlow(op.getInput(), op.isFieldFlipped()
194 .Case<SubindexOp, SubaccessOp, OpenSubindexOp, RefSubOp>(
195 [&](
auto op) {
return foldFlow(op.getInput(), accumulatedFlow); })
197 .Case<RegOp, RegResetOp, WireOp, MemoryPortOp>(
199 .Case<InstanceOp, InstanceChoiceOp>([&](
auto inst) {
200 auto resultNo = cast<OpResult>(val).getResultNumber();
202 return accumulatedFlow;
205 .Case<MemOp>([&](
auto op) {
211 .Case<ObjectSubfieldOp>([&](ObjectSubfieldOp op) {
212 auto input = op.getInput();
213 auto *inputOp = input.getDefiningOp();
216 if (
auto objectOp = dyn_cast_or_null<ObjectOp>(inputOp)) {
217 auto classType = input.getType();
218 auto direction = classType.getElement(op.getIndex()).direction;
230 auto classType = input.getType();
231 auto direction = classType.getElement(op.getIndex()).direction;
235 op = dyn_cast_or_null<ObjectSubfieldOp>(inputOp);
237 input = op.getInput();
238 inputOp = input.getDefiningOp();
242 return accumulatedFlow;
246 .Default([&](
auto) {
return accumulatedFlow; });
252 Operation *op = val.getDefiningOp();
256 return TypeSwitch<Operation *, DeclKind>(op)
258 .Case<SubfieldOp, SubindexOp, SubaccessOp, OpenSubfieldOp, OpenSubindexOp,
264 if (
auto module = dyn_cast<FModuleLike>(op))
265 return module.getNumPorts();
266 return op->getNumResults();
280 if (
auto *op = value.getDefiningOp())
282 auto arg = dyn_cast<BlockArgument>(value);
283 auto module = dyn_cast<FModuleOp>(arg.getOwner()->getParentOp());
286 return (module.getPortSymbolAttr(arg.getArgNumber())) ||
297 auto *block = ®ion.front();
300 auto argAttr = parentOp->getAttrOfType<ArrayAttr>(
"portNames");
302 if (!argAttr || argAttr.size() != block->getNumArguments())
305 for (
size_t i = 0, e = block->getNumArguments(); i != e; ++i) {
306 auto str = cast<StringAttr>(argAttr[i]).getValue();
308 setNameFn(block->getArgument(i), str);
314 firrtl::NameKindEnumAttr &result);
325 for (; op !=
nullptr; op = op->getParentOp()) {
326 if (
auto module = dyn_cast<FModuleLike>(op)) {
327 auto layers =
module.getLayersAttr().getAsRange<SymbolRefAttr>();
328 result.insert(layers.begin(), layers.end());
331 if (
auto layerblock = dyn_cast<LayerBlockOp>(op)) {
332 result.insert(layerblock.getLayerName());
350 if (
auto type = dyn_cast<RefType>(value.getType()))
351 if (
auto layer = type.getLayer())
352 result.insert(type.getLayer());
361 mlir::SymbolRefAttr dstLayer) {
371 if (srcLayer.getRootReference() != dstLayer.getRootReference())
374 auto srcNames = srcLayer.getNestedReferences();
375 auto dstNames = dstLayer.getNestedReferences();
376 if (dstNames.size() < srcNames.size())
379 return llvm::all_of(llvm::zip_first(srcNames, dstNames),
380 [](
auto x) {
return std::get<0>(x) == std::get<1>(x); });
387 if (dstLayers.contains(srcLayer))
392 return any_of(dstLayers, [=](SymbolRefAttr dstLayer) {
401 SmallVectorImpl<SymbolRefAttr> &missing) {
402 for (
auto srcLayer : src)
404 missing.push_back(srcLayer);
407 return missing.empty();
412 const Twine &errorMsg,
413 const Twine ¬eMsg = Twine(
"missing layer requirements")) {
414 SmallVector<SymbolRefAttr> missing;
417 interleaveComma(missing, op->emitOpError(errorMsg).attachNote()
426void CircuitOp::build(OpBuilder &builder, OperationState &result,
427 StringAttr name, ArrayAttr annotations) {
429 result.getOrAddProperties<Properties>().setName(name);
432 annotations = builder.getArrayAttr({});
433 result.getOrAddProperties<Properties>().setAnnotations(annotations);
436 Region *bodyRegion = result.addRegion();
438 bodyRegion->push_back(body);
442 NamedAttrList &resultAttrs) {
443 auto result = parser.parseOptionalAttrDictWithKeyword(resultAttrs);
444 if (!resultAttrs.get(
"annotations"))
445 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
451 DictionaryAttr attr) {
453 SmallVector<StringRef> elidedAttrs = {
"name"};
455 auto annotationsAttr = op->getAttrOfType<ArrayAttr>(
"annotations");
456 if (annotationsAttr.empty())
457 elidedAttrs.push_back(
"annotations");
459 p.printOptionalAttrDictWithKeyword(op->getAttrs(), elidedAttrs);
462LogicalResult CircuitOp::verifyRegions() {
467 emitOpError(
"must have a non-empty name");
471 mlir::SymbolTable symtbl(getOperation());
473 auto *mainModule = symtbl.lookup(
main);
475 return emitOpError().append(
476 "does not contain module with same name as circuit");
477 if (!isa<FModuleLike>(mainModule))
478 return mainModule->emitError(
479 "entity with name of circuit must be a module");
480 if (symtbl.getSymbolVisibility(mainModule) !=
481 mlir::SymbolTable::Visibility::Public)
482 return mainModule->emitError(
"main module must be public");
487 llvm::DenseMap<Attribute, FExtModuleOp> defnameMap;
489 auto verifyExtModule = [&](FExtModuleOp extModule) -> LogicalResult {
493 auto defname = extModule.getDefnameAttr();
499 if (
auto collidingModule = symtbl.lookup<FModuleOp>(defname.getValue()))
500 return extModule.emitOpError()
501 .append(
"attribute 'defname' with value ", defname,
502 " conflicts with the name of another module in the circuit")
503 .attachNote(collidingModule.getLoc())
504 .append(
"previous module declared here");
512 FExtModuleOp collidingExtModule;
513 if (
auto &value = defnameMap[defname]) {
514 collidingExtModule = value;
515 if (!value.getParameters().empty() && extModule.getParameters().empty())
525 SmallVector<PortInfo> ports = extModule.getPorts();
526 SmallVector<PortInfo> collidingPorts = collidingExtModule.getPorts();
528 if (ports.size() != collidingPorts.size())
529 return extModule.emitOpError()
530 .append(
"with 'defname' attribute ", defname,
" has ", ports.size(),
531 " ports which is different from a previously defined "
532 "extmodule with the same 'defname' which has ",
533 collidingPorts.size(),
" ports")
534 .attachNote(collidingExtModule.getLoc())
535 .append(
"previous extmodule definition occurred here");
541 for (
auto p : llvm::zip(ports, collidingPorts)) {
542 StringAttr aName = std::get<0>(p).name, bName = std::get<1>(p).name;
543 Type aType = std::get<0>(p).type, bType = std::get<1>(p).type;
546 return extModule.emitOpError()
547 .append(
"with 'defname' attribute ", defname,
548 " has a port with name ", aName,
549 " which does not match the name of the port in the same "
550 "position of a previously defined extmodule with the same "
551 "'defname', expected port to have name ",
553 .attachNote(collidingExtModule.getLoc())
554 .append(
"previous extmodule definition occurred here");
556 if (!extModule.getParameters().empty() ||
557 !collidingExtModule.getParameters().empty()) {
560 aType = base.getWidthlessType();
562 bType = base.getWidthlessType();
565 return extModule.emitOpError()
566 .append(
"with 'defname' attribute ", defname,
567 " has a port with name ", aName,
568 " which has a different type ", aType,
569 " which does not match the type of the port in the same "
570 "position of a previously defined extmodule with the same "
571 "'defname', expected port to have type ",
573 .attachNote(collidingExtModule.getLoc())
574 .append(
"previous extmodule definition occurred here");
579 SmallVector<FModuleOp, 1> dutModules;
582 if (
auto moduleOp = dyn_cast<FModuleOp>(op)) {
583 if (AnnotationSet(moduleOp).hasAnnotation(markDUTAnnoClass))
584 dutModules.push_back(moduleOp);
589 if (
auto extModule = dyn_cast<FExtModuleOp>(op)) {
590 if (verifyExtModule(extModule).failed())
596 if (dutModules.size() > 1) {
597 auto diag = dutModules[0]->emitOpError()
598 <<
"is annotated as the design-under-test (DUT), but other "
599 "modules are also annotated";
600 for (
auto moduleOp : ArrayRef(dutModules).drop_front())
601 diag.attachNote(moduleOp.getLoc()) <<
"is also annotated as the DUT";
608Block *CircuitOp::getBodyBlock() {
return &getBody().front(); }
615 SmallVector<PortInfo> results;
616 results.reserve(module.getNumPorts());
617 ArrayRef<Attribute> domains =
module.getDomainInfo();
618 for (
unsigned i = 0, e = module.getNumPorts(); i < e; ++i) {
619 results.push_back({
module.getPortNameAttr(i), module.getPortType(i),
620 module.getPortDirection(i), module.getPortSymbolAttr(i),
621 module.getPortLocation(i),
622 AnnotationSet::forPort(module, i),
623 domains.empty() ? Attribute{} : domains[i]});
628SmallVector<PortInfo> FModuleOp::getPorts() { return ::getPortImpl(*
this); }
630SmallVector<PortInfo> FExtModuleOp::getPorts() { return ::getPortImpl(*
this); }
632SmallVector<PortInfo> FIntModuleOp::getPorts() { return ::getPortImpl(*
this); }
634SmallVector<PortInfo> FMemModuleOp::getPorts() { return ::getPortImpl(*
this); }
637 if (dir == Direction::In)
639 if (dir == Direction::Out)
641 assert(0 &&
"invalid direction");
646 SmallVector<hw::PortInfo> results;
647 auto aname = StringAttr::get(module.getContext(),
648 hw::HWModuleLike::getPortSymbolAttrName());
649 auto emptyDict = DictionaryAttr::get(module.getContext());
650 for (
unsigned i = 0, e =
getNumPorts(module); i < e; ++i) {
651 auto sym =
module.getPortSymbolAttr(i);
653 {{
module.getPortNameAttr(i), module.getPortType(i),
654 dirFtoH(module.getPortDirection(i))},
656 sym ? DictionaryAttr::get(
658 ArrayRef<mlir::NamedAttribute>{NamedAttribute{aname, sym}})
660 module.getPortLocation(i)});
665SmallVector<::circt::hw::PortInfo> FModuleOp::getPortList() {
666 return ::getPortListImpl(*
this);
669SmallVector<::circt::hw::PortInfo> FExtModuleOp::getPortList() {
670 return ::getPortListImpl(*
this);
673SmallVector<::circt::hw::PortInfo> FIntModuleOp::getPortList() {
674 return ::getPortListImpl(*
this);
677SmallVector<::circt::hw::PortInfo> FMemModuleOp::getPortList() {
678 return ::getPortListImpl(*
this);
682 auto sym =
module.getPortSymbolAttr(idx);
683 auto attrs = sym ? DictionaryAttr::getWithSorted(
685 ArrayRef(mlir::NamedAttribute(
686 hw::HWModuleLike::getPortSymbolAttrName(), sym)))
687 : DictionaryAttr::get(module.getContext());
688 return {{
module.getPortNameAttr(idx), module.getPortType(idx),
689 dirFtoH(module.getPortDirection(idx))},
692 module.getPortLocation(idx)};
696 return ::getPortImpl(*
this, idx);
700 return ::getPortImpl(*
this, idx);
704 return ::getPortImpl(*
this, idx);
708 return ::getPortImpl(*
this, idx);
712BlockArgument FModuleOp::getArgument(
size_t portNumber) {
719 Attribute domainInfoAttr,
720 ArrayRef<unsigned> indexMap) {
722 auto di = dyn_cast_or_null<ArrayAttr>(domainInfoAttr);
723 if (!di || di.empty())
724 return domainInfoAttr;
727 SmallVector<Attribute> domainInfo;
728 for (
auto attr : di) {
729 auto oldIdx = cast<IntegerAttr>(attr).getUInt();
730 auto newIdx = indexMap[oldIdx];
731 if (oldIdx == newIdx)
732 domainInfo.push_back(attr);
734 domainInfo.push_back(IntegerAttr::get(
735 IntegerType::get(
context, 32, IntegerType::Unsigned), newIdx));
737 return ArrayAttr::get(
context, domainInfo);
744 ArrayRef<std::pair<unsigned, PortInfo>> ports) {
747 unsigned oldNumArgs = op.getNumPorts();
748 unsigned newNumArgs = oldNumArgs + ports.size();
751 SmallVector<unsigned> indexMap(oldNumArgs);
753 for (
size_t i = 0; i < oldNumArgs; ++i) {
754 while (inserted < ports.size() && ports[inserted].first == i)
756 indexMap[i] = i + inserted;
760 auto existingDirections = op.getPortDirectionsAttr();
761 ArrayRef<Attribute> existingNames = op.getPortNames();
762 ArrayRef<Attribute> existingTypes = op.getPortTypes();
763 ArrayRef<Attribute> existingLocs = op.getPortLocations();
764 assert(existingDirections.size() == oldNumArgs);
765 assert(existingNames.size() == oldNumArgs);
766 assert(existingTypes.size() == oldNumArgs);
767 assert(existingLocs.size() == oldNumArgs);
769 SmallVector<bool> newDirections;
770 SmallVector<Attribute> newNames, newTypes, newDomains, newAnnos, newSyms,
772 newDirections.reserve(newNumArgs);
773 newNames.reserve(newNumArgs);
774 newTypes.reserve(newNumArgs);
775 newDomains.reserve(newNumArgs);
776 newAnnos.reserve(newNumArgs);
777 newSyms.reserve(newNumArgs);
778 newLocs.reserve(newNumArgs);
780 auto emptyArray = ArrayAttr::get(op.getContext(), {});
783 auto migrateOldPorts = [&](
unsigned untilOldIdx) {
784 while (oldIdx < oldNumArgs && oldIdx < untilOldIdx) {
785 newDirections.push_back(existingDirections[oldIdx]);
786 newNames.push_back(existingNames[oldIdx]);
787 newTypes.push_back(existingTypes[oldIdx]);
789 op.getContext(), op.getDomainInfoAttrForPort(oldIdx), indexMap));
790 newAnnos.push_back(op.getAnnotationsAttrForPort(oldIdx));
791 newSyms.push_back(op.getPortSymbolAttr(oldIdx));
792 newLocs.push_back(existingLocs[oldIdx]);
797 for (
auto [idx, port] : ports) {
798 migrateOldPorts(idx);
800 newNames.push_back(port.name);
801 newTypes.push_back(TypeAttr::get(port.type));
804 port.domains ? port.domains : ArrayAttr::get(op.getContext(), {}),
806 auto annos = port.annotations.getArrayAttr();
807 newAnnos.push_back(annos ? annos : emptyArray);
808 newSyms.push_back(port.sym);
809 newLocs.push_back(port.loc);
812 migrateOldPorts(oldNumArgs);
816 if (llvm::all_of(newAnnos, [](Attribute attr) {
817 return cast<ArrayAttr>(attr).empty();
823 if (llvm::all_of(newDomains, [](Attribute attr) {
826 if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr))
827 return arrayAttr.empty();
833 op->setAttr(
"portDirections",
835 op->setAttr(
"portNames", ArrayAttr::get(op.getContext(), newNames));
836 op->setAttr(
"portTypes", ArrayAttr::get(op.getContext(), newTypes));
837 op->setAttr(
"domainInfo", ArrayAttr::get(op.getContext(), newDomains));
838 op->setAttr(
"portAnnotations", ArrayAttr::get(op.getContext(), newAnnos));
839 FModuleLike::fixupPortSymsArray(newSyms, op.getContext());
840 op.setPortSymbols(newSyms);
841 op->setAttr(
"portLocations", ArrayAttr::get(op.getContext(), newLocs));
852 ArrayAttr domainInfoAttr,
853 const llvm::BitVector &portIndices,
854 bool supportsEmptyAttr) {
855 if (supportsEmptyAttr && domainInfoAttr.empty())
856 return domainInfoAttr;
859 SmallVector<unsigned> indexMap(portIndices.size());
861 for (
size_t i = 0, e = portIndices.size(); i != e; ++i) {
862 indexMap[i] = i - deleted;
869 auto getEmpty = [&]() {
871 eEmpty = ArrayAttr::get(
context, {});
876 SmallVector<Attribute> newDomainInfo;
877 newDomainInfo.reserve(portIndices.size() - portIndices.count());
878 for (
size_t i = 0, e = portIndices.size(); i != e; ++i) {
880 if (portIndices.test(i))
883 if (domainInfoAttr.empty()) {
884 newDomainInfo.push_back(getEmpty());
887 auto attr = domainInfoAttr[i];
889 auto domains = dyn_cast<ArrayAttr>(attr);
890 if (!domains || domains.empty()) {
891 newDomainInfo.push_back(attr);
895 SmallVector<Attribute> newDomains;
896 for (
auto domain : domains) {
898 auto oldIdx = cast<IntegerAttr>(domain).getUInt();
899 if (portIndices.test(oldIdx))
902 auto newIdx = indexMap[oldIdx];
903 if (oldIdx == newIdx) {
904 newDomains.push_back(domain);
908 newDomains.push_back(IntegerAttr::get(
909 IntegerType::get(
context, 32, IntegerType::Unsigned), newIdx));
911 newDomainInfo.push_back(ArrayAttr::get(
context, newDomains));
914 return ArrayAttr::get(
context, newDomainInfo);
918static void erasePorts(FModuleLike op,
const llvm::BitVector &portIndices) {
919 if (portIndices.none())
923 ArrayRef<bool> portDirections = op.getPortDirectionsAttr().asArrayRef();
924 ArrayRef<Attribute> portNames = op.getPortNames();
925 ArrayRef<Attribute> portTypes = op.getPortTypes();
926 ArrayRef<Attribute> portAnnos = op.getPortAnnotations();
927 ArrayRef<Attribute> portSyms = op.getPortSymbols();
928 ArrayRef<Attribute> portLocs = op.getPortLocations();
929 ArrayRef<Attribute> portDomains = op.getDomainInfo();
931 auto numPorts = op.getNumPorts();
933 assert(portDirections.size() == numPorts);
934 assert(portNames.size() == numPorts);
935 assert(portAnnos.size() == numPorts || portAnnos.empty());
936 assert(portTypes.size() == numPorts);
937 assert(portSyms.size() == numPorts || portSyms.empty());
938 assert(portLocs.size() == numPorts);
939 assert(portDomains.size() == numPorts || portDomains.empty());
941 SmallVector<bool> newPortDirections =
943 SmallVector<Attribute> newPortNames, newPortTypes, newPortAnnos, newPortSyms,
951 op->setAttr(
"portDirections",
953 op->setAttr(
"portNames", ArrayAttr::get(op.getContext(), newPortNames));
954 op->setAttr(
"portAnnotations", ArrayAttr::get(op.getContext(), newPortAnnos));
955 op->setAttr(
"portTypes", ArrayAttr::get(op.getContext(), newPortTypes));
956 FModuleLike::fixupPortSymsArray(newPortSyms, op.getContext());
957 op->setAttr(
"portSymbols", ArrayAttr::get(op.getContext(), newPortSyms));
958 op->setAttr(
"portLocations", ArrayAttr::get(op.getContext(), newPortLocs));
959 op->setAttr(
"domainInfo",
964void FExtModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
965 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
968void FIntModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
969 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
972void FMemModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
973 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
976void FModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
977 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
984void FModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
989 for (
size_t i = 0, e = ports.size(); i < e; ++i) {
992 auto &[index, port] = ports[i];
993 body->insertArgument(index + i, port.type, port.loc);
997void FExtModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1001void FIntModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1002 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1008void FMemModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1009 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1012template <
typename OpTy>
1014 StringAttr name, ArrayRef<PortInfo> ports) {
1016 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
1017 properties.setSymName(name);
1020 SmallVector<Direction, 4> portDirections;
1021 SmallVector<Attribute, 4> portNames, portTypes, portSyms, portLocs,
1023 portDirections.reserve(ports.size());
1024 portNames.reserve(ports.size());
1025 portTypes.reserve(ports.size());
1026 portSyms.reserve(ports.size());
1027 portLocs.reserve(ports.size());
1028 portDomains.reserve(ports.size());
1030 for (
const auto &port : ports) {
1031 portDirections.push_back(port.direction);
1032 portNames.push_back(port.name);
1033 portTypes.push_back(TypeAttr::get(port.type));
1034 portSyms.push_back(port.sym);
1035 portLocs.push_back(port.loc);
1036 portDomains.push_back(port.domains);
1038 if (llvm::all_of(portDomains, [](Attribute attr) {
1041 if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr))
1042 return arrayAttr.empty();
1045 portDomains.clear();
1047 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1050 properties.setPortDirections(
1052 properties.setPortNames(builder.getArrayAttr(portNames));
1053 properties.setPortTypes(builder.getArrayAttr(portTypes));
1054 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1055 properties.setPortLocations(builder.getArrayAttr(portLocs));
1056 properties.setDomainInfo(builder.getArrayAttr(portDomains));
1061template <
typename OpTy>
1063 StringAttr name, ArrayRef<PortInfo> ports,
1064 ArrayAttr annotations, ArrayAttr layers) {
1066 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
1069 annotations = builder.getArrayAttr({});
1070 properties.setAnnotations(annotations);
1074 SmallVector<Attribute, 4> portAnnotations;
1075 for (
const auto &port : ports)
1076 portAnnotations.push_back(port.annotations.getArrayAttr());
1077 if (llvm::all_of(portAnnotations, [](Attribute attr) {
1078 return cast<ArrayAttr>(attr).empty();
1080 portAnnotations.clear();
1081 properties.setPortAnnotations(builder.getArrayAttr(portAnnotations));
1085 layers = builder.getArrayAttr({});
1086 properties.setLayers(layers);
1089template <
typename OpTy>
1090static void buildClass(OpBuilder &builder, OperationState &result,
1091 StringAttr name, ArrayRef<PortInfo> ports) {
1095void FModuleOp::build(OpBuilder &builder, OperationState &result,
1096 StringAttr name, ConventionAttr convention,
1097 ArrayRef<PortInfo> ports, ArrayAttr annotations,
1100 auto &properties = result.getOrAddProperties<Properties>();
1101 properties.setConvention(convention);
1104 auto *bodyRegion = result.regions[0].get();
1106 bodyRegion->push_back(body);
1109 for (
auto &elt : ports)
1110 body->addArgument(elt.type, elt.loc);
1113void FExtModuleOp::build(OpBuilder &builder, OperationState &result,
1114 StringAttr name, ConventionAttr convention,
1115 ArrayRef<PortInfo> ports, ArrayAttr knownLayers,
1116 StringRef defnameAttr, ArrayAttr annotations,
1117 ArrayAttr parameters, ArrayAttr layers,
1118 ArrayAttr externalRequirements) {
1120 auto &properties = result.getOrAddProperties<Properties>();
1121 properties.setConvention(convention);
1123 knownLayers = builder.getArrayAttr({});
1124 properties.setKnownLayers(knownLayers);
1125 if (!defnameAttr.empty())
1126 properties.setDefname(builder.getStringAttr(defnameAttr));
1128 parameters = builder.getArrayAttr({});
1129 properties.setParameters(parameters);
1130 if (externalRequirements)
1131 properties.setExternalRequirements(externalRequirements);
1134void FIntModuleOp::build(OpBuilder &builder, OperationState &result,
1135 StringAttr name, ArrayRef<PortInfo> ports,
1136 StringRef intrinsicNameStr, ArrayAttr annotations,
1137 ArrayAttr parameters, ArrayAttr layers) {
1139 auto &properties = result.getOrAddProperties<Properties>();
1140 properties.setIntrinsic(builder.getStringAttr(intrinsicNameStr));
1142 parameters = builder.getArrayAttr({});
1143 properties.setParameters(parameters);
1146void FMemModuleOp::build(OpBuilder &builder, OperationState &result,
1147 StringAttr name, ArrayRef<PortInfo> ports,
1148 uint32_t numReadPorts, uint32_t numWritePorts,
1149 uint32_t numReadWritePorts, uint32_t dataWidth,
1150 uint32_t maskBits, uint32_t readLatency,
1151 uint32_t writeLatency, uint64_t depth, RUWBehavior ruw,
1152 ArrayAttr annotations, ArrayAttr layers) {
1153 auto *
context = builder.getContext();
1155 auto ui32Type = IntegerType::get(
context, 32, IntegerType::Unsigned);
1156 auto ui64Type = IntegerType::get(
context, 64, IntegerType::Unsigned);
1157 auto &properties = result.getOrAddProperties<Properties>();
1158 properties.setNumReadPorts(IntegerAttr::get(ui32Type, numReadPorts));
1159 properties.setNumWritePorts(IntegerAttr::get(ui32Type, numWritePorts));
1160 properties.setNumReadWritePorts(
1161 IntegerAttr::get(ui32Type, numReadWritePorts));
1162 properties.setDataWidth(IntegerAttr::get(ui32Type, dataWidth));
1163 properties.setMaskBits(IntegerAttr::get(ui32Type, maskBits));
1164 properties.setReadLatency(IntegerAttr::get(ui32Type, readLatency));
1165 properties.setWriteLatency(IntegerAttr::get(ui32Type, writeLatency));
1166 properties.setDepth(IntegerAttr::get(ui64Type, depth));
1167 properties.setExtraPorts(ArrayAttr::get(
context, {}));
1168 properties.setRuw(RUWBehaviorAttr::get(
context, ruw));
1185 ArrayRef<Attribute> portNames, ArrayRef<Attribute> portTypes,
1186 ArrayRef<Attribute> portAnnotations,
1187 ArrayRef<Attribute> portSyms, ArrayRef<Attribute> portLocs,
1188 ArrayRef<Attribute> domainInfo) {
1191 bool printedNamesDontMatch =
false;
1193 mlir::OpPrintingFlags flags;
1196 DenseMap<unsigned, std::string> ssaNames;
1197 auto getSsaName = [&](
unsigned idx) -> StringRef {
1199 auto itr = ssaNames.find(idx);
1200 if (itr != ssaNames.end())
1201 return itr->getSecond();
1205 SmallString<32> resultNameStr;
1207 llvm::raw_svector_ostream tmpStream(resultNameStr);
1208 p.printOperand(block->getArgument(idx), tmpStream);
1211 auto portName = cast<StringAttr>(portNames[idx]).getValue();
1212 if (tmpStream.str().drop_front() != portName)
1213 printedNamesDontMatch =
true;
1214 return ssaNames.insert({idx, tmpStream.str().str()}).first->getSecond();
1217 auto name = cast<StringAttr>(portNames[idx]).getValue();
1218 return ssaNames.insert({idx, name.str()}).first->getSecond();
1224 for (
unsigned i = 0, e = portTypes.size(); i < e; ++i) {
1233 auto portType = cast<TypeAttr>(portTypes[i]).getValue();
1237 p.printKeywordOrString(getSsaName(i));
1242 p.printType(portType);
1245 if (!portSyms.empty()) {
1246 if (!cast<hw::InnerSymAttr>(portSyms[i]).
empty()) {
1248 cast<hw::InnerSymAttr>(portSyms[i]).print(p);
1256 if (!domainInfo.empty()) {
1257 auto domains = cast<ArrayAttr>(domainInfo[i]);
1258 if (!domains.empty()) {
1260 llvm::interleaveComma(domains, p, [&](Attribute attr) {
1261 p << getSsaName(cast<IntegerAttr>(attr).getUInt());
1269 if (!portAnnotations.empty() &&
1270 !cast<ArrayAttr>(portAnnotations[i]).empty()) {
1272 p.printAttribute(portAnnotations[i]);
1279 if (flags.shouldPrintDebugInfo() && !portLocs.empty())
1280 p.printOptionalLocationSpecifier(cast<LocationAttr>(portLocs[i]));
1284 return printedNamesDontMatch;
1290 OpAsmParser &parser,
bool hasSSAIdentifiers,
bool supportsSymbols,
1291 bool supportsDomains, SmallVectorImpl<OpAsmParser::Argument> &entryArgs,
1292 SmallVectorImpl<Direction> &portDirections,
1293 SmallVectorImpl<Attribute> &portNames,
1294 SmallVectorImpl<Attribute> &portTypes,
1295 SmallVectorImpl<Attribute> &portAnnotations,
1296 SmallVectorImpl<Attribute> &portSyms, SmallVectorImpl<Attribute> &portLocs,
1297 SmallVectorImpl<Attribute> &domains) {
1298 auto *
context = parser.getContext();
1301 DenseMap<Attribute, size_t> domainIndex;
1304 using DomainAndLoc = std::pair<Attribute, llvm::SMLoc>;
1305 DenseMap<size_t, SmallVector<DomainAndLoc>> domainStrings;
1307 auto parseArgument = [&]() -> ParseResult {
1309 if (succeeded(parser.parseOptionalKeyword(
"out")))
1310 portDirections.push_back(Direction::Out);
1311 else if (succeeded(parser.parseKeyword(
"in",
" or 'out'")))
1312 portDirections.push_back(Direction::In);
1319 auto portIdx = portNames.size();
1321 if (hasSSAIdentifiers) {
1322 OpAsmParser::Argument arg;
1323 if (parser.parseArgument(arg))
1325 entryArgs.push_back(arg);
1329 assert(arg.ssaName.name.size() > 1 && arg.ssaName.name[0] ==
'%' &&
1330 "Unknown MLIR name");
1331 if (
isdigit(arg.ssaName.name[1]))
1332 portNames.push_back(StringAttr::get(
context,
""));
1334 portNames.push_back(
1335 StringAttr::get(
context, arg.ssaName.name.drop_front()));
1338 irLoc = arg.ssaName.location;
1342 irLoc = parser.getCurrentLocation();
1343 std::string portName;
1344 if (parser.parseKeywordOrString(&portName))
1346 portNames.push_back(StringAttr::get(
context, portName));
1351 if (parser.parseColonType(portType))
1353 portTypes.push_back(TypeAttr::get(portType));
1354 if (isa<DomainType>(portType))
1355 domainIndex[portNames.back()] = portIdx;
1357 if (hasSSAIdentifiers)
1358 entryArgs.back().type = portType;
1361 if (supportsSymbols) {
1362 hw::InnerSymAttr innerSymAttr;
1363 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
1364 NamedAttrList dummyAttrs;
1365 if (parser.parseCustomAttributeWithFallback(
1366 innerSymAttr, ::mlir::Type{},
1368 return ::mlir::failure();
1371 portSyms.push_back(innerSymAttr);
1377 Attribute domainInfo = ArrayAttr::get(
context, {});
1378 if (supportsDomains) {
1379 if (
auto domainType = dyn_cast<DomainType>(portType)) {
1381 domainInfo = ArrayAttr::get(
context, {});
1382 }
else if (succeeded(parser.parseOptionalKeyword(
"domains"))) {
1383 auto result = parser.parseCommaSeparatedList(
1384 OpAsmParser::Delimiter::Square, [&]() -> ParseResult {
1386 if (hasSSAIdentifiers) {
1387 OpAsmParser::Argument arg;
1388 if (parser.parseArgument(arg))
1391 StringAttr::get(
context, arg.ssaName.name.drop_front());
1393 std::string portName;
1394 if (parser.parseKeywordOrString(&portName))
1396 argName = StringAttr::get(
context, portName);
1398 domainStrings[portIdx].push_back({argName, irLoc});
1405 domainInfo =
nullptr;
1408 domains.push_back(domainInfo);
1412 auto parseResult = parser.parseOptionalAttribute(annos);
1413 if (!parseResult.has_value())
1414 annos = parser.getBuilder().getArrayAttr({});
1415 else if (failed(*parseResult))
1417 portAnnotations.push_back(annos);
1420 std::optional<Location> maybeLoc;
1421 if (failed(parser.parseOptionalLocationSpecifier(maybeLoc)))
1423 Location loc = maybeLoc ? *maybeLoc : parser.getEncodedSourceLoc(irLoc);
1424 portLocs.push_back(loc);
1425 if (hasSSAIdentifiers)
1426 entryArgs.back().sourceLoc = loc;
1435 if (failed(parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
1441 for (
auto [portIdx, domainInfo] : llvm::enumerate(domains)) {
1446 SmallVector<Attribute> portDomains;
1447 for (
auto [domainName, loc] : domainStrings[portIdx]) {
1448 auto index = domainIndex.find(domainName);
1449 if (index == domainIndex.end()) {
1450 parser.emitError(loc) <<
"domain name '" << domainName <<
"' not found";
1453 portDomains.push_back(IntegerAttr::get(
1454 IntegerType::get(
context, 32, IntegerType::Unsigned), index->second));
1456 domains[portIdx] = parser.getBuilder().getArrayAttr(portDomains);
1464 ArrayAttr parameters) {
1465 if (!parameters || parameters.empty())
1469 llvm::interleaveComma(parameters, p, [&](Attribute param) {
1470 auto paramAttr = cast<ParamDeclAttr>(param);
1471 p << paramAttr.getName().getValue() <<
": " << paramAttr.getType();
1472 if (
auto value = paramAttr.getValue()) {
1474 p.printAttributeWithoutType(value);
1480template <
typename ModuleTy>
1485 StringRef visibilityAttrName =
1486 mlir::SymbolOpInterface::getDefaultVisibilityAttrName();
1487 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
1488 p << visibility.getValue() <<
' ';
1491 p.printSymbolName(cast<mlir::SymbolOpInterface>(op.getOperation()).getName());
1498 Block *body =
nullptr;
1499 if (!op->getRegion(0).empty())
1500 body = &op->getRegion(0).front();
1503 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
1504 op.getPortAnnotations(), op.getPortSymbols(), op.getPortLocations(),
1505 op.getDomainInfo());
1507 SmallVector<StringRef, 13> omittedAttrs = {
1508 ModuleTy::getSymNameAttrName(op->getName()),
1518 if (op.getConvention() == Convention::Internal)
1519 omittedAttrs.push_back(
"convention");
1523 if (!needPortNamesAttr)
1524 omittedAttrs.push_back(
"portNames");
1527 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
1528 omittedAttrs.push_back(
"annotations");
1531 if (
auto knownLayers = op->getAttrOfType<ArrayAttr>(
"knownLayers"))
1532 if (knownLayers.empty())
1533 omittedAttrs.push_back(
"knownLayers");
1536 if (
auto layers = op->getAttrOfType<ArrayAttr>(
"layers"))
1538 omittedAttrs.push_back(
"layers");
1541 if (
auto extReqs = op->getAttrOfType<ArrayAttr>(
"externalRequirements"))
1542 if (extReqs.empty())
1543 omittedAttrs.push_back(
"externalRequirements");
1545 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
1548void FExtModuleOp::print(OpAsmPrinter &p) {
1552void FIntModuleOp::print(OpAsmPrinter &p) {
1556void FMemModuleOp::print(OpAsmPrinter &p) {
1560void FModuleOp::print(OpAsmPrinter &p) {
1566 Region &fbody = getBody();
1567 if (!fbody.empty()) {
1569 p.printRegion(fbody,
false,
1581 SmallVectorImpl<Attribute> ¶meters) {
1583 return parser.parseCommaSeparatedList(
1584 OpAsmParser::Delimiter::OptionalLessGreater, [&]() {
1589 if (parser.parseKeywordOrString(&name) || parser.parseColonType(type))
1593 if (succeeded(parser.parseOptionalEqual())) {
1594 if (parser.parseAttribute(value, type))
1598 auto &builder = parser.getBuilder();
1599 parameters.push_back(ParamDeclAttr::get(
1600 builder.getContext(), builder.getStringAttr(name), type, value));
1607 ArrayAttr ¶meters) {
1608 SmallVector<Attribute> parseParameters;
1612 parameters = ArrayAttr::get(parser.getContext(), parseParameters);
1617template <
typename Properties,
typename =
void>
1620template <
typename Properties>
1622 Properties, std::void_t<decltype(std::declval<Properties>().parameters)>>
1623 : std::true_type {};
1625template <
typename OpTy>
1627 OperationState &result,
1628 bool hasSSAIdentifiers) {
1629 auto *
context = result.getContext();
1630 auto &builder = parser.getBuilder();
1631 using Properties =
typename OpTy::Properties;
1632 auto &properties = result.getOrAddProperties<Properties>();
1636 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
1639 StringAttr nameAttr;
1640 if (parser.parseSymbolName(nameAttr))
1642 properties.setSymName(nameAttr);
1646 SmallVector<Attribute, 4> parameters;
1649 properties.setParameters(builder.getArrayAttr(parameters));
1653 SmallVector<OpAsmParser::Argument> entryArgs;
1654 SmallVector<Direction, 4> portDirections;
1655 SmallVector<Attribute, 4> portNames;
1656 SmallVector<Attribute, 4> portTypes;
1657 SmallVector<Attribute, 4> portAnnotations;
1658 SmallVector<Attribute, 4> portSyms;
1659 SmallVector<Attribute, 4> portLocs;
1660 SmallVector<Attribute, 4> domains;
1662 true, entryArgs, portDirections,
1663 portNames, portTypes, portAnnotations, portSyms,
1668 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
1671 assert(portNames.size() == portTypes.size());
1677 properties.setPortDirections(
1681 properties.setPortNames(builder.getArrayAttr(portNames));
1684 properties.setPortTypes(ArrayAttr::get(
context, portTypes));
1688 if (llvm::any_of(portAnnotations, [&](Attribute anno) {
1689 return !cast<ArrayAttr>(anno).empty();
1691 properties.setPortAnnotations(ArrayAttr::get(
context, portAnnotations));
1693 properties.setPortAnnotations(builder.getArrayAttr({}));
1696 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1697 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1700 properties.setPortLocations(ArrayAttr::get(
context, portLocs));
1703 properties.setAnnotations(builder.getArrayAttr({}));
1706 if (llvm::all_of(domains, [&](Attribute attr) {
1707 auto arrayAttr = dyn_cast<ArrayAttr>(attr);
1708 return arrayAttr && arrayAttr.empty();
1710 properties.setDomainInfo(ArrayAttr::get(
context, {}));
1712 properties.setDomainInfo(ArrayAttr::get(
context, domains));
1715 auto *body = result.addRegion();
1717 if (hasSSAIdentifiers) {
1718 if (parser.parseRegion(*body, entryArgs))
1721 body->push_back(
new Block());
1726ParseResult FModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1730 auto &properties = result.getOrAddProperties<Properties>();
1731 properties.setConvention(
1732 ConventionAttr::get(result.getContext(), Convention::Internal));
1733 properties.setLayers(ArrayAttr::get(parser.getContext(), {}));
1737ParseResult FExtModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1741 auto &properties = result.getOrAddProperties<Properties>();
1742 properties.setConvention(
1743 ConventionAttr::get(result.getContext(), Convention::Internal));
1744 properties.setKnownLayers(ArrayAttr::get(result.getContext(), {}));
1748ParseResult FIntModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1753ParseResult FMemModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1758LogicalResult FModuleOp::verify() {
1761 auto portTypes = getPortTypes();
1762 auto portLocs = getPortLocations();
1763 auto numPorts = portTypes.size();
1766 if (body->getNumArguments() != numPorts)
1767 return emitOpError(
"entry block must have ")
1768 << numPorts <<
" arguments to match module signature";
1771 for (
auto [arg, type, loc] : zip(body->getArguments(), portTypes, portLocs)) {
1772 if (arg.getType() != cast<TypeAttr>(type).getValue())
1773 return emitOpError(
"block argument types should match signature types");
1774 if (arg.getLoc() != cast<LocationAttr>(loc))
1776 "block argument locations should match signature locations");
1782LogicalResult FExtModuleOp::verify() {
1783 auto params = getParameters();
1785 auto checkParmValue = [&](Attribute elt) ->
bool {
1786 auto param = cast<ParamDeclAttr>(elt);
1787 auto value = param.getValue();
1788 if (isa<IntegerAttr, StringAttr, FloatAttr, hw::ParamVerbatimAttr>(value))
1790 emitError() <<
"has unknown extmodule parameter value '"
1791 << param.getName().getValue() <<
"' = " << value;
1795 if (!llvm::all_of(params, checkParmValue))
1800 known.insert_range(getKnownLayersAttr().getAsRange<SymbolRefAttr>());
1803 referenced.insert_range(getLayersAttr().getAsRange<SymbolRefAttr>());
1804 for (
auto attr : getPortTypes()) {
1805 auto type = cast<TypeAttr>(attr).getValue();
1807 if (
auto layer = refType.getLayer())
1808 referenced.insert(layer);
1812 "references unknown layers",
"unknown layers");
1815LogicalResult FIntModuleOp::verify() {
1816 auto params = getParameters();
1820 auto checkParmValue = [&](Attribute elt) ->
bool {
1821 auto param = cast<ParamDeclAttr>(elt);
1822 auto value = param.getValue();
1823 if (isa<IntegerAttr, StringAttr, FloatAttr>(value))
1825 emitError() <<
"has unknown intmodule parameter value '"
1826 << param.getName().getValue() <<
"' = " << value;
1830 if (!llvm::all_of(params, checkParmValue))
1837 CircuitOp circuitOp,
1838 SymbolTableCollection &symbolTable,
1840 auto layer = refType.getLayer();
1843 auto *layerOp = symbolTable.lookupSymbolIn(circuitOp, layer);
1845 return emitError(loc) << start <<
" associated with layer '" << layer
1846 <<
"', but this layer was not defined";
1847 if (!isa<LayerOp>(layerOp)) {
1848 auto diag = emitError(loc)
1849 << start <<
" associated with layer '" << layer
1850 <<
"', but symbol '" << layer <<
"' does not refer to a '"
1851 << LayerOp::getOperationName() <<
"' op";
1852 return diag.attachNote(layerOp->getLoc()) <<
"symbol refers to this op";
1858 SymbolTableCollection &symbolTable) {
1860 auto circuitOp =
module->getParentOfType<CircuitOp>();
1861 for (
size_t i = 0, e = module.getNumPorts(); i < e; ++i) {
1862 auto type =
module.getPortType(i);
1866 refType, module.getPortLocation(i), circuitOp, symbolTable,
1867 Twine(
"probe port '") + module.getPortName(i) +
"' is")))
1872 if (
auto classType = dyn_cast<ClassType>(type)) {
1873 auto className = classType.getNameAttr();
1874 auto classOp = dyn_cast_or_null<ClassLike>(
1875 symbolTable.lookupSymbolIn(circuitOp, className));
1877 return module.emitOpError() << "references unknown class " << className;
1880 if (failed(classOp.verifyType(classType,
1881 [&]() { return module.emitOpError(); })))
1886 if (
auto domainType = dyn_cast<DomainType>(type)) {
1888 domainType.verifySymbolUses(module.getOperation(), symbolTable)))
1897LogicalResult FModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1901 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
1902 for (
auto layer : getLayers()) {
1903 if (!symbolTable.lookupSymbolIn(circuitOp, cast<SymbolRefAttr>(layer)))
1904 return emitOpError() <<
"enables undefined layer '" << layer <<
"'";
1911FExtModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1915 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
1916 for (
auto layer : getKnownLayersAttr().getAsRange<SymbolRefAttr>()) {
1917 if (!symbolTable.lookupSymbolIn(circuitOp, layer))
1918 return emitOpError() <<
"knows undefined layer '" << layer <<
"'";
1920 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>()) {
1921 if (!symbolTable.lookupSymbolIn(circuitOp, layer))
1922 return emitOpError() <<
"enables undefined layer '" << layer <<
"'";
1929FIntModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1934FMemModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1938void FModuleOp::getAsmBlockArgumentNames(mlir::Region ®ion,
1943void FExtModuleOp::getAsmBlockArgumentNames(
1948StringAttr FExtModuleOp::getExtModuleNameAttr() {
1949 if (
auto defnameAttr = getDefnameAttr(); defnameAttr && !defnameAttr.empty())
1951 return getNameAttr();
1954StringRef FExtModuleOp::getExtModuleName() {
1955 if (
auto defname = getDefname(); defname && !defname->empty())
1960void FIntModuleOp::getAsmBlockArgumentNames(
1965void FMemModuleOp::getAsmBlockArgumentNames(
1970ArrayAttr FMemModuleOp::getParameters() {
return {}; }
1972ArrayAttr FModuleOp::getParameters() {
return {}; }
1974Convention FIntModuleOp::getConvention() {
return Convention::Internal; }
1976ConventionAttr FIntModuleOp::getConventionAttr() {
1977 return ConventionAttr::get(getContext(), getConvention());
1980Convention FMemModuleOp::getConvention() {
return Convention::Internal; }
1982ConventionAttr FMemModuleOp::getConventionAttr() {
1983 return ConventionAttr::get(getContext(), getConvention());
1991 ClassLike classOp, ClassType type,
1992 function_ref<InFlightDiagnostic()> emitError) {
1994 auto name = type.getNameAttr().getAttr();
1995 auto expectedName = classOp.getModuleNameAttr();
1996 if (name != expectedName)
1997 return emitError() <<
"type has wrong name, got " << name <<
", expected "
2000 auto elements = type.getElements();
2002 auto expectedNumElements = classOp.getNumPorts();
2004 return emitError() <<
"has wrong number of ports, got " <<
numElements
2005 <<
", expected " << expectedNumElements;
2007 auto portNames = classOp.getPortNames();
2008 auto portDirections = classOp.getPortDirections();
2009 auto portTypes = classOp.getPortTypes();
2012 auto element = elements[i];
2014 auto name = element.name;
2015 auto expectedName = portNames[i];
2016 if (name != expectedName)
2017 return emitError() <<
"port #" << i <<
" has wrong name, got " << name
2018 <<
", expected " << expectedName;
2021 auto expectedDirection =
Direction(portDirections[i]);
2023 return emitError() <<
"port " << name <<
" has wrong direction, got "
2027 auto type = element.type;
2028 auto expectedType = cast<TypeAttr>(portTypes[i]).getValue();
2029 if (type != expectedType)
2030 return emitError() <<
"port " << name <<
" has wrong type, got " << type
2031 <<
", expected " << expectedType;
2038 auto n = classOp.getNumPorts();
2039 SmallVector<ClassElement> elements;
2040 elements.reserve(n);
2041 for (
size_t i = 0; i < n; ++i)
2042 elements.push_back({classOp.getPortNameAttr(i), classOp.getPortType(i),
2043 classOp.getPortDirection(i)});
2044 auto name = FlatSymbolRefAttr::get(classOp.getModuleNameAttr());
2045 return ClassType::get(name, elements);
2048template <
typename OpTy>
2050 bool hasSSAIdentifiers) {
2051 auto *
context = result.getContext();
2052 auto &builder = parser.getBuilder();
2053 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
2057 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
2060 StringAttr nameAttr;
2061 if (parser.parseSymbolName(nameAttr))
2063 properties.setSymName(nameAttr);
2066 SmallVector<OpAsmParser::Argument> entryArgs;
2067 SmallVector<Direction, 4> portDirections;
2068 SmallVector<Attribute, 4> portNames;
2069 SmallVector<Attribute, 4> portTypes;
2070 SmallVector<Attribute, 4> portAnnotations;
2071 SmallVector<Attribute, 4> portSyms;
2072 SmallVector<Attribute, 4> portLocs;
2073 SmallVector<Attribute, 4> domains;
2076 entryArgs, portDirections, portNames, portTypes,
2077 portAnnotations, portSyms, portLocs, domains))
2081 for (
auto annos : portAnnotations)
2082 if (!cast<ArrayAttr>(annos).
empty())
2086 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
2089 assert(portNames.size() == portTypes.size());
2095 properties.setPortDirections(
2099 properties.setPortNames(builder.getArrayAttr(portNames));
2102 properties.setPortTypes(builder.getArrayAttr(portTypes));
2105 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
2106 properties.setPortSymbols(builder.getArrayAttr(portSyms));
2109 properties.setPortLocations(ArrayAttr::get(
context, portLocs));
2115 auto *bodyRegion = result.addRegion();
2117 if (hasSSAIdentifiers) {
2118 if (parser.parseRegion(*bodyRegion, entryArgs))
2120 if (bodyRegion->empty())
2121 bodyRegion->push_back(
new Block());
2127template <
typename ClassTy>
2132 StringRef visibilityAttrName =
2133 mlir::SymbolOpInterface::getDefaultVisibilityAttrName();
2134 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
2135 p << visibility.getValue() <<
' ';
2138 p.printSymbolName(cast<mlir::SymbolOpInterface>(op.getOperation()).getName());
2142 Region ®ion = op->getRegion(0);
2143 Block *body =
nullptr;
2144 if (!region.empty())
2145 body = ®ion.front();
2148 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
2149 {}, op.getPortSymbols(), op.getPortLocations(), {});
2152 SmallVector<StringRef, 8> omittedAttrs = {
2153 ClassTy::getSymNameAttrName(op->getName()),
2164 if (!needPortNamesAttr)
2165 omittedAttrs.push_back(
"portNames");
2167 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
2170 if (!region.empty()) {
2172 auto printEntryBlockArgs =
false;
2173 auto printBlockTerminators =
false;
2174 p.printRegion(region, printEntryBlockArgs, printBlockTerminators);
2182void ClassOp::build(OpBuilder &builder, OperationState &result, StringAttr name,
2183 ArrayRef<PortInfo> ports) {
2186 [](
const auto &port) {
return port.annotations.empty(); }) &&
2187 "class ports may not have annotations");
2192 auto *bodyRegion = result.regions[0].get();
2194 bodyRegion->push_back(body);
2197 for (
auto &elt : ports)
2198 body->addArgument(elt.type, elt.loc);
2201void ClassOp::build(::mlir::OpBuilder &odsBuilder,
2202 ::mlir::OperationState &odsState, Twine name,
2203 mlir::ArrayRef<mlir::StringRef> fieldNames,
2204 mlir::ArrayRef<mlir::Type> fieldTypes) {
2206 SmallVector<PortInfo, 10> ports;
2207 ports.reserve(fieldNames.size() * 2);
2208 for (
auto [fieldName, fieldType] : llvm::zip(fieldNames, fieldTypes)) {
2209 ports.emplace_back(odsBuilder.getStringAttr(fieldName +
"_in"), fieldType,
2211 ports.emplace_back(odsBuilder.getStringAttr(fieldName), fieldType,
2214 build(odsBuilder, odsState, odsBuilder.getStringAttr(name), ports);
2216 auto &body = odsState.regions[0]->getBlocks().front();
2217 auto prevLoc = odsBuilder.saveInsertionPoint();
2218 odsBuilder.setInsertionPointToEnd(&body);
2219 auto args = body.getArguments();
2220 auto loc = odsState.location;
2221 for (
unsigned i = 0, e = ports.size(); i != e; i += 2)
2222 PropAssignOp::create(odsBuilder, loc, args[i + 1], args[i]);
2224 odsBuilder.restoreInsertionPoint(prevLoc);
2226void ClassOp::print(OpAsmPrinter &p) {
2230ParseResult ClassOp::parse(OpAsmParser &parser, OperationState &result) {
2231 auto hasSSAIdentifiers =
true;
2235LogicalResult ClassOp::verify() {
2237 auto type = operand.getType();
2238 if (!isa<PropertyType>(type)) {
2239 emitOpError(
"ports on a class must be properties");
2248ClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2252void ClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2257SmallVector<PortInfo> ClassOp::getPorts() {
2258 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2261void ClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2262 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2266void ClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2267 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2270Convention ClassOp::getConvention() {
return Convention::Internal; }
2272ConventionAttr ClassOp::getConventionAttr() {
2273 return ConventionAttr::get(getContext(), getConvention());
2276ArrayAttr ClassOp::getParameters() {
return {}; }
2278ArrayAttr ClassOp::getPortAnnotationsAttr() {
2279 return ArrayAttr::get(getContext(), {});
2282ArrayRef<Attribute> ClassOp::getPortAnnotations() {
return {}; }
2284void ClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2285 llvm_unreachable(
"classes do not support annotations");
2288ArrayAttr ClassOp::getLayersAttr() {
return ArrayAttr::get(getContext(), {}); }
2290ArrayRef<Attribute> ClassOp::getLayers() {
return {}; }
2292SmallVector<::circt::hw::PortInfo> ClassOp::getPortList() {
2293 return ::getPortListImpl(*
this);
2297 return ::getPortImpl(*
this, idx);
2300BlockArgument ClassOp::getArgument(
size_t portNumber) {
2304bool ClassOp::canDiscardOnUseEmpty() {
2315void ExtClassOp::build(OpBuilder &builder, OperationState &result,
2316 StringAttr name, ArrayRef<PortInfo> ports) {
2319 [](
const auto &port) {
return port.annotations.empty(); }) &&
2320 "class ports may not have annotations");
2324void ExtClassOp::print(OpAsmPrinter &p) {
2328ParseResult ExtClassOp::parse(OpAsmParser &parser, OperationState &result) {
2329 auto hasSSAIdentifiers =
false;
2334ExtClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2338void ExtClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2343SmallVector<PortInfo> ExtClassOp::getPorts() {
2344 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2347void ExtClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2348 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2351void ExtClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2352 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2355Convention ExtClassOp::getConvention() {
return Convention::Internal; }
2357ConventionAttr ExtClassOp::getConventionAttr() {
2358 return ConventionAttr::get(getContext(), getConvention());
2361ArrayAttr ExtClassOp::getLayersAttr() {
2362 return ArrayAttr::get(getContext(), {});
2365ArrayRef<Attribute> ExtClassOp::getLayers() {
return {}; }
2367ArrayAttr ExtClassOp::getParameters() {
return {}; }
2369ArrayAttr ExtClassOp::getPortAnnotationsAttr() {
2370 return ArrayAttr::get(getContext(), {});
2373ArrayRef<Attribute> ExtClassOp::getPortAnnotations() {
return {}; }
2375void ExtClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2376 llvm_unreachable(
"classes do not support annotations");
2379SmallVector<::circt::hw::PortInfo> ExtClassOp::getPortList() {
2380 return ::getPortListImpl(*
this);
2384 return ::getPortImpl(*
this, idx);
2387bool ExtClassOp::canDiscardOnUseEmpty() {
2398void InstanceOp::build(
2399 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2400 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2401 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2402 ArrayRef<Attribute> domainInfo, ArrayRef<Attribute> annotations,
2403 ArrayRef<Attribute> portAnnotations, ArrayRef<Attribute> layers,
2404 bool lowerToBind,
bool doNotPrint, StringAttr innerSym) {
2405 build(builder, result, resultTypes, moduleName, name, nameKind,
2406 portDirections, portNames, domainInfo, annotations, portAnnotations,
2407 layers, lowerToBind, doNotPrint,
2408 innerSym ? hw::InnerSymAttr::get(innerSym) : hw::InnerSymAttr());
2411void InstanceOp::build(
2412 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2413 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2414 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2415 ArrayRef<Attribute> domainInfo, ArrayRef<Attribute> annotations,
2416 ArrayRef<Attribute> portAnnotations, ArrayRef<Attribute> layers,
2417 bool lowerToBind,
bool doNotPrint, hw::InnerSymAttr innerSym) {
2418 result.addTypes(resultTypes);
2419 result.getOrAddProperties<Properties>().setModuleName(
2420 SymbolRefAttr::get(builder.getContext(), moduleName));
2421 result.getOrAddProperties<Properties>().setName(builder.getStringAttr(name));
2422 result.getOrAddProperties<Properties>().setPortDirections(
2424 result.getOrAddProperties<Properties>().setPortNames(
2425 builder.getArrayAttr(portNames));
2427 if (domainInfo.empty()) {
2428 SmallVector<Attribute, 16> domainInfoVec(resultTypes.size(),
2429 builder.getArrayAttr({}));
2430 result.getOrAddProperties<Properties>().setDomainInfo(
2431 builder.getArrayAttr(domainInfoVec));
2433 assert(domainInfo.size() == resultTypes.size());
2434 result.getOrAddProperties<Properties>().setDomainInfo(
2435 builder.getArrayAttr(domainInfo));
2438 result.getOrAddProperties<Properties>().setAnnotations(
2439 builder.getArrayAttr(annotations));
2440 result.getOrAddProperties<Properties>().setLayers(
2441 builder.getArrayAttr(layers));
2443 result.getOrAddProperties<Properties>().setLowerToBind(
2444 builder.getUnitAttr());
2446 result.getOrAddProperties<Properties>().setDoNotPrint(
2447 builder.getUnitAttr());
2449 result.getOrAddProperties<Properties>().setInnerSym(innerSym);
2451 result.getOrAddProperties<Properties>().setNameKind(
2452 NameKindEnumAttr::get(builder.getContext(), nameKind));
2454 if (portAnnotations.empty()) {
2455 SmallVector<Attribute, 16> portAnnotationsVec(resultTypes.size(),
2456 builder.getArrayAttr({}));
2457 result.getOrAddProperties<Properties>().setPortAnnotations(
2458 builder.getArrayAttr(portAnnotationsVec));
2460 assert(portAnnotations.size() == resultTypes.size());
2461 result.getOrAddProperties<Properties>().setPortAnnotations(
2462 builder.getArrayAttr(portAnnotations));
2466void InstanceOp::build(OpBuilder &builder, OperationState &result,
2467 FModuleLike module, StringRef name,
2468 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2469 ArrayRef<Attribute> portAnnotations,
bool lowerToBind,
2470 bool doNotPrint, hw::InnerSymAttr innerSym) {
2473 SmallVector<Type> resultTypes;
2474 resultTypes.reserve(module.getNumPorts());
2476 module.getPortTypes(), std::back_inserter(resultTypes),
2477 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2482 ArrayAttr portAnnotationsAttr;
2483 if (portAnnotations.empty()) {
2484 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2485 resultTypes.size(), builder.getArrayAttr({})));
2487 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2489 ArrayAttr domainInfoAttr =
module.getDomainInfoAttr();
2490 if (domainInfoAttr.empty()) {
2491 domainInfoAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2492 resultTypes.size(), builder.getArrayAttr({})));
2496 builder, result, resultTypes,
2497 SymbolRefAttr::get(builder.getContext(), module.getModuleNameAttr()),
2498 builder.getStringAttr(name),
2499 NameKindEnumAttr::get(builder.getContext(), nameKind),
2500 module.getPortDirectionsAttr(), module.getPortNamesAttr(), domainInfoAttr,
2501 builder.getArrayAttr(annotations), portAnnotationsAttr,
2502 module.getLayersAttr(), lowerToBind ? builder.getUnitAttr() : UnitAttr(),
2503 doNotPrint ? builder.getUnitAttr() : UnitAttr(), innerSym);
2506void InstanceOp::build(OpBuilder &builder, OperationState &odsState,
2507 ArrayRef<PortInfo> ports, StringRef moduleName,
2508 StringRef name, NameKindEnum nameKind,
2509 ArrayRef<Attribute> annotations,
2510 ArrayRef<Attribute> layers,
bool lowerToBind,
2511 bool doNotPrint, hw::InnerSymAttr innerSym) {
2513 SmallVector<Type> newResultTypes;
2514 SmallVector<Direction> newPortDirections;
2515 SmallVector<Attribute> newPortNames, newPortAnnotations, newDomainInfo;
2516 newResultTypes.reserve(ports.size());
2517 newPortDirections.reserve(ports.size());
2518 newPortNames.reserve(ports.size());
2519 newPortAnnotations.reserve(ports.size());
2520 newDomainInfo.reserve(ports.size());
2522 for (
auto &p : ports) {
2523 newResultTypes.push_back(p.type);
2524 newPortDirections.push_back(p.direction);
2525 newPortNames.push_back(p.name);
2526 newPortAnnotations.push_back(p.annotations.getArrayAttr());
2528 newDomainInfo.push_back(p.domains);
2530 newDomainInfo.push_back(builder.getArrayAttr({}));
2533 return build(builder, odsState, newResultTypes, moduleName, name, nameKind,
2534 newPortDirections, newPortNames, newDomainInfo, annotations,
2535 newPortAnnotations, layers, lowerToBind, doNotPrint, innerSym);
2538LogicalResult InstanceOp::verify() {
2541 SmallVector<SymbolRefAttr> missingLayers;
2542 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
2544 missingLayers.push_back(layer);
2546 if (missingLayers.empty())
2550 emitOpError(
"ambient layers are insufficient to instantiate module");
2551 auto ¬e = diag.attachNote();
2552 note <<
"missing layer requirements: ";
2553 interleaveComma(missingLayers, note);
2558 Operation *op1, Operation *op2,
2559 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2561 size_t n = insertions.size();
2562 size_t inserted = 0;
2563 for (
size_t i = 0, e = op1->getNumResults(); i < e; ++i) {
2564 while (inserted < n) {
2565 auto &[index, portInfo] = insertions[inserted];
2570 auto r1 = op1->getResult(i);
2571 auto r2 = op2->getResult(i + inserted);
2572 r1.replaceAllUsesWith(r2);
2577 const llvm::BitVector &erasures) {
2580 for (
size_t i = 0, e = op1->getNumResults(); i < e; ++i) {
2581 auto r1 = op1->getResult(i);
2583 assert(r1.use_empty() &&
"removed instance port has uses");
2587 auto r2 = op2->getResult(i - erased);
2588 r1.replaceAllUsesWith(r2);
2593InstanceOp::cloneWithErasedPorts(
const llvm::BitVector &erasures) {
2594 assert(erasures.size() >= getNumResults() &&
2595 "erasures is not at least as large as getNumResults()");
2598 SmallVector<Type>(result_type_begin(), result_type_end()), erasures);
2601 SmallVector<Attribute> newPortNames =
2603 SmallVector<Attribute> newPortAnnotations =
2605 ArrayAttr newDomainInfo =
2609 OpBuilder builder(*
this);
2610 auto clone = InstanceOp::create(
2611 builder,
getLoc(), newResultTypes, getModuleName(),
getName(),
2612 getNameKind(), newPortDirections, newPortNames, newDomainInfo.getValue(),
2613 getAnnotations().getValue(), newPortAnnotations, getLayers(),
2614 getLowerToBind(), getDoNotPrint(), getInnerSymAttr());
2616 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2617 clone->setAttr(
"output_file", outputFile);
2622FInstanceLike InstanceOp::cloneWithErasedPortsAndReplaceUses(
2623 const llvm::BitVector &erasures) {
2629ArrayAttr InstanceOp::getPortAnnotation(
unsigned portIdx) {
2630 assert(portIdx < getNumResults() &&
2631 "index should be smaller than result number");
2632 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
2635void InstanceOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
2636 assert(annotations.size() == getNumResults() &&
2637 "number of annotations is not equal to result number");
2638 (*this)->setAttr(
"portAnnotations",
2639 ArrayAttr::get(getContext(), annotations));
2642FInstanceLike InstanceOp::cloneWithInsertedPorts(
2643 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2647 auto oldPortCount = getNumResults();
2648 auto numInsertions = insertions.size();
2649 auto newPortCount = oldPortCount + numInsertions;
2651 SmallVector<Direction> newPortDirections;
2652 SmallVector<Attribute> newPortNames;
2653 SmallVector<Type> newPortTypes;
2654 SmallVector<Attribute> newPortAnnos;
2655 SmallVector<Attribute> newDomainInfo;
2657 newPortDirections.reserve(newPortCount);
2658 newPortNames.reserve(newPortCount);
2659 newPortTypes.reserve(newPortCount);
2660 newPortAnnos.reserve(newPortCount);
2661 newDomainInfo.reserve(newPortCount);
2667 SmallVector<unsigned> indexMap(oldPortCount);
2668 size_t inserted = 0;
2669 for (
size_t i = 0; i < oldPortCount; ++i) {
2670 while (inserted < numInsertions && insertions[inserted].first <= i)
2672 indexMap[i] = i + inserted;
2677 for (
size_t i = 0; i < oldPortCount; ++i) {
2678 while (inserted < numInsertions) {
2679 auto &[index,
info] = insertions[inserted];
2685 newPortDirections.push_back(
info.direction);
2686 newPortNames.push_back(
info.name);
2687 newPortTypes.push_back(
info.type);
2688 newPortAnnos.push_back(
info.annotations.getArrayAttr());
2689 newDomainInfo.push_back(domains);
2693 newPortDirections.push_back(getPortDirection(i));
2694 newPortNames.push_back(getPortNameAttr(i));
2695 newPortTypes.push_back(getType(i));
2696 newPortAnnos.push_back(getPortAnnotation(i));
2699 newDomainInfo.push_back(domains);
2702 while (inserted < numInsertions) {
2703 auto &[index,
info] = insertions[inserted];
2706 newPortDirections.push_back(
info.direction);
2707 newPortNames.push_back(
info.name);
2708 newPortTypes.push_back(
info.type);
2709 newPortAnnos.push_back(
info.annotations.getArrayAttr());
2710 newDomainInfo.push_back(domains);
2714 OpBuilder builder(*
this);
2715 auto clone = InstanceOp::create(
2716 builder,
getLoc(), newPortTypes, getModuleName(),
getName(),
2717 getNameKind(), newPortDirections, newPortNames, newDomainInfo,
2718 getAnnotations().getValue(), newPortAnnos, getLayers(), getLowerToBind(),
2719 getDoNotPrint(), getInnerSymAttr());
2721 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2722 clone->setAttr(
"output_file", outputFile);
2727FInstanceLike InstanceOp::cloneWithInsertedPortsAndReplaceUses(
2728 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2729 auto clone = cloneWithInsertedPorts(insertions);
2734LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2736 getModuleNameAttr());
2739StringRef InstanceOp::getInstanceName() {
return getName(); }
2741StringAttr InstanceOp::getInstanceNameAttr() {
return getNameAttr(); }
2743void InstanceOp::print(OpAsmPrinter &p) {
2746 p.printKeywordOrString(
getName());
2747 if (
auto attr = getInnerSymAttr()) {
2749 p.printSymbolName(attr.getSymName());
2751 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2752 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2755 SmallVector<StringRef, 10> omittedAttrs = {
2756 "moduleName",
"name",
"portDirections",
2757 "portNames",
"portTypes",
"portAnnotations",
2758 "inner_sym",
"nameKind",
"domainInfo"};
2759 if (getAnnotations().
empty())
2760 omittedAttrs.push_back(
"annotations");
2761 if (getLayers().
empty())
2762 omittedAttrs.push_back(
"layers");
2763 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2767 p.printSymbolName(getModuleName());
2770 SmallVector<Attribute> portTypes;
2771 portTypes.reserve(getNumResults());
2772 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2776 getPortNames().getValue(), portTypes,
2777 getPortAnnotations().getValue(), {}, {},
2778 getDomainInfo().getValue());
2781ParseResult InstanceOp::parse(OpAsmParser &parser, OperationState &result) {
2782 auto *
context = parser.getContext();
2783 auto &properties = result.getOrAddProperties<Properties>();
2786 hw::InnerSymAttr innerSymAttr;
2787 FlatSymbolRefAttr moduleName;
2788 SmallVector<OpAsmParser::Argument> entryArgs;
2789 SmallVector<Direction, 4> portDirections;
2790 SmallVector<Attribute, 4> portNames;
2791 SmallVector<Attribute, 4> portTypes;
2792 SmallVector<Attribute, 4> portAnnotations;
2793 SmallVector<Attribute, 4> portSyms;
2794 SmallVector<Attribute, 4> portLocs;
2795 SmallVector<Attribute, 4> domains;
2796 NameKindEnumAttr nameKind;
2798 if (parser.parseKeywordOrString(&name))
2800 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
2801 if (parser.parseCustomAttributeWithFallback(
2802 innerSymAttr, ::mlir::Type{},
2804 result.attributes)) {
2805 return ::mlir::failure();
2809 parser.parseOptionalAttrDict(result.attributes) ||
2810 parser.parseAttribute(moduleName) ||
2813 entryArgs, portDirections, portNames, portTypes,
2814 portAnnotations, portSyms, portLocs, domains))
2820 properties.setModuleName(moduleName);
2821 properties.setName(StringAttr::get(
context, name));
2822 properties.setNameKind(nameKind);
2823 properties.setPortDirections(
2825 properties.setPortNames(ArrayAttr::get(
context, portNames));
2826 properties.setPortAnnotations(ArrayAttr::get(
context, portAnnotations));
2830 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
2831 properties.setLayers(parser.getBuilder().getArrayAttr({}));
2834 properties.setDomainInfo(ArrayAttr::get(
context, domains));
2837 result.types.reserve(portTypes.size());
2839 portTypes, std::back_inserter(result.types),
2840 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2850 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
2851 setNameFn(getResult(i), (base +
"_" + getPortName(i)).str());
2855std::optional<size_t> InstanceOp::getTargetResultIndex() {
2857 return std::nullopt;
2864void InstanceChoiceOp::build(
2865 OpBuilder &builder, OperationState &result, FModuleLike defaultModule,
2866 ArrayRef<std::pair<OptionCaseOp, FModuleLike>> cases, StringRef name,
2867 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2868 ArrayRef<Attribute> portAnnotations, StringAttr innerSym,
2869 FlatSymbolRefAttr instanceMacro) {
2871 SmallVector<Type> resultTypes;
2872 for (Attribute portType : defaultModule.getPortTypes())
2873 resultTypes.push_back(cast<TypeAttr>(portType).getValue());
2876 ArrayAttr portAnnotationsAttr;
2877 if (portAnnotations.empty()) {
2878 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2879 resultTypes.size(), builder.getArrayAttr({})));
2881 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2885 ArrayAttr domainInfoAttr = defaultModule.getDomainInfoAttr();
2886 if (domainInfoAttr.empty()) {
2887 domainInfoAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2888 resultTypes.size(), builder.getArrayAttr({})));
2892 SmallVector<Attribute> moduleNames, caseNames;
2893 moduleNames.push_back(SymbolRefAttr::get(defaultModule.getModuleNameAttr()));
2894 for (
auto [caseOption, caseModule] : cases) {
2895 auto caseGroup = caseOption->getParentOfType<OptionOp>();
2896 caseNames.push_back(SymbolRefAttr::get(caseGroup.getSymNameAttr(),
2897 {SymbolRefAttr::get(caseOption)}));
2898 moduleNames.push_back(SymbolRefAttr::get(caseModule.getModuleNameAttr()));
2901 return build(builder, result, resultTypes, builder.getArrayAttr(moduleNames),
2902 builder.getArrayAttr(caseNames), builder.getStringAttr(name),
2903 NameKindEnumAttr::get(builder.getContext(), nameKind),
2904 defaultModule.getPortDirectionsAttr(),
2905 defaultModule.getPortNamesAttr(), domainInfoAttr,
2906 builder.getArrayAttr(annotations), portAnnotationsAttr,
2907 defaultModule.getLayersAttr(),
2908 innerSym ? hw::InnerSymAttr::get(innerSym) : hw::InnerSymAttr(),
2912void InstanceChoiceOp::build(OpBuilder &builder, OperationState &odsState,
2913 ArrayRef<PortInfo> ports, ArrayAttr moduleNames,
2914 ArrayAttr caseNames, StringRef name,
2915 NameKindEnum nameKind, ArrayAttr annotations,
2916 ArrayAttr layers, hw::InnerSymAttr innerSym,
2917 FlatSymbolRefAttr instanceMacro) {
2919 SmallVector<Type> newResultTypes;
2920 SmallVector<bool> newPortDirections;
2921 SmallVector<Attribute> newPortNames, newPortAnnotations, newDomainInfo;
2922 newPortDirections.reserve(ports.size());
2923 newResultTypes.reserve(ports.size());
2924 newPortAnnotations.reserve(ports.size());
2925 newDomainInfo.reserve(ports.size());
2926 newPortNames.reserve(ports.size());
2927 for (
auto &p : ports) {
2928 newResultTypes.push_back(p.type);
2930 newPortDirections.push_back(p.direction == Direction::Out);
2931 newPortNames.push_back(p.name);
2932 newPortAnnotations.push_back(p.annotations.getArrayAttr());
2934 newDomainInfo.push_back(p.domains);
2936 newDomainInfo.push_back(builder.getArrayAttr({}));
2939 return build(builder, odsState, newResultTypes, moduleNames, caseNames, name,
2940 nameKind, newPortDirections, builder.getArrayAttr(newPortNames),
2941 builder.getArrayAttr(newDomainInfo), annotations,
2942 builder.getArrayAttr(newPortAnnotations), layers.getValue(),
2943 innerSym, instanceMacro);
2946std::optional<size_t> InstanceChoiceOp::getTargetResultIndex() {
2947 return std::nullopt;
2950StringRef InstanceChoiceOp::getInstanceName() {
return getName(); }
2952StringAttr InstanceChoiceOp::getInstanceNameAttr() {
return getNameAttr(); }
2954ArrayAttr InstanceChoiceOp::getReferencedModuleNamesAttr() {
2956 auto moduleNames = getModuleNamesAttr();
2957 SmallVector<Attribute> moduleNameStrings;
2958 moduleNameStrings.reserve(moduleNames.size());
2959 for (
auto moduleName : moduleNames)
2960 moduleNameStrings.push_back(cast<FlatSymbolRefAttr>(moduleName).getAttr());
2962 return ArrayAttr::get(getContext(), moduleNameStrings);
2965void InstanceChoiceOp::print(OpAsmPrinter &p) {
2968 p.printKeywordOrString(
getName());
2969 if (
auto attr = getInnerSymAttr()) {
2971 p.printSymbolName(attr.getSymName());
2973 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2974 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2977 SmallVector<StringRef, 11> omittedAttrs = {
2978 "moduleNames",
"caseNames",
"name",
2979 "portDirections",
"portNames",
"portTypes",
2980 "portAnnotations",
"inner_sym",
"nameKind",
2982 if (getAnnotations().
empty())
2983 omittedAttrs.push_back(
"annotations");
2984 if (getLayers().
empty())
2985 omittedAttrs.push_back(
"layers");
2986 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2991 auto moduleNames = getModuleNamesAttr();
2992 auto caseNames = getCaseNamesAttr();
2994 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[0]).getValue());
2996 p <<
" alternatives ";
2998 cast<SymbolRefAttr>(caseNames[0]).getRootReference().getValue());
3000 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3004 auto symbol = cast<SymbolRefAttr>(caseNames[i]);
3005 p.printSymbolName(symbol.getNestedReferences()[0].getValue());
3007 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[i + 1]).getValue());
3013 SmallVector<Attribute> portTypes;
3014 portTypes.reserve(getNumResults());
3015 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
3018 getPortNames().getValue(), portTypes,
3019 getPortAnnotations().getValue(), {}, {},
3020 getDomainInfo().getValue());
3023ParseResult InstanceChoiceOp::parse(OpAsmParser &parser,
3024 OperationState &result) {
3025 auto *
context = parser.getContext();
3026 auto &properties = result.getOrAddProperties<Properties>();
3029 hw::InnerSymAttr innerSymAttr;
3030 SmallVector<Attribute> moduleNames;
3031 SmallVector<Attribute> caseNames;
3032 SmallVector<OpAsmParser::Argument> entryArgs;
3033 SmallVector<Direction, 4> portDirections;
3034 SmallVector<Attribute, 4> portNames;
3035 SmallVector<Attribute, 4> portTypes;
3036 SmallVector<Attribute, 4> portAnnotations;
3037 SmallVector<Attribute, 4> portSyms;
3038 SmallVector<Attribute, 4> portLocs;
3039 SmallVector<Attribute, 4> domains;
3040 NameKindEnumAttr nameKind;
3042 if (parser.parseKeywordOrString(&name))
3044 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
3045 if (parser.parseCustomAttributeWithFallback(
3046 innerSymAttr, Type{},
3048 result.attributes)) {
3053 parser.parseOptionalAttrDict(result.attributes))
3056 FlatSymbolRefAttr defaultModuleName;
3057 if (parser.parseAttribute(defaultModuleName))
3059 moduleNames.push_back(defaultModuleName);
3063 FlatSymbolRefAttr optionName;
3064 if (parser.parseKeyword(
"alternatives") ||
3065 parser.parseAttribute(optionName) || parser.parseLBrace())
3068 FlatSymbolRefAttr moduleName;
3069 StringAttr caseName;
3070 while (succeeded(parser.parseOptionalSymbolName(caseName))) {
3071 if (parser.parseArrow() || parser.parseAttribute(moduleName))
3073 moduleNames.push_back(moduleName);
3074 caseNames.push_back(SymbolRefAttr::get(
3075 optionName.getAttr(), {FlatSymbolRefAttr::get(caseName)}));
3076 if (failed(parser.parseOptionalComma()))
3079 if (parser.parseRBrace())
3085 entryArgs, portDirections, portNames, portTypes,
3086 portAnnotations, portSyms, portLocs, domains))
3091 properties.setModuleNames(ArrayAttr::get(
context, moduleNames));
3092 properties.setCaseNames(ArrayAttr::get(
context, caseNames));
3093 properties.setName(StringAttr::get(
context, name));
3094 properties.setNameKind(nameKind);
3095 properties.setPortDirections(
3097 properties.setPortNames(ArrayAttr::get(
context, portNames));
3098 properties.setDomainInfo(ArrayAttr::get(
context, domains));
3099 properties.setPortAnnotations(ArrayAttr::get(
context, portAnnotations));
3103 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
3104 properties.setLayers(parser.getBuilder().getArrayAttr({}));
3107 result.types.reserve(portTypes.size());
3109 portTypes, std::back_inserter(result.types),
3110 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
3117 for (
auto [result, name] : llvm::zip(getResults(), getPortNames()))
3118 setNameFn(result, (base +
"_" + cast<StringAttr>(name).getValue()).str());
3121LogicalResult InstanceChoiceOp::verify() {
3122 if (getCaseNamesAttr().
empty())
3123 return emitOpError() <<
"must have at least one case";
3124 if (getModuleNamesAttr().size() != getCaseNamesAttr().size() + 1)
3125 return emitOpError() <<
"number of referenced modules does not match the "
3126 "number of options";
3131 SmallVector<SymbolRefAttr> missingLayers;
3132 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
3134 missingLayers.push_back(layer);
3136 if (missingLayers.empty())
3140 emitOpError(
"ambient layers are insufficient to instantiate module");
3141 auto ¬e = diag.attachNote();
3142 note <<
"missing layer requirements: ";
3143 interleaveComma(missingLayers, note);
3148InstanceChoiceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3149 auto caseNames = getCaseNamesAttr();
3150 for (
auto moduleName : getModuleNamesAttr()) {
3151 auto moduleNameRef = cast<FlatSymbolRefAttr>(moduleName);
3157 auto referencedModule =
3158 symbolTable.lookupNearestSymbolFrom<FModuleLike>(*
this, moduleNameRef);
3159 if (isa<FIntModuleOp>(referencedModule))
3160 return emitOpError(
"intmodule must be instantiated with instance op, "
3161 "not via 'firrtl.instance_choice'");
3164 auto root = cast<SymbolRefAttr>(caseNames[0]).getRootReference();
3165 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3166 auto ref = cast<SymbolRefAttr>(caseNames[i]);
3167 auto refRoot = ref.getRootReference();
3168 if (ref.getRootReference() != root)
3169 return emitOpError() <<
"case " << ref
3170 <<
" is not in the same option group as "
3173 if (!symbolTable.lookupNearestSymbolFrom<OptionOp>(*
this, refRoot))
3174 return emitOpError() <<
"option " << refRoot <<
" does not exist";
3176 if (!symbolTable.lookupNearestSymbolFrom<OptionCaseOp>(*
this, ref))
3177 return emitOpError() <<
"option " << refRoot
3178 <<
" does not contain option case " << ref;
3181 if (
auto instanceMacro = getInstanceMacroAttr())
3182 if (!symbolTable.lookupNearestSymbolFrom(*
this, instanceMacro))
3183 return emitOpError() <<
"instance_macro " << instanceMacro
3184 <<
" does not exist";
3190InstanceChoiceOp::getTargetOrDefaultAttr(OptionCaseOp option) {
3191 auto caseNames = getCaseNamesAttr();
3192 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3193 StringAttr caseSym = cast<SymbolRefAttr>(caseNames[i]).getLeafReference();
3194 if (caseSym == option.getSymName())
3195 return cast<FlatSymbolRefAttr>(getModuleNamesAttr()[i + 1]);
3197 return getDefaultTargetAttr();
3200SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1>
3201InstanceChoiceOp::getTargetChoices() {
3202 auto caseNames = getCaseNamesAttr();
3203 auto moduleNames = getModuleNamesAttr();
3204 SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1> choices;
3205 for (
size_t i = 0; i < caseNames.size(); ++i) {
3206 choices.emplace_back(cast<SymbolRefAttr>(caseNames[i]),
3207 cast<FlatSymbolRefAttr>(moduleNames[i + 1]));
3213FInstanceLike InstanceChoiceOp::cloneWithInsertedPorts(
3214 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
3218 auto oldPortCount = getNumResults();
3219 auto numInsertions = insertions.size();
3220 auto newPortCount = oldPortCount + numInsertions;
3222 SmallVector<Direction> newPortDirections;
3223 SmallVector<Attribute> newPortNames;
3224 SmallVector<Type> newPortTypes;
3225 SmallVector<Attribute> newPortAnnos;
3226 SmallVector<Attribute> newDomainInfo;
3228 newPortDirections.reserve(newPortCount);
3229 newPortNames.reserve(newPortCount);
3230 newPortTypes.reserve(newPortCount);
3231 newPortAnnos.reserve(newPortCount);
3232 newDomainInfo.reserve(newPortCount);
3238 SmallVector<unsigned> indexMap(oldPortCount);
3239 size_t inserted = 0;
3240 for (
size_t i = 0; i < oldPortCount; ++i) {
3241 while (inserted < numInsertions && insertions[inserted].first <= i)
3243 indexMap[i] = i + inserted;
3248 for (
size_t i = 0; i < oldPortCount; ++i) {
3249 while (inserted < numInsertions) {
3250 auto &[index,
info] = insertions[inserted];
3256 newPortDirections.push_back(
info.direction);
3257 newPortNames.push_back(
info.name);
3258 newPortTypes.push_back(
info.type);
3259 newPortAnnos.push_back(
info.annotations.getArrayAttr());
3260 newDomainInfo.push_back(domains);
3264 newPortDirections.push_back(getPortDirection(i));
3265 newPortNames.push_back(getPortNameAttr(i));
3266 newPortTypes.push_back(getType(i));
3267 newPortAnnos.push_back(getPortAnnotations()[i]);
3270 newDomainInfo.push_back(domains);
3273 while (inserted < numInsertions) {
3274 auto &[index,
info] = insertions[inserted];
3277 newPortDirections.push_back(
info.direction);
3278 newPortNames.push_back(
info.name);
3279 newPortTypes.push_back(
info.type);
3280 newPortAnnos.push_back(
info.annotations.getArrayAttr());
3281 newDomainInfo.push_back(domains);
3285 OpBuilder builder(*
this);
3286 auto clone = InstanceChoiceOp::create(
3287 builder,
getLoc(), newPortTypes, getModuleNames(), getCaseNames(),
3290 ArrayAttr::get(
context, newPortNames),
3291 ArrayAttr::get(
context, newDomainInfo), getAnnotationsAttr(),
3292 ArrayAttr::get(
context, newPortAnnos), getLayers(), getInnerSymAttr(),
3293 getInstanceMacroAttr());
3295 if (
auto outputFile = (*this)->getAttr(
"output_file"))
3296 clone->setAttr(
"output_file", outputFile);
3301FInstanceLike InstanceChoiceOp::cloneWithInsertedPortsAndReplaceUses(
3302 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
3303 auto clone = cloneWithInsertedPorts(insertions);
3309InstanceChoiceOp::cloneWithErasedPorts(
const llvm::BitVector &erasures) {
3310 assert(erasures.size() >= getNumResults() &&
3311 "erasures is not at least as large as getNumResults()");
3314 SmallVector<Type>(result_type_begin(), result_type_end()), erasures);
3317 SmallVector<Attribute> newPortNames =
3319 SmallVector<Attribute> newPortAnnotations =
3321 ArrayAttr newPortDomains =
3325 OpBuilder builder(*
this);
3326 auto clone = InstanceChoiceOp::create(
3327 builder,
getLoc(), newResultTypes, getModuleNames(), getCaseNames(),
3330 ArrayAttr::get(getContext(), newPortNames), newPortDomains,
3331 getAnnotationsAttr(), ArrayAttr::get(getContext(), newPortAnnotations),
3332 getLayers(), getInnerSymAttr(), getInstanceMacroAttr());
3334 if (
auto outputFile = (*this)->getAttr(
"output_file"))
3335 clone->setAttr(
"output_file", outputFile);
3340FInstanceLike InstanceChoiceOp::cloneWithErasedPortsAndReplaceUses(
3341 const llvm::BitVector &erasures) {
3351ArrayAttr MemOp::getPortAnnotation(
unsigned portIdx) {
3352 assert(portIdx < getNumResults() &&
3353 "index should be smaller than result number");
3354 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
3357void MemOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
3358 assert(annotations.size() == getNumResults() &&
3359 "number of annotations is not equal to result number");
3360 (*this)->setAttr(
"portAnnotations",
3361 ArrayAttr::get(getContext(), annotations));
3365void MemOp::getNumPorts(
size_t &numReadPorts,
size_t &numWritePorts,
3366 size_t &numReadWritePorts,
size_t &numDbgsPorts) {
3369 numReadWritePorts = 0;
3371 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3372 auto portKind = getPortKind(i);
3373 if (portKind == MemOp::PortKind::Debug)
3375 else if (portKind == MemOp::PortKind::Read)
3377 else if (portKind == MemOp::PortKind::Write) {
3380 ++numReadWritePorts;
3385LogicalResult MemOp::verify() {
3389 llvm::SmallDenseSet<Attribute, 8> portNamesSet;
3395 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3396 auto portName = getPortNameAttr(i);
3401 BundleType portBundleType =
3405 if (!portNamesSet.insert(portName).second) {
3406 emitOpError() <<
"has non-unique port name " << portName;
3414 auto elt = getPortNamed(portName);
3416 emitOpError() <<
"could not get port with name " << portName;
3422 if (portKind == MemOp::PortKind::Debug &&
3424 return emitOpError() <<
"has an invalid type on port " << portName
3425 <<
" (expected Read/Write/ReadWrite/Debug)";
3427 return emitOpError()
3428 <<
"cannot have only one port of debug type. Debug port can only "
3429 "exist alongside other read/write/read-write port";
3434 if (portKind == MemOp::PortKind::Debug) {
3437 return emitOpError() <<
"debug ports must be a RefType of FVectorType";
3440 auto dataTypeOption = portBundleType.getElement(
"data");
3441 if (!dataTypeOption && portKind == MemOp::PortKind::ReadWrite)
3442 dataTypeOption = portBundleType.getElement(
"wdata");
3443 if (!dataTypeOption) {
3444 emitOpError() <<
"has no data field on port " << portName
3445 <<
" (expected to see \"data\" for a read or write "
3446 "port or \"rdata\" for a read/write port)";
3449 dataType = dataTypeOption->type;
3451 if (portKind == MemOp::PortKind::Read) {
3458 emitOpError() <<
"has non-passive data type on port " << portName
3459 <<
" (memory types must be passive)";
3464 if (dataType.containsAnalog()) {
3465 emitOpError() <<
"has a data type that contains an analog type on port "
3467 <<
" (memory types cannot contain analog types)";
3475 getTypeForPort(getDepth(), dataType, portKind,
3476 dataType.isGround() ? getMaskBits() : 0);
3479 auto originalType = getResult(i).getType();
3480 if (originalType != expectedType) {
3481 StringRef portKindName;
3483 case MemOp::PortKind::Read:
3484 portKindName =
"read";
3486 case MemOp::PortKind::Write:
3487 portKindName =
"write";
3489 case MemOp::PortKind::ReadWrite:
3490 portKindName =
"readwrite";
3492 case MemOp::PortKind::Debug:
3493 portKindName =
"dbg";
3496 emitOpError() <<
"has an invalid type for port " << portName
3497 <<
" of determined kind \"" << portKindName
3498 <<
"\" (expected " << expectedType <<
", but got "
3499 << originalType <<
")";
3505 if (oldDataType && oldDataType != dataType) {
3506 emitOpError() <<
"port " << getPortNameAttr(i)
3507 <<
" has a different type than port "
3508 << getPortNameAttr(i - 1) <<
" (expected " << oldDataType
3509 <<
", but got " << dataType <<
")";
3513 oldDataType = dataType;
3516 auto maskWidth = getMaskBits();
3518 auto dataWidth = getDataType().getBitWidthOrSentinel();
3519 if (dataWidth > 0 && maskWidth > (
size_t)dataWidth)
3520 return emitOpError(
"the mask width cannot be greater than "
3523 if (getPortAnnotations().size() != getNumResults())
3524 return emitOpError(
"the number of result annotations should be "
3525 "equal to the number of results");
3531 return std::max(1U, llvm::Log2_64_Ceil(depth));
3537 PortKind portKind,
size_t maskBits) {
3539 auto *
context = dataType.getContext();
3540 if (portKind == PortKind::Debug)
3541 return RefType::get(FVectorType::get(dataType, depth));
3547 maskType = UIntType::get(
context, maskBits);
3549 auto getId = [&](StringRef name) -> StringAttr {
3550 return StringAttr::get(
context, name);
3553 SmallVector<BundleType::BundleElement, 7> portFields;
3557 portFields.push_back({getId(
"addr"),
false, addressType});
3558 portFields.push_back({getId(
"en"),
false, UIntType::get(
context, 1)});
3559 portFields.push_back({getId(
"clk"),
false, ClockType::get(
context)});
3562 case PortKind::Read:
3563 portFields.push_back({getId(
"data"),
true, dataType});
3566 case PortKind::Write:
3567 portFields.push_back({getId(
"data"),
false, dataType});
3568 portFields.push_back({getId(
"mask"),
false, maskType});
3571 case PortKind::ReadWrite:
3572 portFields.push_back({getId(
"rdata"),
true, dataType});
3573 portFields.push_back({getId(
"wmode"),
false, UIntType::get(
context, 1)});
3574 portFields.push_back({getId(
"wdata"),
false, dataType});
3575 portFields.push_back({getId(
"wmask"),
false, maskType});
3578 llvm::report_fatal_error(
"memory port kind not handled");
3582 return BundleType::get(
context, portFields);
3586SmallVector<MemOp::NamedPort> MemOp::getPorts() {
3587 SmallVector<MemOp::NamedPort> result;
3589 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3598MemOp::PortKind MemOp::getPortKind(StringRef portName) {
3604MemOp::PortKind MemOp::getPortKind(
size_t resultNo) {
3610size_t MemOp::getMaskBits() {
3612 for (
auto res : getResults()) {
3622 if (t.name.getValue().contains(
"mask"))
3635 assert(getNumResults() != 0 &&
"Mems with no read/write ports are illegal");
3641 StringRef dataFieldName =
"data";
3643 dataFieldName =
"rdata";
3646 .getElementType(dataFieldName);
3649StringAttr MemOp::getPortNameAttr(
size_t resultNo) {
3650 return cast<StringAttr>(getPortNames()[resultNo]);
3657Value MemOp::getPortNamed(StringAttr name) {
3658 auto namesArray = getPortNames();
3659 for (
size_t i = 0, e = namesArray.size(); i != e; ++i) {
3660 if (namesArray[i] == name) {
3661 assert(i < getNumResults() &&
" names array out of sync with results");
3662 return getResult(i);
3671 size_t numReadPorts = 0;
3672 size_t numWritePorts = 0;
3673 size_t numReadWritePorts = 0;
3675 SmallVector<int32_t> writeClockIDs;
3677 for (
size_t i = 0, e = op.getNumResults(); i != e; ++i) {
3678 auto portKind = op.getPortKind(i);
3679 if (portKind == MemOp::PortKind::Read)
3681 else if (portKind == MemOp::PortKind::Write) {
3682 for (
auto *a : op.getResult(i).getUsers()) {
3683 auto subfield = dyn_cast<SubfieldOp>(a);
3684 if (!subfield || subfield.getFieldIndex() != 2)
3686 auto clockPort = a->getResult(0);
3687 for (
auto *b : clockPort.getUsers()) {
3688 if (
auto connect = dyn_cast<FConnectLike>(b)) {
3689 if (
connect.getDest() == clockPort) {
3692 connect.getSrc(),
true,
true,
true),
3694 if (result.second) {
3695 writeClockIDs.push_back(numWritePorts);
3697 writeClockIDs.push_back(result.first->second);
3706 ++numReadWritePorts;
3713 op.emitError(
"'firrtl.mem' should have simple type and known width");
3714 MemoryInitAttr init = op->getAttrOfType<MemoryInitAttr>(
"init");
3716 if (op->hasAttr(
"modName"))
3717 modName = op->getAttrOfType<StringAttr>(
"modName");
3719 SmallString<8> clocks;
3720 for (
auto a : writeClockIDs)
3721 clocks.append(Twine((
char)(a +
'a')).str());
3722 SmallString<32> initStr;
3727 for (
auto c : init.getFilename().getValue())
3728 if ((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') ||
3729 (c >=
'0' && c <=
'9'))
3730 initStr.push_back(c);
3731 initStr.push_back(
'_');
3732 initStr.push_back(init.getIsBinary() ?
't' :
'f');
3733 initStr.push_back(
'_');
3734 initStr.push_back(init.getIsInline() ?
't' :
'f');
3736 modName = StringAttr::get(
3739 "{0}FIRRTLMem_{1}_{2}_{3}_{4}_{5}_{6}_{7}_{8}_{9}_{10}{11}{12}",
3740 op.getPrefix().value_or(
""), numReadPorts, numWritePorts,
3741 numReadWritePorts, (
size_t)width, op.getDepth(),
3742 op.getReadLatency(), op.getWriteLatency(), op.getMaskBits(),
3743 (
unsigned)op.getRuw(), (
unsigned)seq::WUW::PortOrder,
3744 clocks.empty() ?
"" :
"_" + clocks, init ? initStr.str() :
""));
3746 return {numReadPorts,
3751 op.getReadLatency(),
3752 op.getWriteLatency(),
3754 *seq::symbolizeRUW(
unsigned(op.getRuw())),
3755 seq::WUW::PortOrder,
3758 op.getMaskBits() > 1,
3769 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
3770 setNameFn(getResult(i), (base +
"_" + getPortName(i)).str());
3774std::optional<size_t> MemOp::getTargetResultIndex() {
3776 return std::nullopt;
3787 setNameFn(op.getDataRaw(), name);
3788 if (op.isForceable())
3789 setNameFn(op.getDataRef(), (name +
"_ref").str());
3796LogicalResult NodeOp::inferReturnTypes(
3797 mlir::MLIRContext *
context, std::optional<mlir::Location> location,
3798 ::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes,
3799 ::mlir::PropertyRef properties, ::mlir::RegionRange regions,
3800 ::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
3801 if (operands.empty())
3803 Adaptor adaptor(operands, attributes, properties, regions);
3804 inferredReturnTypes.push_back(adaptor.getInput().getType());
3805 if (adaptor.getForceable()) {
3807 true, adaptor.getInput().getType());
3808 if (!forceableType) {
3810 ::mlir::emitError(*location,
"cannot force a node of type ")
3811 << operands[0].getType();
3814 inferredReturnTypes.push_back(forceableType);
3819std::optional<size_t> NodeOp::getTargetResultIndex() {
return 0; }
3825std::optional<size_t> RegOp::getTargetResultIndex() {
return 0; }
3827SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3828RegOp::computeDataFlow() {
3837 IntegerAttr initial) {
3844 return op->emitError(
3845 "'initial' value is only supported on ground-type registers");
3848 auto width = intType.getWidthOrSentinel();
3849 if (width != -1 && (
int)initial.getValue().getBitWidth() != width)
3850 return op->emitError(
"'initial' value bitwidth (")
3851 << initial.getValue().getBitWidth()
3852 <<
") doesn't match register type width (" << width <<
")";
3856 if (attrType.isSignless() || attrType.isSigned() != intType.isSigned())
3857 return op->emitError(
"'initial' value has wrong sign");
3862LogicalResult RegOp::verify() {
3866LogicalResult RegResetOp::verify() {
3867 auto reset = getResetValue();
3874 return emitError(
"type mismatch between register ")
3875 << regType <<
" and reset value " << resetType;
3880std::optional<size_t> RegResetOp::getTargetResultIndex() {
return 0; }
3891FormalOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3892 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3894 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3896 if (!isa<FModuleLike>(op)) {
3897 auto d = emitOpError() <<
"target " << getModuleNameAttr()
3898 <<
" is not a module";
3899 d.attachNote(op->getLoc()) <<
"target defined here";
3911SimulationOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3912 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3914 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3916 auto complain = [&] {
3917 auto d = emitOpError() <<
"target " << getModuleNameAttr() <<
" ";
3918 d.attachNote(op->getLoc()) <<
"target defined here";
3922 auto module = dyn_cast<FModuleLike>(op);
3924 return complain() <<
"is not a module";
3926 auto numPorts =
module.getNumPorts();
3928 return complain() <<
"must have at least 4 ports, got " << numPorts
3932 auto checkPort = [&](
unsigned idx, StringRef expName,
Direction expDir,
3933 llvm::function_ref<bool(Type)> checkType,
3934 StringRef expType) {
3935 auto name =
module.getPortNameAttr(idx);
3936 if (name != expName) {
3937 complain() <<
"port " << idx <<
" must be called \"" << expName
3938 <<
"\", got " << name <<
" instead";
3941 if (
auto dir = module.getPortDirection(idx); dir != expDir) {
3945 complain() <<
"port " << name <<
" must be " << stringify(expDir)
3946 <<
", got " << stringify(dir) <<
" instead";
3949 if (
auto type = module.getPortType(idx); !checkType(type)) {
3950 complain() <<
"port " << name <<
" must be a '!firrtl." << expType
3951 <<
"', got " << type <<
" instead";
3957 auto isClock = [](Type type) {
return isa<ClockType>(type); };
3958 auto isBool = [](Type type) {
3959 if (
auto uintType = dyn_cast<UIntType>(type))
3960 return uintType.getWidth() == 1;
3964 if (!checkPort(0,
"clock",
Direction::In, isClock,
"clock") ||
3971 for (
unsigned i = 4; i < numPorts; ++i) {
3972 auto type =
module.getPortType(i);
3975 return complain() <<
"port " << i <<
" contains hardware types: " << type;
3989SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3990RegResetOp::computeDataFlow() {
3995std::optional<size_t> WireOp::getTargetResultIndex() {
return 0; }
3997LogicalResult WireOp::verify() {
4000 return emitOpError(
"of domain type must not have domain associations");
4003 auto domains = getDomains();
4004 if (!domains.size())
4017 using oldValueAndDiag = std::pair<Value, std::unique_ptr<InFlightDiagnostic>>;
4018 llvm::SmallMapVector<SymbolRefAttr, oldValueAndDiag, 2> domainInfo;
4019 bool hasErrors =
false;
4020 for (
auto domain : domains) {
4021 auto domainType = cast<DomainType>(domain.getType());
4022 auto domainName = domainType.getName();
4025 auto [it, inserted] =
4026 domainInfo.try_emplace(domainName, std::make_pair(domain,
nullptr));
4033 auto &[value, diag] = it->second;
4039 diag = std::make_unique<InFlightDiagnostic>(
4040 emitOpError() <<
"associated with multiple operands of '"
4041 << domainName.getValue() <<
"' kind");
4042 diag->attachNote(value.getLoc()) <<
"first domain operand here";
4047 diag->attachNote(domain.getLoc())
4048 <<
"additional colliding domain operand here";
4060 for (
auto &[_, diag] : domainInfo.values())
4066LogicalResult WireOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
4069 refType,
getLoc(), getOperation()->getParentOfType<CircuitOp>(),
4070 symbolTable, Twine(
"'") + getOperationName() +
"' op is");
4073 return domainType.verifySymbolUses(getOperation(), symbolTable);
4082LogicalResult ContractOp::verify() {
4083 if (getBody().getArgumentTypes() != getInputs().getType())
4084 return emitOpError(
"result types and region argument types must match");
4093OptionCaseOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
4094 auto caseMacro = getCaseMacroAttr();
4099 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
4100 auto *refOp = symbolTable.lookupSymbolIn(circuitOp, caseMacro);
4102 return emitOpError(
"case_macro references an undefined symbol: ")
4105 if (!isa<sv::MacroDeclOp>(refOp))
4106 return emitOpError(
"case_macro must reference a macro declaration");
4115void ObjectOp::build(OpBuilder &builder, OperationState &state, ClassLike klass,
4117 build(builder, state, klass.getInstanceType(),
4118 StringAttr::get(builder.getContext(), name));
4123 auto circuit =
object->getParentOfType<CircuitOp>();
4124 auto classOp = dyn_cast_or_null<ClassLike>(
4125 symbolTable.lookupSymbolIn(circuit,
object.getClassSymbolAttr()));
4127 return object->emitOpError(
"references unknown class ")
4128 <<
object.getClassSymbolAttr();
4129 return classOp.verifyType(
object.getClassType(),
4130 [&]() {
return object->emitOpError(); });
4133LogicalResult ObjectOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
4137StringRef ObjectOp::getInstanceName() {
return getName(); }
4139StringAttr ObjectOp::getInstanceNameAttr() {
return getNameAttr(); }
4142 setNameFn(getResult(),
getName());
4149LogicalResult ObjectCreateOp::verify() {
4150 unsigned inputIndex = 0;
4151 for (
const auto &element : getType().getInputElements()) {
4152 if (inputIndex >= getInputs().size())
4153 return emitOpError(
"missing operand for class input ") << element.name;
4154 auto inputType = getInputs()[inputIndex].getType();
4155 if (inputType != element.type)
4156 return emitOpError(
"class input ")
4157 << element.name <<
" expects " << element.type <<
", but operand "
4158 << inputIndex <<
" has type " << inputType;
4161 if (inputIndex != getInputs().size())
4162 return emitOpError(
"expected ")
4163 << inputIndex <<
" input operands, but got " << getInputs().size();
4168ObjectCreateOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
4172StringRef ObjectCreateOp::getInstanceName() {
return getName(); }
4174StringAttr ObjectCreateOp::getInstanceNameAttr() {
return getNameAttr(); }
4177 setNameFn(getResult(),
getName());
4184LogicalResult AttachOp::verify() {
4186 std::optional<int32_t> commonWidth;
4187 for (
auto operand : getOperands()) {
4192 commonWidth = thisWidth;
4195 if (commonWidth != thisWidth)
4196 return emitOpError(
"is inavlid as not all known operand widths match");
4203 Value dst = connect->getOperand(0);
4204 Value src = connect->getOperand(1);
4213 if (isa<PropertyType>(src.getType()) ||
4217 auto diag = emitError(connect->getLoc());
4218 diag <<
"connect has invalid flow: the source expression ";
4220 diag <<
"\"" << srcName <<
"\" ";
4221 diag <<
"has " <<
toString(srcFlow) <<
", expected source or duplex flow";
4222 return diag.attachNote(srcRef.getLoc()) <<
"the source was defined here";
4230 auto diag = emitError(connect->getLoc());
4231 diag <<
"connect has invalid flow: the destination expression ";
4233 diag <<
"\"" << dstName <<
"\" ";
4234 diag <<
"has " <<
toString(dstFlow) <<
", expected sink or duplex flow";
4235 return diag.attachNote(dstRef.getLoc())
4236 <<
"the destination was defined here";
4245 bool outerTypeIsConst =
false) {
4246 auto typeIsConst = outerTypeIsConst || type.
isConst();
4252 return llvm::any_of(bundleType.getElements(), [&](
auto &element) {
4253 return isConstFieldDriven(element.type, isFlip ^ element.isFlip,
4269 auto dest = connect.getDest();
4271 auto src = connect.getSrc();
4273 if (!destType || !srcType)
4276 auto destRefinedType = destType;
4277 auto srcRefinedType = srcType;
4282 auto findFieldDeclarationRefiningFieldType =
4284 while (
auto *definingOp = value.getDefiningOp()) {
4285 bool shouldContinue =
true;
4286 TypeSwitch<Operation *>(definingOp)
4287 .Case<SubfieldOp, SubindexOp>([&](
auto op) { value = op.getInput(); })
4288 .Case<SubaccessOp>([&](SubaccessOp op) {
4292 .getElementTypePreservingConst()
4294 originalFieldType = originalFieldType.getConstType(
true);
4295 value = op.getInput();
4297 .Default([&](Operation *) { shouldContinue =
false; });
4298 if (!shouldContinue)
4304 auto destDeclaration =
4305 findFieldDeclarationRefiningFieldType(dest, destRefinedType);
4306 auto srcDeclaration =
4307 findFieldDeclarationRefiningFieldType(src, srcRefinedType);
4309 auto checkConstConditionality = [&](Value value,
FIRRTLBaseType type,
4310 Value declaration) -> LogicalResult {
4311 auto *declarationBlock = declaration.getParentBlock();
4312 auto *block = connect->getBlock();
4313 while (block && block != declarationBlock) {
4314 auto *parentOp = block->getParentOp();
4316 if (
auto whenOp = dyn_cast<WhenOp>(parentOp);
4317 whenOp && !whenOp.getCondition().getType().
isConst()) {
4319 return connect.emitOpError()
4320 <<
"assignment to 'const' type " << type
4321 <<
" is dependent on a non-'const' condition";
4322 return connect->emitOpError()
4323 <<
"assignment to nested 'const' member of type " << type
4324 <<
" is dependent on a non-'const' condition";
4327 block = parentOp->getBlock();
4332 auto emitSubaccessError = [&] {
4333 return connect.emitError(
4334 "assignment to non-'const' subaccess of 'const' type is disallowed");
4340 if (destType != destRefinedType)
4341 return emitSubaccessError();
4343 if (failed(checkConstConditionality(dest, destType, destDeclaration)))
4348 if (srcRefinedType.containsConst() &&
4351 if (srcType != srcRefinedType)
4352 return emitSubaccessError();
4353 if (failed(checkConstConditionality(src, srcType, srcDeclaration)))
4370 auto dest = connect.getDest();
4371 for (
auto *user : dest.getUsers()) {
4372 if (
auto c = dyn_cast<FConnectLike>(user);
4373 c && c.getDest() == dest && c != connect) {
4374 auto diag = connect.emitError(
"destination cannot be driven by multiple "
4376 diag.attachNote(c->getLoc()) <<
"other driver is here";
4383LogicalResult ConnectOp::verify() {
4384 auto dstType = getDest().getType();
4385 auto srcType = getSrc().getType();
4388 if (!dstBaseType || !srcBaseType) {
4389 if (dstType != srcType)
4390 return emitError(
"may not connect different non-base types");
4393 if (dstBaseType.containsAnalog() || srcBaseType.containsAnalog())
4394 return emitError(
"analog types may not be connected");
4398 return emitError(
"type mismatch between destination ")
4399 << dstBaseType <<
" and source " << srcBaseType;
4404 return emitError(
"destination ")
4405 << dstBaseType <<
" is not as wide as the source " << srcBaseType;
4418LogicalResult MatchingConnectOp::verify() {
4423 if (baseType && baseType.containsAnalog())
4424 return emitError(
"analog types may not be connected");
4429 "`SameAnonTypeOperands` trait should have already rejected "
4430 "structurally non-equivalent types");
4443LogicalResult RefDefineOp::verify() {
4450 if (
auto *op = getDest().getDefiningOp()) {
4452 if (isa<RefSubOp>(op))
4454 "destination reference cannot be a sub-element of a reference");
4455 if (isa<RefCastOp>(op))
4457 "destination reference cannot be a cast of another reference");
4465 SmallVector<SymbolRefAttr> missingLayers;
4468 "has more layer requirements than destination",
4469 "additional layers required");
4472LogicalResult PropAssignOp::verify() {
4482LogicalResult PropertyAssertOp::verify() {
4485 if (
auto *defOp = getCondition().getDefiningOp())
4486 if (
auto boolConst = dyn_cast<BoolConstantOp>(defOp))
4487 if (!boolConst.getValue())
4488 return emitOpError(
"property assertion is statically false");
4493 auto domainType = dyn_cast<DomainType>(value.getType());
4498 return domainType.getName();
4501LogicalResult DomainDefineOp::verify() {
4508 auto dst = getDest();
4509 auto src = getSrc();
4517 if (
auto *srcDefOp = src.getDefiningOp())
4518 if (isa<WireOp>(srcDefOp))
4520 if (
auto *dstDefOp = dst.getDefiningOp())
4521 if (isa<WireOp>(dstDefOp))
4526 return emitError(
"could not determine domain-type of destination");
4530 return emitError(
"could not determine domain-type of source");
4532 if (dstDomain != srcDomain) {
4533 auto diag = emitError()
4534 <<
"source domain type " << srcDomain
4535 <<
" does not match destination domain type " << dstDomain;
4542void WhenOp::createElseRegion() {
4543 assert(!hasElseRegion() &&
"already has an else region");
4544 getElseRegion().push_back(
new Block());
4547void WhenOp::build(OpBuilder &builder, OperationState &result, Value condition,
4548 bool withElseRegion, std::function<
void()> thenCtor,
4549 std::function<
void()> elseCtor) {
4550 OpBuilder::InsertionGuard guard(builder);
4551 result.addOperands(condition);
4554 builder.createBlock(result.addRegion());
4559 Region *elseRegion = result.addRegion();
4560 if (withElseRegion) {
4561 builder.createBlock(elseRegion);
4571LogicalResult MatchOp::verify() {
4572 FEnumType type = getInput().getType();
4575 auto numCases = getTags().size();
4576 auto numRegions = getNumRegions();
4577 if (numRegions != numCases)
4578 return emitOpError(
"expected ")
4579 << numRegions <<
" tags but got " << numCases;
4581 auto numTags = type.getNumElements();
4583 SmallDenseSet<int64_t> seen;
4584 for (
const auto &[tag, region] : llvm::zip(getTags(), getRegions())) {
4585 auto tagIndex = size_t(cast<IntegerAttr>(tag).
getInt());
4588 if (region.getNumArguments() != 1)
4589 return emitOpError(
"region should have exactly one argument");
4592 if (tagIndex >= numTags)
4593 return emitOpError(
"the tag index ")
4594 << tagIndex <<
" is out of the range of valid tags in " << type;
4597 auto [it, inserted] = seen.insert(tagIndex);
4599 return emitOpError(
"the tag ") << type.getElementNameAttr(tagIndex)
4600 <<
" is matched more than once";
4603 auto expectedType = type.getElementTypePreservingConst(tagIndex);
4604 auto regionType = region.getArgument(0).getType();
4605 if (regionType != expectedType)
4606 return emitOpError(
"region type ")
4607 << regionType <<
" does not match the expected type "
4612 for (
size_t i = 0, e = type.getNumElements(); i < e; ++i)
4613 if (!seen.contains(i))
4614 return emitOpError(
"missing case for tag ") << type.getElementNameAttr(i);
4619void MatchOp::print(OpAsmPrinter &p) {
4620 auto input = getInput();
4621 FEnumType type = input.getType();
4622 auto regions = getRegions();
4623 p <<
" " << input <<
" : " << type;
4624 SmallVector<StringRef> elided = {
"tags"};
4625 p.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elided);
4628 for (
const auto &[tag, region] : llvm::zip(getTags(), regions)) {
4631 p.printKeywordOrString(
4632 type.getElementName(cast<IntegerAttr>(tag).getInt()));
4634 p.printRegionArgument(region.front().getArgument(0), {},
4637 p.printRegion(region,
false);
4644ParseResult MatchOp::parse(OpAsmParser &parser, OperationState &result) {
4645 auto *
context = parser.getContext();
4646 auto &properties = result.getOrAddProperties<Properties>();
4647 OpAsmParser::UnresolvedOperand input;
4648 if (parser.parseOperand(input) || parser.parseColon())
4651 auto loc = parser.getCurrentLocation();
4653 if (parser.parseType(type))
4657 return parser.emitError(loc,
"expected enumeration type but got") << type;
4659 if (parser.resolveOperand(input, type, result.operands) ||
4660 parser.parseOptionalAttrDictWithKeyword(result.attributes) ||
4661 parser.parseLBrace())
4664 auto i32Type = IntegerType::get(
context, 32);
4665 SmallVector<Attribute> tags;
4668 if (failed(parser.parseOptionalKeyword(
"case")))
4672 auto nameLoc = parser.getCurrentLocation();
4674 OpAsmParser::Argument arg;
4675 auto *region = result.addRegion();
4676 if (parser.parseKeywordOrString(&name) || parser.parseLParen() ||
4677 parser.parseArgument(arg) || parser.parseRParen())
4681 auto index = enumType.getElementIndex(name);
4683 return parser.emitError(nameLoc,
"the tag \"")
4684 << name <<
"\" is not a member of the enumeration " << enumType;
4685 tags.push_back(IntegerAttr::get(i32Type, *index));
4688 arg.type = enumType.getElementTypePreservingConst(*index);
4689 if (parser.parseRegion(*region, arg))
4692 properties.setTags(ArrayAttr::get(
context, tags));
4694 return parser.parseRBrace();
4697void MatchOp::build(OpBuilder &builder, OperationState &result, Value input,
4699 MutableArrayRef<std::unique_ptr<Region>> regions) {
4700 auto &properties = result.getOrAddProperties<Properties>();
4701 result.addOperands(input);
4702 properties.setTags(tags);
4703 result.addRegions(regions);
4712 struct IsExprClassifier :
public ExprVisitor<IsExprClassifier, bool> {
4713 bool visitInvalidExpr(Operation *op) {
return false; }
4714 bool visitUnhandledExpr(Operation *op) {
return true; }
4724 const char *base = ty.isSigned() ?
"invalid_si" :
"invalid_ui";
4725 auto width = ty.getWidthOrSentinel();
4729 name = (Twine(base) + Twine(width)).str();
4731 auto width = ty.getWidthOrSentinel();
4733 name =
"invalid_analog";
4735 name = (
"invalid_analog" + Twine(width)).str();
4737 name =
"invalid_asyncreset";
4739 name =
"invalid_reset";
4741 name =
"invalid_clock";
4745 setNameFn(getResult(), name);
4748void ConstantOp::print(OpAsmPrinter &p) {
4750 p.printAttributeWithoutType(getValueAttr());
4752 p.printType(getType());
4753 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4756ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
4757 auto &properties = result.getOrAddProperties<Properties>();
4760 auto loc = parser.getCurrentLocation();
4761 auto valueResult = parser.parseOptionalInteger(value);
4762 if (!valueResult.has_value())
4763 return parser.emitError(loc,
"expected integer value");
4767 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4768 parser.parseOptionalAttrDict(result.attributes))
4770 result.addTypes(resultType);
4776 if (width > value.getBitWidth()) {
4780 value = value.sext(width);
4781 }
else if (width < value.getBitWidth()) {
4784 unsigned neededBits = value.isNegative() ? value.getSignificantBits()
4785 : value.getActiveBits();
4786 if (width < neededBits)
4787 return parser.emitError(loc,
"constant out of range for result type ")
4789 value = value.trunc(width);
4793 auto intType = parser.getBuilder().getIntegerType(value.getBitWidth(),
4795 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4796 properties.setValue(valueAttr);
4800LogicalResult ConstantOp::verify() {
4804 if (width != -1 && (
int)getValue().
getBitWidth() != width)
4806 "firrtl.constant attribute bitwidth doesn't match return type");
4810 if (attrType.isSignless() || attrType.isSigned() != intType.
isSigned())
4811 return emitError(
"firrtl.constant attribute has wrong sign");
4818void ConstantOp::build(OpBuilder &builder, OperationState &result,
IntType type,
4819 const APInt &value) {
4822 assert((width == -1 || (int32_t)value.getBitWidth() == width) &&
4823 "incorrect attribute bitwidth for firrtl.constant");
4826 IntegerAttr::get(type.getContext(), APSInt(value, !type.
isSigned()));
4827 return build(builder, result, type, attr);
4832void ConstantOp::build(OpBuilder &builder, OperationState &result,
4833 const APSInt &value) {
4834 auto attr = IntegerAttr::get(builder.getContext(), value);
4836 IntType::get(builder.getContext(), value.isSigned(), value.getBitWidth());
4837 return build(builder, result, type, attr);
4847 SmallString<32> specialNameBuffer;
4848 llvm::raw_svector_ostream specialName(specialNameBuffer);
4850 getValue().print(specialName, intTy.
isSigned());
4852 specialName << (intTy.
isSigned() ?
"_si" :
"_ui");
4855 specialName << width;
4856 setNameFn(getResult(), specialName.str());
4859void SpecialConstantOp::print(OpAsmPrinter &p) {
4862 p << static_cast<unsigned>(getValue());
4864 p.printType(getType());
4865 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4868ParseResult SpecialConstantOp::parse(OpAsmParser &parser,
4869 OperationState &result) {
4870 auto &properties = result.getOrAddProperties<Properties>();
4874 auto loc = parser.getCurrentLocation();
4875 auto valueResult = parser.parseOptionalInteger(value);
4876 if (!valueResult.has_value())
4877 return parser.emitError(loc,
"expected integer value");
4880 if (value != 0 && value != 1)
4881 return parser.emitError(loc,
"special constants can only be 0 or 1.");
4885 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4886 parser.parseOptionalAttrDict(result.attributes))
4888 result.addTypes(resultType);
4891 auto valueAttr = parser.getBuilder().getBoolAttr(value == 1);
4892 properties.setValue(valueAttr);
4897 SmallString<32> specialNameBuffer;
4898 llvm::raw_svector_ostream specialName(specialNameBuffer);
4900 specialName << static_cast<unsigned>(getValue());
4901 auto type = getType();
4903 specialName <<
"_clock";
4905 specialName <<
"_reset";
4907 specialName <<
"_asyncreset";
4909 setNameFn(getResult(), specialName.str());
4916 if (type.isGround()) {
4917 if (!isa<IntegerAttr>(attr)) {
4918 op->emitOpError(
"Ground type is not an integer attribute");
4923 auto attrlist = dyn_cast<ArrayAttr>(attr);
4925 op->emitOpError(
"expected array attribute for aggregate constant");
4929 if (array.getNumElements() != attrlist.size()) {
4930 op->emitOpError(
"array attribute (")
4931 << attrlist.size() <<
") has wrong size for vector constant ("
4932 << array.getNumElements() <<
")";
4935 return llvm::all_of(attrlist, [&array, op](Attribute attr) {
4940 if (bundle.getNumElements() != attrlist.size()) {
4941 op->emitOpError(
"array attribute (")
4942 << attrlist.size() <<
") has wrong size for bundle constant ("
4943 << bundle.getNumElements() <<
")";
4946 for (
size_t i = 0; i < bundle.getNumElements(); ++i) {
4947 if (bundle.getElement(i).isFlip) {
4948 op->emitOpError(
"Cannot have constant bundle type with flip");
4956 op->emitOpError(
"Unknown aggregate type");
4960LogicalResult AggregateConstantOp::verify() {
4966Attribute AggregateConstantOp::getAttributeFromFieldID(uint64_t fieldID) {
4968 Attribute value = getFields();
4969 while (fieldID != 0) {
4971 auto index = bundle.getIndexForFieldID(fieldID);
4972 fieldID -= bundle.getFieldID(index);
4973 type = bundle.getElementType(index);
4974 value = cast<ArrayAttr>(value)[index];
4977 auto index = vector.getIndexForFieldID(fieldID);
4978 fieldID -= vector.getFieldID(index);
4979 type = vector.getElementType();
4980 value = cast<ArrayAttr>(value)[index];
4986LogicalResult FIntegerConstantOp::verify() {
4987 auto i = getValueAttr();
4988 if (!i.getType().isSignedInteger())
4989 return emitOpError(
"value must be signed");
4993void FIntegerConstantOp::print(OpAsmPrinter &p) {
4995 p.printAttributeWithoutType(getValueAttr());
4996 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4999ParseResult FIntegerConstantOp::parse(OpAsmParser &parser,
5000 OperationState &result) {
5001 auto *
context = parser.getContext();
5002 auto &properties = result.getOrAddProperties<Properties>();
5004 if (parser.parseInteger(value) ||
5005 parser.parseOptionalAttrDict(result.attributes))
5007 result.addTypes(FIntegerType::get(
context));
5009 IntegerType::get(
context, value.getBitWidth(), IntegerType::Signed);
5010 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
5011 properties.setValue(valueAttr);
5015ParseResult ListCreateOp::parse(OpAsmParser &parser, OperationState &result) {
5016 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
5019 if (parser.parseOperandList(operands) ||
5020 parser.parseOptionalAttrDict(result.attributes) ||
5021 parser.parseColonType(type))
5023 result.addTypes(type);
5025 return parser.resolveOperands(operands, type.getElementType(),
5029void ListCreateOp::print(OpAsmPrinter &p) {
5031 p.printOperands(getElements());
5032 p.printOptionalAttrDict((*this)->getAttrs());
5033 p <<
" : " << getType();
5036LogicalResult ListCreateOp::verify() {
5037 if (getElements().
empty())
5040 auto elementType = getElements().front().getType();
5041 auto listElementType = getType().getElementType();
5043 return emitOpError(
"has elements of type ")
5044 <<
elementType <<
" instead of " << listElementType;
5049LogicalResult BundleCreateOp::verify() {
5050 BundleType resultType = getType();
5051 if (resultType.getNumElements() != getFields().size())
5052 return emitOpError(
"number of fields doesn't match type");
5053 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
5055 resultType.getElementTypePreservingConst(i),
5057 return emitOpError(
"type of element doesn't match bundle for field ")
5058 << resultType.getElement(i).name;
5063LogicalResult VectorCreateOp::verify() {
5064 FVectorType resultType = getType();
5065 if (resultType.getNumElements() != getFields().size())
5066 return emitOpError(
"number of fields doesn't match type");
5067 auto elemTy = resultType.getElementTypePreservingConst();
5068 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
5071 return emitOpError(
"type of element doesn't match vector element");
5077UnknownValueOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
5079 auto classType = dyn_cast<ClassType>(getType());
5083 auto className = classType.getNameAttr();
5085 Operation *op = symbolTable.lookupNearestSymbolFrom(*
this, className);
5087 return emitOpError() <<
"refers to non-existent class ("
5088 << className.getAttr() <<
")";
5091 if (!isa<ClassLike>(op))
5092 return emitOpError() <<
"refers to a non-class type ("
5093 << className.getAttr() <<
")";
5102LogicalResult FEnumCreateOp::verify() {
5103 FEnumType resultType = getResult().getType();
5104 auto elementIndex = resultType.getElementIndex(
getFieldName());
5106 return emitOpError(
"label ")
5107 <<
getFieldName() <<
" is not a member of the enumeration type "
5110 resultType.getElementTypePreservingConst(*elementIndex),
5111 getInput().getType()))
5112 return emitOpError(
"type of element doesn't match enum element");
5116void FEnumCreateOp::print(OpAsmPrinter &printer) {
5119 printer <<
'(' << getInput() <<
')';
5120 SmallVector<StringRef> elidedAttrs = {
"fieldIndex"};
5121 printer.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elidedAttrs);
5123 printer.printFunctionalType(ArrayRef<Type>{getInput().getType()},
5124 ArrayRef<Type>{getResult().getType()});
5127ParseResult FEnumCreateOp::parse(OpAsmParser &parser, OperationState &result) {
5128 auto *
context = parser.getContext();
5129 auto &properties = result.getOrAddProperties<Properties>();
5131 OpAsmParser::UnresolvedOperand input;
5132 std::string fieldName;
5133 mlir::FunctionType functionType;
5134 if (parser.parseKeywordOrString(&fieldName) || parser.parseLParen() ||
5135 parser.parseOperand(input) || parser.parseRParen() ||
5136 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5137 parser.parseType(functionType))
5140 if (functionType.getNumInputs() != 1)
5141 return parser.emitError(parser.getNameLoc(),
"single input type required");
5142 if (functionType.getNumResults() != 1)
5143 return parser.emitError(parser.getNameLoc(),
"single result type required");
5145 auto inputType = functionType.getInput(0);
5146 if (parser.resolveOperand(input, inputType, result.operands))
5149 auto outputType = functionType.getResult(0);
5152 return parser.emitError(parser.getNameLoc(),
5153 "output must be enum type, got ")
5155 auto fieldIndex = enumType.getElementIndex(fieldName);
5157 return parser.emitError(parser.getNameLoc(),
5158 "unknown field " + fieldName +
" in enum type ")
5161 properties.setFieldIndex(
5162 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5164 result.addTypes(enumType);
5173LogicalResult IsTagOp::verify() {
5174 if (getFieldIndex() >= getInput().getType().base().getNumElements())
5175 return emitOpError(
"element index is greater than the number of fields in "
5180void IsTagOp::print(::mlir::OpAsmPrinter &printer) {
5181 printer <<
' ' << getInput() <<
' ';
5183 SmallVector<::llvm::StringRef, 1> elidedAttrs = {
"fieldIndex"};
5184 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
5185 printer <<
" : " << getInput().getType();
5188ParseResult IsTagOp::parse(OpAsmParser &parser, OperationState &result) {
5189 auto *
context = parser.getContext();
5190 auto &properties = result.getOrAddProperties<Properties>();
5192 OpAsmParser::UnresolvedOperand input;
5193 std::string fieldName;
5195 if (parser.parseOperand(input) || parser.parseKeywordOrString(&fieldName) ||
5196 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5197 parser.parseType(inputType))
5200 if (parser.resolveOperand(input, inputType, result.operands))
5205 return parser.emitError(parser.getNameLoc(),
5206 "input must be enum type, got ")
5208 auto fieldIndex = enumType.getElementIndex(fieldName);
5210 return parser.emitError(parser.getNameLoc(),
5211 "unknown field " + fieldName +
" in enum type ")
5214 properties.setFieldIndex(
5215 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5217 result.addTypes(UIntType::get(
context, 1,
false));
5222FIRRTLType IsTagOp::inferReturnType(ValueRange operands, DictionaryAttr
attrs,
5223 PropertyRef properties,
5224 mlir::RegionRange regions,
5225 std::optional<Location> loc) {
5226 Adaptor adaptor(operands,
attrs, properties, regions);
5227 return UIntType::get(
attrs.getContext(), 1,
5228 isConst(adaptor.getInput().getType()));
5231template <
typename OpTy>
5233 auto *
context = parser.getContext();
5235 OpAsmParser::UnresolvedOperand input;
5236 std::string fieldName;
5238 if (parser.parseOperand(input) || parser.parseLSquare() ||
5239 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5240 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5241 parser.parseType(inputType))
5244 if (parser.resolveOperand(input, inputType, result.operands))
5249 return parser.emitError(parser.getNameLoc(),
5250 "input must be bundle type, got ")
5252 auto fieldIndex = bundleType.getElementIndex(fieldName);
5254 return parser.emitError(parser.getNameLoc(),
5255 "unknown field " + fieldName +
" in bundle type ")
5258 result.getOrAddProperties<
typename OpTy::Properties>().setFieldIndex(
5259 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5261 auto type = OpTy::inferReturnType(inputType, *fieldIndex, {});
5264 result.addTypes(type);
5269ParseResult SubtagOp::parse(OpAsmParser &parser, OperationState &result) {
5270 auto *
context = parser.getContext();
5272 OpAsmParser::UnresolvedOperand input;
5273 std::string fieldName;
5275 if (parser.parseOperand(input) || parser.parseLSquare() ||
5276 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5277 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5278 parser.parseType(inputType))
5281 if (parser.resolveOperand(input, inputType, result.operands))
5286 return parser.emitError(parser.getNameLoc(),
5287 "input must be enum type, got ")
5289 auto fieldIndex = enumType.getElementIndex(fieldName);
5291 return parser.emitError(parser.getNameLoc(),
5292 "unknown field " + fieldName +
" in enum type ")
5295 result.getOrAddProperties<Properties>().setFieldIndex(
5296 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5298 SmallVector<Type> inferredReturnTypes;
5299 if (failed(SubtagOp::inferReturnTypes(
5300 context, result.location, result.operands,
5301 result.attributes.getDictionary(
context), result.getRawProperties(),
5302 result.regions, inferredReturnTypes)))
5304 result.addTypes(inferredReturnTypes);
5309ParseResult SubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
5312ParseResult OpenSubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
5316template <
typename OpTy>
5318 printer <<
' ' << op.getInput() <<
'[';
5319 printer.printKeywordOrString(op.getFieldName());
5321 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
5322 elidedAttrs.push_back(
"fieldIndex");
5323 printer.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
5324 printer <<
" : " << op.getInput().getType();
5326void SubfieldOp::print(::mlir::OpAsmPrinter &printer) {
5329void OpenSubfieldOp::print(::mlir::OpAsmPrinter &printer) {
5333void SubtagOp::print(::mlir::OpAsmPrinter &printer) {
5334 printer <<
' ' << getInput() <<
'[';
5337 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
5338 elidedAttrs.push_back(
"fieldIndex");
5339 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
5340 printer <<
" : " << getInput().getType();
5343template <
typename OpTy>
5345 if (op.getFieldIndex() >=
5348 return op.emitOpError(
"subfield element index is greater than the number "
5349 "of fields in the bundle type");
5352LogicalResult SubfieldOp::verify() {
5355LogicalResult OpenSubfieldOp::verify() {
5359LogicalResult SubtagOp::verify() {
5360 if (getFieldIndex() >= getInput().getType().base().getNumElements())
5361 return emitOpError(
"subfield element index is greater than the number "
5362 "of fields in the bundle type");
5372 SmallVector<Operation *, 8> worklist({op});
5376 bool constant =
true;
5382 while (constant && !(worklist.empty()))
5383 TypeSwitch<Operation *>(worklist.pop_back_val())
5384 .Case<NodeOp, AsSIntPrimOp, AsUIntPrimOp>([&](
auto op) {
5385 if (
auto definingOp = op.getInput().getDefiningOp())
5386 worklist.push_back(definingOp);
5389 .Case<WireOp, SubindexOp, SubfieldOp>([&](
auto op) {
5390 for (
auto &use : op.getResult().getUses())
5391 worklist.push_back(use.getOwner());
5393 .Case<ConstantOp, SpecialConstantOp, AggregateConstantOp>([](
auto) {})
5394 .Default([&](
auto) { constant =
false; });
5403 if (
auto *op = value.getDefiningOp())
5408LogicalResult ConstCastOp::verify() {
5410 return emitOpError() << getInput().getType()
5411 <<
" is not 'const'-castable to "
5412 << getResult().getType();
5416FIRRTLType SubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
5417 std::optional<Location> loc) {
5420 if (fieldIndex >= inType.getNumElements())
5422 "subfield element index is greater than the "
5423 "number of fields in the bundle type");
5427 return inType.getElementTypePreservingConst(fieldIndex);
5430FIRRTLType OpenSubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
5431 std::optional<Location> loc) {
5434 if (fieldIndex >= inType.getNumElements())
5436 "subfield element index is greater than the "
5437 "number of fields in the bundle type");
5441 return inType.getElementTypePreservingConst(fieldIndex);
5444bool SubfieldOp::isFieldFlipped() {
5445 BundleType bundle = getInput().getType();
5446 return bundle.getElement(getFieldIndex()).isFlip;
5448bool OpenSubfieldOp::isFieldFlipped() {
5449 auto bundle = getInput().getType();
5450 return bundle.getElement(getFieldIndex()).isFlip;
5453FIRRTLType SubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
5454 std::optional<Location> loc) {
5456 if (fieldIndex < vectorType.getNumElements())
5457 return vectorType.getElementTypePreservingConst();
5459 "' in vector type ", type);
5464FIRRTLType OpenSubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
5465 std::optional<Location> loc) {
5467 if (fieldIndex < vectorType.getNumElements())
5468 return vectorType.getElementTypePreservingConst();
5470 "' in vector type ", type);
5476FIRRTLType SubtagOp::inferReturnType(ValueRange operands, DictionaryAttr
attrs,
5477 PropertyRef properties,
5478 mlir::RegionRange regions,
5479 std::optional<Location> loc) {
5480 Adaptor adaptor(operands,
attrs, properties, regions);
5482 auto fieldIndex = adaptor.getFieldIndex();
5484 if (fieldIndex >= inType.getNumElements())
5486 "subtag element index is greater than the "
5487 "number of fields in the enum type");
5491 auto elementType = inType.getElement(fieldIndex).type;
5495FIRRTLType SubaccessOp::inferReturnType(Type inType, Type indexType,
5496 std::optional<Location> loc) {
5503 return vectorType.getElementTypePreservingConst();
5504 return vectorType.getElementType().getAllConstDroppedType();
5512 std::optional<Location> loc) {
5514 return UIntType::get(inType.getContext(), inType.getTagWidth());
5517ParseResult MultibitMuxOp::parse(OpAsmParser &parser, OperationState &result) {
5518 OpAsmParser::UnresolvedOperand index;
5519 SmallVector<OpAsmParser::UnresolvedOperand, 16> inputs;
5520 Type indexType, elemType;
5522 if (parser.parseOperand(index) || parser.parseComma() ||
5523 parser.parseOperandList(inputs) ||
5524 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5525 parser.parseType(indexType) || parser.parseComma() ||
5526 parser.parseType(elemType))
5529 if (parser.resolveOperand(index, indexType, result.operands))
5532 result.addTypes(elemType);
5534 return parser.resolveOperands(inputs, elemType, result.operands);
5537void MultibitMuxOp::print(OpAsmPrinter &p) {
5538 p <<
" " << getIndex() <<
", ";
5539 p.printOperands(getInputs());
5540 p.printOptionalAttrDict((*this)->getAttrs());
5541 p <<
" : " << getIndex().getType() <<
", " << getType();
5544FIRRTLType MultibitMuxOp::inferReturnType(ValueRange operands,
5545 DictionaryAttr
attrs,
5546 PropertyRef properties,
5547 mlir::RegionRange regions,
5548 std::optional<Location> loc) {
5549 if (operands.size() < 2)
5553 if (!llvm::all_of(operands.drop_front(2), [&](
auto op) {
5554 return operands[1].getType() == op.getType();
5565LogicalResult ObjectSubfieldOp::inferReturnTypes(
5566 MLIRContext *
context, std::optional<mlir::Location> location,
5567 ValueRange operands, DictionaryAttr attributes, PropertyRef properties,
5568 RegionRange regions, llvm::SmallVectorImpl<Type> &inferredReturnTypes) {
5570 inferReturnType(operands, attributes, properties, regions, location);
5573 inferredReturnTypes.push_back(type);
5577Type ObjectSubfieldOp::inferReturnType(Type inType, uint32_t fieldIndex,
5578 std::optional<Location> loc) {
5579 auto classType = dyn_cast<ClassType>(inType);
5583 if (classType.getNumElements() <= fieldIndex)
5585 "number of fields in the object");
5586 return classType.getElement(fieldIndex).type;
5589void ObjectSubfieldOp::print(OpAsmPrinter &p) {
5590 auto input = getInput();
5591 auto classType = input.getType();
5592 p <<
' ' << input <<
"[";
5593 p.printKeywordOrString(classType.getElement(getIndex()).name);
5595 p.printOptionalAttrDict((*this)->getAttrs(), std::array{StringRef(
"index")});
5596 p <<
" : " << classType;
5599ParseResult ObjectSubfieldOp::parse(OpAsmParser &parser,
5600 OperationState &result) {
5601 auto *
context = parser.getContext();
5603 OpAsmParser::UnresolvedOperand input;
5604 std::string fieldName;
5605 ClassType inputType;
5606 if (parser.parseOperand(input) || parser.parseLSquare() ||
5607 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5608 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5609 parser.parseType(inputType) ||
5610 parser.resolveOperand(input, inputType, result.operands))
5613 auto index = inputType.getElementIndex(fieldName);
5615 return parser.emitError(parser.getNameLoc(),
5616 "unknown field " + fieldName +
" in class type ")
5618 result.getOrAddProperties<Properties>().setIndex(
5619 IntegerAttr::get(IntegerType::get(
context, 32), *index));
5621 SmallVector<Type> inferredReturnTypes;
5622 if (failed(inferReturnTypes(
context, result.location, result.operands,
5623 result.attributes.getDictionary(
context),
5624 result.getRawProperties(), result.regions,
5625 inferredReturnTypes)))
5627 result.addTypes(inferredReturnTypes);
5644 int32_t &rhsWidth,
bool &isConstResult,
5645 std::optional<Location> loc) {
5649 if (!lhsi || !rhsi || lhsi.isSigned() != rhsi.isSigned()) {
5652 mlir::emitError(*loc,
"second operand must be an integer type, not ")
5654 else if (!lhsi && rhsi)
5655 mlir::emitError(*loc,
"first operand must be an integer type, not ")
5657 else if (!lhsi && !rhsi)
5658 mlir::emitError(*loc,
"operands must be integer types, not ")
5659 << lhs <<
" and " << rhs;
5661 mlir::emitError(*loc,
"operand signedness must match");
5666 lhsWidth = lhsi.getWidthOrSentinel();
5667 rhsWidth = rhsi.getWidthOrSentinel();
5668 isConstResult = lhsi.isConst() && rhsi.isConst();
5673 assert(op->getNumOperands() == 2 &&
5674 "SameOperandsIntTypeKind on non-binary op");
5675 int32_t lhsWidth, rhsWidth;
5678 op->getOperand(1).getType(), lhsWidth,
5679 rhsWidth, isConstResult, op->getLoc()));
5683 std::optional<Location> loc) {
5684 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5685 bool isConstResult =
false;
5689 if (lhsWidth != -1 && rhsWidth != -1)
5690 resultWidth = std::max(lhsWidth, rhsWidth) + 1;
5696 std::optional<Location> loc) {
5697 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5698 bool isConstResult =
false;
5702 if (lhsWidth != -1 && rhsWidth != -1)
5703 resultWidth = lhsWidth + rhsWidth;
5710 std::optional<Location> loc) {
5711 int32_t lhsWidth, rhsWidth;
5712 bool isConstResult =
false;
5718 return UIntType::get(lhs.getContext(), lhsWidth, isConstResult);
5721 int32_t resultWidth = lhsWidth != -1 ? lhsWidth + 1 : -1;
5722 return SIntType::get(lhs.getContext(), resultWidth, isConstResult);
5726 std::optional<Location> loc) {
5727 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5728 bool isConstResult =
false;
5732 if (lhsWidth != -1 && rhsWidth != -1)
5733 resultWidth = std::min(lhsWidth, rhsWidth);
5739 std::optional<Location> loc) {
5740 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5741 bool isConstResult =
false;
5745 if (lhsWidth != -1 && rhsWidth != -1) {
5746 resultWidth = std::max(lhsWidth, rhsWidth);
5747 if (lhsWidth == resultWidth && lhs.
isConst() == isConstResult &&
5750 if (rhsWidth == resultWidth && rhs.
isConst() == isConstResult &&
5754 return UIntType::get(lhs.getContext(), resultWidth, isConstResult);
5758 std::optional<Location> loc) {
5765 if (lhsVec.getNumElements() != rhsVec.getNumElements())
5770 rhsVec.getElementTypePreservingConst(), loc);
5774 return FVectorType::get(elemBaseType, lhsVec.getNumElements(),
5775 lhsVec.isConst() && rhsVec.isConst() &&
5776 elemBaseType.isConst());
5780 std::optional<Location> loc) {
5781 return UIntType::get(lhs.getContext(), 1,
isConst(lhs) &&
isConst(rhs));
5784FIRRTLType CatPrimOp::inferReturnType(ValueRange operands, DictionaryAttr
attrs,
5785 PropertyRef properties,
5786 mlir::RegionRange regions,
5787 std::optional<Location> loc) {
5789 if (operands.empty())
5790 return UIntType::get(
attrs.getContext(), 0);
5794 for (
auto operand : operands) {
5798 if (type.isSigned() != isSigned)
5800 "all operands must have same signedness");
5804 int32_t resultWidth = 0;
5805 bool isConstResult =
true;
5807 for (
auto operand : operands) {
5809 int32_t width = type.getWidthOrSentinel();
5816 if (resultWidth != -1)
5817 resultWidth += width;
5820 isConstResult &= type.isConst();
5824 return UIntType::get(
attrs.getContext(), resultWidth, isConstResult);
5828 std::optional<Location> loc) {
5831 if (!rhsui || !lhsi)
5833 loc,
"first operand should be integer, second unsigned int");
5837 auto width = lhsi.getWidthOrSentinel();
5838 if (width == -1 || !rhsui.getWidth().has_value()) {
5841 auto amount = *rhsui.getWidth();
5844 "shift amount too large: second operand of "
5845 "dshl is wider than 31 bits");
5846 int64_t newWidth = (int64_t)width + ((int64_t)1 << amount) - 1;
5847 if (newWidth > INT32_MAX)
5849 loc,
"shift amount too large: first operand shifted by maximum "
5850 "amount exceeds maximum width");
5853 return IntType::get(lhs.getContext(), lhsi.isSigned(), width,
5854 lhsi.
isConst() && rhsui.isConst());
5858 std::optional<Location> loc) {
5863 loc,
"first operand should be integer, second unsigned int");
5864 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5868 std::optional<Location> loc) {
5873 loc,
"first operand should be integer, second unsigned int");
5874 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5882 std::optional<Location> loc) {
5883 return UIntType::get(input.getContext(), 32);
5887 std::optional<Location> loc) {
5891 int32_t width = base.getBitWidthOrSentinel();
5894 return SIntType::get(input.getContext(), width, base.isConst());
5898 std::optional<Location> loc) {
5902 int32_t width = base.getBitWidthOrSentinel();
5905 return UIntType::get(input.getContext(), width, base.isConst());
5909 std::optional<Location> loc) {
5913 "operand must be single bit scalar base type");
5914 int32_t width = base.getBitWidthOrSentinel();
5915 if (width == -2 || width == 0 || width > 1)
5917 return AsyncResetType::get(input.getContext(), base.isConst());
5921 std::optional<Location> loc) {
5925 return ResetType::get(input.getContext(), base.isConst());
5929 std::optional<Location> loc) {
5930 return ClockType::get(input.getContext(),
isConst(input));
5934 std::optional<Location> loc) {
5936 auto width = uiType.getWidthOrSentinel();
5939 return SIntType::get(input.getContext(), width, uiType.
isConst());
5949 std::optional<Location> loc) {
5953 int32_t width = inputi.getWidthOrSentinel();
5956 return SIntType::get(input.getContext(), width, inputi.
isConst());
5960 std::optional<Location> loc) {
5964 if (isa<UIntType>(inputi))
5966 return UIntType::get(input.getContext(), inputi.getWidthOrSentinel(),
5971 std::optional<Location> loc) {
5972 return UIntType::get(input.getContext(), 1,
isConst(input));
5981 std::optional<Location> loc) {
5985 loc,
"input type should be the int type but got ", input);
5990 loc,
"high must be equal or greater than low, but got high = ", high,
5998 int32_t width = inputi.getWidthOrSentinel();
5999 if (width != -1 && high >= width)
6002 "high must be smaller than the width of input, but got high = ", high,
6003 ", width = ", width);
6005 return UIntType::get(input.getContext(), high - low + 1, inputi.
isConst());
6009 std::optional<Location> loc) {
6012 if (amount < 0 || !inputi)
6014 loc,
"operand must have integer type and amount must be >= 0");
6016 int32_t width = inputi.getWidthOrSentinel();
6017 if (width != -1 && amount > width)
6020 return UIntType::get(input.getContext(), amount, inputi.
isConst());
6035 bool isConstCondition,
6036 std::optional<Location> loc) {
6042 if (high.getTypeID() != low.getTypeID())
6044 loc,
"incompatible mux operand types, true value type: ", high,
6045 ", false value type: ", low);
6047 bool outerTypeIsConst = isConstCondition && low.
isConst() && high.
isConst();
6057 if (highWidth == -1)
6059 return (lowWidth > highWidth ? low : high).
getConstType(outerTypeIsConst);
6066 if (lowEnum && highEnum) {
6067 if (lowEnum.getNumElements() != highEnum.getNumElements())
6069 loc,
"incompatible mux operand types, true value type: ", high,
6070 ", false value type: ", low);
6071 SmallVector<FEnumType::EnumElement> elements;
6072 for (
auto [high, low] : llvm::zip_equal(highEnum, lowEnum)) {
6074 if (high.name != low.name || high.value != low.value)
6076 loc,
"incompatible mux operand types, true value type: ", highEnum,
6077 ", false value type: ", lowEnum);
6084 elements.emplace_back(high.name, high.value, inner);
6086 return FEnumType::get(high.getContext(), elements, outerTypeIsConst);
6092 if (highVector && lowVector &&
6093 highVector.getNumElements() == lowVector.getNumElements()) {
6095 lowVector.getElementTypePreservingConst(),
6096 isConstCondition, loc);
6099 return FVectorType::get(inner, lowVector.getNumElements(),
6106 if (highBundle && lowBundle) {
6107 auto highElements = highBundle.getElements();
6108 auto lowElements = lowBundle.getElements();
6111 SmallVector<BundleType::BundleElement> newElements;
6113 bool failed =
false;
6115 if (highElements[i].name != lowElements[i].name ||
6116 highElements[i].isFlip != lowElements[i].isFlip) {
6120 auto element = highElements[i];
6122 highBundle.getElementTypePreservingConst(i),
6123 lowBundle.getElementTypePreservingConst(i), isConstCondition, loc);
6126 newElements.push_back(element);
6129 return BundleType::get(low.getContext(), newElements, outerTypeIsConst);
6132 loc,
"incompatible mux operand bundle fields, true value type: ", high,
6133 ", false value type: ", low);
6139 loc,
"invalid mux operand types, true value type: ", high,
6140 ", false value type: ", low);
6145 std::optional<Location> loc) {
6148 if (!highType || !lowType)
6153FIRRTLType Mux2CellIntrinsicOp::inferReturnType(ValueRange operands,
6154 DictionaryAttr
attrs,
6155 PropertyRef properties,
6156 mlir::RegionRange regions,
6157 std::optional<Location> loc) {
6160 if (!highType || !lowType)
6166FIRRTLType Mux4CellIntrinsicOp::inferReturnType(ValueRange operands,
6167 DictionaryAttr
attrs,
6168 PropertyRef properties,
6169 mlir::RegionRange regions,
6170 std::optional<Location> loc) {
6171 SmallVector<FIRRTLBaseType> types;
6173 for (
unsigned i = 1; i < 5; i++) {
6179 isConst(operands[0].getType()), loc);
6183 result = types.back();
6190 std::optional<Location> loc) {
6192 if (amount < 0 || !inputi)
6194 loc,
"pad input must be integer and amount must be >= 0");
6196 int32_t width = inputi.getWidthOrSentinel();
6200 width = std::max<int32_t>(width, amount);
6201 return IntType::get(input.getContext(), inputi.isSigned(), width,
6206 std::optional<Location> loc) {
6208 if (amount < 0 || !inputi)
6210 loc,
"shl input must be integer and amount must be >= 0");
6212 int32_t width = inputi.getWidthOrSentinel();
6216 return IntType::get(input.getContext(), inputi.isSigned(), width,
6221 std::optional<Location> loc) {
6223 if (amount < 0 || !inputi)
6225 loc,
"shr input must be integer and amount must be >= 0");
6227 int32_t width = inputi.getWidthOrSentinel();
6230 int32_t minWidth = inputi.isUnsigned() ? 0 : 1;
6231 width = std::max<int32_t>(minWidth, width - amount);
6234 return IntType::get(input.getContext(), inputi.isSigned(), width,
6239 std::optional<Location> loc) {
6242 if (amount < 0 || !inputi)
6244 loc,
"tail input must be integer and amount must be >= 0");
6246 int32_t width = inputi.getWidthOrSentinel();
6250 loc,
"amount must be less than or equal operand width");
6261void VerbatimExprOp::getAsmResultNames(
6262 function_ref<
void(Value, StringRef)> setNameFn) {
6266 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
6267 auto name = getText();
6269 if (name.starts_with(
"`"))
6270 name = name.drop_front();
6271 name = name.take_while(isOkCharacter);
6273 setNameFn(getResult(), name);
6280void VerbatimWireOp::getAsmResultNames(
6281 function_ref<
void(Value, StringRef)> setNameFn) {
6285 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
6286 auto name = getText();
6288 if (name.starts_with(
"`"))
6289 name = name.drop_front();
6290 name = name.take_while(isOkCharacter);
6292 setNameFn(getResult(), name);
6303 op->emitError() <<
"unknown width is not allowed for DPI";
6304 return WalkResult::interrupt();
6306 if (width == 1 || width == 8 || width == 16 || width == 32 ||
6308 return WalkResult::advance();
6310 <<
"integer types used by DPI functions must have a "
6311 "specific bit width; "
6312 "it must be equal to 1(bit), 8(byte), 16(shortint), "
6313 "32(int), 64(longint) "
6314 "or greater than 64, but got "
6316 return WalkResult::interrupt();
6321LogicalResult DPICallIntrinsicOp::verify() {
6322 if (
auto inputNames = getInputNames()) {
6323 if (getInputs().size() != inputNames->size())
6324 return emitError() <<
"inputNames has " << inputNames->size()
6325 <<
" elements but there are " << getInputs().size()
6326 <<
" input arguments";
6328 if (
auto outputName = getOutputName())
6329 if (getNumResults() == 0)
6330 return emitError() <<
"output name is given but there is no result";
6332 auto checkType = [
this](Type type) {
6335 return success(llvm::all_of(this->getResultTypes(), checkType) &&
6336 llvm::all_of(this->getOperandTypes(), checkType));
6339SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
6340DPICallIntrinsicOp::computeDataFlow() {
6344 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
6346 for (
auto operand : getOperands()) {
6349 SmallVector<circt::FieldRef> operandFields;
6352 operandFields.push_back(baseFieldRef.getSubField(dstIndex));
6356 for (
auto result : getResults())
6359 for (
auto field : operandFields)
6360 deps.emplace_back(circt::FieldRef(result, dstIndex), field);
6370LogicalResult HWStructCastOp::verify() {
6372 BundleType bundleType;
6373 hw::StructType structType;
6375 structType = dyn_cast<hw::StructType>(getType());
6377 return emitError(
"result type must be a struct");
6379 structType = dyn_cast<hw::StructType>(getOperand().getType());
6381 return emitError(
"operand type must be a struct");
6383 return emitError(
"either source or result type must be a bundle type");
6386 auto firFields = bundleType.getElements();
6387 auto hwFields = structType.getElements();
6388 if (firFields.size() != hwFields.size())
6389 return emitError(
"bundle and struct have different number of fields");
6391 for (
size_t findex = 0, fend = firFields.size(); findex < fend; ++findex) {
6392 if (firFields[findex].name.getValue() != hwFields[findex].name)
6393 return emitError(
"field names don't match '")
6394 << firFields[findex].name.getValue() <<
"', '"
6395 << hwFields[findex].name.getValue() <<
"'";
6399 if (firWidth > 0 && hwWidth > 0 && firWidth != hwWidth)
6400 return emitError(
"size of field '")
6401 << hwFields[findex].name.getValue() <<
"' don't match " << firWidth
6408LogicalResult BitCastOp::verify() {
6409 auto inTypeBits =
getBitWidth(getInput().getType(),
true);
6411 if (inTypeBits.has_value() && resTypeBits.has_value()) {
6413 if (*inTypeBits == *resTypeBits) {
6416 return emitError(
"cannot cast non-'const' input type ")
6417 << getOperand().getType() <<
" to 'const' result type "
6421 return emitError(
"the bitwidth of input (")
6422 << *inTypeBits <<
") and result (" << *resTypeBits
6425 if (!inTypeBits.has_value())
6426 return emitError(
"bitwidth cannot be determined for input operand type ")
6427 << getInput().getType();
6428 return emitError(
"bitwidth cannot be determined for result type ")
6439 NamedAttrList &resultAttrs) {
6440 auto result = parser.parseOptionalAttrDict(resultAttrs);
6441 if (!resultAttrs.get(
"annotations"))
6442 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
6448 DictionaryAttr attr,
6449 ArrayRef<StringRef> extraElides = {}) {
6450 SmallVector<StringRef> elidedAttrs(extraElides.begin(), extraElides.end());
6452 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
6453 elidedAttrs.push_back(
"annotations");
6455 elidedAttrs.push_back(
"nameKind");
6457 p.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
6463 NamedAttrList &resultAttrs) {
6466 if (!resultAttrs.get(
"portAnnotations")) {
6467 SmallVector<Attribute, 16> portAnnotations(
6468 parser.getNumResults(), parser.getBuilder().getArrayAttr({}));
6469 resultAttrs.append(
"portAnnotations",
6470 parser.getBuilder().getArrayAttr(portAnnotations));
6477 DictionaryAttr attr,
6478 ArrayRef<StringRef> extraElides = {}) {
6479 SmallVector<StringRef, 2> elidedAttrs(extraElides.begin(), extraElides.end());
6481 if (llvm::all_of(op->getAttrOfType<ArrayAttr>(
"portAnnotations"),
6482 [&](Attribute a) { return cast<ArrayAttr>(a).empty(); }))
6483 elidedAttrs.push_back(
"portAnnotations");
6492 firrtl::NameKindEnumAttr &result) {
6495 if (!parser.parseOptionalKeyword(&keyword,
6496 {
"interesting_name",
"droppable_name"})) {
6497 auto kind = symbolizeNameKindEnum(keyword);
6498 result = NameKindEnumAttr::get(parser.getContext(), kind.value());
6504 NameKindEnumAttr::get(parser.getContext(), NameKindEnum::DroppableName);
6509 firrtl::NameKindEnumAttr attr,
6510 ArrayRef<StringRef> extraElides = {}) {
6511 if (attr.getValue() != NameKindEnum::DroppableName)
6512 p <<
" " << stringifyNameKindEnum(attr.getValue());
6520 NamedAttrList &resultAttrs) {
6528 DictionaryAttr
attrs) {
6529 SmallVector<StringRef, 4> elides;
6531 elides.push_back(Forceable::getForceableAttrName());
6541 OpAsmParser &parser,
6542 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &fieldValues,
6543 SmallVectorImpl<Type> &fieldTypes, Type &resultType) {
6545 if (parser.parseType(resultType))
6548 auto domainType = dyn_cast<DomainType>(resultType);
6550 return parser.emitError(parser.getCurrentLocation(),
6551 "expected domain type");
6554 auto fields = domainType.getFields();
6557 if (fieldValues.size() != fields.size())
6558 return parser.emitError(parser.getCurrentLocation(),
6559 "number of field values (" +
6560 Twine(fieldValues.size()) +
6561 ") does not match domain field count (" +
6562 Twine(fields.size()) +
")");
6565 fieldTypes.reserve(fields.size());
6566 for (
auto field : fields)
6567 fieldTypes.push_back(cast<DomainFieldAttr>(field).getType());
6573 OperandRange fieldValues,
6574 TypeRange fieldTypes, Type resultType) {
6582static ParseResult
parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs) {
6587static void printMemOp(OpAsmPrinter &p, Operation *op, DictionaryAttr attr) {
6598 if (ClassType::parseInterface(parser, type))
6605 type.printInterface(p);
6613 NamedAttrList &resultAttrs) {
6614 auto result = p.parseOptionalAttrDict(resultAttrs);
6615 if (!resultAttrs.get(
"name"))
6616 resultAttrs.append(
"name", p.getBuilder().getStringAttr(
""));
6622 DictionaryAttr attr,
6623 ArrayRef<StringRef> extraElides = {}) {
6624 SmallVector<StringRef> elides(extraElides.begin(), extraElides.end());
6625 if (op->getAttrOfType<StringAttr>(
"name").getValue().empty())
6626 elides.push_back(
"name");
6628 p.printOptionalAttrDict(op->getAttrs(), elides);
6632 NamedAttrList &resultAttrs) {
6637 DictionaryAttr attr) {
6642 NamedAttrList &resultAttrs) {
6647 DictionaryAttr attr) {
6649 {
"formatString",
"outputFile",
"operandSegmentSizes"});
6657 DictionaryAttr attr) {
6666 DictionaryAttr attr) {
6678 if (op->getNumResults() == 1)
6679 if (
auto nameAttr = op->getAttrOfType<StringAttr>(
"name"))
6680 setNameFn(op->getResult(0), nameAttr.getValue());
6785void PlusArgsValueIntrinsicOp::getAsmResultNames(
6929FIRRTLType RefResolveOp::inferReturnType(ValueRange operands,
6930 DictionaryAttr
attrs,
6931 PropertyRef properties,
6932 mlir::RegionRange regions,
6933 std::optional<Location> loc) {
6934 Type inType = operands[0].getType();
6938 loc,
"ref.resolve operand must be ref type, not ", inType);
6939 return inRefType.getType();
6942FIRRTLType RefSendOp::inferReturnType(ValueRange operands, DictionaryAttr
attrs,
6943 PropertyRef properties,
6944 mlir::RegionRange regions,
6945 std::optional<Location> loc) {
6946 Type inType = operands[0].getType();
6950 loc,
"ref.send operand must be base type, not ", inType);
6951 return RefType::get(inBaseType.getPassiveType());
6954FIRRTLType RefSubOp::inferReturnType(Type type, uint32_t fieldIndex,
6955 std::optional<Location> loc) {
6959 auto inType = refType.getType();
6966 if (fieldIndex < vectorType.getNumElements())
6967 return RefType::get(
6968 vectorType.getElementType().getConstType(
6969 vectorType.isConst() || vectorType.getElementType().isConst()),
6970 refType.getForceable(), refType.getLayer());
6972 "' in RefType of vector type ", refType);
6975 if (fieldIndex >= bundleType.getNumElements()) {
6977 "subfield element index is greater than "
6978 "the number of fields in the bundle type");
6980 return RefType::get(
6981 bundleType.getElement(fieldIndex)
6983 bundleType.isConst() ||
6984 bundleType.getElement(fieldIndex).type.isConst()),
6985 refType.getForceable(), refType.getLayer());
6989 loc,
"ref.sub op requires a RefType of vector or bundle base type");
6992LogicalResult RefCastOp::verify() {
6996 getOperation(), srcLayers, dstLayers,
6997 "cannot discard layer requirements of input reference",
6998 "discarding layer requirements");
7001LogicalResult RefResolveOp::verify() {
7005 getOperation(), srcLayers, dstLayers,
7006 "ambient layers are insufficient to resolve reference");
7009LogicalResult RWProbeOp::verifyInnerRefs(hw::InnerRefNamespace &ns) {
7010 auto targetRef = getTarget();
7011 if (targetRef.getModule() !=
7012 (*this)->getParentOfType<FModuleLike>().getModuleNameAttr())
7013 return emitOpError() <<
"has non-local target";
7015 auto target = ns.
lookup(targetRef);
7017 return emitOpError() <<
"has target that cannot be resolved: " << targetRef;
7019 auto checkFinalType = [&](
auto type, Location loc) -> LogicalResult {
7025 if (!baseType || baseType.getPassiveType() != getType().getType()) {
7026 auto diag = emitOpError(
"has type mismatch: target resolves to ")
7027 << fType <<
" instead of expected " << getType().getType();
7028 diag.attachNote(loc) <<
"target resolves here";
7033 if (target.isPort()) {
7034 auto mod = cast<FModuleLike>(target.getOp());
7035 return checkFinalType(mod.getPortType(target.getPort()),
7036 mod.getPortLocation(target.getPort()));
7038 hw::InnerSymbolOpInterface symOp =
7039 cast<hw::InnerSymbolOpInterface>(target.getOp());
7040 if (!symOp.getTargetResult())
7041 return emitOpError(
"has target that cannot be probed")
7042 .attachNote(symOp.getLoc())
7043 .append(
"target resolves here");
7045 symOp.getTargetResult().getParentBlock()->findAncestorOpInBlock(**
this);
7046 if (!ancestor || !symOp->isBeforeInBlock(ancestor))
7047 return emitOpError(
"is not dominated by target")
7048 .attachNote(symOp.getLoc())
7049 .append(
"target here");
7050 return checkFinalType(symOp.getTargetResult().getType(), symOp.getLoc());
7053LogicalResult RefForceOp::verify() {
7057 getOperation(), destLayers, ambientLayers,
7058 "has insufficient ambient layers to force its reference");
7061LogicalResult RefForceInitialOp::verify() {
7065 getOperation(), destLayers, ambientLayers,
7066 "has insufficient ambient layers to force its reference");
7069LogicalResult RefReleaseOp::verify() {
7073 getOperation(), destLayers, ambientLayers,
7074 "has insufficient ambient layers to release its reference");
7077LogicalResult RefReleaseInitialOp::verify() {
7081 getOperation(), destLayers, ambientLayers,
7082 "has insufficient ambient layers to release its reference");
7085LogicalResult XMRRefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7086 auto *target = symbolTable.lookupNearestSymbolFrom(*
this, getRefAttr());
7088 return emitOpError(
"has an invalid symbol reference");
7090 if (!isa<hw::HierPathOp>(target))
7091 return emitOpError(
"does not target a hierpath op");
7097LogicalResult XMRDerefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7098 auto *target = symbolTable.lookupNearestSymbolFrom(*
this, getRefAttr());
7100 return emitOpError(
"has an invalid symbol reference");
7102 if (!isa<hw::HierPathOp>(target))
7103 return emitOpError(
"does not target a hierpath op");
7113LogicalResult LayerBlockOp::verify() {
7114 auto layerName = getLayerName();
7115 auto *parentOp = (*this)->getParentOp();
7118 while (isa<WhenOp, MatchOp>(parentOp))
7119 parentOp = parentOp->getParentOp();
7123 auto nestedReferences = layerName.getNestedReferences();
7124 if (nestedReferences.empty()) {
7125 if (!isa<FModuleOp>(parentOp)) {
7126 auto diag = emitOpError() <<
"has an un-nested layer symbol, but does "
7127 "not have a 'firrtl.module' op as a parent";
7128 return diag.attachNote(parentOp->getLoc())
7129 <<
"illegal parent op defined here";
7132 auto parentLayerBlock = dyn_cast<LayerBlockOp>(parentOp);
7133 if (!parentLayerBlock) {
7134 auto diag = emitOpError()
7135 <<
"has a nested layer symbol, but does not have a '"
7136 << getOperationName() <<
"' op as a parent'";
7137 return diag.attachNote(parentOp->getLoc())
7138 <<
"illegal parent op defined here";
7140 auto parentLayerBlockName = parentLayerBlock.getLayerName();
7141 if (parentLayerBlockName.getRootReference() !=
7142 layerName.getRootReference() ||
7143 parentLayerBlockName.getNestedReferences() !=
7144 layerName.getNestedReferences().drop_back()) {
7145 auto diag = emitOpError() <<
"is nested under an illegal layer block";
7146 return diag.attachNote(parentLayerBlock->getLoc())
7147 <<
"illegal parent layer block defined here";
7153 auto result = getBody(0)->walk<mlir::WalkOrder::PreOrder>(
7154 [&](Operation *op) -> WalkResult {
7156 if (isa<LayerBlockOp>(op))
7157 return WalkResult::skip();
7161 for (
auto operand : op->getOperands()) {
7163 if (
auto *definingOp = operand.getDefiningOp())
7167 auto type = operand.getType();
7170 if (isa<PropertyType>(type)) {
7171 auto diag = emitOpError() <<
"captures a property operand";
7172 diag.attachNote(operand.getLoc()) <<
"operand is defined here";
7173 diag.attachNote(op->getLoc()) <<
"operand is used here";
7174 return WalkResult::interrupt();
7179 if (
auto connect = dyn_cast<FConnectLike>(op)) {
7181 if (isa<RefDefineOp>(connect))
7182 return WalkResult::advance();
7189 bool passive =
true;
7192 passive = type.isPassive();
7201 return WalkResult::advance();
7204 return WalkResult::advance();
7208 <<
"connects to a destination which is defined outside its "
7209 "enclosing layer block";
7210 diag.attachNote(
getLoc()) <<
"enclosing layer block is defined here";
7211 diag.attachNote(dest.getLoc()) <<
"destination is defined here";
7212 return WalkResult::interrupt();
7215 return WalkResult::advance();
7218 return failure(result.wasInterrupted());
7222LayerBlockOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7224 symbolTable.lookupNearestSymbolFrom<LayerOp>(*
this, getLayerNameAttr());
7226 return emitOpError(
"invalid symbol reference");
7237 setNameFn(getResult(),
"time");
7240void HierarchicalModuleNameOp::getAsmResultNames(
7242 setNameFn(getResult(),
"hierarchicalmodulename");
7245ParseResult FPrintFOp::parse(::mlir::OpAsmParser &parser,
7246 ::mlir::OperationState &result) {
7248 OpAsmParser::UnresolvedOperand clock, cond;
7249 if (parser.parseOperand(clock) || parser.parseComma() ||
7250 parser.parseOperand(cond) || parser.parseComma())
7254 [&parser](llvm::SMLoc &loc, StringAttr &result,
7255 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &operands)
7257 loc = parser.getCurrentLocation();
7260 std::string resultStr;
7261 if (parser.parseString(&resultStr))
7263 result = parser.getBuilder().getStringAttr(resultStr);
7266 if (parser.parseOperandList(operands, AsmParser::Delimiter::OptionalParen))
7272 SmallVector<OpAsmParser::UnresolvedOperand> outputFileSubstitutions,
7274 llvm::SMLoc outputFileLoc, formatStringLoc;
7278 result.getOrAddProperties<FPrintFOp::Properties>().outputFile,
7279 outputFileSubstitutions) ||
7280 parser.parseComma() ||
7283 result.getOrAddProperties<FPrintFOp::Properties>().formatString,
7291 Type clockType, condType;
7292 SmallVector<Type> restTypes;
7294 if (parser.parseColon() || parser.parseType(clockType) ||
7295 parser.parseComma() || parser.parseType(condType))
7298 if (succeeded(parser.parseOptionalComma())) {
7299 if (parser.parseTypeList(restTypes))
7304 result.getOrAddProperties<FPrintFOp::Properties>().operandSegmentSizes = {
7305 1, 1,
static_cast<int32_t
>(outputFileSubstitutions.size()),
7306 static_cast<int32_t
>(substitutions.size())};
7309 if (parser.resolveOperand(clock, clockType, result.operands) ||
7310 parser.resolveOperand(cond, condType, result.operands) ||
7311 parser.resolveOperands(
7312 outputFileSubstitutions,
7313 ArrayRef(restTypes).take_front(outputFileSubstitutions.size()),
7314 outputFileLoc, result.operands) ||
7315 parser.resolveOperands(
7317 ArrayRef(restTypes).drop_front(outputFileSubstitutions.size()),
7318 formatStringLoc, result.operands))
7324void FPrintFOp::print(OpAsmPrinter &p) {
7325 p <<
" " << getClock() <<
", " << getCond() <<
", ";
7326 p.printAttributeWithoutType(getOutputFileAttr());
7327 if (!getOutputFileSubstitutions().
empty()) {
7329 p.printOperands(getOutputFileSubstitutions());
7333 p.printAttributeWithoutType(getFormatStringAttr());
7334 if (!getSubstitutions().
empty()) {
7336 p.printOperands(getSubstitutions());
7340 p <<
" : " << getClock().getType() <<
", " << getCond().getType();
7341 if (!getOutputFileSubstitutions().
empty() || !getSubstitutions().
empty()) {
7342 for (
auto type : getOperands().drop_front(2).getTypes()) {
7353LogicalResult FFlushOp::verify() {
7354 if (!getOutputFileAttr() && !getOutputFileSubstitutions().
empty())
7355 return emitOpError(
"substitutions without output file are not allowed");
7363LogicalResult BindOp::verifyInnerRefs(hw::InnerRefNamespace &ns) {
7364 auto ref = getInstanceAttr();
7365 auto target = ns.
lookup(ref);
7367 return emitError() <<
"target " << ref <<
" cannot be resolved";
7369 if (!target.isOpOnly())
7370 return emitError() <<
"target " << ref <<
" is not an operation";
7372 auto instance = dyn_cast<InstanceOp>(target.getOp());
7374 return emitError() <<
"target " << ref <<
" is not an instance";
7376 if (!instance.getDoNotPrint())
7377 return emitError() <<
"target " << ref <<
" is not marked doNotPrint";
7391DomainCreateAnonOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7392 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
7393 auto domainAttr = getDomainAttr();
7395 auto *symbol = symbolTable.lookupSymbolIn(circuitOp, domainAttr);
7397 return emitOpError() <<
"references undefined symbol '" << domainAttr
7400 if (!isa<DomainOp>(symbol))
7401 return emitOpError() <<
"references symbol '" << domainAttr
7402 <<
"' which is not a domain";
7405 auto domainType = getResult().getType();
7406 return domainType.verifySymbolUses(getOperation(), symbolTable);
7414DomainCreateOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7415 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
7416 auto domainAttr = getDomainAttr();
7418 auto *symbol = symbolTable.lookupSymbolIn(circuitOp, domainAttr);
7420 return emitOpError() <<
"references undefined symbol '" << domainAttr
7423 if (!isa<DomainOp>(symbol))
7424 return emitOpError() <<
"references symbol '" << domainAttr
7425 <<
"' which is not a domain";
7428 auto domainType = getResult().getType();
7429 return domainType.verifySymbolUses(getOperation(), symbolTable);
7432LogicalResult DomainCreateOp::verify() {
7434 auto domainType = getResult().getType();
7435 auto fields = domainType.getFields();
7436 auto fieldValues = getFieldValues();
7439 if (fieldValues.size() != fields.size())
7440 return emitOpError() <<
"has " << fieldValues.size()
7441 <<
" field value(s) but domain '"
7442 << domainType.getName() <<
"' expects "
7443 << fields.size() <<
" field(s)";
7446 for (
size_t i = 0; i < fields.size(); ++i) {
7447 auto fieldAttr = cast<DomainFieldAttr>(fields[i]);
7448 auto expectedType = fieldAttr.getType();
7449 auto actualType = fieldValues[i].getType();
7451 if (expectedType == actualType)
7454 return emitOpError() <<
"field value " << i <<
" has type " << actualType
7455 <<
" but domain field '" << fieldAttr.getName()
7456 <<
"' expects type " << expectedType;
7466StringAttr DomainSubfieldOp::getFieldName() {
7467 auto domainType = getInput().getType();
7468 auto fields = domainType.getFields();
7469 auto index = getFieldIndex();
7471 if (index >= fields.size())
7474 return cast<DomainFieldAttr>(fields[index]).getName();
7477Type DomainSubfieldOp::inferReturnType(Type inType, uint32_t fieldIndex,
7478 std::optional<Location> loc) {
7479 auto domainType = dyn_cast<DomainType>(inType);
7483 auto fields = domainType.getFields();
7484 if (fieldIndex >= fields.size())
7486 loc,
"field index ", fieldIndex,
7487 +
" is greater than the number of fields in the domain");
7489 return cast<DomainFieldAttr>(fields[fieldIndex]).getType();
7492Type DomainSubfieldOp::inferReturnType(ValueRange operands,
7493 mlir::DictionaryAttr
attrs,
7494 mlir::PropertyRef properties,
7495 mlir::RegionRange regions,
7496 std::optional<Location> loc) {
7497 Adaptor adaptor(operands,
attrs, properties, regions);
7498 return inferReturnType(adaptor.getInput().getType(), adaptor.getFieldIndex(),
7502DomainSubfieldOp DomainSubfieldOp::create(OpBuilder &builder, Type resultType,
7503 Value base,
unsigned fieldIndex) {
7504 OperationState state(builder.getUnknownLoc(),
7505 DomainSubfieldOp::getOperationName());
7506 state.addOperands(base);
7507 state.addAttribute(
"fieldIndex", builder.getI32IntegerAttr(fieldIndex));
7508 state.addTypes(resultType);
7509 return cast<DomainSubfieldOp>(builder.create(state));
7512LogicalResult DomainSubfieldOp::inferReturnTypes(
7513 MLIRContext *
context, std::optional<Location> location, ValueRange operands,
7514 DictionaryAttr attributes, PropertyRef properties, RegionRange regions,
7515 SmallVectorImpl<Type> &inferredReturnTypes) {
7516 Adaptor adaptor(operands, attributes, properties, regions);
7517 auto resultType = inferReturnType(adaptor.getInput().getType(),
7518 adaptor.getFieldIndex(), location);
7521 inferredReturnTypes.push_back(resultType);
7525void DomainSubfieldOp::print(OpAsmPrinter &p) {
7526 p <<
' ' << getInput() <<
"[";
7529 p.printOptionalAttrDict((*this)->getAttrs(), {
"fieldIndex"});
7530 p <<
" : " << getInput().getType();
7533ParseResult DomainSubfieldOp::parse(OpAsmParser &parser,
7534 OperationState &result) {
7535 auto *
context = parser.getContext();
7537 OpAsmParser::UnresolvedOperand input;
7538 std::string fieldName;
7539 DomainType inputType;
7541 if (parser.parseOperand(input) || parser.parseLSquare() ||
7542 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
7543 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
7544 parser.parseType(inputType) ||
7545 parser.resolveOperand(input, inputType, result.operands))
7549 auto fieldIndex = inputType.getFieldIndex(fieldName);
7551 return parser.emitError(parser.getNameLoc(),
7552 "unknown field '" + fieldName +
"' in domain type");
7555 result.addAttribute(
7557 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
7560 auto resultType = inferReturnType(inputType, *fieldIndex, std::nullopt);
7564 result.addTypes(resultType);
7573#define GET_OP_CLASSES
7574#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 void printClassLike(OpAsmPrinter &p, ClassLike op)
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 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 ParseResult parseFieldsFromDomain(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &fieldValues, SmallVectorImpl< Type > &fieldTypes, Type &resultType)
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 printFieldsFromDomain(OpAsmPrinter &p, Operation *op, OperandRange fieldValues, TypeRange fieldTypes, Type resultType)
static void printSubfieldLikeOp(OpTy op, ::mlir::OpAsmPrinter &printer)
static bool checkAggConstant(Operation *op, Attribute attr, FIRRTLBaseType type)
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 LogicalResult verifyInitialAttr(Operation *op, FIRRTLBaseType regType, IntegerAttr initial)
Verify that an optional initial time-zero value attribute is a constant of the correct ground type.
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 verifyObjectSymbolUses(FObjectLike object, SymbolTableCollection &symbolTable)
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 InstanceOp cloneWithErasedPorts(InstanceOp &instance, const llvm::BitVector &inErasures, const llvm::BitVector &outErasures)
Clone instance, but with ports deleted according to the inErasures and outErasures BitVectors.
static bool isAncestor(Block *block, Block *other)
static Location getLoc(DefSlot slot)
false return failure()
Parse an optional keyword or string and set instance into 'result'.
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.
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).
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)
constexpr bool isValidSrc(Flow flow)
SmallSet< SymbolRefAttr, 4, LayerSetCompare > LayerSet
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 hasHardwareElements(FIRRTLType type)
Return true if the given type contains any elements of hardware types.
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.
BaseTy type_dyn_cast(Type type)
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...
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...
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn
StringAttr getFirMemoryName() const
Compares two SymbolRefAttr lexicographically, returning true if LHS should be ordered before RHS.
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.