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;
48using namespace firrtl;
49using namespace chirrtl;
60 const llvm::BitVector &indicesToDrop) {
63 int lastIndex = indicesToDrop.find_last();
65 assert((
size_t)lastIndex < input.size() &&
"index out of range");
75 size_t lastCopied = 0;
76 SmallVector<T> result;
77 result.reserve(input.size() - indicesToDrop.count());
79 for (
unsigned indexToDrop : indicesToDrop.set_bits()) {
81 if (indexToDrop > lastCopied) {
82 result.append(input.begin() + lastCopied, input.begin() + indexToDrop);
83 lastCopied = indexToDrop;
90 if (lastCopied < input.size())
91 result.append(input.begin() + lastCopied, input.end());
97template <
typename RetTy =
FIRRTLType,
typename... Args>
99 const Twine &message, Args &&...args) {
101 (mlir::emitError(*loc, message) << ... << std::forward<Args>(args));
107 while (Operation *op = val.getDefiningOp()) {
109 TypeSwitch<Operation *, std::optional<bool>>(op)
110 .Case<SubfieldOp, SubindexOp, SubaccessOp>([&val](
auto op) {
114 .Case<RegOp, RegResetOp, WireOp>([](
auto) {
return true; })
115 .Default([](
auto) {
return false; });
122SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
123MemOp::computeDataFlow() {
126 if (getReadLatency() > 0)
128 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
130 for (
auto memPort : getResults())
131 if (auto type =
type_dyn_cast<BundleType>(memPort.getType())) {
132 auto enableFieldId = type.getFieldID((
unsigned)ReadPortSubfield::en);
133 auto addressFieldId = type.getFieldID((
unsigned)ReadPortSubfield::addr);
134 auto dataFieldId = type.getFieldID((
unsigned)ReadPortSubfield::data);
136 FieldRef(memPort,
static_cast<unsigned>(dataFieldId)),
137 FieldRef(memPort,
static_cast<unsigned>(enableFieldId)));
139 FieldRef(memPort,
static_cast<unsigned>(dataFieldId)),
140 FieldRef(memPort,
static_cast<unsigned>(addressFieldId)));
147 constexpr unsigned int addr = 1 << 0;
148 constexpr unsigned int en = 1 << 1;
149 constexpr unsigned int clk = 1 << 2;
150 constexpr unsigned int data = 1 << 3;
151 constexpr unsigned int mask = 1 << 4;
152 constexpr unsigned int rdata = 1 << 5;
153 constexpr unsigned int wdata = 1 << 6;
154 constexpr unsigned int wmask = 1 << 7;
155 constexpr unsigned int wmode = 1 << 8;
156 constexpr unsigned int def = 1 << 9;
158 auto portType = type_dyn_cast<BundleType>(type);
160 return MemOp::PortKind::Debug;
163 for (
auto elem : portType.getElements()) {
164 fields |= llvm::StringSwitch<unsigned>(elem.name.getValue())
170 .Case(
"rdata",
rdata)
171 .Case(
"wdata",
wdata)
172 .Case(
"wmask",
wmask)
173 .Case(
"wmode",
wmode)
177 return MemOp::PortKind::Read;
179 return MemOp::PortKind::Write;
181 return MemOp::PortKind::ReadWrite;
182 return MemOp::PortKind::Debug;
197 llvm_unreachable(
"Unsupported Flow type.");
205 return "source flow";
209 return "duplex flow";
212 llvm_unreachable(
"Unsupported Flow type.");
217 if (
auto blockArg = dyn_cast<BlockArgument>(val)) {
218 auto *op = val.getParentBlock()->getParentOp();
219 if (
auto moduleLike = dyn_cast<FModuleLike>(op)) {
220 auto direction = moduleLike.getPortDirection(blockArg.getArgNumber());
221 if (direction == Direction::Out)
224 return accumulatedFlow;
227 Operation *op = val.getDefiningOp();
229 return TypeSwitch<Operation *, Flow>(op)
230 .Case<SubfieldOp, OpenSubfieldOp>([&](
auto op) {
231 return foldFlow(op.getInput(), op.isFieldFlipped()
235 .Case<SubindexOp, SubaccessOp, OpenSubindexOp, RefSubOp>(
236 [&](
auto op) {
return foldFlow(op.getInput(), accumulatedFlow); })
238 .Case<RegOp, RegResetOp, WireOp, MemoryPortOp>(
239 [](
auto) {
return Flow::Duplex; })
240 .Case<InstanceOp, InstanceChoiceOp>([&](
auto inst) {
241 auto resultNo = cast<OpResult>(val).getResultNumber();
242 if (inst.getPortDirection(resultNo) == Direction::Out)
243 return accumulatedFlow;
246 .Case<MemOp>([&](
auto op) {
248 if (type_isa<RefType>(val.getType()))
252 .Case<ObjectSubfieldOp>([&](ObjectSubfieldOp op) {
253 auto input = op.getInput();
254 auto *inputOp = input.getDefiningOp();
257 if (
auto objectOp = dyn_cast_or_null<ObjectOp>(inputOp)) {
258 auto classType = input.getType();
259 auto direction = classType.getElement(op.getIndex()).direction;
260 if (direction == Direction::In)
271 auto classType = input.getType();
272 auto direction = classType.getElement(op.getIndex()).direction;
273 if (direction == Direction::In)
276 op = dyn_cast_or_null<ObjectSubfieldOp>(inputOp);
278 input = op.getInput();
279 inputOp = input.getDefiningOp();
283 return accumulatedFlow;
287 .Default([&](
auto) {
return accumulatedFlow; });
293 Operation *op = val.getDefiningOp();
295 return DeclKind::Port;
297 return TypeSwitch<Operation *, DeclKind>(op)
298 .Case<InstanceOp>([](
auto) {
return DeclKind::Instance; })
299 .Case<SubfieldOp, SubindexOp, SubaccessOp, OpenSubfieldOp, OpenSubindexOp,
301 .Default([](
auto) {
return DeclKind::Other; });
305 if (
auto module = dyn_cast<FModuleLike>(op))
306 return module.getNumPorts();
307 return op->getNumResults();
321 if (
auto *op = value.getDefiningOp())
323 auto arg = dyn_cast<BlockArgument>(value);
324 auto module = dyn_cast<FModuleOp>(arg.getOwner()->getParentOp());
327 return (module.getPortSymbolAttr(arg.getArgNumber())) ||
334 OpAsmSetValueNameFn setNameFn) {
338 auto *block = ®ion.front();
341 auto argAttr = parentOp->getAttrOfType<ArrayAttr>(
"portNames");
343 if (!argAttr || argAttr.size() != block->getNumArguments())
346 for (
size_t i = 0, e = block->getNumArguments(); i != e; ++i) {
347 auto str = cast<StringAttr>(argAttr[i]).getValue();
349 setNameFn(block->getArgument(i), str);
355 firrtl::NameKindEnumAttr &result);
366 for (; op !=
nullptr; op = op->getParentOp()) {
367 if (
auto module = dyn_cast<FModuleLike>(op)) {
368 auto layers =
module.getLayersAttr().getAsRange<SymbolRefAttr>();
369 result.insert(layers.begin(), layers.end());
372 if (
auto layerblock = dyn_cast<LayerBlockOp>(op)) {
373 result.insert(layerblock.getLayerName());
391 if (
auto type = dyn_cast<RefType>(value.getType()))
392 if (
auto layer = type.getLayer())
393 result.insert(type.getLayer());
402 mlir::SymbolRefAttr dstLayer) {
412 if (srcLayer.getRootReference() != dstLayer.getRootReference())
415 auto srcNames = srcLayer.getNestedReferences();
416 auto dstNames = dstLayer.getNestedReferences();
417 if (dstNames.size() < srcNames.size())
420 return llvm::all_of(llvm::zip_first(srcNames, dstNames),
421 [](
auto x) {
return std::get<0>(x) == std::get<1>(x); });
428 if (dstLayers.contains(srcLayer))
433 return any_of(dstLayers, [=](SymbolRefAttr dstLayer) {
442 SmallVectorImpl<SymbolRefAttr> &missing) {
443 for (
auto srcLayer : src)
445 missing.push_back(srcLayer);
448 return missing.empty();
453 const Twine &errorMsg,
454 const Twine ¬eMsg = Twine(
"missing layer requirements")) {
455 SmallVector<SymbolRefAttr> missing;
458 interleaveComma(missing, op->emitOpError(errorMsg).attachNote()
467void CircuitOp::build(OpBuilder &builder, OperationState &result,
468 StringAttr name, ArrayAttr annotations) {
470 result.getOrAddProperties<Properties>().setName(name);
473 annotations = builder.getArrayAttr({});
474 result.getOrAddProperties<Properties>().setAnnotations(annotations);
477 Region *bodyRegion = result.addRegion();
479 bodyRegion->push_back(body);
483 NamedAttrList &resultAttrs) {
484 auto result = parser.parseOptionalAttrDictWithKeyword(resultAttrs);
485 if (!resultAttrs.get(
"annotations"))
486 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
492 DictionaryAttr attr) {
494 SmallVector<StringRef> elidedAttrs = {
"name"};
496 auto annotationsAttr = op->getAttrOfType<ArrayAttr>(
"annotations");
497 if (annotationsAttr.empty())
498 elidedAttrs.push_back(
"annotations");
500 p.printOptionalAttrDictWithKeyword(op->getAttrs(), elidedAttrs);
503LogicalResult CircuitOp::verifyRegions() {
508 emitOpError(
"must have a non-empty name");
512 mlir::SymbolTable symtbl(getOperation());
514 auto *mainModule = symtbl.lookup(
main);
516 return emitOpError().append(
517 "does not contain module with same name as circuit");
518 if (!isa<FModuleLike>(mainModule))
519 return mainModule->emitError(
520 "entity with name of circuit must be a module");
521 if (symtbl.getSymbolVisibility(mainModule) !=
522 mlir::SymbolTable::Visibility::Public)
523 return mainModule->emitError(
"main module must be public");
528 llvm::DenseMap<Attribute, FExtModuleOp> defnameMap;
530 auto verifyExtModule = [&](FExtModuleOp extModule) -> LogicalResult {
534 auto defname = extModule.getDefnameAttr();
540 if (
auto collidingModule = symtbl.lookup<FModuleOp>(defname.getValue()))
541 return extModule.emitOpError()
542 .append(
"attribute 'defname' with value ", defname,
543 " conflicts with the name of another module in the circuit")
544 .attachNote(collidingModule.getLoc())
545 .append(
"previous module declared here");
553 FExtModuleOp collidingExtModule;
554 if (
auto &value = defnameMap[defname]) {
555 collidingExtModule = value;
556 if (!value.getParameters().empty() && extModule.getParameters().empty())
566 SmallVector<PortInfo> ports = extModule.getPorts();
567 SmallVector<PortInfo> collidingPorts = collidingExtModule.getPorts();
569 if (ports.size() != collidingPorts.size())
570 return extModule.emitOpError()
571 .append(
"with 'defname' attribute ", defname,
" has ", ports.size(),
572 " ports which is different from a previously defined "
573 "extmodule with the same 'defname' which has ",
574 collidingPorts.size(),
" ports")
575 .attachNote(collidingExtModule.getLoc())
576 .append(
"previous extmodule definition occurred here");
582 for (
auto p :
llvm::zip(ports, collidingPorts)) {
583 StringAttr aName = std::get<0>(p).name, bName = std::get<1>(p).name;
584 Type aType = std::get<0>(p).type, bType = std::get<1>(p).type;
587 return extModule.emitOpError()
588 .append(
"with 'defname' attribute ", defname,
589 " has a port with name ", aName,
590 " which does not match the name of the port in the same "
591 "position of a previously defined extmodule with the same "
592 "'defname', expected port to have name ",
594 .attachNote(collidingExtModule.getLoc())
595 .append(
"previous extmodule definition occurred here");
597 if (!extModule.getParameters().empty() ||
598 !collidingExtModule.getParameters().empty()) {
600 if (
auto base = type_dyn_cast<FIRRTLBaseType>(aType))
601 aType = base.getWidthlessType();
602 if (
auto base = type_dyn_cast<FIRRTLBaseType>(bType))
603 bType = base.getWidthlessType();
606 return extModule.emitOpError()
607 .append(
"with 'defname' attribute ", defname,
608 " has a port with name ", aName,
609 " which has a different type ", aType,
610 " which does not match the type of the port in the same "
611 "position of a previously defined extmodule with the same "
612 "'defname', expected port to have type ",
614 .attachNote(collidingExtModule.getLoc())
615 .append(
"previous extmodule definition occurred here");
620 SmallVector<FModuleOp, 1> dutModules;
623 if (
auto moduleOp = dyn_cast<FModuleOp>(op)) {
625 dutModules.push_back(moduleOp);
630 if (
auto extModule = dyn_cast<FExtModuleOp>(op)) {
631 if (verifyExtModule(extModule).failed())
637 if (dutModules.size() > 1) {
638 auto diag = dutModules[0]->emitOpError()
639 <<
"is annotated as the design-under-test (DUT), but other "
640 "modules are also annotated";
641 for (
auto moduleOp : ArrayRef(dutModules).drop_front())
642 diag.attachNote(moduleOp.
getLoc()) <<
"is also annotated as the DUT";
649Block *CircuitOp::getBodyBlock() {
return &getBody().front(); }
656 SmallVector<PortInfo> results;
657 results.reserve(module.getNumPorts());
658 ArrayRef<Attribute> domains =
module.getDomainInfo();
659 for (
unsigned i = 0, e = module.getNumPorts(); i < e; ++i) {
660 results.push_back({
module.getPortNameAttr(i), module.getPortType(i),
661 module.getPortDirection(i), module.getPortSymbolAttr(i),
662 module.getPortLocation(i),
663 AnnotationSet::forPort(module, i),
664 domains.empty() ? Attribute{} : domains[i]});
669SmallVector<PortInfo> FModuleOp::getPorts() { return ::getPortImpl(*
this); }
671SmallVector<PortInfo> FExtModuleOp::getPorts() { return ::getPortImpl(*
this); }
673SmallVector<PortInfo> FIntModuleOp::getPorts() { return ::getPortImpl(*
this); }
675SmallVector<PortInfo> FMemModuleOp::getPorts() { return ::getPortImpl(*
this); }
678 if (dir == Direction::In)
679 return hw::ModulePort::Direction::Input;
680 if (dir == Direction::Out)
681 return hw::ModulePort::Direction::Output;
682 assert(0 &&
"invalid direction");
687 SmallVector<hw::PortInfo> results;
688 auto aname = StringAttr::get(module.getContext(),
689 hw::HWModuleLike::getPortSymbolAttrName());
690 auto emptyDict = DictionaryAttr::get(module.getContext());
691 for (
unsigned i = 0, e =
getNumPorts(module); i < e; ++i) {
692 auto sym =
module.getPortSymbolAttr(i);
694 {{
module.getPortNameAttr(i), module.getPortType(i),
695 dirFtoH(module.getPortDirection(i))},
697 sym ? DictionaryAttr::get(
699 ArrayRef<mlir::NamedAttribute>{NamedAttribute{aname, sym}})
701 module.getPortLocation(i)});
706SmallVector<::circt::hw::PortInfo> FModuleOp::getPortList() {
707 return ::getPortListImpl(*
this);
710SmallVector<::circt::hw::PortInfo> FExtModuleOp::getPortList() {
711 return ::getPortListImpl(*
this);
714SmallVector<::circt::hw::PortInfo> FIntModuleOp::getPortList() {
715 return ::getPortListImpl(*
this);
718SmallVector<::circt::hw::PortInfo> FMemModuleOp::getPortList() {
719 return ::getPortListImpl(*
this);
723 auto sym =
module.getPortSymbolAttr(idx);
724 auto attrs = sym ? DictionaryAttr::getWithSorted(
726 ArrayRef(mlir::NamedAttribute(
727 hw::HWModuleLike::getPortSymbolAttrName(), sym)))
728 : DictionaryAttr::get(module.getContext());
729 return {{
module.getPortNameAttr(idx), module.getPortType(idx),
730 dirFtoH(module.getPortDirection(idx))},
733 module.getPortLocation(idx)};
737 return ::getPortImpl(*
this, idx);
741 return ::getPortImpl(*
this, idx);
745 return ::getPortImpl(*
this, idx);
749 return ::getPortImpl(*
this, idx);
753BlockArgument FModuleOp::getArgument(
size_t portNumber) {
760 Attribute domainInfoAttr,
761 ArrayRef<unsigned> indexMap) {
763 auto di = dyn_cast_or_null<ArrayAttr>(domainInfoAttr);
764 if (!di || di.empty())
765 return domainInfoAttr;
768 SmallVector<Attribute> domainInfo;
769 for (
auto attr : di) {
770 auto oldIdx = cast<IntegerAttr>(attr).getUInt();
771 auto newIdx = indexMap[oldIdx];
772 if (oldIdx == newIdx)
773 domainInfo.push_back(attr);
775 domainInfo.push_back(IntegerAttr::get(
776 IntegerType::get(
context, 32, IntegerType::Unsigned), newIdx));
778 return ArrayAttr::get(
context, domainInfo);
785 ArrayRef<std::pair<unsigned, PortInfo>> ports) {
788 unsigned oldNumArgs = op.getNumPorts();
789 unsigned newNumArgs = oldNumArgs + ports.size();
792 SmallVector<unsigned> indexMap(oldNumArgs);
794 for (
size_t i = 0; i < oldNumArgs; ++i) {
795 while (inserted < ports.size() && ports[inserted].first == i)
797 indexMap[i] = i + inserted;
801 auto existingDirections = op.getPortDirectionsAttr();
802 ArrayRef<Attribute> existingNames = op.getPortNames();
803 ArrayRef<Attribute> existingTypes = op.getPortTypes();
804 ArrayRef<Attribute> existingLocs = op.getPortLocations();
805 assert(existingDirections.size() == oldNumArgs);
806 assert(existingNames.size() == oldNumArgs);
807 assert(existingTypes.size() == oldNumArgs);
808 assert(existingLocs.size() == oldNumArgs);
810 SmallVector<bool> newDirections;
811 SmallVector<Attribute> newNames, newTypes, newDomains, newAnnos, newSyms,
813 newDirections.reserve(newNumArgs);
814 newNames.reserve(newNumArgs);
815 newTypes.reserve(newNumArgs);
816 newDomains.reserve(newNumArgs);
817 newAnnos.reserve(newNumArgs);
818 newSyms.reserve(newNumArgs);
819 newLocs.reserve(newNumArgs);
821 auto emptyArray = ArrayAttr::get(op.getContext(), {});
824 auto migrateOldPorts = [&](
unsigned untilOldIdx) {
825 while (oldIdx < oldNumArgs && oldIdx < untilOldIdx) {
826 newDirections.push_back(existingDirections[oldIdx]);
827 newNames.push_back(existingNames[oldIdx]);
828 newTypes.push_back(existingTypes[oldIdx]);
830 op.getContext(), op.getDomainInfoAttrForPort(oldIdx), indexMap));
831 newAnnos.push_back(op.getAnnotationsAttrForPort(oldIdx));
832 newSyms.push_back(op.getPortSymbolAttr(oldIdx));
833 newLocs.push_back(existingLocs[oldIdx]);
838 for (
auto [idx, port] : ports) {
839 migrateOldPorts(idx);
841 newNames.push_back(port.name);
842 newTypes.push_back(TypeAttr::get(port.type));
845 port.domains ? port.domains : ArrayAttr::get(op.getContext(), {}),
847 auto annos = port.annotations.getArrayAttr();
848 newAnnos.push_back(annos ? annos : emptyArray);
849 newSyms.push_back(port.sym);
850 newLocs.push_back(port.loc);
853 migrateOldPorts(oldNumArgs);
857 if (llvm::all_of(newAnnos, [](Attribute attr) {
858 return cast<ArrayAttr>(attr).empty();
864 if (llvm::all_of(newDomains, [](Attribute attr) {
867 if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr))
868 return arrayAttr.empty();
874 op->setAttr(
"portDirections",
876 op->setAttr(
"portNames", ArrayAttr::get(op.getContext(), newNames));
877 op->setAttr(
"portTypes", ArrayAttr::get(op.getContext(), newTypes));
878 op->setAttr(
"domainInfo", ArrayAttr::get(op.getContext(), newDomains));
879 op->setAttr(
"portAnnotations", ArrayAttr::get(op.getContext(), newAnnos));
880 FModuleLike::fixupPortSymsArray(newSyms, op.getContext());
881 op.setPortSymbols(newSyms);
882 op->setAttr(
"portLocations", ArrayAttr::get(op.getContext(), newLocs));
893 ArrayAttr domainInfoAttr,
894 const llvm::BitVector &portIndices,
895 bool supportsEmptyAttr) {
896 if (supportsEmptyAttr && domainInfoAttr.empty())
897 return domainInfoAttr;
900 SmallVector<unsigned> indexMap(portIndices.size());
902 for (
size_t i = 0, e = portIndices.size(); i != e; ++i) {
903 indexMap[i] = i - deleted;
910 auto getEmpty = [&]() {
912 eEmpty = ArrayAttr::get(
context, {});
917 SmallVector<Attribute> newDomainInfo;
918 newDomainInfo.reserve(portIndices.size() - portIndices.count());
919 for (
size_t i = 0, e = portIndices.size(); i != e; ++i) {
921 if (portIndices.test(i))
924 if (domainInfoAttr.empty()) {
925 newDomainInfo.push_back(getEmpty());
928 auto attr = domainInfoAttr[i];
930 auto domains = dyn_cast<ArrayAttr>(attr);
931 if (!domains || domains.empty()) {
932 newDomainInfo.push_back(attr);
936 SmallVector<Attribute> newDomains;
937 for (
auto domain : domains) {
939 auto oldIdx = cast<IntegerAttr>(domain).getUInt();
940 if (portIndices.test(oldIdx))
943 auto newIdx = indexMap[oldIdx];
944 if (oldIdx == newIdx) {
945 newDomains.push_back(domain);
949 newDomains.push_back(IntegerAttr::get(
950 IntegerType::get(
context, 32, IntegerType::Unsigned), newIdx));
952 newDomainInfo.push_back(ArrayAttr::get(
context, newDomains));
955 return ArrayAttr::get(
context, newDomainInfo);
959static void erasePorts(FModuleLike op,
const llvm::BitVector &portIndices) {
960 if (portIndices.none())
964 ArrayRef<bool> portDirections = op.getPortDirectionsAttr().asArrayRef();
965 ArrayRef<Attribute> portNames = op.getPortNames();
966 ArrayRef<Attribute> portTypes = op.getPortTypes();
967 ArrayRef<Attribute> portAnnos = op.getPortAnnotations();
968 ArrayRef<Attribute> portSyms = op.getPortSymbols();
969 ArrayRef<Attribute> portLocs = op.getPortLocations();
970 ArrayRef<Attribute> portDomains = op.getDomainInfo();
971 auto numPorts = op.getNumPorts();
973 assert(portDirections.size() == numPorts);
974 assert(portNames.size() == numPorts);
975 assert(portAnnos.size() == numPorts || portAnnos.empty());
976 assert(portTypes.size() == numPorts);
977 assert(portSyms.size() == numPorts || portSyms.empty());
978 assert(portLocs.size() == numPorts);
979 assert(portDomains.size() == numPorts || portDomains.empty());
981 SmallVector<bool> newPortDirections =
982 removeElementsAtIndices<bool>(portDirections, portIndices);
983 SmallVector<Attribute> newPortNames, newPortTypes, newPortAnnos, newPortSyms,
991 op->setAttr(
"portDirections",
993 op->setAttr(
"portNames", ArrayAttr::get(op.getContext(), newPortNames));
994 op->setAttr(
"portAnnotations", ArrayAttr::get(op.getContext(), newPortAnnos));
995 op->setAttr(
"portTypes", ArrayAttr::get(op.getContext(), newPortTypes));
996 FModuleLike::fixupPortSymsArray(newPortSyms, op.getContext());
997 op->setAttr(
"portSymbols", ArrayAttr::get(op.getContext(), newPortSyms));
998 op->setAttr(
"portLocations", ArrayAttr::get(op.getContext(), newPortLocs));
999 op->setAttr(
"domainInfo",
1001 portIndices,
true));
1004void FExtModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1005 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1008void FIntModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1009 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1012void FMemModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1013 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1016void FModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1017 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1024void FModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1025 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1029 for (
size_t i = 0, e = ports.size(); i < e; ++i) {
1032 auto &[index, port] = ports[i];
1033 body->insertArgument(index + i, port.type, port.loc);
1037void FExtModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1038 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1041void FIntModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1042 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1048void FMemModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1049 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1052template <
typename OpTy>
1054 StringAttr name, ArrayRef<PortInfo> ports) {
1056 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
1057 properties.setSymName(name);
1060 SmallVector<Direction, 4> portDirections;
1061 SmallVector<Attribute, 4> portNames, portTypes, portSyms, portLocs,
1063 portDirections.reserve(ports.size());
1064 portNames.reserve(ports.size());
1065 portTypes.reserve(ports.size());
1066 portSyms.reserve(ports.size());
1067 portLocs.reserve(ports.size());
1068 portDomains.reserve(ports.size());
1070 for (
const auto &port : ports) {
1071 portDirections.push_back(port.direction);
1072 portNames.push_back(port.name);
1073 portTypes.push_back(TypeAttr::get(port.type));
1074 portSyms.push_back(port.sym);
1075 portLocs.push_back(port.loc);
1076 portDomains.push_back(port.domains);
1078 if (llvm::all_of(portDomains, [](Attribute attr) {
1081 if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr))
1082 return arrayAttr.empty();
1085 portDomains.clear();
1087 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1090 properties.setPortDirections(
1092 properties.setPortNames(builder.getArrayAttr(portNames));
1093 properties.setPortTypes(builder.getArrayAttr(portTypes));
1094 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1095 properties.setPortLocations(builder.getArrayAttr(portLocs));
1096 properties.setDomainInfo(builder.getArrayAttr(portDomains));
1101template <
typename OpTy>
1103 StringAttr name, ArrayRef<PortInfo> ports,
1104 ArrayAttr annotations, ArrayAttr layers) {
1105 buildModuleLike<OpTy>(builder, result, name, ports);
1106 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
1109 annotations = builder.getArrayAttr({});
1110 properties.setAnnotations(annotations);
1114 SmallVector<Attribute, 4> portAnnotations;
1115 for (
const auto &port : ports)
1116 portAnnotations.push_back(port.annotations.getArrayAttr());
1117 if (llvm::all_of(portAnnotations, [](Attribute attr) {
1118 return cast<ArrayAttr>(attr).empty();
1120 portAnnotations.clear();
1121 properties.setPortAnnotations(builder.getArrayAttr(portAnnotations));
1125 layers = builder.getArrayAttr({});
1126 properties.setLayers(layers);
1129template <
typename OpTy>
1130static void buildClass(OpBuilder &builder, OperationState &result,
1131 StringAttr name, ArrayRef<PortInfo> ports) {
1132 return buildModuleLike<OpTy>(builder, result, name, ports);
1135void FModuleOp::build(OpBuilder &builder, OperationState &result,
1136 StringAttr name, ConventionAttr convention,
1137 ArrayRef<PortInfo> ports, ArrayAttr annotations,
1139 buildModule<FModuleOp>(builder, result, name, ports, annotations, layers);
1140 auto &properties = result.getOrAddProperties<Properties>();
1141 properties.setConvention(convention);
1144 auto *bodyRegion = result.regions[0].get();
1146 bodyRegion->push_back(body);
1149 for (
auto &elt : ports)
1150 body->addArgument(elt.type, elt.loc);
1153void FExtModuleOp::build(OpBuilder &builder, OperationState &result,
1154 StringAttr name, ConventionAttr convention,
1155 ArrayRef<PortInfo> ports, ArrayAttr knownLayers,
1156 StringRef defnameAttr, ArrayAttr annotations,
1157 ArrayAttr parameters, ArrayAttr layers,
1158 ArrayAttr externalRequirements) {
1159 buildModule<FExtModuleOp>(builder, result, name, ports, annotations, layers);
1160 auto &properties = result.getOrAddProperties<Properties>();
1161 properties.setConvention(convention);
1163 knownLayers = builder.getArrayAttr({});
1164 properties.setKnownLayers(knownLayers);
1165 if (!defnameAttr.empty())
1166 properties.setDefname(builder.getStringAttr(defnameAttr));
1168 parameters = builder.getArrayAttr({});
1169 properties.setParameters(parameters);
1170 if (externalRequirements)
1171 properties.setExternalRequirements(externalRequirements);
1174void FIntModuleOp::build(OpBuilder &builder, OperationState &result,
1175 StringAttr name, ArrayRef<PortInfo> ports,
1176 StringRef intrinsicNameStr, ArrayAttr annotations,
1177 ArrayAttr parameters, ArrayAttr layers) {
1178 buildModule<FIntModuleOp>(builder, result, name, ports, annotations, layers);
1179 auto &properties = result.getOrAddProperties<Properties>();
1180 properties.setIntrinsic(builder.getStringAttr(intrinsicNameStr));
1182 parameters = builder.getArrayAttr({});
1183 properties.setParameters(parameters);
1186void FMemModuleOp::build(OpBuilder &builder, OperationState &result,
1187 StringAttr name, ArrayRef<PortInfo> ports,
1188 uint32_t numReadPorts, uint32_t numWritePorts,
1189 uint32_t numReadWritePorts, uint32_t dataWidth,
1190 uint32_t maskBits, uint32_t readLatency,
1191 uint32_t writeLatency, uint64_t depth, RUWBehavior ruw,
1192 ArrayAttr annotations, ArrayAttr layers) {
1193 auto *
context = builder.getContext();
1194 buildModule<FMemModuleOp>(builder, result, name, ports, annotations, layers);
1195 auto ui32Type = IntegerType::get(
context, 32, IntegerType::Unsigned);
1196 auto ui64Type = IntegerType::get(
context, 64, IntegerType::Unsigned);
1197 auto &properties = result.getOrAddProperties<Properties>();
1198 properties.setNumReadPorts(IntegerAttr::get(ui32Type, numReadPorts));
1199 properties.setNumWritePorts(IntegerAttr::get(ui32Type, numWritePorts));
1200 properties.setNumReadWritePorts(
1201 IntegerAttr::get(ui32Type, numReadWritePorts));
1202 properties.setDataWidth(IntegerAttr::get(ui32Type, dataWidth));
1203 properties.setMaskBits(IntegerAttr::get(ui32Type, maskBits));
1204 properties.setReadLatency(IntegerAttr::get(ui32Type, readLatency));
1205 properties.setWriteLatency(IntegerAttr::get(ui32Type, writeLatency));
1206 properties.setDepth(IntegerAttr::get(ui64Type, depth));
1207 properties.setExtraPorts(ArrayAttr::get(
context, {}));
1208 properties.setRuw(RUWBehaviorAttr::get(
context, ruw));
1225 ArrayRef<Attribute> portNames, ArrayRef<Attribute> portTypes,
1226 ArrayRef<Attribute> portAnnotations,
1227 ArrayRef<Attribute> portSyms, ArrayRef<Attribute> portLocs,
1228 ArrayRef<Attribute> domainInfo) {
1231 bool printedNamesDontMatch =
false;
1233 mlir::OpPrintingFlags flags;
1236 DenseMap<unsigned, std::string> ssaNames;
1237 auto getSsaName = [&](
unsigned idx) -> StringRef {
1239 auto itr = ssaNames.find(idx);
1240 if (itr != ssaNames.end())
1241 return itr->getSecond();
1245 SmallString<32> resultNameStr;
1247 llvm::raw_svector_ostream tmpStream(resultNameStr);
1248 p.printOperand(block->getArgument(idx), tmpStream);
1251 auto portName = cast<StringAttr>(portNames[idx]).getValue();
1252 if (tmpStream.str().drop_front() != portName)
1253 printedNamesDontMatch =
true;
1254 return ssaNames.insert({idx, tmpStream.str().str()}).first->getSecond();
1257 auto name = cast<StringAttr>(portNames[idx]).getValue();
1258 return ssaNames.insert({idx, name.str()}).first->getSecond();
1264 for (
unsigned i = 0, e = portTypes.size(); i < e; ++i) {
1273 auto portType = cast<TypeAttr>(portTypes[i]).getValue();
1277 p.printKeywordOrString(getSsaName(i));
1282 p.printType(portType);
1285 if (!portSyms.empty()) {
1286 if (!cast<hw::InnerSymAttr>(portSyms[i]).
empty()) {
1288 cast<hw::InnerSymAttr>(portSyms[i]).print(p);
1296 if (!domainInfo.empty()) {
1297 auto domains = cast<ArrayAttr>(domainInfo[i]);
1298 if (!domains.empty()) {
1300 llvm::interleaveComma(domains, p, [&](Attribute attr) {
1301 p << getSsaName(cast<IntegerAttr>(attr).getUInt());
1309 if (!portAnnotations.empty() &&
1310 !cast<ArrayAttr>(portAnnotations[i]).empty()) {
1312 p.printAttribute(portAnnotations[i]);
1319 if (flags.shouldPrintDebugInfo() && !portLocs.empty())
1320 p.printOptionalLocationSpecifier(cast<LocationAttr>(portLocs[i]));
1324 return printedNamesDontMatch;
1330 OpAsmParser &parser,
bool hasSSAIdentifiers,
bool supportsSymbols,
1331 bool supportsDomains, SmallVectorImpl<OpAsmParser::Argument> &entryArgs,
1332 SmallVectorImpl<Direction> &portDirections,
1333 SmallVectorImpl<Attribute> &portNames,
1334 SmallVectorImpl<Attribute> &portTypes,
1335 SmallVectorImpl<Attribute> &portAnnotations,
1336 SmallVectorImpl<Attribute> &portSyms, SmallVectorImpl<Attribute> &portLocs,
1337 SmallVectorImpl<Attribute> &domains) {
1338 auto *
context = parser.getContext();
1341 DenseMap<Attribute, size_t> domainIndex;
1344 using DomainAndLoc = std::pair<Attribute, llvm::SMLoc>;
1345 DenseMap<size_t, SmallVector<DomainAndLoc>> domainStrings;
1347 auto parseArgument = [&]() -> ParseResult {
1349 if (succeeded(parser.parseOptionalKeyword(
"out")))
1350 portDirections.push_back(Direction::Out);
1351 else if (succeeded(parser.parseKeyword(
"in",
" or 'out'")))
1352 portDirections.push_back(Direction::In);
1359 auto portIdx = portNames.size();
1361 if (hasSSAIdentifiers) {
1362 OpAsmParser::Argument arg;
1363 if (parser.parseArgument(arg))
1365 entryArgs.push_back(arg);
1369 assert(arg.ssaName.name.size() > 1 && arg.ssaName.name[0] ==
'%' &&
1370 "Unknown MLIR name");
1371 if (
isdigit(arg.ssaName.name[1]))
1372 portNames.push_back(StringAttr::get(
context,
""));
1374 portNames.push_back(
1375 StringAttr::get(
context, arg.ssaName.name.drop_front()));
1378 irLoc = arg.ssaName.location;
1382 irLoc = parser.getCurrentLocation();
1383 std::string portName;
1384 if (parser.parseKeywordOrString(&portName))
1386 portNames.push_back(StringAttr::get(
context, portName));
1391 if (parser.parseColonType(portType))
1393 portTypes.push_back(TypeAttr::get(portType));
1394 if (isa<DomainType>(portType))
1395 domainIndex[portNames.back()] = portIdx;
1397 if (hasSSAIdentifiers)
1398 entryArgs.back().type = portType;
1401 if (supportsSymbols) {
1402 hw::InnerSymAttr innerSymAttr;
1403 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
1404 NamedAttrList dummyAttrs;
1405 if (parser.parseCustomAttributeWithFallback(
1406 innerSymAttr, ::mlir::Type{},
1408 return ::mlir::failure();
1411 portSyms.push_back(innerSymAttr);
1417 Attribute domainInfo = ArrayAttr::get(
context, {});
1418 if (supportsDomains) {
1419 if (
auto domainType = dyn_cast<DomainType>(portType)) {
1421 domainInfo = ArrayAttr::get(
context, {});
1422 }
else if (succeeded(parser.parseOptionalKeyword(
"domains"))) {
1423 auto result = parser.parseCommaSeparatedList(
1424 OpAsmParser::Delimiter::Square, [&]() -> ParseResult {
1426 if (hasSSAIdentifiers) {
1427 OpAsmParser::Argument arg;
1428 if (parser.parseArgument(arg))
1431 StringAttr::get(
context, arg.ssaName.name.drop_front());
1433 std::string portName;
1434 if (parser.parseKeywordOrString(&portName))
1436 argName = StringAttr::get(
context, portName);
1438 domainStrings[portIdx].push_back({argName, irLoc});
1445 domainInfo =
nullptr;
1448 domains.push_back(domainInfo);
1452 auto parseResult = parser.parseOptionalAttribute(annos);
1453 if (!parseResult.has_value())
1454 annos = parser.getBuilder().getArrayAttr({});
1455 else if (failed(*parseResult))
1457 portAnnotations.push_back(annos);
1460 std::optional<Location> maybeLoc;
1461 if (failed(parser.parseOptionalLocationSpecifier(maybeLoc)))
1463 Location loc = maybeLoc ? *maybeLoc : parser.getEncodedSourceLoc(irLoc);
1464 portLocs.push_back(loc);
1465 if (hasSSAIdentifiers)
1466 entryArgs.back().sourceLoc = loc;
1475 if (failed(parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
1481 for (
auto [portIdx, domainInfo] : llvm::enumerate(domains)) {
1486 SmallVector<Attribute> portDomains;
1487 for (
auto [domainName, loc] : domainStrings[portIdx]) {
1488 auto index = domainIndex.find(domainName);
1489 if (index == domainIndex.end()) {
1490 parser.emitError(loc) <<
"domain name '" << domainName <<
"' not found";
1493 portDomains.push_back(IntegerAttr::get(
1494 IntegerType::get(
context, 32, IntegerType::Unsigned), index->second));
1496 domains[portIdx] = parser.getBuilder().getArrayAttr(portDomains);
1504 ArrayAttr parameters) {
1505 if (!parameters || parameters.empty())
1509 llvm::interleaveComma(parameters, p, [&](Attribute param) {
1510 auto paramAttr = cast<ParamDeclAttr>(param);
1511 p << paramAttr.getName().getValue() <<
": " << paramAttr.getType();
1512 if (
auto value = paramAttr.getValue()) {
1514 p.printAttributeWithoutType(value);
1524 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
1525 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
1526 p << visibility.getValue() <<
' ';
1529 p.printSymbolName(op.getModuleName());
1536 Block *body =
nullptr;
1537 if (!op->getRegion(0).empty())
1538 body = &op->getRegion(0).front();
1541 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
1542 op.getPortAnnotations(), op.getPortSymbols(), op.getPortLocations(),
1543 op.getDomainInfo());
1545 SmallVector<StringRef, 13> omittedAttrs = {
1546 "sym_name",
"portDirections",
"portTypes",
1547 "portAnnotations",
"portSymbols",
"portLocations",
1548 "parameters", visibilityAttrName,
"domainInfo"};
1550 if (op.getConvention() == Convention::Internal)
1551 omittedAttrs.push_back(
"convention");
1555 if (!needPortNamesAttr)
1556 omittedAttrs.push_back(
"portNames");
1559 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
1560 omittedAttrs.push_back(
"annotations");
1563 if (
auto knownLayers = op->getAttrOfType<ArrayAttr>(
"knownLayers"))
1564 if (knownLayers.empty())
1565 omittedAttrs.push_back(
"knownLayers");
1568 if (
auto layers = op->getAttrOfType<ArrayAttr>(
"layers"))
1570 omittedAttrs.push_back(
"layers");
1573 if (
auto extReqs = op->getAttrOfType<ArrayAttr>(
"externalRequirements"))
1574 if (extReqs.empty())
1575 omittedAttrs.push_back(
"externalRequirements");
1577 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
1586void FModuleOp::print(OpAsmPrinter &p) {
1592 Region &fbody = getBody();
1593 if (!fbody.empty()) {
1595 p.printRegion(fbody,
false,
1607 SmallVectorImpl<Attribute> ¶meters) {
1609 return parser.parseCommaSeparatedList(
1610 OpAsmParser::Delimiter::OptionalLessGreater, [&]() {
1615 if (parser.parseKeywordOrString(&name) || parser.parseColonType(type))
1619 if (succeeded(parser.parseOptionalEqual())) {
1620 if (parser.parseAttribute(value, type))
1624 auto &builder = parser.getBuilder();
1625 parameters.push_back(ParamDeclAttr::get(
1626 builder.getContext(), builder.getStringAttr(name), type, value));
1633 ArrayAttr ¶meters) {
1634 SmallVector<Attribute> parseParameters;
1638 parameters = ArrayAttr::get(parser.getContext(), parseParameters);
1643template <
typename Properties,
typename =
void>
1646template <
typename Properties>
1648 Properties, std::void_t<decltype(std::declval<Properties>().parameters)>>
1649 : std::true_type {};
1651template <
typename OpTy>
1653 OperationState &result,
1654 bool hasSSAIdentifiers) {
1655 auto *
context = result.getContext();
1656 auto &builder = parser.getBuilder();
1657 using Properties =
typename OpTy::Properties;
1658 auto &properties = result.getOrAddProperties<Properties>();
1662 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
1665 StringAttr nameAttr;
1666 if (parser.parseSymbolName(nameAttr))
1668 properties.setSymName(nameAttr);
1672 SmallVector<Attribute, 4> parameters;
1675 properties.setParameters(builder.getArrayAttr(parameters));
1679 SmallVector<OpAsmParser::Argument> entryArgs;
1680 SmallVector<Direction, 4> portDirections;
1681 SmallVector<Attribute, 4> portNames;
1682 SmallVector<Attribute, 4> portTypes;
1683 SmallVector<Attribute, 4> portAnnotations;
1684 SmallVector<Attribute, 4> portSyms;
1685 SmallVector<Attribute, 4> portLocs;
1686 SmallVector<Attribute, 4> domains;
1688 true, entryArgs, portDirections,
1689 portNames, portTypes, portAnnotations, portSyms,
1694 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
1697 assert(portNames.size() == portTypes.size());
1703 properties.setPortDirections(
1707 properties.setPortNames(builder.getArrayAttr(portNames));
1710 properties.setPortTypes(ArrayAttr::get(
context, portTypes));
1714 if (llvm::any_of(portAnnotations, [&](Attribute anno) {
1715 return !cast<ArrayAttr>(anno).empty();
1717 properties.setPortAnnotations(ArrayAttr::get(
context, portAnnotations));
1719 properties.setPortAnnotations(builder.getArrayAttr({}));
1722 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1723 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1726 properties.setPortLocations(ArrayAttr::get(
context, portLocs));
1729 properties.setAnnotations(builder.getArrayAttr({}));
1732 if (llvm::all_of(domains, [&](Attribute attr) {
1733 auto arrayAttr = dyn_cast<ArrayAttr>(attr);
1734 return arrayAttr && arrayAttr.empty();
1736 properties.setDomainInfo(ArrayAttr::get(
context, {}));
1738 properties.setDomainInfo(ArrayAttr::get(
context, domains));
1741 auto *body = result.addRegion();
1743 if (hasSSAIdentifiers) {
1744 if (parser.parseRegion(*body, entryArgs))
1747 body->push_back(
new Block());
1752ParseResult FModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1753 if (parseFModuleLikeOp<FModuleOp>(parser, result,
1756 auto &properties = result.getOrAddProperties<Properties>();
1757 properties.setConvention(
1758 ConventionAttr::get(result.getContext(), Convention::Internal));
1759 properties.setLayers(ArrayAttr::get(parser.getContext(), {}));
1763ParseResult FExtModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1764 if (parseFModuleLikeOp<FExtModuleOp>(parser, result,
1767 auto &properties = result.getOrAddProperties<Properties>();
1768 properties.setConvention(
1769 ConventionAttr::get(result.getContext(), Convention::Internal));
1770 properties.setKnownLayers(ArrayAttr::get(result.getContext(), {}));
1774ParseResult FIntModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1775 return parseFModuleLikeOp<FIntModuleOp>(parser, result,
1779ParseResult FMemModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1780 return parseFModuleLikeOp<FMemModuleOp>(parser, result,
1784LogicalResult FModuleOp::verify() {
1787 auto portTypes = getPortTypes();
1788 auto portLocs = getPortLocations();
1789 auto numPorts = portTypes.size();
1792 if (body->getNumArguments() != numPorts)
1793 return emitOpError(
"entry block must have ")
1794 << numPorts <<
" arguments to match module signature";
1797 for (
auto [arg, type, loc] : zip(body->getArguments(), portTypes, portLocs)) {
1798 if (arg.getType() != cast<TypeAttr>(type).getValue())
1799 return emitOpError(
"block argument types should match signature types");
1800 if (arg.getLoc() != cast<LocationAttr>(loc))
1802 "block argument locations should match signature locations");
1808LogicalResult FExtModuleOp::verify() {
1809 auto params = getParameters();
1811 auto checkParmValue = [&](Attribute elt) ->
bool {
1812 auto param = cast<ParamDeclAttr>(elt);
1813 auto value = param.getValue();
1814 if (isa<IntegerAttr, StringAttr, FloatAttr, hw::ParamVerbatimAttr>(value))
1816 emitError() <<
"has unknown extmodule parameter value '"
1817 << param.getName().getValue() <<
"' = " << value;
1821 if (!llvm::all_of(params, checkParmValue))
1826 known.insert_range(getKnownLayersAttr().getAsRange<SymbolRefAttr>());
1829 referenced.insert_range(getLayersAttr().getAsRange<SymbolRefAttr>());
1830 for (
auto attr : getPortTypes()) {
1831 auto type = cast<TypeAttr>(attr).getValue();
1832 if (
auto refType = type_dyn_cast<RefType>(type))
1833 if (
auto layer = refType.getLayer())
1834 referenced.insert(layer);
1838 "references unknown layers",
"unknown layers");
1841LogicalResult FIntModuleOp::verify() {
1842 auto params = getParameters();
1846 auto checkParmValue = [&](Attribute elt) ->
bool {
1847 auto param = cast<ParamDeclAttr>(elt);
1848 auto value = param.getValue();
1849 if (isa<IntegerAttr, StringAttr, FloatAttr>(value))
1851 emitError() <<
"has unknown intmodule parameter value '"
1852 << param.getName().getValue() <<
"' = " << value;
1856 if (!llvm::all_of(params, checkParmValue))
1863 CircuitOp circuitOp,
1864 SymbolTableCollection &symbolTable,
1866 auto layer = refType.getLayer();
1869 auto *layerOp = symbolTable.lookupSymbolIn(circuitOp, layer);
1871 return emitError(loc) << start <<
" associated with layer '" << layer
1872 <<
"', but this layer was not defined";
1873 if (!isa<LayerOp>(layerOp)) {
1874 auto diag = emitError(loc)
1875 << start <<
" associated with layer '" << layer
1876 <<
"', but symbol '" << layer <<
"' does not refer to a '"
1877 << LayerOp::getOperationName() <<
"' op";
1878 return diag.attachNote(layerOp->getLoc()) <<
"symbol refers to this op";
1884 SymbolTableCollection &symbolTable) {
1886 auto circuitOp =
module->getParentOfType<CircuitOp>();
1887 for (
size_t i = 0, e = module.getNumPorts(); i < e; ++i) {
1888 auto type =
module.getPortType(i);
1890 if (
auto refType = type_dyn_cast<RefType>(type)) {
1892 refType, module.getPortLocation(i), circuitOp, symbolTable,
1893 Twine(
"probe port '") + module.getPortName(i) +
"' is")))
1898 if (
auto classType = dyn_cast<ClassType>(type)) {
1899 auto className = classType.getNameAttr();
1900 auto classOp = dyn_cast_or_null<ClassLike>(
1901 symbolTable.lookupSymbolIn(circuitOp, className));
1903 return module.emitOpError() << "references unknown class " << className;
1906 if (failed(classOp.verifyType(classType,
1907 [&]() { return module.emitOpError(); })))
1912 if (
auto domainType = dyn_cast<DomainType>(type)) {
1914 domainType.verifySymbolUses(module.getOperation(), symbolTable)))
1923LogicalResult FModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1927 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
1928 for (
auto layer : getLayers()) {
1929 if (!symbolTable.lookupSymbolIn(circuitOp, cast<SymbolRefAttr>(layer)))
1930 return emitOpError() <<
"enables undefined layer '" << layer <<
"'";
1937FExtModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1941 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
1942 for (
auto layer : getKnownLayersAttr().getAsRange<SymbolRefAttr>()) {
1943 if (!symbolTable.lookupSymbolIn(circuitOp, layer))
1944 return emitOpError() <<
"knows undefined layer '" << layer <<
"'";
1946 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>()) {
1947 if (!symbolTable.lookupSymbolIn(circuitOp, layer))
1948 return emitOpError() <<
"enables undefined layer '" << layer <<
"'";
1955FIntModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1960FMemModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1964void FModuleOp::getAsmBlockArgumentNames(mlir::Region ®ion,
1969void FExtModuleOp::getAsmBlockArgumentNames(
1974StringAttr FExtModuleOp::getExtModuleNameAttr() {
1975 if (
auto defnameAttr = getDefnameAttr(); defnameAttr && !defnameAttr.empty())
1977 return getNameAttr();
1980StringRef FExtModuleOp::getExtModuleName() {
1981 if (
auto defname = getDefname(); defname && !defname->empty())
1986void FIntModuleOp::getAsmBlockArgumentNames(
1991void FMemModuleOp::getAsmBlockArgumentNames(
1996ArrayAttr FMemModuleOp::getParameters() {
return {}; }
1998ArrayAttr FModuleOp::getParameters() {
return {}; }
2000Convention FIntModuleOp::getConvention() {
return Convention::Internal; }
2002ConventionAttr FIntModuleOp::getConventionAttr() {
2003 return ConventionAttr::get(getContext(), getConvention());
2006Convention FMemModuleOp::getConvention() {
return Convention::Internal; }
2008ConventionAttr FMemModuleOp::getConventionAttr() {
2009 return ConventionAttr::get(getContext(), getConvention());
2017 ClassLike classOp, ClassType type,
2018 function_ref<InFlightDiagnostic()> emitError) {
2020 auto name = type.getNameAttr().getAttr();
2021 auto expectedName = classOp.getModuleNameAttr();
2022 if (name != expectedName)
2023 return emitError() <<
"type has wrong name, got " << name <<
", expected "
2026 auto elements = type.getElements();
2028 auto expectedNumElements = classOp.getNumPorts();
2030 return emitError() <<
"has wrong number of ports, got " <<
numElements
2031 <<
", expected " << expectedNumElements;
2033 auto portNames = classOp.getPortNames();
2034 auto portDirections = classOp.getPortDirections();
2035 auto portTypes = classOp.getPortTypes();
2038 auto element = elements[i];
2040 auto name = element.name;
2041 auto expectedName = portNames[i];
2042 if (name != expectedName)
2043 return emitError() <<
"port #" << i <<
" has wrong name, got " << name
2044 <<
", expected " << expectedName;
2046 auto direction = element.direction;
2047 auto expectedDirection =
Direction(portDirections[i]);
2048 if (direction != expectedDirection)
2049 return emitError() <<
"port " << name <<
" has wrong direction, got "
2053 auto type = element.type;
2054 auto expectedType = cast<TypeAttr>(portTypes[i]).getValue();
2055 if (type != expectedType)
2056 return emitError() <<
"port " << name <<
" has wrong type, got " << type
2057 <<
", expected " << expectedType;
2064 auto n = classOp.getNumPorts();
2065 SmallVector<ClassElement> elements;
2066 elements.reserve(n);
2067 for (
size_t i = 0; i < n; ++i)
2068 elements.push_back({classOp.getPortNameAttr(i), classOp.getPortType(i),
2069 classOp.getPortDirection(i)});
2070 auto name = FlatSymbolRefAttr::get(classOp.getNameAttr());
2071 return ClassType::get(name, elements);
2074template <
typename OpTy>
2076 bool hasSSAIdentifiers) {
2077 auto *
context = result.getContext();
2078 auto &builder = parser.getBuilder();
2079 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
2083 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
2086 StringAttr nameAttr;
2087 if (parser.parseSymbolName(nameAttr))
2089 properties.setSymName(nameAttr);
2092 SmallVector<OpAsmParser::Argument> entryArgs;
2093 SmallVector<Direction, 4> portDirections;
2094 SmallVector<Attribute, 4> portNames;
2095 SmallVector<Attribute, 4> portTypes;
2096 SmallVector<Attribute, 4> portAnnotations;
2097 SmallVector<Attribute, 4> portSyms;
2098 SmallVector<Attribute, 4> portLocs;
2099 SmallVector<Attribute, 4> domains;
2102 entryArgs, portDirections, portNames, portTypes,
2103 portAnnotations, portSyms, portLocs, domains))
2107 for (
auto annos : portAnnotations)
2108 if (!cast<ArrayAttr>(annos).empty())
2112 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
2115 assert(portNames.size() == portTypes.size());
2121 properties.setPortDirections(
2125 properties.setPortNames(builder.getArrayAttr(portNames));
2128 properties.setPortTypes(builder.getArrayAttr(portTypes));
2131 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
2132 properties.setPortSymbols(builder.getArrayAttr(portSyms));
2135 properties.setPortLocations(ArrayAttr::get(
context, portLocs));
2141 auto *bodyRegion = result.addRegion();
2143 if (hasSSAIdentifiers) {
2144 if (parser.parseRegion(*bodyRegion, entryArgs))
2146 if (bodyRegion->empty())
2147 bodyRegion->push_back(
new Block());
2157 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
2158 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
2159 p << visibility.getValue() <<
' ';
2162 p.printSymbolName(op.getName());
2166 Region ®ion = op->getRegion(0);
2167 Block *body =
nullptr;
2168 if (!region.empty())
2169 body = ®ion.front();
2172 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
2173 {}, op.getPortSymbols(), op.getPortLocations(), {});
2176 SmallVector<StringRef, 8> omittedAttrs = {
2177 "sym_name",
"portNames",
"portTypes",
"portDirections",
2178 "portSymbols",
"portLocations", visibilityAttrName,
"domainInfo"};
2182 if (!needPortNamesAttr)
2183 omittedAttrs.push_back(
"portNames");
2185 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
2188 if (!region.empty()) {
2190 auto printEntryBlockArgs =
false;
2191 auto printBlockTerminators =
false;
2192 p.printRegion(region, printEntryBlockArgs, printBlockTerminators);
2200void ClassOp::build(OpBuilder &builder, OperationState &result, StringAttr name,
2201 ArrayRef<PortInfo> ports) {
2204 [](
const auto &port) {
return port.annotations.empty(); }) &&
2205 "class ports may not have annotations");
2207 buildClass<ClassOp>(builder, result, name, ports);
2210 auto *bodyRegion = result.regions[0].get();
2212 bodyRegion->push_back(body);
2215 for (
auto &elt : ports)
2216 body->addArgument(elt.type, elt.loc);
2219void ClassOp::build(::mlir::OpBuilder &odsBuilder,
2220 ::mlir::OperationState &odsState, Twine name,
2221 mlir::ArrayRef<mlir::StringRef> fieldNames,
2222 mlir::ArrayRef<mlir::Type> fieldTypes) {
2224 SmallVector<PortInfo, 10> ports;
2225 ports.reserve(fieldNames.size() * 2);
2226 for (
auto [fieldName, fieldType] :
llvm::zip(fieldNames, fieldTypes)) {
2227 ports.emplace_back(odsBuilder.getStringAttr(fieldName +
"_in"), fieldType,
2229 ports.emplace_back(odsBuilder.getStringAttr(fieldName), fieldType,
2232 build(odsBuilder, odsState, odsBuilder.getStringAttr(name), ports);
2234 auto &body = odsState.regions[0]->getBlocks().front();
2235 auto prevLoc = odsBuilder.saveInsertionPoint();
2236 odsBuilder.setInsertionPointToEnd(&body);
2237 auto args = body.getArguments();
2238 auto loc = odsState.location;
2239 for (
unsigned i = 0, e = ports.size(); i != e; i += 2)
2240 PropAssignOp::create(odsBuilder, loc, args[i + 1], args[i]);
2242 odsBuilder.restoreInsertionPoint(prevLoc);
2244void ClassOp::print(OpAsmPrinter &p) {
2248ParseResult ClassOp::parse(OpAsmParser &parser, OperationState &result) {
2249 auto hasSSAIdentifiers =
true;
2250 return parseClassLike<ClassOp>(parser, result, hasSSAIdentifiers);
2253LogicalResult ClassOp::verify() {
2255 auto type = operand.getType();
2256 if (!isa<PropertyType>(type)) {
2257 emitOpError(
"ports on a class must be properties");
2266ClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2270void ClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2275SmallVector<PortInfo> ClassOp::getPorts() {
2276 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2279void ClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2280 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2284void ClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2285 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2288Convention ClassOp::getConvention() {
return Convention::Internal; }
2290ConventionAttr ClassOp::getConventionAttr() {
2291 return ConventionAttr::get(getContext(), getConvention());
2294ArrayAttr ClassOp::getParameters() {
return {}; }
2296ArrayAttr ClassOp::getPortAnnotationsAttr() {
2297 return ArrayAttr::get(getContext(), {});
2300ArrayRef<Attribute> ClassOp::getPortAnnotations() {
return {}; }
2302void ClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2303 llvm_unreachable(
"classes do not support annotations");
2306ArrayAttr ClassOp::getLayersAttr() {
return ArrayAttr::get(getContext(), {}); }
2308ArrayRef<Attribute> ClassOp::getLayers() {
return {}; }
2310SmallVector<::circt::hw::PortInfo> ClassOp::getPortList() {
2311 return ::getPortListImpl(*
this);
2315 return ::getPortImpl(*
this, idx);
2318BlockArgument ClassOp::getArgument(
size_t portNumber) {
2322bool ClassOp::canDiscardOnUseEmpty() {
2333void ExtClassOp::build(OpBuilder &builder, OperationState &result,
2334 StringAttr name, ArrayRef<PortInfo> ports) {
2337 [](
const auto &port) {
return port.annotations.empty(); }) &&
2338 "class ports may not have annotations");
2339 buildClass<ClassOp>(builder, result, name, ports);
2342void ExtClassOp::print(OpAsmPrinter &p) {
2346ParseResult ExtClassOp::parse(OpAsmParser &parser, OperationState &result) {
2347 auto hasSSAIdentifiers =
false;
2348 return parseClassLike<ExtClassOp>(parser, result, hasSSAIdentifiers);
2352ExtClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2356void ExtClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2361SmallVector<PortInfo> ExtClassOp::getPorts() {
2362 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2365void ExtClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2366 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2369void ExtClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2370 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2373Convention ExtClassOp::getConvention() {
return Convention::Internal; }
2375ConventionAttr ExtClassOp::getConventionAttr() {
2376 return ConventionAttr::get(getContext(), getConvention());
2379ArrayAttr ExtClassOp::getLayersAttr() {
2380 return ArrayAttr::get(getContext(), {});
2383ArrayRef<Attribute> ExtClassOp::getLayers() {
return {}; }
2385ArrayAttr ExtClassOp::getParameters() {
return {}; }
2387ArrayAttr ExtClassOp::getPortAnnotationsAttr() {
2388 return ArrayAttr::get(getContext(), {});
2391ArrayRef<Attribute> ExtClassOp::getPortAnnotations() {
return {}; }
2393void ExtClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2394 llvm_unreachable(
"classes do not support annotations");
2397SmallVector<::circt::hw::PortInfo> ExtClassOp::getPortList() {
2398 return ::getPortListImpl(*
this);
2402 return ::getPortImpl(*
this, idx);
2405bool ExtClassOp::canDiscardOnUseEmpty() {
2416void InstanceOp::build(
2417 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2418 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2419 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2420 ArrayRef<Attribute> domainInfo, ArrayRef<Attribute> annotations,
2421 ArrayRef<Attribute> portAnnotations, ArrayRef<Attribute> layers,
2422 bool lowerToBind,
bool doNotPrint, StringAttr innerSym) {
2423 build(builder, result, resultTypes, moduleName, name, nameKind,
2424 portDirections, portNames, domainInfo, annotations, portAnnotations,
2425 layers, lowerToBind, doNotPrint,
2426 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr());
2429void InstanceOp::build(
2430 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2431 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2432 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2433 ArrayRef<Attribute> domainInfo, ArrayRef<Attribute> annotations,
2434 ArrayRef<Attribute> portAnnotations, ArrayRef<Attribute> layers,
2435 bool lowerToBind,
bool doNotPrint, hw::InnerSymAttr innerSym) {
2436 result.addTypes(resultTypes);
2437 result.getOrAddProperties<Properties>().setModuleName(
2438 SymbolRefAttr::get(builder.getContext(), moduleName));
2439 result.getOrAddProperties<Properties>().setName(builder.getStringAttr(name));
2440 result.getOrAddProperties<Properties>().setPortDirections(
2442 result.getOrAddProperties<Properties>().setPortNames(
2443 builder.getArrayAttr(portNames));
2445 if (domainInfo.empty()) {
2446 SmallVector<Attribute, 16> domainInfoVec(resultTypes.size(),
2447 builder.getArrayAttr({}));
2448 result.getOrAddProperties<Properties>().setDomainInfo(
2449 builder.getArrayAttr(domainInfoVec));
2451 assert(domainInfo.size() == resultTypes.size());
2452 result.getOrAddProperties<Properties>().setDomainInfo(
2453 builder.getArrayAttr(domainInfo));
2456 result.getOrAddProperties<Properties>().setAnnotations(
2457 builder.getArrayAttr(annotations));
2458 result.getOrAddProperties<Properties>().setLayers(
2459 builder.getArrayAttr(layers));
2461 result.getOrAddProperties<Properties>().setLowerToBind(
2462 builder.getUnitAttr());
2464 result.getOrAddProperties<Properties>().setDoNotPrint(
2465 builder.getUnitAttr());
2467 result.getOrAddProperties<Properties>().setInnerSym(innerSym);
2469 result.getOrAddProperties<Properties>().setNameKind(
2470 NameKindEnumAttr::get(builder.getContext(), nameKind));
2472 if (portAnnotations.empty()) {
2473 SmallVector<Attribute, 16> portAnnotationsVec(resultTypes.size(),
2474 builder.getArrayAttr({}));
2475 result.getOrAddProperties<Properties>().setPortAnnotations(
2476 builder.getArrayAttr(portAnnotationsVec));
2478 assert(portAnnotations.size() == resultTypes.size());
2479 result.getOrAddProperties<Properties>().setPortAnnotations(
2480 builder.getArrayAttr(portAnnotations));
2484void InstanceOp::build(OpBuilder &builder, OperationState &result,
2485 FModuleLike module, StringRef name,
2486 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2487 ArrayRef<Attribute> portAnnotations,
bool lowerToBind,
2488 bool doNotPrint, hw::InnerSymAttr innerSym) {
2491 SmallVector<Type> resultTypes;
2492 resultTypes.reserve(module.getNumPorts());
2494 module.getPortTypes(), std::back_inserter(resultTypes),
2495 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2500 ArrayAttr portAnnotationsAttr;
2501 if (portAnnotations.empty()) {
2502 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2503 resultTypes.size(), builder.getArrayAttr({})));
2505 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2507 ArrayAttr domainInfoAttr =
module.getDomainInfoAttr();
2508 if (domainInfoAttr.empty()) {
2509 domainInfoAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2510 resultTypes.size(), builder.getArrayAttr({})));
2514 builder, result, resultTypes,
2515 SymbolRefAttr::get(builder.getContext(), module.getModuleNameAttr()),
2516 builder.getStringAttr(name),
2517 NameKindEnumAttr::get(builder.getContext(), nameKind),
2518 module.getPortDirectionsAttr(), module.getPortNamesAttr(), domainInfoAttr,
2519 builder.getArrayAttr(annotations), portAnnotationsAttr,
2520 module.getLayersAttr(), lowerToBind ? builder.getUnitAttr() : UnitAttr(),
2521 doNotPrint ? builder.getUnitAttr() : UnitAttr(), innerSym);
2524void InstanceOp::build(OpBuilder &builder, OperationState &odsState,
2525 ArrayRef<PortInfo> ports, StringRef moduleName,
2526 StringRef name, NameKindEnum nameKind,
2527 ArrayRef<Attribute> annotations,
2528 ArrayRef<Attribute> layers,
bool lowerToBind,
2529 bool doNotPrint, hw::InnerSymAttr innerSym) {
2531 SmallVector<Type> newResultTypes;
2532 SmallVector<Direction> newPortDirections;
2533 SmallVector<Attribute> newPortNames, newPortAnnotations, newDomainInfo;
2534 newResultTypes.reserve(ports.size());
2535 newPortDirections.reserve(ports.size());
2536 newPortNames.reserve(ports.size());
2537 newPortAnnotations.reserve(ports.size());
2538 newDomainInfo.reserve(ports.size());
2540 for (
auto &p : ports) {
2541 newResultTypes.push_back(p.type);
2542 newPortDirections.push_back(p.direction);
2543 newPortNames.push_back(p.name);
2544 newPortAnnotations.push_back(p.annotations.getArrayAttr());
2546 newDomainInfo.push_back(p.domains);
2548 newDomainInfo.push_back(builder.getArrayAttr({}));
2551 return build(builder, odsState, newResultTypes, moduleName, name, nameKind,
2552 newPortDirections, newPortNames, newDomainInfo, annotations,
2553 newPortAnnotations, layers, lowerToBind, doNotPrint, innerSym);
2556LogicalResult InstanceOp::verify() {
2559 SmallVector<SymbolRefAttr> missingLayers;
2560 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
2562 missingLayers.push_back(layer);
2564 if (missingLayers.empty())
2568 emitOpError(
"ambient layers are insufficient to instantiate module");
2569 auto ¬e = diag.attachNote();
2570 note <<
"missing layer requirements: ";
2571 interleaveComma(missingLayers, note);
2576 Operation *op1, Operation *op2,
2577 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2579 size_t n = insertions.size();
2580 size_t inserted = 0;
2581 for (
size_t i = 0, e = op1->getNumResults(); i < e; ++i) {
2582 while (inserted < n) {
2583 auto &[index, portInfo] = insertions[inserted];
2588 auto r1 = op1->getResult(i);
2589 auto r2 = op2->getResult(i + inserted);
2590 r1.replaceAllUsesWith(r2);
2595 const llvm::BitVector &erasures) {
2598 for (
size_t i = 0, e = op1->getNumResults(); i < e; ++i) {
2599 auto r1 = op1->getResult(i);
2601 assert(r1.use_empty() &&
"removed instance port has uses");
2605 auto r2 = op2->getResult(i - erased);
2606 r1.replaceAllUsesWith(r2);
2611InstanceOp::cloneWithErasedPorts(
const llvm::BitVector &erasures) {
2612 assert(erasures.size() >= getNumResults() &&
2613 "erasures is not at least as large as getNumResults()");
2615 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
2616 SmallVector<Type>(result_type_begin(), result_type_end()), erasures);
2617 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
2619 SmallVector<Attribute> newPortNames =
2621 SmallVector<Attribute> newPortAnnotations =
2623 ArrayAttr newDomainInfo =
2627 OpBuilder builder(*
this);
2628 auto clone = InstanceOp::create(
2629 builder,
getLoc(), newResultTypes, getModuleName(),
getName(),
2630 getNameKind(), newPortDirections, newPortNames, newDomainInfo.getValue(),
2631 getAnnotations().getValue(), newPortAnnotations, getLayers(),
2632 getLowerToBind(), getDoNotPrint(), getInnerSymAttr());
2634 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2635 clone->setAttr(
"output_file", outputFile);
2640FInstanceLike InstanceOp::cloneWithErasedPortsAndReplaceUses(
2641 const llvm::BitVector &erasures) {
2642 auto clone = cloneWithErasedPorts(erasures);
2647ArrayAttr InstanceOp::getPortAnnotation(
unsigned portIdx) {
2648 assert(portIdx < getNumResults() &&
2649 "index should be smaller than result number");
2650 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
2653void InstanceOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
2654 assert(annotations.size() == getNumResults() &&
2655 "number of annotations is not equal to result number");
2656 (*this)->setAttr(
"portAnnotations",
2657 ArrayAttr::get(getContext(), annotations));
2660FInstanceLike InstanceOp::cloneWithInsertedPorts(
2661 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2665 auto oldPortCount = getNumResults();
2666 auto numInsertions = insertions.size();
2667 auto newPortCount = oldPortCount + numInsertions;
2669 SmallVector<Direction> newPortDirections;
2670 SmallVector<Attribute> newPortNames;
2671 SmallVector<Type> newPortTypes;
2672 SmallVector<Attribute> newPortAnnos;
2673 SmallVector<Attribute> newDomainInfo;
2675 newPortDirections.reserve(newPortCount);
2676 newPortNames.reserve(newPortCount);
2677 newPortTypes.reserve(newPortCount);
2678 newPortAnnos.reserve(newPortCount);
2679 newDomainInfo.reserve(newPortCount);
2685 SmallVector<unsigned> indexMap(oldPortCount);
2686 size_t inserted = 0;
2687 for (
size_t i = 0; i < oldPortCount; ++i) {
2688 while (inserted < numInsertions && insertions[inserted].first <= i)
2690 indexMap[i] = i + inserted;
2695 for (
size_t i = 0; i < oldPortCount; ++i) {
2696 while (inserted < numInsertions) {
2697 auto &[index,
info] = insertions[inserted];
2703 newPortDirections.push_back(
info.direction);
2704 newPortNames.push_back(
info.name);
2705 newPortTypes.push_back(
info.type);
2706 newPortAnnos.push_back(
info.annotations.getArrayAttr());
2707 newDomainInfo.push_back(domains);
2711 newPortDirections.push_back(getPortDirection(i));
2712 newPortNames.push_back(getPortNameAttr(i));
2713 newPortTypes.push_back(getType(i));
2714 newPortAnnos.push_back(getPortAnnotation(i));
2717 newDomainInfo.push_back(domains);
2720 while (inserted < numInsertions) {
2721 auto &[index,
info] = insertions[inserted];
2724 newPortDirections.push_back(
info.direction);
2725 newPortNames.push_back(
info.name);
2726 newPortTypes.push_back(
info.type);
2727 newPortAnnos.push_back(
info.annotations.getArrayAttr());
2728 newDomainInfo.push_back(domains);
2732 OpBuilder builder(*
this);
2733 auto clone = InstanceOp::create(
2734 builder,
getLoc(), newPortTypes, getModuleName(),
getName(),
2735 getNameKind(), newPortDirections, newPortNames, newDomainInfo,
2736 getAnnotations().getValue(), newPortAnnos, getLayers(), getLowerToBind(),
2737 getDoNotPrint(), getInnerSymAttr());
2739 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2740 clone->setAttr(
"output_file", outputFile);
2745FInstanceLike InstanceOp::cloneWithInsertedPortsAndReplaceUses(
2746 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2747 auto clone = cloneWithInsertedPorts(insertions);
2752LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2754 getModuleNameAttr());
2757StringRef InstanceOp::getInstanceName() {
return getName(); }
2759StringAttr InstanceOp::getInstanceNameAttr() {
return getNameAttr(); }
2761void InstanceOp::print(OpAsmPrinter &p) {
2764 p.printKeywordOrString(
getName());
2765 if (
auto attr = getInnerSymAttr()) {
2767 p.printSymbolName(attr.getSymName());
2769 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2770 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2773 SmallVector<StringRef, 10> omittedAttrs = {
2774 "moduleName",
"name",
"portDirections",
2775 "portNames",
"portTypes",
"portAnnotations",
2776 "inner_sym",
"nameKind",
"domainInfo"};
2777 if (getAnnotations().
empty())
2778 omittedAttrs.push_back(
"annotations");
2779 if (getLayers().
empty())
2780 omittedAttrs.push_back(
"layers");
2781 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2785 p.printSymbolName(getModuleName());
2788 SmallVector<Attribute> portTypes;
2789 portTypes.reserve(getNumResults());
2790 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2794 getPortNames().getValue(), portTypes,
2795 getPortAnnotations().getValue(), {}, {},
2796 getDomainInfo().getValue());
2799ParseResult InstanceOp::parse(OpAsmParser &parser, OperationState &result) {
2800 auto *
context = parser.getContext();
2801 auto &properties = result.getOrAddProperties<Properties>();
2804 hw::InnerSymAttr innerSymAttr;
2805 FlatSymbolRefAttr moduleName;
2806 SmallVector<OpAsmParser::Argument> entryArgs;
2807 SmallVector<Direction, 4> portDirections;
2808 SmallVector<Attribute, 4> portNames;
2809 SmallVector<Attribute, 4> portTypes;
2810 SmallVector<Attribute, 4> portAnnotations;
2811 SmallVector<Attribute, 4> portSyms;
2812 SmallVector<Attribute, 4> portLocs;
2813 SmallVector<Attribute, 4> domains;
2814 NameKindEnumAttr nameKind;
2816 if (parser.parseKeywordOrString(&name))
2818 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
2819 if (parser.parseCustomAttributeWithFallback(
2820 innerSymAttr, ::mlir::Type{},
2822 result.attributes)) {
2823 return ::mlir::failure();
2827 parser.parseOptionalAttrDict(result.attributes) ||
2828 parser.parseAttribute(moduleName) ||
2831 entryArgs, portDirections, portNames, portTypes,
2832 portAnnotations, portSyms, portLocs, domains))
2838 properties.setModuleName(moduleName);
2839 properties.setName(StringAttr::get(
context, name));
2840 properties.setNameKind(nameKind);
2841 properties.setPortDirections(
2843 properties.setPortNames(ArrayAttr::get(
context, portNames));
2844 properties.setPortAnnotations(ArrayAttr::get(
context, portAnnotations));
2848 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
2849 properties.setLayers(parser.getBuilder().getArrayAttr({}));
2852 properties.setDomainInfo(ArrayAttr::get(
context, domains));
2855 result.types.reserve(portTypes.size());
2857 portTypes, std::back_inserter(result.types),
2858 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2863void InstanceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
2868 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
2869 setNameFn(getResult(i), (base +
"_" + getPortName(i)).str());
2873std::optional<size_t> InstanceOp::getTargetResultIndex() {
2875 return std::nullopt;
2882void InstanceChoiceOp::build(
2883 OpBuilder &builder, OperationState &result, FModuleLike defaultModule,
2884 ArrayRef<std::pair<OptionCaseOp, FModuleLike>> cases, StringRef name,
2885 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2886 ArrayRef<Attribute> portAnnotations, StringAttr innerSym,
2887 FlatSymbolRefAttr instanceMacro) {
2889 SmallVector<Type> resultTypes;
2890 for (Attribute portType : defaultModule.getPortTypes())
2891 resultTypes.push_back(cast<TypeAttr>(portType).getValue());
2894 ArrayAttr portAnnotationsAttr;
2895 if (portAnnotations.empty()) {
2896 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2897 resultTypes.size(), builder.getArrayAttr({})));
2899 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2903 ArrayAttr domainInfoAttr = defaultModule.getDomainInfoAttr();
2904 if (domainInfoAttr.empty()) {
2905 domainInfoAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2906 resultTypes.size(), builder.getArrayAttr({})));
2910 SmallVector<Attribute> moduleNames, caseNames;
2911 moduleNames.push_back(SymbolRefAttr::get(defaultModule.getModuleNameAttr()));
2912 for (
auto [caseOption, caseModule] : cases) {
2913 auto caseGroup = caseOption->getParentOfType<OptionOp>();
2914 caseNames.push_back(SymbolRefAttr::get(caseGroup.getSymNameAttr(),
2915 {SymbolRefAttr::get(caseOption)}));
2916 moduleNames.push_back(SymbolRefAttr::get(caseModule.getModuleNameAttr()));
2919 return build(builder, result, resultTypes, builder.getArrayAttr(moduleNames),
2920 builder.getArrayAttr(caseNames), builder.getStringAttr(name),
2921 NameKindEnumAttr::get(builder.getContext(), nameKind),
2922 defaultModule.getPortDirectionsAttr(),
2923 defaultModule.getPortNamesAttr(), domainInfoAttr,
2924 builder.getArrayAttr(annotations), portAnnotationsAttr,
2925 defaultModule.getLayersAttr(),
2926 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr(),
2930void InstanceChoiceOp::build(OpBuilder &builder, OperationState &odsState,
2931 ArrayRef<PortInfo> ports, ArrayAttr moduleNames,
2932 ArrayAttr caseNames, StringRef name,
2933 NameKindEnum nameKind, ArrayAttr annotations,
2934 ArrayAttr layers, hw::InnerSymAttr innerSym,
2935 FlatSymbolRefAttr instanceMacro) {
2937 SmallVector<Type> newResultTypes;
2938 SmallVector<bool> newPortDirections;
2939 SmallVector<Attribute> newPortNames, newPortAnnotations, newDomainInfo;
2940 newPortDirections.reserve(ports.size());
2941 newResultTypes.reserve(ports.size());
2942 newPortAnnotations.reserve(ports.size());
2943 newDomainInfo.reserve(ports.size());
2944 newPortNames.reserve(ports.size());
2945 for (
auto &p : ports) {
2946 newResultTypes.push_back(p.type);
2948 newPortDirections.push_back(p.direction == Direction::Out);
2949 newPortNames.push_back(p.name);
2950 newPortAnnotations.push_back(p.annotations.getArrayAttr());
2952 newDomainInfo.push_back(p.domains);
2954 newDomainInfo.push_back(builder.getArrayAttr({}));
2957 return build(builder, odsState, newResultTypes, moduleNames, caseNames, name,
2958 nameKind, newPortDirections, builder.getArrayAttr(newPortNames),
2959 builder.getArrayAttr(newDomainInfo), annotations,
2960 builder.getArrayAttr(newPortAnnotations), layers.getValue(),
2961 innerSym, instanceMacro);
2964std::optional<size_t> InstanceChoiceOp::getTargetResultIndex() {
2965 return std::nullopt;
2968StringRef InstanceChoiceOp::getInstanceName() {
return getName(); }
2970StringAttr InstanceChoiceOp::getInstanceNameAttr() {
return getNameAttr(); }
2972ArrayAttr InstanceChoiceOp::getReferencedModuleNamesAttr() {
2974 auto moduleNames = getModuleNamesAttr();
2975 SmallVector<Attribute> moduleNameStrings;
2976 moduleNameStrings.reserve(moduleNames.size());
2977 for (
auto moduleName : moduleNames)
2978 moduleNameStrings.push_back(cast<FlatSymbolRefAttr>(moduleName).getAttr());
2980 return ArrayAttr::get(getContext(), moduleNameStrings);
2983void InstanceChoiceOp::print(OpAsmPrinter &p) {
2986 p.printKeywordOrString(
getName());
2987 if (
auto attr = getInnerSymAttr()) {
2989 p.printSymbolName(attr.getSymName());
2991 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2992 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2995 SmallVector<StringRef, 11> omittedAttrs = {
2996 "moduleNames",
"caseNames",
"name",
2997 "portDirections",
"portNames",
"portTypes",
2998 "portAnnotations",
"inner_sym",
"nameKind",
3000 if (getAnnotations().
empty())
3001 omittedAttrs.push_back(
"annotations");
3002 if (getLayers().
empty())
3003 omittedAttrs.push_back(
"layers");
3004 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
3009 auto moduleNames = getModuleNamesAttr();
3010 auto caseNames = getCaseNamesAttr();
3012 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[0]).getValue());
3014 p <<
" alternatives ";
3016 cast<SymbolRefAttr>(caseNames[0]).getRootReference().getValue());
3018 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3022 auto symbol = cast<SymbolRefAttr>(caseNames[i]);
3023 p.printSymbolName(symbol.getNestedReferences()[0].getValue());
3025 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[i + 1]).getValue());
3031 SmallVector<Attribute> portTypes;
3032 portTypes.reserve(getNumResults());
3033 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
3036 getPortNames().getValue(), portTypes,
3037 getPortAnnotations().getValue(), {}, {},
3038 getDomainInfo().getValue());
3041ParseResult InstanceChoiceOp::parse(OpAsmParser &parser,
3042 OperationState &result) {
3043 auto *
context = parser.getContext();
3044 auto &properties = result.getOrAddProperties<Properties>();
3047 hw::InnerSymAttr innerSymAttr;
3048 SmallVector<Attribute> moduleNames;
3049 SmallVector<Attribute> caseNames;
3050 SmallVector<OpAsmParser::Argument> entryArgs;
3051 SmallVector<Direction, 4> portDirections;
3052 SmallVector<Attribute, 4> portNames;
3053 SmallVector<Attribute, 4> portTypes;
3054 SmallVector<Attribute, 4> portAnnotations;
3055 SmallVector<Attribute, 4> portSyms;
3056 SmallVector<Attribute, 4> portLocs;
3057 SmallVector<Attribute, 4> domains;
3058 NameKindEnumAttr nameKind;
3060 if (parser.parseKeywordOrString(&name))
3062 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
3063 if (parser.parseCustomAttributeWithFallback(
3064 innerSymAttr, Type{},
3066 result.attributes)) {
3071 parser.parseOptionalAttrDict(result.attributes))
3074 FlatSymbolRefAttr defaultModuleName;
3075 if (parser.parseAttribute(defaultModuleName))
3077 moduleNames.push_back(defaultModuleName);
3081 FlatSymbolRefAttr optionName;
3082 if (parser.parseKeyword(
"alternatives") ||
3083 parser.parseAttribute(optionName) || parser.parseLBrace())
3086 FlatSymbolRefAttr moduleName;
3087 StringAttr caseName;
3088 while (succeeded(parser.parseOptionalSymbolName(caseName))) {
3089 if (parser.parseArrow() || parser.parseAttribute(moduleName))
3091 moduleNames.push_back(moduleName);
3092 caseNames.push_back(SymbolRefAttr::get(
3093 optionName.getAttr(), {FlatSymbolRefAttr::get(caseName)}));
3094 if (failed(parser.parseOptionalComma()))
3097 if (parser.parseRBrace())
3103 entryArgs, portDirections, portNames, portTypes,
3104 portAnnotations, portSyms, portLocs, domains))
3109 properties.setModuleNames(ArrayAttr::get(
context, moduleNames));
3110 properties.setCaseNames(ArrayAttr::get(
context, caseNames));
3111 properties.setName(StringAttr::get(
context, name));
3112 properties.setNameKind(nameKind);
3113 properties.setPortDirections(
3115 properties.setPortNames(ArrayAttr::get(
context, portNames));
3116 properties.setDomainInfo(ArrayAttr::get(
context, domains));
3117 properties.setPortAnnotations(ArrayAttr::get(
context, portAnnotations));
3121 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
3122 properties.setLayers(parser.getBuilder().getArrayAttr({}));
3125 result.types.reserve(portTypes.size());
3127 portTypes, std::back_inserter(result.types),
3128 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
3133void InstanceChoiceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3135 for (
auto [result, name] :
llvm::zip(getResults(), getPortNames()))
3136 setNameFn(result, (base +
"_" + cast<StringAttr>(name).getValue()).str());
3139LogicalResult InstanceChoiceOp::verify() {
3140 if (getCaseNamesAttr().
empty())
3141 return emitOpError() <<
"must have at least one case";
3142 if (getModuleNamesAttr().size() != getCaseNamesAttr().size() + 1)
3143 return emitOpError() <<
"number of referenced modules does not match the "
3144 "number of options";
3149 SmallVector<SymbolRefAttr> missingLayers;
3150 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
3152 missingLayers.push_back(layer);
3154 if (missingLayers.empty())
3158 emitOpError(
"ambient layers are insufficient to instantiate module");
3159 auto ¬e = diag.attachNote();
3160 note <<
"missing layer requirements: ";
3161 interleaveComma(missingLayers, note);
3166InstanceChoiceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3167 auto caseNames = getCaseNamesAttr();
3168 for (
auto moduleName : getModuleNamesAttr()) {
3169 auto moduleNameRef = cast<FlatSymbolRefAttr>(moduleName);
3175 auto referencedModule =
3176 symbolTable.lookupNearestSymbolFrom<FModuleLike>(*
this, moduleNameRef);
3177 if (isa<FIntModuleOp>(referencedModule))
3178 return emitOpError(
"intmodule must be instantiated with instance op, "
3179 "not via 'firrtl.instance_choice'");
3182 auto root = cast<SymbolRefAttr>(caseNames[0]).getRootReference();
3183 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3184 auto ref = cast<SymbolRefAttr>(caseNames[i]);
3185 auto refRoot = ref.getRootReference();
3186 if (ref.getRootReference() != root)
3187 return emitOpError() <<
"case " << ref
3188 <<
" is not in the same option group as "
3191 if (!symbolTable.lookupNearestSymbolFrom<OptionOp>(*
this, refRoot))
3192 return emitOpError() <<
"option " << refRoot <<
" does not exist";
3194 if (!symbolTable.lookupNearestSymbolFrom<OptionCaseOp>(*
this, ref))
3195 return emitOpError() <<
"option " << refRoot
3196 <<
" does not contain option case " << ref;
3199 if (
auto instanceMacro = getInstanceMacroAttr())
3200 if (!symbolTable.lookupNearestSymbolFrom(*
this, instanceMacro))
3201 return emitOpError() <<
"instance_macro " << instanceMacro
3202 <<
" does not exist";
3208InstanceChoiceOp::getTargetOrDefaultAttr(OptionCaseOp option) {
3209 auto caseNames = getCaseNamesAttr();
3210 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3211 StringAttr caseSym = cast<SymbolRefAttr>(caseNames[i]).getLeafReference();
3212 if (caseSym == option.getSymName())
3213 return cast<FlatSymbolRefAttr>(getModuleNamesAttr()[i + 1]);
3215 return getDefaultTargetAttr();
3218SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1>
3219InstanceChoiceOp::getTargetChoices() {
3220 auto caseNames = getCaseNamesAttr();
3221 auto moduleNames = getModuleNamesAttr();
3222 SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1> choices;
3223 for (
size_t i = 0; i < caseNames.size(); ++i) {
3224 choices.emplace_back(cast<SymbolRefAttr>(caseNames[i]),
3225 cast<FlatSymbolRefAttr>(moduleNames[i + 1]));
3231FInstanceLike InstanceChoiceOp::cloneWithInsertedPorts(
3232 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
3236 auto oldPortCount = getNumResults();
3237 auto numInsertions = insertions.size();
3238 auto newPortCount = oldPortCount + numInsertions;
3240 SmallVector<Direction> newPortDirections;
3241 SmallVector<Attribute> newPortNames;
3242 SmallVector<Type> newPortTypes;
3243 SmallVector<Attribute> newPortAnnos;
3244 SmallVector<Attribute> newDomainInfo;
3246 newPortDirections.reserve(newPortCount);
3247 newPortNames.reserve(newPortCount);
3248 newPortTypes.reserve(newPortCount);
3249 newPortAnnos.reserve(newPortCount);
3250 newDomainInfo.reserve(newPortCount);
3256 SmallVector<unsigned> indexMap(oldPortCount);
3257 size_t inserted = 0;
3258 for (
size_t i = 0; i < oldPortCount; ++i) {
3259 while (inserted < numInsertions && insertions[inserted].first <= i)
3261 indexMap[i] = i + inserted;
3266 for (
size_t i = 0; i < oldPortCount; ++i) {
3267 while (inserted < numInsertions) {
3268 auto &[index,
info] = insertions[inserted];
3274 newPortDirections.push_back(
info.direction);
3275 newPortNames.push_back(
info.name);
3276 newPortTypes.push_back(
info.type);
3277 newPortAnnos.push_back(
info.annotations.getArrayAttr());
3278 newDomainInfo.push_back(domains);
3282 newPortDirections.push_back(getPortDirection(i));
3283 newPortNames.push_back(getPortNameAttr(i));
3284 newPortTypes.push_back(getType(i));
3285 newPortAnnos.push_back(getPortAnnotations()[i]);
3288 newDomainInfo.push_back(domains);
3291 while (inserted < numInsertions) {
3292 auto &[index,
info] = insertions[inserted];
3295 newPortDirections.push_back(
info.direction);
3296 newPortNames.push_back(
info.name);
3297 newPortTypes.push_back(
info.type);
3298 newPortAnnos.push_back(
info.annotations.getArrayAttr());
3299 newDomainInfo.push_back(domains);
3303 OpBuilder builder(*
this);
3304 auto clone = InstanceChoiceOp::create(
3305 builder,
getLoc(), newPortTypes, getModuleNames(), getCaseNames(),
3308 ArrayAttr::get(
context, newPortNames),
3309 ArrayAttr::get(
context, newDomainInfo), getAnnotationsAttr(),
3310 ArrayAttr::get(
context, newPortAnnos), getLayers(), getInnerSymAttr(),
3311 getInstanceMacroAttr());
3313 if (
auto outputFile = (*this)->getAttr(
"output_file"))
3314 clone->setAttr(
"output_file", outputFile);
3319FInstanceLike InstanceChoiceOp::cloneWithInsertedPortsAndReplaceUses(
3320 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
3321 auto clone = cloneWithInsertedPorts(insertions);
3327InstanceChoiceOp::cloneWithErasedPorts(
const llvm::BitVector &erasures) {
3328 assert(erasures.size() >= getNumResults() &&
3329 "erasures is not at least as large as getNumResults()");
3331 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
3332 SmallVector<Type>(result_type_begin(), result_type_end()), erasures);
3333 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
3335 SmallVector<Attribute> newPortNames =
3337 SmallVector<Attribute> newPortAnnotations =
3339 ArrayAttr newPortDomains =
3343 OpBuilder builder(*
this);
3344 auto clone = InstanceChoiceOp::create(
3345 builder,
getLoc(), newResultTypes, getModuleNames(), getCaseNames(),
3348 ArrayAttr::get(getContext(), newPortNames), newPortDomains,
3349 getAnnotationsAttr(), ArrayAttr::get(getContext(), newPortAnnotations),
3350 getLayers(), getInnerSymAttr(), getInstanceMacroAttr());
3352 if (
auto outputFile = (*this)->getAttr(
"output_file"))
3353 clone->setAttr(
"output_file", outputFile);
3358FInstanceLike InstanceChoiceOp::cloneWithErasedPortsAndReplaceUses(
3359 const llvm::BitVector &erasures) {
3360 auto clone = cloneWithErasedPorts(erasures);
3369ArrayAttr MemOp::getPortAnnotation(
unsigned portIdx) {
3370 assert(portIdx < getNumResults() &&
3371 "index should be smaller than result number");
3372 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
3375void MemOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
3376 assert(annotations.size() == getNumResults() &&
3377 "number of annotations is not equal to result number");
3378 (*this)->setAttr(
"portAnnotations",
3379 ArrayAttr::get(getContext(), annotations));
3383void MemOp::getNumPorts(
size_t &numReadPorts,
size_t &numWritePorts,
3384 size_t &numReadWritePorts,
size_t &numDbgsPorts) {
3387 numReadWritePorts = 0;
3389 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3390 auto portKind = getPortKind(i);
3391 if (portKind == MemOp::PortKind::Debug)
3393 else if (portKind == MemOp::PortKind::Read)
3395 else if (portKind == MemOp::PortKind::Write) {
3398 ++numReadWritePorts;
3403LogicalResult MemOp::verify() {
3407 llvm::SmallDenseSet<Attribute, 8> portNamesSet;
3413 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3414 auto portName = getPortNameAttr(i);
3419 BundleType portBundleType =
3420 type_dyn_cast<BundleType>(getResult(i).getType());
3423 if (!portNamesSet.insert(portName).second) {
3424 emitOpError() <<
"has non-unique port name " << portName;
3432 auto elt = getPortNamed(portName);
3434 emitOpError() <<
"could not get port with name " << portName;
3437 auto firrtlType = type_cast<FIRRTLType>(elt.getType());
3440 if (portKind == MemOp::PortKind::Debug &&
3441 !type_isa<RefType>(getResult(i).getType()))
3442 return emitOpError() <<
"has an invalid type on port " << portName
3443 <<
" (expected Read/Write/ReadWrite/Debug)";
3444 if (type_isa<RefType>(firrtlType) && e == 1)
3445 return emitOpError()
3446 <<
"cannot have only one port of debug type. Debug port can only "
3447 "exist alongside other read/write/read-write port";
3452 if (portKind == MemOp::PortKind::Debug) {
3453 auto resType = type_cast<RefType>(getResult(i).getType());
3454 if (!(resType && type_isa<FVectorType>(resType.getType())))
3455 return emitOpError() <<
"debug ports must be a RefType of FVectorType";
3456 dataType = type_cast<FVectorType>(resType.getType()).getElementType();
3458 auto dataTypeOption = portBundleType.getElement(
"data");
3459 if (!dataTypeOption && portKind == MemOp::PortKind::ReadWrite)
3460 dataTypeOption = portBundleType.getElement(
"wdata");
3461 if (!dataTypeOption) {
3462 emitOpError() <<
"has no data field on port " << portName
3463 <<
" (expected to see \"data\" for a read or write "
3464 "port or \"rdata\" for a read/write port)";
3467 dataType = dataTypeOption->type;
3469 if (portKind == MemOp::PortKind::Read) {
3476 emitOpError() <<
"has non-passive data type on port " << portName
3477 <<
" (memory types must be passive)";
3482 if (dataType.containsAnalog()) {
3483 emitOpError() <<
"has a data type that contains an analog type on port "
3485 <<
" (memory types cannot contain analog types)";
3493 getTypeForPort(getDepth(), dataType, portKind,
3494 dataType.isGround() ? getMaskBits() : 0);
3497 auto originalType = getResult(i).getType();
3498 if (originalType != expectedType) {
3499 StringRef portKindName;
3501 case MemOp::PortKind::Read:
3502 portKindName =
"read";
3504 case MemOp::PortKind::Write:
3505 portKindName =
"write";
3507 case MemOp::PortKind::ReadWrite:
3508 portKindName =
"readwrite";
3510 case MemOp::PortKind::Debug:
3511 portKindName =
"dbg";
3514 emitOpError() <<
"has an invalid type for port " << portName
3515 <<
" of determined kind \"" << portKindName
3516 <<
"\" (expected " << expectedType <<
", but got "
3517 << originalType <<
")";
3523 if (oldDataType && oldDataType != dataType) {
3524 emitOpError() <<
"port " << getPortNameAttr(i)
3525 <<
" has a different type than port "
3526 << getPortNameAttr(i - 1) <<
" (expected " << oldDataType
3527 <<
", but got " << dataType <<
")";
3531 oldDataType = dataType;
3534 auto maskWidth = getMaskBits();
3536 auto dataWidth = getDataType().getBitWidthOrSentinel();
3537 if (dataWidth > 0 && maskWidth > (
size_t)dataWidth)
3538 return emitOpError(
"the mask width cannot be greater than "
3541 if (getPortAnnotations().size() != getNumResults())
3542 return emitOpError(
"the number of result annotations should be "
3543 "equal to the number of results");
3549 return std::max(1U, llvm::Log2_64_Ceil(depth));
3555 PortKind portKind,
size_t maskBits) {
3557 auto *
context = dataType.getContext();
3558 if (portKind == PortKind::Debug)
3559 return RefType::get(FVectorType::get(dataType, depth));
3565 maskType = UIntType::get(
context, maskBits);
3567 auto getId = [&](StringRef name) -> StringAttr {
3568 return StringAttr::get(
context, name);
3571 SmallVector<BundleType::BundleElement, 7> portFields;
3575 portFields.push_back({getId(
"addr"),
false, addressType});
3576 portFields.push_back({getId(
"en"),
false, UIntType::get(
context, 1)});
3577 portFields.push_back({getId(
"clk"),
false, ClockType::get(
context)});
3580 case PortKind::Read:
3581 portFields.push_back({getId(
"data"),
true, dataType});
3584 case PortKind::Write:
3585 portFields.push_back({getId(
"data"),
false, dataType});
3586 portFields.push_back({getId(
"mask"),
false, maskType});
3589 case PortKind::ReadWrite:
3590 portFields.push_back({getId(
"rdata"),
true, dataType});
3591 portFields.push_back({getId(
"wmode"),
false, UIntType::get(
context, 1)});
3592 portFields.push_back({getId(
"wdata"),
false, dataType});
3593 portFields.push_back({getId(
"wmask"),
false, maskType});
3596 llvm::report_fatal_error(
"memory port kind not handled");
3600 return BundleType::get(
context, portFields);
3604SmallVector<MemOp::NamedPort> MemOp::getPorts() {
3605 SmallVector<MemOp::NamedPort> result;
3607 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3609 auto portType = type_cast<FIRRTLType>(getResult(i).getType());
3616MemOp::PortKind MemOp::getPortKind(StringRef portName) {
3618 type_cast<FIRRTLType>(getPortNamed(portName).getType()));
3622MemOp::PortKind MemOp::getPortKind(
size_t resultNo) {
3624 type_cast<FIRRTLType>(getResult(resultNo).getType()));
3628size_t MemOp::getMaskBits() {
3630 for (
auto res : getResults()) {
3631 if (type_isa<RefType>(res.getType()))
3633 auto firstPortType = type_cast<FIRRTLBaseType>(res.getType());
3640 if (t.name.getValue().contains(
"mask"))
3643 if (type_isa<UIntType>(mType))
3653 assert(getNumResults() != 0 &&
"Mems with no read/write ports are illegal");
3655 if (
auto refType = type_dyn_cast<RefType>(getResult(0).getType()))
3656 return type_cast<FVectorType>(refType.getType()).getElementType();
3657 auto firstPortType = type_cast<FIRRTLBaseType>(getResult(0).getType());
3659 StringRef dataFieldName =
"data";
3661 dataFieldName =
"rdata";
3663 return type_cast<BundleType>(firstPortType.getPassiveType())
3664 .getElementType(dataFieldName);
3667StringAttr MemOp::getPortNameAttr(
size_t resultNo) {
3668 return cast<StringAttr>(getPortNames()[resultNo]);
3672 return type_cast<FIRRTLBaseType>(getResults()[resultNo].getType());
3675Value MemOp::getPortNamed(StringAttr name) {
3676 auto namesArray = getPortNames();
3677 for (
size_t i = 0, e = namesArray.size(); i != e; ++i) {
3678 if (namesArray[i] == name) {
3679 assert(i < getNumResults() &&
" names array out of sync with results");
3680 return getResult(i);
3689 size_t numReadPorts = 0;
3690 size_t numWritePorts = 0;
3691 size_t numReadWritePorts = 0;
3693 SmallVector<int32_t> writeClockIDs;
3695 for (
size_t i = 0, e = op.getNumResults(); i != e; ++i) {
3696 auto portKind = op.getPortKind(i);
3697 if (portKind == MemOp::PortKind::Read)
3699 else if (portKind == MemOp::PortKind::Write) {
3700 for (
auto *a : op.getResult(i).getUsers()) {
3701 auto subfield = dyn_cast<SubfieldOp>(a);
3702 if (!subfield || subfield.getFieldIndex() != 2)
3704 auto clockPort =
a->getResult(0);
3705 for (
auto *b : clockPort.getUsers()) {
3706 if (
auto connect = dyn_cast<FConnectLike>(b)) {
3707 if (
connect.getDest() == clockPort) {
3710 connect.getSrc(),
true,
true,
true),
3712 if (result.second) {
3713 writeClockIDs.push_back(numWritePorts);
3715 writeClockIDs.push_back(result.first->second);
3724 ++numReadWritePorts;
3731 op.emitError(
"'firrtl.mem' should have simple type and known width");
3732 MemoryInitAttr init = op->getAttrOfType<MemoryInitAttr>(
"init");
3734 if (op->hasAttr(
"modName"))
3735 modName = op->getAttrOfType<StringAttr>(
"modName");
3737 SmallString<8> clocks;
3738 for (
auto a : writeClockIDs)
3739 clocks.
append(Twine((char)(
a +
'a')).str());
3740 SmallString<32> initStr;
3745 for (
auto c : init.getFilename().getValue())
3746 if ((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') ||
3747 (c >=
'0' && c <=
'9'))
3748 initStr.push_back(c);
3749 initStr.push_back(
'_');
3750 initStr.push_back(init.getIsBinary() ?
't' :
'f');
3751 initStr.push_back(
'_');
3752 initStr.push_back(init.getIsInline() ?
't' :
'f');
3754 modName = StringAttr::get(
3757 "{0}FIRRTLMem_{1}_{2}_{3}_{4}_{5}_{6}_{7}_{8}_{9}_{10}{11}{12}",
3758 op.getPrefix().value_or(
""), numReadPorts, numWritePorts,
3759 numReadWritePorts, (
size_t)width, op.getDepth(),
3760 op.getReadLatency(), op.getWriteLatency(), op.getMaskBits(),
3761 (
unsigned)op.getRuw(), (
unsigned)seq::WUW::PortOrder,
3762 clocks.empty() ?
"" :
"_" + clocks, init ? initStr.str() :
""));
3764 return {numReadPorts,
3769 op.getReadLatency(),
3770 op.getWriteLatency(),
3772 *seq::symbolizeRUW(
unsigned(op.getRuw())),
3773 seq::WUW::PortOrder,
3776 op.getMaskBits() > 1,
3782void MemOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3787 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
3788 setNameFn(getResult(i), (base +
"_" + getPortName(i)).str());
3792std::optional<size_t> MemOp::getTargetResultIndex() {
3794 return std::nullopt;
3802 OpAsmSetValueNameFn setNameFn) {
3805 setNameFn(op.getDataRaw(), name);
3806 if (op.isForceable())
3807 setNameFn(op.getDataRef(), (name +
"_ref").str());
3810void NodeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3814LogicalResult NodeOp::inferReturnTypes(
3815 mlir::MLIRContext *
context, std::optional<mlir::Location> location,
3816 ::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes,
3817 ::mlir::OpaqueProperties properties, ::mlir::RegionRange regions,
3818 ::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
3819 if (operands.empty())
3821 Adaptor adaptor(operands, attributes, properties, regions);
3822 inferredReturnTypes.push_back(adaptor.getInput().getType());
3823 if (adaptor.getForceable()) {
3825 true, adaptor.getInput().getType());
3826 if (!forceableType) {
3828 ::mlir::emitError(*location,
"cannot force a node of type ")
3829 << operands[0].getType();
3832 inferredReturnTypes.push_back(forceableType);
3837std::optional<size_t> NodeOp::getTargetResultIndex() {
return 0; }
3839void RegOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3843std::optional<size_t> RegOp::getTargetResultIndex() {
return 0; }
3845SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3846RegOp::computeDataFlow() {
3851LogicalResult RegResetOp::verify() {
3852 auto reset = getResetValue();
3859 return emitError(
"type mismatch between register ")
3860 << regType <<
" and reset value " << resetType;
3865std::optional<size_t> RegResetOp::getTargetResultIndex() {
return 0; }
3867void RegResetOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3876FormalOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3877 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3879 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3881 if (!isa<FModuleLike>(op)) {
3882 auto d = emitOpError() <<
"target " << getModuleNameAttr()
3883 <<
" is not a module";
3884 d.attachNote(op->getLoc()) <<
"target defined here";
3896SimulationOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3897 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3899 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3901 auto complain = [&] {
3902 auto d = emitOpError() <<
"target " << getModuleNameAttr() <<
" ";
3903 d.attachNote(op->getLoc()) <<
"target defined here";
3907 auto module = dyn_cast<FModuleLike>(op);
3909 return complain() <<
"is not a module";
3911 auto numPorts =
module.getNumPorts();
3913 return complain() <<
"must have at least 4 ports, got " << numPorts
3917 auto checkPort = [&](
unsigned idx, StringRef expName,
Direction expDir,
3918 llvm::function_ref<bool(Type)> checkType,
3919 StringRef expType) {
3920 auto name =
module.getPortNameAttr(idx);
3921 if (name != expName) {
3922 complain() <<
"port " << idx <<
" must be called \"" << expName
3923 <<
"\", got " << name <<
" instead";
3926 if (
auto dir = module.getPortDirection(idx); dir != expDir) {
3930 complain() <<
"port " << name <<
" must be " << stringify(expDir)
3931 <<
", got " << stringify(dir) <<
" instead";
3934 if (
auto type = module.getPortType(idx); !checkType(type)) {
3935 complain() <<
"port " << name <<
" must be a '!firrtl." << expType
3936 <<
"', got " << type <<
" instead";
3942 auto isClock = [](Type type) {
return isa<ClockType>(type); };
3943 auto isBool = [](Type type) {
3944 if (
auto uintType = dyn_cast<UIntType>(type))
3945 return uintType.getWidth() == 1;
3949 if (!checkPort(0,
"clock",
Direction::In, isClock,
"clock") ||
3956 for (
unsigned i = 4; i < numPorts; ++i) {
3957 auto type =
module.getPortType(i);
3958 if (!isa<PropertyType>(type))
3959 return complain() <<
"port " << i <<
" may only be a property type, got "
3960 << type <<
" instead";
3970void WireOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3974SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3975RegResetOp::computeDataFlow() {
3980std::optional<size_t> WireOp::getTargetResultIndex() {
return 0; }
3982LogicalResult WireOp::verify() {
3984 if (type_isa<DomainType>(getResult().getType()) && !getDomains().
empty())
3985 return emitOpError(
"of domain type must not have domain associations");
3988 auto domains = getDomains();
3989 if (!domains.size())
4002 using oldValueAndDiag = std::pair<Value, std::unique_ptr<InFlightDiagnostic>>;
4003 llvm::SmallMapVector<SymbolRefAttr, oldValueAndDiag, 2> domainInfo;
4004 bool hasErrors =
false;
4005 for (
auto domain : domains) {
4006 auto domainType = cast<DomainType>(domain.getType());
4007 auto domainName = domainType.getName();
4010 auto [it, inserted] =
4011 domainInfo.try_emplace(domainName, std::make_pair(domain,
nullptr));
4018 auto &[value, diag] = it->second;
4024 diag = std::make_unique<InFlightDiagnostic>(
4025 emitOpError() <<
"associated with multiple operands of '"
4026 << domainName.getValue() <<
"' kind");
4027 diag->attachNote(value.getLoc()) <<
"first domain operand here";
4032 diag->attachNote(domain.getLoc())
4033 <<
"additional colliding domain operand here";
4045 for (
auto &[_, diag] : domainInfo.values())
4051LogicalResult WireOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
4052 if (
auto refType = type_dyn_cast<RefType>(getType(0)))
4054 refType,
getLoc(), getOperation()->getParentOfType<CircuitOp>(),
4055 symbolTable, Twine(
"'") + getOperationName() +
"' op is");
4057 if (
auto domainType = type_dyn_cast<DomainType>(getType(0)))
4058 return domainType.verifySymbolUses(getOperation(), symbolTable);
4067LogicalResult ContractOp::verify() {
4068 if (getBody().getArgumentTypes() != getInputs().getType())
4069 return emitOpError(
"result types and region argument types must match");
4078OptionCaseOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
4079 auto caseMacro = getCaseMacroAttr();
4084 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
4085 auto *refOp = symbolTable.lookupSymbolIn(circuitOp, caseMacro);
4087 return emitOpError(
"case_macro references an undefined symbol: ")
4090 if (!isa<sv::MacroDeclOp>(refOp))
4091 return emitOpError(
"case_macro must reference a macro declaration");
4100void ObjectOp::build(OpBuilder &builder, OperationState &state, ClassLike klass,
4102 build(builder, state, klass.getInstanceType(),
4103 StringAttr::get(builder.getContext(), name));
4106LogicalResult ObjectOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
4107 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
4108 auto classType = getType();
4109 auto className = classType.getNameAttr();
4112 auto classOp = dyn_cast_or_null<ClassLike>(
4113 symbolTable.lookupSymbolIn(circuitOp, className));
4115 return emitOpError() <<
"references unknown class " << className;
4118 if (failed(classOp.verifyType(classType, [&]() { return emitOpError(); })))
4124StringAttr ObjectOp::getClassNameAttr() {
4125 return getType().getNameAttr().getAttr();
4128StringRef ObjectOp::getClassName() {
return getType().getName(); }
4130ClassLike ObjectOp::getReferencedClass(
const SymbolTable &symbolTable) {
4131 auto symRef = getType().getNameAttr();
4132 return symbolTable.lookup<ClassLike>(symRef.getLeafReference());
4135Operation *ObjectOp::getReferencedOperation(
const SymbolTable &symtbl) {
4136 return getReferencedClass(symtbl);
4139StringRef ObjectOp::getInstanceName() {
return getName(); }
4141StringAttr ObjectOp::getInstanceNameAttr() {
return getNameAttr(); }
4143StringAttr ObjectOp::getReferencedModuleNameAttr() {
4144 return getClassNameAttr();
4147void ObjectOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4148 setNameFn(getResult(),
getName());
4155LogicalResult AttachOp::verify() {
4157 std::optional<int32_t> commonWidth;
4158 for (
auto operand : getOperands()) {
4159 auto thisWidth = type_cast<AnalogType>(operand.getType()).getWidth();
4163 commonWidth = thisWidth;
4166 if (commonWidth != thisWidth)
4167 return emitOpError(
"is inavlid as not all known operand widths match");
4174 Value dst = connect->getOperand(0);
4175 Value src = connect->getOperand(1);
4184 if (isa<PropertyType>(src.getType()) ||
4188 auto diag = emitError(connect->getLoc());
4189 diag <<
"connect has invalid flow: the source expression ";
4191 diag <<
"\"" << srcName <<
"\" ";
4192 diag <<
"has " <<
toString(srcFlow) <<
", expected source or duplex flow";
4193 return diag.attachNote(srcRef.getLoc()) <<
"the source was defined here";
4201 auto diag = emitError(connect->getLoc());
4202 diag <<
"connect has invalid flow: the destination expression ";
4204 diag <<
"\"" << dstName <<
"\" ";
4205 diag <<
"has " <<
toString(dstFlow) <<
", expected sink or duplex flow";
4206 return diag.attachNote(dstRef.getLoc())
4207 <<
"the destination was defined here";
4216 bool outerTypeIsConst =
false) {
4217 auto typeIsConst = outerTypeIsConst || type.
isConst();
4222 if (
auto bundleType = type_dyn_cast<BundleType>(type))
4223 return llvm::any_of(bundleType.getElements(), [&](
auto &element) {
4224 return isConstFieldDriven(element.type, isFlip ^ element.isFlip,
4228 if (
auto vectorType = type_dyn_cast<FVectorType>(type))
4240 auto dest = connect.getDest();
4241 auto destType = type_dyn_cast<FIRRTLBaseType>(dest.getType());
4242 auto src = connect.getSrc();
4243 auto srcType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4244 if (!destType || !srcType)
4247 auto destRefinedType = destType;
4248 auto srcRefinedType = srcType;
4253 auto findFieldDeclarationRefiningFieldType =
4255 while (
auto *definingOp = value.getDefiningOp()) {
4256 bool shouldContinue =
true;
4257 TypeSwitch<Operation *>(definingOp)
4258 .Case<SubfieldOp, SubindexOp>([&](
auto op) { value = op.getInput(); })
4259 .Case<SubaccessOp>([&](SubaccessOp op) {
4263 .getElementTypePreservingConst()
4265 originalFieldType = originalFieldType.getConstType(
true);
4266 value = op.getInput();
4268 .Default([&](Operation *) { shouldContinue =
false; });
4269 if (!shouldContinue)
4275 auto destDeclaration =
4276 findFieldDeclarationRefiningFieldType(dest, destRefinedType);
4277 auto srcDeclaration =
4278 findFieldDeclarationRefiningFieldType(src, srcRefinedType);
4280 auto checkConstConditionality = [&](Value value,
FIRRTLBaseType type,
4281 Value declaration) -> LogicalResult {
4282 auto *declarationBlock = declaration.getParentBlock();
4283 auto *block = connect->getBlock();
4284 while (block && block != declarationBlock) {
4285 auto *parentOp = block->getParentOp();
4287 if (
auto whenOp = dyn_cast<WhenOp>(parentOp);
4288 whenOp && !whenOp.getCondition().getType().isConst()) {
4290 return connect.emitOpError()
4291 <<
"assignment to 'const' type " << type
4292 <<
" is dependent on a non-'const' condition";
4293 return connect->emitOpError()
4294 <<
"assignment to nested 'const' member of type " << type
4295 <<
" is dependent on a non-'const' condition";
4298 block = parentOp->getBlock();
4303 auto emitSubaccessError = [&] {
4304 return connect.emitError(
4305 "assignment to non-'const' subaccess of 'const' type is disallowed");
4311 if (destType != destRefinedType)
4312 return emitSubaccessError();
4314 if (failed(checkConstConditionality(dest, destType, destDeclaration)))
4319 if (srcRefinedType.containsConst() &&
4322 if (srcType != srcRefinedType)
4323 return emitSubaccessError();
4324 if (failed(checkConstConditionality(src, srcType, srcDeclaration)))
4341 auto dest = connect.getDest();
4342 for (
auto *user : dest.getUsers()) {
4343 if (
auto c = dyn_cast<FConnectLike>(user);
4344 c && c.getDest() == dest && c != connect) {
4345 auto diag = connect.emitError(
"destination cannot be driven by multiple "
4347 diag.attachNote(c->getLoc()) <<
"other driver is here";
4354LogicalResult ConnectOp::verify() {
4355 auto dstType = getDest().getType();
4356 auto srcType = getSrc().getType();
4357 auto dstBaseType = type_dyn_cast<FIRRTLBaseType>(dstType);
4358 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(srcType);
4359 if (!dstBaseType || !srcBaseType) {
4360 if (dstType != srcType)
4361 return emitError(
"may not connect different non-base types");
4364 if (dstBaseType.containsAnalog() || srcBaseType.containsAnalog())
4365 return emitError(
"analog types may not be connected");
4369 return emitError(
"type mismatch between destination ")
4370 << dstBaseType <<
" and source " << srcBaseType;
4375 return emitError(
"destination ")
4376 << dstBaseType <<
" is not as wide as the source " << srcBaseType;
4389LogicalResult MatchingConnectOp::verify() {
4390 if (
auto type = type_dyn_cast<FIRRTLType>(getDest().getType())) {
4391 auto baseType = type_cast<FIRRTLBaseType>(type);
4394 if (baseType && baseType.containsAnalog())
4395 return emitError(
"analog types may not be connected");
4400 "`SameAnonTypeOperands` trait should have already rejected "
4401 "structurally non-equivalent types");
4414LogicalResult RefDefineOp::verify() {
4421 if (
auto *op = getDest().getDefiningOp()) {
4423 if (isa<RefSubOp>(op))
4425 "destination reference cannot be a sub-element of a reference");
4426 if (isa<RefCastOp>(op))
4428 "destination reference cannot be a cast of another reference");
4436 SmallVector<SymbolRefAttr> missingLayers;
4439 "has more layer requirements than destination",
4440 "additional layers required");
4443LogicalResult PropAssignOp::verify() {
4454 auto domainType = dyn_cast<DomainType>(value.getType());
4459 return domainType.getName();
4462LogicalResult DomainDefineOp::verify() {
4469 auto dst = getDest();
4470 auto src = getSrc();
4478 if (
auto *srcDefOp = src.getDefiningOp())
4479 if (isa<WireOp>(srcDefOp))
4481 if (
auto *dstDefOp = dst.getDefiningOp())
4482 if (isa<WireOp>(dstDefOp))
4487 return emitError(
"could not determine domain-type of destination");
4491 return emitError(
"could not determine domain-type of source");
4493 if (dstDomain != srcDomain) {
4494 auto diag = emitError()
4495 <<
"source domain type " << srcDomain
4496 <<
" does not match destination domain type " << dstDomain;
4503void WhenOp::createElseRegion() {
4504 assert(!hasElseRegion() &&
"already has an else region");
4505 getElseRegion().push_back(
new Block());
4508void WhenOp::build(OpBuilder &builder, OperationState &result, Value condition,
4509 bool withElseRegion, std::function<
void()> thenCtor,
4510 std::function<
void()> elseCtor) {
4511 OpBuilder::InsertionGuard guard(builder);
4512 result.addOperands(condition);
4515 builder.createBlock(result.addRegion());
4520 Region *elseRegion = result.addRegion();
4521 if (withElseRegion) {
4522 builder.createBlock(elseRegion);
4532LogicalResult MatchOp::verify() {
4533 FEnumType type = getInput().getType();
4536 auto numCases = getTags().size();
4537 auto numRegions = getNumRegions();
4538 if (numRegions != numCases)
4539 return emitOpError(
"expected ")
4540 << numRegions <<
" tags but got " << numCases;
4542 auto numTags = type.getNumElements();
4544 SmallDenseSet<int64_t> seen;
4545 for (
const auto &[tag, region] :
llvm::zip(getTags(), getRegions())) {
4546 auto tagIndex = size_t(cast<IntegerAttr>(tag).
getInt());
4549 if (region.getNumArguments() != 1)
4550 return emitOpError(
"region should have exactly one argument");
4553 if (tagIndex >= numTags)
4554 return emitOpError(
"the tag index ")
4555 << tagIndex <<
" is out of the range of valid tags in " << type;
4558 auto [it, inserted] = seen.insert(tagIndex);
4560 return emitOpError(
"the tag ") << type.getElementNameAttr(tagIndex)
4561 <<
" is matched more than once";
4564 auto expectedType = type.getElementTypePreservingConst(tagIndex);
4565 auto regionType = region.getArgument(0).getType();
4566 if (regionType != expectedType)
4567 return emitOpError(
"region type ")
4568 << regionType <<
" does not match the expected type "
4573 for (
size_t i = 0, e = type.getNumElements(); i < e; ++i)
4574 if (!seen.contains(i))
4575 return emitOpError(
"missing case for tag ") << type.getElementNameAttr(i);
4580void MatchOp::print(OpAsmPrinter &p) {
4581 auto input = getInput();
4582 FEnumType type = input.getType();
4583 auto regions = getRegions();
4584 p <<
" " << input <<
" : " << type;
4585 SmallVector<StringRef> elided = {
"tags"};
4586 p.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elided);
4589 for (
const auto &[tag, region] :
llvm::zip(getTags(), regions)) {
4592 p.printKeywordOrString(
4593 type.getElementName(cast<IntegerAttr>(tag).getInt()));
4595 p.printRegionArgument(region.front().getArgument(0), {},
4598 p.printRegion(region,
false);
4605ParseResult MatchOp::parse(OpAsmParser &parser, OperationState &result) {
4606 auto *
context = parser.getContext();
4607 auto &properties = result.getOrAddProperties<Properties>();
4608 OpAsmParser::UnresolvedOperand input;
4609 if (parser.parseOperand(input) || parser.parseColon())
4612 auto loc = parser.getCurrentLocation();
4614 if (parser.parseType(type))
4616 auto enumType = type_dyn_cast<FEnumType>(type);
4618 return parser.emitError(loc,
"expected enumeration type but got") << type;
4620 if (parser.resolveOperand(input, type, result.operands) ||
4621 parser.parseOptionalAttrDictWithKeyword(result.attributes) ||
4622 parser.parseLBrace())
4625 auto i32Type = IntegerType::get(
context, 32);
4626 SmallVector<Attribute> tags;
4629 if (failed(parser.parseOptionalKeyword(
"case")))
4633 auto nameLoc = parser.getCurrentLocation();
4635 OpAsmParser::Argument arg;
4636 auto *region = result.addRegion();
4637 if (parser.parseKeywordOrString(&name) || parser.parseLParen() ||
4638 parser.parseArgument(arg) || parser.parseRParen())
4642 auto index = enumType.getElementIndex(name);
4644 return parser.emitError(nameLoc,
"the tag \"")
4645 << name <<
"\" is not a member of the enumeration " << enumType;
4646 tags.push_back(IntegerAttr::get(i32Type, *index));
4649 arg.type = enumType.getElementTypePreservingConst(*index);
4650 if (parser.parseRegion(*region, arg))
4653 properties.setTags(ArrayAttr::get(
context, tags));
4655 return parser.parseRBrace();
4658void MatchOp::build(OpBuilder &builder, OperationState &result, Value input,
4660 MutableArrayRef<std::unique_ptr<Region>> regions) {
4661 auto &properties = result.getOrAddProperties<Properties>();
4662 result.addOperands(input);
4663 properties.setTags(tags);
4664 result.addRegions(regions);
4673 struct IsExprClassifier :
public ExprVisitor<IsExprClassifier, bool> {
4674 bool visitInvalidExpr(Operation *op) {
return false; }
4675 bool visitUnhandledExpr(Operation *op) {
return true; }
4681void InvalidValueOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4684 if (
auto ty = type_dyn_cast<IntType>(getType())) {
4685 const char *base = ty.isSigned() ?
"invalid_si" :
"invalid_ui";
4686 auto width = ty.getWidthOrSentinel();
4690 name = (Twine(base) + Twine(width)).str();
4691 }
else if (
auto ty = type_dyn_cast<AnalogType>(getType())) {
4692 auto width = ty.getWidthOrSentinel();
4694 name =
"invalid_analog";
4696 name = (
"invalid_analog" + Twine(width)).str();
4697 }
else if (type_isa<AsyncResetType>(getType()))
4698 name =
"invalid_asyncreset";
4699 else if (type_isa<ResetType>(getType()))
4700 name =
"invalid_reset";
4701 else if (type_isa<ClockType>(getType()))
4702 name =
"invalid_clock";
4706 setNameFn(getResult(), name);
4709void ConstantOp::print(OpAsmPrinter &p) {
4711 p.printAttributeWithoutType(getValueAttr());
4713 p.printType(getType());
4714 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4717ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
4718 auto &properties = result.getOrAddProperties<Properties>();
4721 auto loc = parser.getCurrentLocation();
4722 auto valueResult = parser.parseOptionalInteger(value);
4723 if (!valueResult.has_value())
4724 return parser.emitError(loc,
"expected integer value");
4728 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4729 parser.parseOptionalAttrDict(result.attributes))
4731 result.addTypes(resultType);
4737 if (width > value.getBitWidth()) {
4741 value = value.sext(width);
4742 }
else if (width < value.getBitWidth()) {
4745 unsigned neededBits = value.isNegative() ? value.getSignificantBits()
4746 : value.getActiveBits();
4747 if (width < neededBits)
4748 return parser.emitError(loc,
"constant out of range for result type ")
4750 value = value.trunc(width);
4754 auto intType = parser.getBuilder().getIntegerType(value.getBitWidth(),
4756 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4757 properties.setValue(valueAttr);
4761LogicalResult ConstantOp::verify() {
4765 if (width != -1 && (
int)getValue().
getBitWidth() != width)
4767 "firrtl.constant attribute bitwidth doesn't match return type");
4770 auto attrType = type_cast<IntegerType>(getValueAttr().getType());
4771 if (attrType.isSignless() || attrType.isSigned() != intType.
isSigned())
4772 return emitError(
"firrtl.constant attribute has wrong sign");
4779void ConstantOp::build(OpBuilder &builder, OperationState &result,
IntType type,
4780 const APInt &value) {
4783 assert((width == -1 || (int32_t)value.getBitWidth() == width) &&
4784 "incorrect attribute bitwidth for firrtl.constant");
4787 IntegerAttr::get(type.getContext(), APSInt(value, !type.
isSigned()));
4788 return build(builder, result, type, attr);
4793void ConstantOp::build(OpBuilder &builder, OperationState &result,
4794 const APSInt &value) {
4795 auto attr = IntegerAttr::get(builder.getContext(), value);
4797 IntType::get(builder.getContext(), value.isSigned(), value.getBitWidth());
4798 return build(builder, result, type, attr);
4801void ConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4808 SmallString<32> specialNameBuffer;
4809 llvm::raw_svector_ostream specialName(specialNameBuffer);
4811 getValue().print(specialName, intTy.
isSigned());
4813 specialName << (intTy.
isSigned() ?
"_si" :
"_ui");
4816 specialName << width;
4817 setNameFn(getResult(), specialName.str());
4820void SpecialConstantOp::print(OpAsmPrinter &p) {
4823 p << static_cast<unsigned>(getValue());
4825 p.printType(getType());
4826 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4829ParseResult SpecialConstantOp::parse(OpAsmParser &parser,
4830 OperationState &result) {
4831 auto &properties = result.getOrAddProperties<Properties>();
4835 auto loc = parser.getCurrentLocation();
4836 auto valueResult = parser.parseOptionalInteger(value);
4837 if (!valueResult.has_value())
4838 return parser.emitError(loc,
"expected integer value");
4841 if (value != 0 && value != 1)
4842 return parser.emitError(loc,
"special constants can only be 0 or 1.");
4846 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4847 parser.parseOptionalAttrDict(result.attributes))
4849 result.addTypes(resultType);
4852 auto valueAttr = parser.getBuilder().getBoolAttr(value == 1);
4853 properties.setValue(valueAttr);
4857void SpecialConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4858 SmallString<32> specialNameBuffer;
4859 llvm::raw_svector_ostream specialName(specialNameBuffer);
4861 specialName << static_cast<unsigned>(getValue());
4862 auto type = getType();
4863 if (type_isa<ClockType>(type)) {
4864 specialName <<
"_clock";
4865 }
else if (type_isa<ResetType>(type)) {
4866 specialName <<
"_reset";
4867 }
else if (type_isa<AsyncResetType>(type)) {
4868 specialName <<
"_asyncreset";
4870 setNameFn(getResult(), specialName.str());
4877 if (type.isGround()) {
4878 if (!isa<IntegerAttr>(attr)) {
4879 op->emitOpError(
"Ground type is not an integer attribute");
4884 auto attrlist = dyn_cast<ArrayAttr>(attr);
4886 op->emitOpError(
"expected array attribute for aggregate constant");
4889 if (
auto array = type_dyn_cast<FVectorType>(type)) {
4890 if (array.getNumElements() != attrlist.size()) {
4891 op->emitOpError(
"array attribute (")
4892 << attrlist.size() <<
") has wrong size for vector constant ("
4893 << array.getNumElements() <<
")";
4896 return llvm::all_of(attrlist, [&array, op](Attribute attr) {
4900 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4901 if (bundle.getNumElements() != attrlist.size()) {
4902 op->emitOpError(
"array attribute (")
4903 << attrlist.size() <<
") has wrong size for bundle constant ("
4904 << bundle.getNumElements() <<
")";
4907 for (
size_t i = 0; i < bundle.getNumElements(); ++i) {
4908 if (bundle.getElement(i).isFlip) {
4909 op->emitOpError(
"Cannot have constant bundle type with flip");
4917 op->emitOpError(
"Unknown aggregate type");
4921LogicalResult AggregateConstantOp::verify() {
4927Attribute AggregateConstantOp::getAttributeFromFieldID(uint64_t fieldID) {
4929 Attribute value = getFields();
4930 while (fieldID != 0) {
4931 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4932 auto index = bundle.getIndexForFieldID(fieldID);
4933 fieldID -= bundle.getFieldID(index);
4934 type = bundle.getElementType(index);
4935 value = cast<ArrayAttr>(value)[index];
4937 auto vector = type_cast<FVectorType>(type);
4938 auto index = vector.getIndexForFieldID(fieldID);
4939 fieldID -= vector.getFieldID(index);
4940 type = vector.getElementType();
4941 value = cast<ArrayAttr>(value)[index];
4947LogicalResult FIntegerConstantOp::verify() {
4948 auto i = getValueAttr();
4949 if (!i.getType().isSignedInteger())
4950 return emitOpError(
"value must be signed");
4954void FIntegerConstantOp::print(OpAsmPrinter &p) {
4956 p.printAttributeWithoutType(getValueAttr());
4957 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4960ParseResult FIntegerConstantOp::parse(OpAsmParser &parser,
4961 OperationState &result) {
4962 auto *
context = parser.getContext();
4963 auto &properties = result.getOrAddProperties<Properties>();
4965 if (parser.parseInteger(value) ||
4966 parser.parseOptionalAttrDict(result.attributes))
4968 result.addTypes(FIntegerType::get(
context));
4970 IntegerType::get(
context, value.getBitWidth(), IntegerType::Signed);
4971 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4972 properties.setValue(valueAttr);
4976ParseResult ListCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4977 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
4980 if (parser.parseOperandList(operands) ||
4981 parser.parseOptionalAttrDict(result.attributes) ||
4982 parser.parseColonType(type))
4984 result.addTypes(type);
4986 return parser.resolveOperands(operands, type.getElementType(),
4990void ListCreateOp::print(OpAsmPrinter &p) {
4992 p.printOperands(getElements());
4993 p.printOptionalAttrDict((*this)->getAttrs());
4994 p <<
" : " << getType();
4997LogicalResult ListCreateOp::verify() {
4998 if (getElements().
empty())
5001 auto elementType = getElements().front().getType();
5002 auto listElementType = getType().getElementType();
5004 return emitOpError(
"has elements of type ")
5005 <<
elementType <<
" instead of " << listElementType;
5010LogicalResult BundleCreateOp::verify() {
5011 BundleType resultType = getType();
5012 if (resultType.getNumElements() != getFields().size())
5013 return emitOpError(
"number of fields doesn't match type");
5014 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
5016 resultType.getElementTypePreservingConst(i),
5017 type_cast<FIRRTLBaseType>(getOperand(i).getType())))
5018 return emitOpError(
"type of element doesn't match bundle for field ")
5019 << resultType.getElement(i).name;
5024LogicalResult VectorCreateOp::verify() {
5025 FVectorType resultType = getType();
5026 if (resultType.getNumElements() != getFields().size())
5027 return emitOpError(
"number of fields doesn't match type");
5028 auto elemTy = resultType.getElementTypePreservingConst();
5029 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
5031 elemTy, type_cast<FIRRTLBaseType>(getOperand(i).getType())))
5032 return emitOpError(
"type of element doesn't match vector element");
5038UnknownValueOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
5040 auto classType = dyn_cast<ClassType>(getType());
5044 auto className = classType.getNameAttr();
5046 Operation *op = symbolTable.lookupNearestSymbolFrom(*
this, className);
5048 return emitOpError() <<
"refers to non-existent class ("
5049 << className.getAttr() <<
")";
5052 if (!isa<ClassLike>(op))
5053 return emitOpError() <<
"refers to a non-class type ("
5054 << className.getAttr() <<
")";
5063LogicalResult FEnumCreateOp::verify() {
5064 FEnumType resultType = getResult().getType();
5065 auto elementIndex = resultType.getElementIndex(
getFieldName());
5067 return emitOpError(
"label ")
5068 <<
getFieldName() <<
" is not a member of the enumeration type "
5071 resultType.getElementTypePreservingConst(*elementIndex),
5072 getInput().getType()))
5073 return emitOpError(
"type of element doesn't match enum element");
5077void FEnumCreateOp::print(OpAsmPrinter &printer) {
5080 printer <<
'(' << getInput() <<
')';
5081 SmallVector<StringRef> elidedAttrs = {
"fieldIndex"};
5082 printer.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elidedAttrs);
5084 printer.printFunctionalType(ArrayRef<Type>{getInput().getType()},
5085 ArrayRef<Type>{getResult().getType()});
5088ParseResult FEnumCreateOp::parse(OpAsmParser &parser, OperationState &result) {
5089 auto *
context = parser.getContext();
5090 auto &properties = result.getOrAddProperties<Properties>();
5092 OpAsmParser::UnresolvedOperand input;
5093 std::string fieldName;
5094 mlir::FunctionType functionType;
5095 if (parser.parseKeywordOrString(&fieldName) || parser.parseLParen() ||
5096 parser.parseOperand(input) || parser.parseRParen() ||
5097 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5098 parser.parseType(functionType))
5101 if (functionType.getNumInputs() != 1)
5102 return parser.emitError(parser.getNameLoc(),
"single input type required");
5103 if (functionType.getNumResults() != 1)
5104 return parser.emitError(parser.getNameLoc(),
"single result type required");
5106 auto inputType = functionType.getInput(0);
5107 if (parser.resolveOperand(input, inputType, result.operands))
5110 auto outputType = functionType.getResult(0);
5111 auto enumType = type_dyn_cast<FEnumType>(outputType);
5113 return parser.emitError(parser.getNameLoc(),
5114 "output must be enum type, got ")
5116 auto fieldIndex = enumType.getElementIndex(fieldName);
5118 return parser.emitError(parser.getNameLoc(),
5119 "unknown field " + fieldName +
" in enum type ")
5122 properties.setFieldIndex(
5123 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5125 result.addTypes(enumType);
5134LogicalResult IsTagOp::verify() {
5135 if (getFieldIndex() >= getInput().getType().base().getNumElements())
5136 return emitOpError(
"element index is greater than the number of fields in "
5141void IsTagOp::print(::mlir::OpAsmPrinter &printer) {
5142 printer <<
' ' << getInput() <<
' ';
5144 SmallVector<::llvm::StringRef, 1> elidedAttrs = {
"fieldIndex"};
5145 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
5146 printer <<
" : " << getInput().getType();
5149ParseResult IsTagOp::parse(OpAsmParser &parser, OperationState &result) {
5150 auto *
context = parser.getContext();
5151 auto &properties = result.getOrAddProperties<Properties>();
5153 OpAsmParser::UnresolvedOperand input;
5154 std::string fieldName;
5156 if (parser.parseOperand(input) || parser.parseKeywordOrString(&fieldName) ||
5157 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5158 parser.parseType(inputType))
5161 if (parser.resolveOperand(input, inputType, result.operands))
5164 auto enumType = type_dyn_cast<FEnumType>(inputType);
5166 return parser.emitError(parser.getNameLoc(),
5167 "input must be enum type, got ")
5169 auto fieldIndex = enumType.getElementIndex(fieldName);
5171 return parser.emitError(parser.getNameLoc(),
5172 "unknown field " + fieldName +
" in enum type ")
5175 properties.setFieldIndex(
5176 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5178 result.addTypes(UIntType::get(
context, 1,
false));
5183FIRRTLType IsTagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5184 OpaqueProperties properties,
5185 mlir::RegionRange regions,
5186 std::optional<Location> loc) {
5187 Adaptor adaptor(operands, attrs, properties, regions);
5188 return UIntType::get(attrs.getContext(), 1,
5189 isConst(adaptor.getInput().getType()));
5192template <
typename OpTy>
5194 auto *
context = parser.getContext();
5196 OpAsmParser::UnresolvedOperand input;
5197 std::string fieldName;
5199 if (parser.parseOperand(input) || parser.parseLSquare() ||
5200 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5201 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5202 parser.parseType(inputType))
5205 if (parser.resolveOperand(input, inputType, result.operands))
5208 auto bundleType = type_dyn_cast<typename OpTy::InputType>(inputType);
5210 return parser.emitError(parser.getNameLoc(),
5211 "input must be bundle type, got ")
5213 auto fieldIndex = bundleType.getElementIndex(fieldName);
5215 return parser.emitError(parser.getNameLoc(),
5216 "unknown field " + fieldName +
" in bundle type ")
5219 result.getOrAddProperties<
typename OpTy::Properties>().setFieldIndex(
5220 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5222 auto type = OpTy::inferReturnType(inputType, *fieldIndex, {});
5225 result.addTypes(type);
5230ParseResult SubtagOp::parse(OpAsmParser &parser, OperationState &result) {
5231 auto *
context = parser.getContext();
5233 OpAsmParser::UnresolvedOperand input;
5234 std::string fieldName;
5236 if (parser.parseOperand(input) || parser.parseLSquare() ||
5237 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5238 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5239 parser.parseType(inputType))
5242 if (parser.resolveOperand(input, inputType, result.operands))
5245 auto enumType = type_dyn_cast<FEnumType>(inputType);
5247 return parser.emitError(parser.getNameLoc(),
5248 "input must be enum type, got ")
5250 auto fieldIndex = enumType.getElementIndex(fieldName);
5252 return parser.emitError(parser.getNameLoc(),
5253 "unknown field " + fieldName +
" in enum type ")
5256 result.getOrAddProperties<Properties>().setFieldIndex(
5257 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5259 SmallVector<Type> inferredReturnTypes;
5260 if (failed(SubtagOp::inferReturnTypes(
5261 context, result.location, result.operands,
5262 result.attributes.getDictionary(
context), result.getRawProperties(),
5263 result.regions, inferredReturnTypes)))
5265 result.addTypes(inferredReturnTypes);
5270ParseResult SubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
5271 return parseSubfieldLikeOp<SubfieldOp>(parser, result);
5273ParseResult OpenSubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
5274 return parseSubfieldLikeOp<OpenSubfieldOp>(parser, result);
5277template <
typename OpTy>
5279 printer <<
' ' << op.getInput() <<
'[';
5280 printer.printKeywordOrString(op.getFieldName());
5282 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
5283 elidedAttrs.push_back(
"fieldIndex");
5284 printer.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
5285 printer <<
" : " << op.getInput().getType();
5287void SubfieldOp::print(::mlir::OpAsmPrinter &printer) {
5288 return printSubfieldLikeOp<SubfieldOp>(*
this, printer);
5290void OpenSubfieldOp::print(::mlir::OpAsmPrinter &printer) {
5291 return printSubfieldLikeOp<OpenSubfieldOp>(*
this, printer);
5294void SubtagOp::print(::mlir::OpAsmPrinter &printer) {
5295 printer <<
' ' << getInput() <<
'[';
5298 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
5299 elidedAttrs.push_back(
"fieldIndex");
5300 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
5301 printer <<
" : " << getInput().getType();
5304template <
typename OpTy>
5306 if (op.getFieldIndex() >=
5307 firrtl::type_cast<typename OpTy::InputType>(op.getInput().getType())
5309 return op.emitOpError(
"subfield element index is greater than the number "
5310 "of fields in the bundle type");
5313LogicalResult SubfieldOp::verify() {
5314 return verifySubfieldLike<SubfieldOp>(*
this);
5316LogicalResult OpenSubfieldOp::verify() {
5317 return verifySubfieldLike<OpenSubfieldOp>(*
this);
5320LogicalResult SubtagOp::verify() {
5321 if (getFieldIndex() >= getInput().getType().base().getNumElements())
5322 return emitOpError(
"subfield element index is greater than the number "
5323 "of fields in the bundle type");
5333 SmallVector<Operation *, 8> worklist({op});
5337 bool constant =
true;
5343 while (constant && !(worklist.empty()))
5344 TypeSwitch<Operation *>(worklist.pop_back_val())
5345 .Case<NodeOp, AsSIntPrimOp, AsUIntPrimOp>([&](
auto op) {
5346 if (
auto definingOp = op.getInput().getDefiningOp())
5347 worklist.push_back(definingOp);
5350 .Case<WireOp, SubindexOp, SubfieldOp>([&](
auto op) {
5351 for (
auto &use : op.getResult().getUses())
5352 worklist.push_back(use.getOwner());
5354 .Case<ConstantOp, SpecialConstantOp, AggregateConstantOp>([](
auto) {})
5355 .Default([&](
auto) { constant =
false; });
5364 if (
auto *op = value.getDefiningOp())
5369LogicalResult ConstCastOp::verify() {
5371 return emitOpError() << getInput().getType()
5372 <<
" is not 'const'-castable to "
5373 << getResult().getType();
5377FIRRTLType SubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
5378 std::optional<Location> loc) {
5379 auto inType = type_cast<BundleType>(type);
5381 if (fieldIndex >= inType.getNumElements())
5383 "subfield element index is greater than the "
5384 "number of fields in the bundle type");
5388 return inType.getElementTypePreservingConst(fieldIndex);
5391FIRRTLType OpenSubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
5392 std::optional<Location> loc) {
5393 auto inType = type_cast<OpenBundleType>(type);
5395 if (fieldIndex >= inType.getNumElements())
5397 "subfield element index is greater than the "
5398 "number of fields in the bundle type");
5402 return inType.getElementTypePreservingConst(fieldIndex);
5405bool SubfieldOp::isFieldFlipped() {
5406 BundleType bundle = getInput().getType();
5407 return bundle.getElement(getFieldIndex()).isFlip;
5409bool OpenSubfieldOp::isFieldFlipped() {
5410 auto bundle = getInput().getType();
5411 return bundle.getElement(getFieldIndex()).isFlip;
5414FIRRTLType SubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
5415 std::optional<Location> loc) {
5416 if (
auto vectorType = type_dyn_cast<FVectorType>(type)) {
5417 if (fieldIndex < vectorType.getNumElements())
5418 return vectorType.getElementTypePreservingConst();
5420 "' in vector type ", type);
5425FIRRTLType OpenSubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
5426 std::optional<Location> loc) {
5427 if (
auto vectorType = type_dyn_cast<OpenVectorType>(type)) {
5428 if (fieldIndex < vectorType.getNumElements())
5429 return vectorType.getElementTypePreservingConst();
5431 "' in vector type ", type);
5437FIRRTLType SubtagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5438 OpaqueProperties properties,
5439 mlir::RegionRange regions,
5440 std::optional<Location> loc) {
5441 Adaptor adaptor(operands, attrs, properties, regions);
5442 auto inType = type_cast<FEnumType>(adaptor.getInput().getType());
5443 auto fieldIndex = adaptor.getFieldIndex();
5445 if (fieldIndex >= inType.getNumElements())
5447 "subtag element index is greater than the "
5448 "number of fields in the enum type");
5452 auto elementType = inType.getElement(fieldIndex).type;
5456FIRRTLType SubaccessOp::inferReturnType(Type inType, Type indexType,
5457 std::optional<Location> loc) {
5458 if (!type_isa<UIntType>(indexType))
5462 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
5464 return vectorType.getElementTypePreservingConst();
5465 return vectorType.getElementType().getAllConstDroppedType();
5473 std::optional<Location> loc) {
5474 auto inType = type_cast<FEnumType>(input);
5475 return UIntType::get(inType.getContext(), inType.getTagWidth());
5478ParseResult MultibitMuxOp::parse(OpAsmParser &parser, OperationState &result) {
5479 OpAsmParser::UnresolvedOperand index;
5480 SmallVector<OpAsmParser::UnresolvedOperand, 16> inputs;
5481 Type indexType, elemType;
5483 if (parser.parseOperand(index) || parser.parseComma() ||
5484 parser.parseOperandList(inputs) ||
5485 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5486 parser.parseType(indexType) || parser.parseComma() ||
5487 parser.parseType(elemType))
5490 if (parser.resolveOperand(index, indexType, result.operands))
5493 result.addTypes(elemType);
5495 return parser.resolveOperands(inputs, elemType, result.operands);
5498void MultibitMuxOp::print(OpAsmPrinter &p) {
5499 p <<
" " << getIndex() <<
", ";
5500 p.printOperands(getInputs());
5501 p.printOptionalAttrDict((*this)->getAttrs());
5502 p <<
" : " << getIndex().getType() <<
", " << getType();
5505FIRRTLType MultibitMuxOp::inferReturnType(ValueRange operands,
5506 DictionaryAttr attrs,
5507 OpaqueProperties properties,
5508 mlir::RegionRange regions,
5509 std::optional<Location> loc) {
5510 if (operands.size() < 2)
5514 if (!llvm::all_of(operands.drop_front(2), [&](
auto op) {
5515 return operands[1].getType() == op.getType();
5519 return type_cast<FIRRTLType>(operands[1].getType());
5526LogicalResult ObjectSubfieldOp::inferReturnTypes(
5527 MLIRContext *
context, std::optional<mlir::Location> location,
5528 ValueRange operands, DictionaryAttr attributes, OpaqueProperties properties,
5529 RegionRange regions, llvm::SmallVectorImpl<Type> &inferredReturnTypes) {
5531 inferReturnType(operands, attributes, properties, regions, location);
5534 inferredReturnTypes.push_back(type);
5538Type ObjectSubfieldOp::inferReturnType(Type inType, uint32_t fieldIndex,
5539 std::optional<Location> loc) {
5540 auto classType = dyn_cast<ClassType>(inType);
5544 if (classType.getNumElements() <= fieldIndex)
5546 "number of fields in the object");
5547 return classType.getElement(fieldIndex).type;
5550void ObjectSubfieldOp::print(OpAsmPrinter &p) {
5551 auto input = getInput();
5552 auto classType = input.getType();
5553 p <<
' ' << input <<
"[";
5554 p.printKeywordOrString(classType.getElement(getIndex()).name);
5556 p.printOptionalAttrDict((*this)->getAttrs(), std::array{StringRef(
"index")});
5557 p <<
" : " << classType;
5560ParseResult ObjectSubfieldOp::parse(OpAsmParser &parser,
5561 OperationState &result) {
5562 auto *
context = parser.getContext();
5564 OpAsmParser::UnresolvedOperand input;
5565 std::string fieldName;
5566 ClassType inputType;
5567 if (parser.parseOperand(input) || parser.parseLSquare() ||
5568 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5569 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5570 parser.parseType(inputType) ||
5571 parser.resolveOperand(input, inputType, result.operands))
5574 auto index = inputType.getElementIndex(fieldName);
5576 return parser.emitError(parser.getNameLoc(),
5577 "unknown field " + fieldName +
" in class type ")
5579 result.getOrAddProperties<Properties>().setIndex(
5580 IntegerAttr::get(IntegerType::get(
context, 32), *index));
5582 SmallVector<Type> inferredReturnTypes;
5583 if (failed(inferReturnTypes(
context, result.location, result.operands,
5584 result.attributes.getDictionary(
context),
5585 result.getRawProperties(), result.regions,
5586 inferredReturnTypes)))
5588 result.addTypes(inferredReturnTypes);
5605 int32_t &rhsWidth,
bool &isConstResult,
5606 std::optional<Location> loc) {
5608 auto lhsi = type_dyn_cast<IntType>(lhs);
5609 auto rhsi = type_dyn_cast<IntType>(rhs);
5610 if (!lhsi || !rhsi || lhsi.isSigned() != rhsi.isSigned()) {
5613 mlir::emitError(*loc,
"second operand must be an integer type, not ")
5615 else if (!lhsi && rhsi)
5616 mlir::emitError(*loc,
"first operand must be an integer type, not ")
5618 else if (!lhsi && !rhsi)
5619 mlir::emitError(*loc,
"operands must be integer types, not ")
5620 << lhs <<
" and " << rhs;
5622 mlir::emitError(*loc,
"operand signedness must match");
5627 lhsWidth = lhsi.getWidthOrSentinel();
5628 rhsWidth = rhsi.getWidthOrSentinel();
5629 isConstResult = lhsi.isConst() && rhsi.isConst();
5634 assert(op->getNumOperands() == 2 &&
5635 "SameOperandsIntTypeKind on non-binary op");
5636 int32_t lhsWidth, rhsWidth;
5639 op->getOperand(1).getType(), lhsWidth,
5640 rhsWidth, isConstResult, op->getLoc()));
5644 std::optional<Location> loc) {
5645 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5646 bool isConstResult =
false;
5650 if (lhsWidth != -1 && rhsWidth != -1)
5651 resultWidth = std::max(lhsWidth, rhsWidth) + 1;
5652 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5657 std::optional<Location> loc) {
5658 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5659 bool isConstResult =
false;
5663 if (lhsWidth != -1 && rhsWidth != -1)
5664 resultWidth = lhsWidth + rhsWidth;
5666 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5671 std::optional<Location> loc) {
5672 int32_t lhsWidth, rhsWidth;
5673 bool isConstResult =
false;
5678 if (type_isa<UIntType>(lhs))
5679 return UIntType::get(lhs.getContext(), lhsWidth, isConstResult);
5682 int32_t resultWidth = lhsWidth != -1 ? lhsWidth + 1 : -1;
5683 return SIntType::get(lhs.getContext(), resultWidth, isConstResult);
5687 std::optional<Location> loc) {
5688 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5689 bool isConstResult =
false;
5693 if (lhsWidth != -1 && rhsWidth != -1)
5694 resultWidth = std::min(lhsWidth, rhsWidth);
5695 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5700 std::optional<Location> loc) {
5701 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5702 bool isConstResult =
false;
5706 if (lhsWidth != -1 && rhsWidth != -1) {
5707 resultWidth = std::max(lhsWidth, rhsWidth);
5708 if (lhsWidth == resultWidth && lhs.
isConst() == isConstResult &&
5711 if (rhsWidth == resultWidth && rhs.
isConst() == isConstResult &&
5715 return UIntType::get(lhs.getContext(), resultWidth, isConstResult);
5719 std::optional<Location> loc) {
5720 if (!type_isa<FVectorType>(lhs) || !type_isa<FVectorType>(rhs))
5723 auto lhsVec = type_cast<FVectorType>(lhs);
5724 auto rhsVec = type_cast<FVectorType>(rhs);
5726 if (lhsVec.getNumElements() != rhsVec.getNumElements())
5731 rhsVec.getElementTypePreservingConst(), loc);
5734 auto elemBaseType = type_cast<FIRRTLBaseType>(elemType);
5735 return FVectorType::get(elemBaseType, lhsVec.getNumElements(),
5736 lhsVec.isConst() && rhsVec.isConst() &&
5737 elemBaseType.isConst());
5741 std::optional<Location> loc) {
5742 return UIntType::get(lhs.getContext(), 1,
isConst(lhs) &&
isConst(rhs));
5745FIRRTLType CatPrimOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5746 OpaqueProperties properties,
5747 mlir::RegionRange regions,
5748 std::optional<Location> loc) {
5750 if (operands.empty())
5751 return UIntType::get(attrs.getContext(), 0);
5754 bool isSigned = type_isa<SIntType>(operands[0].getType());
5755 for (
auto operand : operands) {
5756 auto type = type_dyn_cast<IntType>(operand.getType());
5759 if (type.isSigned() != isSigned)
5761 "all operands must have same signedness");
5765 int32_t resultWidth = 0;
5766 bool isConstResult =
true;
5768 for (
auto operand : operands) {
5769 auto type = type_cast<IntType>(operand.getType());
5770 int32_t width = type.getWidthOrSentinel();
5777 if (resultWidth != -1)
5778 resultWidth += width;
5781 isConstResult &= type.isConst();
5785 return UIntType::get(attrs.getContext(), resultWidth, isConstResult);
5789 std::optional<Location> loc) {
5790 auto lhsi = type_dyn_cast<IntType>(lhs);
5791 auto rhsui = type_dyn_cast<UIntType>(rhs);
5792 if (!rhsui || !lhsi)
5794 loc,
"first operand should be integer, second unsigned int");
5798 auto width = lhsi.getWidthOrSentinel();
5799 if (width == -1 || !rhsui.getWidth().has_value()) {
5802 auto amount = *rhsui.getWidth();
5805 "shift amount too large: second operand of "
5806 "dshl is wider than 31 bits");
5807 int64_t newWidth = (int64_t)width + ((int64_t)1 << amount) - 1;
5808 if (newWidth > INT32_MAX)
5810 loc,
"shift amount too large: first operand shifted by maximum "
5811 "amount exceeds maximum width");
5814 return IntType::get(lhs.getContext(), lhsi.isSigned(), width,
5815 lhsi.
isConst() && rhsui.isConst());
5819 std::optional<Location> loc) {
5820 auto lhsi = type_dyn_cast<IntType>(lhs);
5821 auto rhsu = type_dyn_cast<UIntType>(rhs);
5824 loc,
"first operand should be integer, second unsigned int");
5825 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5829 std::optional<Location> loc) {
5830 auto lhsi = type_dyn_cast<IntType>(lhs);
5831 auto rhsu = type_dyn_cast<UIntType>(rhs);
5834 loc,
"first operand should be integer, second unsigned int");
5835 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5843 std::optional<Location> loc) {
5844 return UIntType::get(input.getContext(), 32);
5848 std::optional<Location> loc) {
5849 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5852 int32_t width = base.getBitWidthOrSentinel();
5855 return SIntType::get(input.getContext(), width, base.
isConst());
5859 std::optional<Location> loc) {
5860 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5863 int32_t width = base.getBitWidthOrSentinel();
5866 return UIntType::get(input.getContext(), width, base.
isConst());
5870 std::optional<Location> loc) {
5871 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5874 "operand must be single bit scalar base type");
5875 int32_t width = base.getBitWidthOrSentinel();
5876 if (width == -2 || width == 0 || width > 1)
5878 return AsyncResetType::get(input.getContext(), base.
isConst());
5882 std::optional<Location> loc) {
5883 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5886 return ResetType::get(input.getContext(), base.
isConst());
5890 std::optional<Location> loc) {
5891 return ClockType::get(input.getContext(),
isConst(input));
5895 std::optional<Location> loc) {
5896 if (
auto uiType = type_dyn_cast<UIntType>(input)) {
5897 auto width = uiType.getWidthOrSentinel();
5900 return SIntType::get(input.getContext(), width, uiType.
isConst());
5903 if (type_isa<SIntType>(input))
5910 std::optional<Location> loc) {
5911 auto inputi = type_dyn_cast<IntType>(input);
5914 int32_t width = inputi.getWidthOrSentinel();
5917 return SIntType::get(input.getContext(), width, inputi.
isConst());
5921 std::optional<Location> loc) {
5922 auto inputi = type_dyn_cast<IntType>(input);
5925 if (isa<UIntType>(inputi))
5927 return UIntType::get(input.getContext(), inputi.getWidthOrSentinel(),
5932 std::optional<Location> loc) {
5933 return UIntType::get(input.getContext(), 1,
isConst(input));
5942 std::optional<Location> loc) {
5943 auto inputi = type_dyn_cast<IntType>(input);
5946 loc,
"input type should be the int type but got ", input);
5951 loc,
"high must be equal or greater than low, but got high = ", high,
5959 int32_t width = inputi.getWidthOrSentinel();
5960 if (width != -1 && high >= width)
5963 "high must be smaller than the width of input, but got high = ", high,
5964 ", width = ", width);
5966 return UIntType::get(input.getContext(), high - low + 1, inputi.
isConst());
5970 std::optional<Location> loc) {
5972 auto inputi = type_dyn_cast<IntType>(input);
5973 if (amount < 0 || !inputi)
5975 loc,
"operand must have integer type and amount must be >= 0");
5977 int32_t width = inputi.getWidthOrSentinel();
5978 if (width != -1 && amount > width)
5981 return UIntType::get(input.getContext(), amount, inputi.
isConst());
5996 bool isConstCondition,
5997 std::optional<Location> loc) {
6003 if (high.getTypeID() != low.getTypeID())
6004 return emitInferRetTypeError<FIRRTLBaseType>(
6005 loc,
"incompatible mux operand types, true value type: ", high,
6006 ", false value type: ", low);
6008 bool outerTypeIsConst = isConstCondition && low.
isConst() && high.
isConst();
6013 if (type_isa<IntType>(low)) {
6018 if (highWidth == -1)
6020 return (lowWidth > highWidth ? low : high).getConstType(outerTypeIsConst);
6025 auto highEnum = type_dyn_cast<FEnumType>(high);
6026 auto lowEnum = type_dyn_cast<FEnumType>(low);
6027 if (lowEnum && highEnum) {
6028 if (lowEnum.getNumElements() != highEnum.getNumElements())
6029 return emitInferRetTypeError<FIRRTLBaseType>(
6030 loc,
"incompatible mux operand types, true value type: ", high,
6031 ", false value type: ", low);
6032 SmallVector<FEnumType::EnumElement> elements;
6033 for (
auto [high, low] : llvm::zip_equal(highEnum, lowEnum)) {
6035 if (high.name != low.name || high.value != low.value)
6036 return emitInferRetTypeError<FIRRTLBaseType>(
6037 loc,
"incompatible mux operand types, true value type: ", highEnum,
6038 ", false value type: ", lowEnum);
6045 elements.emplace_back(high.name, high.value, inner);
6047 return FEnumType::get(high.getContext(), elements, outerTypeIsConst);
6051 auto highVector = type_dyn_cast<FVectorType>(high);
6052 auto lowVector = type_dyn_cast<FVectorType>(low);
6053 if (highVector && lowVector &&
6054 highVector.getNumElements() == lowVector.getNumElements()) {
6056 lowVector.getElementTypePreservingConst(),
6057 isConstCondition, loc);
6060 return FVectorType::get(inner, lowVector.getNumElements(),
6065 auto highBundle = type_dyn_cast<BundleType>(high);
6066 auto lowBundle = type_dyn_cast<BundleType>(low);
6067 if (highBundle && lowBundle) {
6068 auto highElements = highBundle.getElements();
6069 auto lowElements = lowBundle.getElements();
6072 SmallVector<BundleType::BundleElement> newElements;
6074 bool failed =
false;
6076 if (highElements[i].name != lowElements[i].name ||
6077 highElements[i].isFlip != lowElements[i].isFlip) {
6081 auto element = highElements[i];
6083 highBundle.getElementTypePreservingConst(i),
6084 lowBundle.getElementTypePreservingConst(i), isConstCondition, loc);
6087 newElements.push_back(element);
6090 return BundleType::get(low.getContext(), newElements, outerTypeIsConst);
6092 return emitInferRetTypeError<FIRRTLBaseType>(
6093 loc,
"incompatible mux operand bundle fields, true value type: ", high,
6094 ", false value type: ", low);
6099 return emitInferRetTypeError<FIRRTLBaseType>(
6100 loc,
"invalid mux operand types, true value type: ", high,
6101 ", false value type: ", low);
6106 std::optional<Location> loc) {
6107 auto highType = type_dyn_cast<FIRRTLBaseType>(high);
6108 auto lowType = type_dyn_cast<FIRRTLBaseType>(low);
6109 if (!highType || !lowType)
6114FIRRTLType Mux2CellIntrinsicOp::inferReturnType(ValueRange operands,
6115 DictionaryAttr attrs,
6116 OpaqueProperties properties,
6117 mlir::RegionRange regions,
6118 std::optional<Location> loc) {
6119 auto highType = type_dyn_cast<FIRRTLBaseType>(operands[1].getType());
6120 auto lowType = type_dyn_cast<FIRRTLBaseType>(operands[2].getType());
6121 if (!highType || !lowType)
6127FIRRTLType Mux4CellIntrinsicOp::inferReturnType(ValueRange operands,
6128 DictionaryAttr attrs,
6129 OpaqueProperties properties,
6130 mlir::RegionRange regions,
6131 std::optional<Location> loc) {
6132 SmallVector<FIRRTLBaseType> types;
6134 for (
unsigned i = 1; i < 5; i++) {
6135 types.push_back(type_dyn_cast<FIRRTLBaseType>(operands[i].getType()));
6140 isConst(operands[0].getType()), loc);
6144 result = types.back();
6151 std::optional<Location> loc) {
6152 auto inputi = type_dyn_cast<IntType>(input);
6153 if (amount < 0 || !inputi)
6155 loc,
"pad input must be integer and amount must be >= 0");
6157 int32_t width = inputi.getWidthOrSentinel();
6161 width = std::max<int32_t>(width, amount);
6162 return IntType::get(input.getContext(), inputi.isSigned(), width,
6167 std::optional<Location> loc) {
6168 auto inputi = type_dyn_cast<IntType>(input);
6169 if (amount < 0 || !inputi)
6171 loc,
"shl input must be integer and amount must be >= 0");
6173 int32_t width = inputi.getWidthOrSentinel();
6177 return IntType::get(input.getContext(), inputi.isSigned(), width,
6182 std::optional<Location> loc) {
6183 auto inputi = type_dyn_cast<IntType>(input);
6184 if (amount < 0 || !inputi)
6186 loc,
"shr input must be integer and amount must be >= 0");
6188 int32_t width = inputi.getWidthOrSentinel();
6191 int32_t minWidth = inputi.isUnsigned() ? 0 : 1;
6192 width = std::max<int32_t>(minWidth, width - amount);
6195 return IntType::get(input.getContext(), inputi.isSigned(), width,
6200 std::optional<Location> loc) {
6202 auto inputi = type_dyn_cast<IntType>(input);
6203 if (amount < 0 || !inputi)
6205 loc,
"tail input must be integer and amount must be >= 0");
6207 int32_t width = inputi.getWidthOrSentinel();
6211 loc,
"amount must be less than or equal operand width");
6222void VerbatimExprOp::getAsmResultNames(
6223 function_ref<
void(Value, StringRef)> setNameFn) {
6227 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
6228 auto name = getText();
6230 if (name.starts_with(
"`"))
6231 name = name.drop_front();
6232 name = name.take_while(isOkCharacter);
6234 setNameFn(getResult(), name);
6241void VerbatimWireOp::getAsmResultNames(
6242 function_ref<
void(Value, StringRef)> setNameFn) {
6246 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
6247 auto name = getText();
6249 if (name.starts_with(
"`"))
6250 name = name.drop_front();
6251 name = name.take_while(isOkCharacter);
6253 setNameFn(getResult(), name);
6264 op->emitError() <<
"unknown width is not allowed for DPI";
6265 return WalkResult::interrupt();
6267 if (width == 1 || width == 8 || width == 16 || width == 32 ||
6269 return WalkResult::advance();
6271 <<
"integer types used by DPI functions must have a "
6272 "specific bit width; "
6273 "it must be equal to 1(bit), 8(byte), 16(shortint), "
6274 "32(int), 64(longint) "
6275 "or greater than 64, but got "
6277 return WalkResult::interrupt();
6282LogicalResult DPICallIntrinsicOp::verify() {
6283 if (
auto inputNames = getInputNames()) {
6284 if (getInputs().size() != inputNames->size())
6285 return emitError() <<
"inputNames has " << inputNames->size()
6286 <<
" elements but there are " << getInputs().size()
6287 <<
" input arguments";
6289 if (
auto outputName = getOutputName())
6290 if (getNumResults() == 0)
6291 return emitError() <<
"output name is given but there is no result";
6293 auto checkType = [
this](Type type) {
6296 return success(llvm::all_of(this->getResultTypes(), checkType) &&
6297 llvm::all_of(this->getOperandTypes(), checkType));
6300SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
6301DPICallIntrinsicOp::computeDataFlow() {
6305 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
6307 for (
auto operand : getOperands()) {
6308 auto type = type_cast<FIRRTLBaseType>(operand.getType());
6310 SmallVector<circt::FieldRef> operandFields;
6313 operandFields.push_back(baseFieldRef.getSubField(dstIndex));
6317 for (
auto result : getResults())
6320 for (
auto field : operandFields)
6321 deps.emplace_back(
circt::
FieldRef(result, dstIndex), field);
6331LogicalResult HWStructCastOp::verify() {
6333 BundleType bundleType;
6334 hw::StructType structType;
6335 if ((bundleType = type_dyn_cast<BundleType>(getOperand().getType()))) {
6336 structType = dyn_cast<hw::StructType>(getType());
6338 return emitError(
"result type must be a struct");
6339 }
else if ((bundleType = type_dyn_cast<BundleType>(getType()))) {
6340 structType = dyn_cast<hw::StructType>(getOperand().getType());
6342 return emitError(
"operand type must be a struct");
6344 return emitError(
"either source or result type must be a bundle type");
6347 auto firFields = bundleType.getElements();
6348 auto hwFields = structType.getElements();
6349 if (firFields.size() != hwFields.size())
6350 return emitError(
"bundle and struct have different number of fields");
6352 for (
size_t findex = 0, fend = firFields.size(); findex < fend; ++findex) {
6353 if (firFields[findex].name.getValue() != hwFields[findex].name)
6354 return emitError(
"field names don't match '")
6355 << firFields[findex].name.getValue() <<
"', '"
6356 << hwFields[findex].name.getValue() <<
"'";
6360 if (firWidth > 0 && hwWidth > 0 && firWidth != hwWidth)
6361 return emitError(
"size of field '")
6362 << hwFields[findex].name.getValue() <<
"' don't match " << firWidth
6369LogicalResult BitCastOp::verify() {
6370 auto inTypeBits =
getBitWidth(getInput().getType(),
true);
6372 if (inTypeBits.has_value() && resTypeBits.has_value()) {
6374 if (*inTypeBits == *resTypeBits) {
6377 return emitError(
"cannot cast non-'const' input type ")
6378 << getOperand().getType() <<
" to 'const' result type "
6382 return emitError(
"the bitwidth of input (")
6383 << *inTypeBits <<
") and result (" << *resTypeBits
6386 if (!inTypeBits.has_value())
6387 return emitError(
"bitwidth cannot be determined for input operand type ")
6388 << getInput().getType();
6389 return emitError(
"bitwidth cannot be determined for result type ")
6400 NamedAttrList &resultAttrs) {
6401 auto result = parser.parseOptionalAttrDict(resultAttrs);
6402 if (!resultAttrs.get(
"annotations"))
6403 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
6409 DictionaryAttr attr,
6410 ArrayRef<StringRef> extraElides = {}) {
6411 SmallVector<StringRef> elidedAttrs(extraElides.begin(), extraElides.end());
6413 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
6414 elidedAttrs.push_back(
"annotations");
6416 elidedAttrs.push_back(
"nameKind");
6418 p.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
6424 NamedAttrList &resultAttrs) {
6427 if (!resultAttrs.get(
"portAnnotations")) {
6428 SmallVector<Attribute, 16> portAnnotations(
6429 parser.getNumResults(), parser.getBuilder().getArrayAttr({}));
6430 resultAttrs.append(
"portAnnotations",
6431 parser.getBuilder().getArrayAttr(portAnnotations));
6438 DictionaryAttr attr,
6439 ArrayRef<StringRef> extraElides = {}) {
6440 SmallVector<StringRef, 2> elidedAttrs(extraElides.begin(), extraElides.end());
6442 if (llvm::all_of(op->getAttrOfType<ArrayAttr>(
"portAnnotations"),
6443 [&](Attribute a) { return cast<ArrayAttr>(a).empty(); }))
6444 elidedAttrs.push_back(
"portAnnotations");
6453 firrtl::NameKindEnumAttr &result) {
6456 if (!parser.parseOptionalKeyword(&keyword,
6457 {
"interesting_name",
"droppable_name"})) {
6458 auto kind = symbolizeNameKindEnum(keyword);
6459 result = NameKindEnumAttr::get(parser.getContext(), kind.value());
6465 NameKindEnumAttr::get(parser.getContext(), NameKindEnum::DroppableName);
6470 firrtl::NameKindEnumAttr attr,
6471 ArrayRef<StringRef> extraElides = {}) {
6472 if (attr.getValue() != NameKindEnum::DroppableName)
6473 p <<
" " << stringifyNameKindEnum(attr.getValue());
6481 NamedAttrList &resultAttrs) {
6489 DictionaryAttr attrs) {
6490 SmallVector<StringRef, 4> elides;
6492 elides.push_back(Forceable::getForceableAttrName());
6502 OpAsmParser &parser,
6503 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &fieldValues,
6504 SmallVectorImpl<Type> &fieldTypes, Type &resultType) {
6506 if (parser.parseType(resultType))
6509 auto domainType = dyn_cast<DomainType>(resultType);
6511 return parser.emitError(parser.getCurrentLocation(),
6512 "expected domain type");
6515 auto fields = domainType.getFields();
6518 if (fieldValues.size() != fields.size())
6519 return parser.emitError(parser.getCurrentLocation(),
6520 "number of field values (" +
6521 Twine(fieldValues.size()) +
6522 ") does not match domain field count (" +
6523 Twine(fields.size()) +
")");
6526 fieldTypes.reserve(fields.size());
6527 for (
auto field : fields)
6528 fieldTypes.push_back(cast<DomainFieldAttr>(field).getType());
6534 OperandRange fieldValues,
6535 TypeRange fieldTypes, Type resultType) {
6543static ParseResult
parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs) {
6548static void printMemOp(OpAsmPrinter &p, Operation *op, DictionaryAttr attr) {
6559 if (ClassType::parseInterface(parser, type))
6566 type.printInterface(p);
6574 NamedAttrList &resultAttrs) {
6575 auto result = p.parseOptionalAttrDict(resultAttrs);
6576 if (!resultAttrs.get(
"name"))
6577 resultAttrs.append(
"name", p.getBuilder().getStringAttr(
""));
6583 DictionaryAttr attr,
6584 ArrayRef<StringRef> extraElides = {}) {
6585 SmallVector<StringRef> elides(extraElides.begin(), extraElides.end());
6586 if (op->getAttrOfType<StringAttr>(
"name").getValue().empty())
6587 elides.push_back(
"name");
6589 p.printOptionalAttrDict(op->getAttrs(), elides);
6593 NamedAttrList &resultAttrs) {
6598 DictionaryAttr attr) {
6603 NamedAttrList &resultAttrs) {
6608 DictionaryAttr attr) {
6610 {
"formatString",
"outputFile",
"operandSegmentSizes"});
6618 DictionaryAttr attr) {
6627 DictionaryAttr attr) {
6636 OpAsmSetValueNameFn setNameFn) {
6639 if (op->getNumResults() == 1)
6640 if (
auto nameAttr = op->getAttrOfType<StringAttr>(
"name"))
6641 setNameFn(op->getResult(0), nameAttr.getValue());
6644void AddPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6648void AndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6652void AndRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6656void SizeOfIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6659void AsAsyncResetPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6662void AsResetPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6665void AsClockPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6668void AsSIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6671void AsUIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6674void BitsPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6677void CatPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6680void CvtPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6683void DShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6686void DShlwPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6689void DShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6692void DivPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6695void EQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6698void GEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6701void GTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6704void GenericIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6707void HeadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6710void IntegerAddOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6713void IntegerMulOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6716void IntegerShrOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6719void IntegerShlOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6722void IsTagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6725void IsXIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6728void PlusArgsValueIntrinsicOp::getAsmResultNames(
6729 OpAsmSetValueNameFn setNameFn) {
6732void PlusArgsTestIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6735void LEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6738void LTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6741void MulPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6744void MultibitMuxOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6747void MuxPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6750void Mux4CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6753void Mux2CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6756void NEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6759void NegPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6762void NotPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6765void OrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6768void OrRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6771void PadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6774void RemPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6777void ShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6780void ShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6784void SubPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6788void SubaccessOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6792void SubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6796void OpenSubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6800void SubtagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6804void SubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6808void OpenSubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6812void TagExtractOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6816void TailPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6820void XorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6824void XorRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6828void UninferredResetCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6832void ConstCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6836void ElementwiseXorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6840void ElementwiseOrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6844void ElementwiseAndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6852void RefCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6856void RefResolveOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6860void RefSendOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6864void RefSubOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6868void RWProbeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6872FIRRTLType RefResolveOp::inferReturnType(ValueRange operands,
6873 DictionaryAttr attrs,
6874 OpaqueProperties properties,
6875 mlir::RegionRange regions,
6876 std::optional<Location> loc) {
6877 Type inType = operands[0].getType();
6878 auto inRefType = type_dyn_cast<RefType>(inType);
6881 loc,
"ref.resolve operand must be ref type, not ", inType);
6882 return inRefType.getType();
6885FIRRTLType RefSendOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
6886 OpaqueProperties properties,
6887 mlir::RegionRange regions,
6888 std::optional<Location> loc) {
6889 Type inType = operands[0].getType();
6890 auto inBaseType = type_dyn_cast<FIRRTLBaseType>(inType);
6893 loc,
"ref.send operand must be base type, not ", inType);
6894 return RefType::get(inBaseType.getPassiveType());
6897FIRRTLType RefSubOp::inferReturnType(Type type, uint32_t fieldIndex,
6898 std::optional<Location> loc) {
6899 auto refType = type_dyn_cast<RefType>(type);
6902 auto inType = refType.getType();
6908 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
6909 if (fieldIndex < vectorType.getNumElements())
6910 return RefType::get(
6911 vectorType.getElementType().getConstType(
6912 vectorType.isConst() || vectorType.getElementType().isConst()),
6913 refType.getForceable(), refType.getLayer());
6915 "' in RefType of vector type ", refType);
6917 if (
auto bundleType = type_dyn_cast<BundleType>(inType)) {
6918 if (fieldIndex >= bundleType.getNumElements()) {
6920 "subfield element index is greater than "
6921 "the number of fields in the bundle type");
6923 return RefType::get(
6924 bundleType.getElement(fieldIndex)
6926 bundleType.isConst() ||
6927 bundleType.getElement(fieldIndex).type.isConst()),
6928 refType.getForceable(), refType.getLayer());
6932 loc,
"ref.sub op requires a RefType of vector or bundle base type");
6935LogicalResult RefCastOp::verify() {
6939 getOperation(), srcLayers, dstLayers,
6940 "cannot discard layer requirements of input reference",
6941 "discarding layer requirements");
6944LogicalResult RefResolveOp::verify() {
6948 getOperation(), srcLayers, dstLayers,
6949 "ambient layers are insufficient to resolve reference");
6953 auto targetRef = getTarget();
6954 if (targetRef.getModule() !=
6955 (*this)->getParentOfType<FModuleLike>().getModuleNameAttr())
6956 return emitOpError() <<
"has non-local target";
6958 auto target = ns.
lookup(targetRef);
6960 return emitOpError() <<
"has target that cannot be resolved: " << targetRef;
6962 auto checkFinalType = [&](
auto type, Location loc) -> LogicalResult {
6967 auto baseType = type_dyn_cast<FIRRTLBaseType>(fType);
6968 if (!baseType || baseType.getPassiveType() != getType().getType()) {
6969 auto diag = emitOpError(
"has type mismatch: target resolves to ")
6970 << fType <<
" instead of expected " << getType().getType();
6971 diag.attachNote(loc) <<
"target resolves here";
6976 if (target.isPort()) {
6977 auto mod = cast<FModuleLike>(target.getOp());
6978 return checkFinalType(mod.getPortType(target.getPort()),
6979 mod.getPortLocation(target.getPort()));
6981 hw::InnerSymbolOpInterface symOp =
6982 cast<hw::InnerSymbolOpInterface>(target.getOp());
6983 if (!symOp.getTargetResult())
6984 return emitOpError(
"has target that cannot be probed")
6985 .attachNote(symOp.getLoc())
6986 .append(
"target resolves here");
6988 symOp.getTargetResult().getParentBlock()->findAncestorOpInBlock(**
this);
6989 if (!ancestor || !symOp->isBeforeInBlock(ancestor))
6990 return emitOpError(
"is not dominated by target")
6991 .attachNote(symOp.getLoc())
6992 .append(
"target here");
6993 return checkFinalType(symOp.getTargetResult().getType(), symOp.getLoc());
6996LogicalResult RefForceOp::verify() {
7000 getOperation(), destLayers, ambientLayers,
7001 "has insufficient ambient layers to force its reference");
7004LogicalResult RefForceInitialOp::verify() {
7008 getOperation(), destLayers, ambientLayers,
7009 "has insufficient ambient layers to force its reference");
7012LogicalResult RefReleaseOp::verify() {
7016 getOperation(), destLayers, ambientLayers,
7017 "has insufficient ambient layers to release its reference");
7020LogicalResult RefReleaseInitialOp::verify() {
7024 getOperation(), destLayers, ambientLayers,
7025 "has insufficient ambient layers to release its reference");
7028LogicalResult XMRRefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7029 auto *target = symbolTable.lookupNearestSymbolFrom(*
this, getRefAttr());
7031 return emitOpError(
"has an invalid symbol reference");
7033 if (!isa<hw::HierPathOp>(target))
7034 return emitOpError(
"does not target a hierpath op");
7040LogicalResult XMRDerefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7041 auto *target = symbolTable.lookupNearestSymbolFrom(*
this, getRefAttr());
7043 return emitOpError(
"has an invalid symbol reference");
7045 if (!isa<hw::HierPathOp>(target))
7046 return emitOpError(
"does not target a hierpath op");
7056LogicalResult LayerBlockOp::verify() {
7057 auto layerName = getLayerName();
7058 auto *parentOp = (*this)->getParentOp();
7061 while (isa<WhenOp, MatchOp>(parentOp))
7062 parentOp = parentOp->getParentOp();
7066 auto nestedReferences = layerName.getNestedReferences();
7067 if (nestedReferences.empty()) {
7068 if (!isa<FModuleOp>(parentOp)) {
7069 auto diag = emitOpError() <<
"has an un-nested layer symbol, but does "
7070 "not have a 'firrtl.module' op as a parent";
7071 return diag.attachNote(parentOp->getLoc())
7072 <<
"illegal parent op defined here";
7075 auto parentLayerBlock = dyn_cast<LayerBlockOp>(parentOp);
7076 if (!parentLayerBlock) {
7077 auto diag = emitOpError()
7078 <<
"has a nested layer symbol, but does not have a '"
7079 << getOperationName() <<
"' op as a parent'";
7080 return diag.attachNote(parentOp->getLoc())
7081 <<
"illegal parent op defined here";
7083 auto parentLayerBlockName = parentLayerBlock.getLayerName();
7084 if (parentLayerBlockName.getRootReference() !=
7085 layerName.getRootReference() ||
7086 parentLayerBlockName.getNestedReferences() !=
7087 layerName.getNestedReferences().drop_back()) {
7088 auto diag = emitOpError() <<
"is nested under an illegal layer block";
7089 return diag.attachNote(parentLayerBlock->getLoc())
7090 <<
"illegal parent layer block defined here";
7096 auto result = getBody(0)->walk<mlir::WalkOrder::PreOrder>(
7097 [&](Operation *op) -> WalkResult {
7099 if (isa<LayerBlockOp>(op))
7100 return WalkResult::skip();
7104 for (
auto operand : op->getOperands()) {
7106 if (
auto *definingOp = operand.getDefiningOp())
7110 auto type = operand.getType();
7113 if (isa<PropertyType>(type)) {
7114 auto diag = emitOpError() <<
"captures a property operand";
7115 diag.attachNote(operand.getLoc()) <<
"operand is defined here";
7116 diag.attachNote(op->getLoc()) <<
"operand is used here";
7117 return WalkResult::interrupt();
7122 if (
auto connect = dyn_cast<FConnectLike>(op)) {
7124 if (isa<RefDefineOp>(connect))
7125 return WalkResult::advance();
7132 bool passive =
true;
7134 type_dyn_cast<FIRRTLBaseType>(
connect.getDest().getType()))
7135 passive = type.isPassive();
7144 return WalkResult::advance();
7147 return WalkResult::advance();
7151 <<
"connects to a destination which is defined outside its "
7152 "enclosing layer block";
7153 diag.attachNote(
getLoc()) <<
"enclosing layer block is defined here";
7154 diag.attachNote(dest.getLoc()) <<
"destination is defined here";
7155 return WalkResult::interrupt();
7158 return WalkResult::advance();
7161 return failure(result.wasInterrupted());
7165LayerBlockOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7167 symbolTable.lookupNearestSymbolFrom<LayerOp>(*
this, getLayerNameAttr());
7169 return emitOpError(
"invalid symbol reference");
7179void TimeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
7180 setNameFn(getResult(),
"time");
7183void HierarchicalModuleNameOp::getAsmResultNames(
7184 OpAsmSetValueNameFn setNameFn) {
7185 setNameFn(getResult(),
"hierarchicalmodulename");
7188ParseResult FPrintFOp::parse(::mlir::OpAsmParser &parser,
7189 ::mlir::OperationState &result) {
7191 OpAsmParser::UnresolvedOperand clock, cond;
7192 if (parser.parseOperand(clock) || parser.parseComma() ||
7193 parser.parseOperand(cond) || parser.parseComma())
7197 [&parser](llvm::SMLoc &loc, StringAttr &result,
7198 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &operands)
7200 loc = parser.getCurrentLocation();
7203 std::string resultStr;
7204 if (parser.parseString(&resultStr))
7206 result = parser.getBuilder().getStringAttr(resultStr);
7209 if (parser.parseOperandList(operands, AsmParser::Delimiter::OptionalParen))
7215 SmallVector<OpAsmParser::UnresolvedOperand> outputFileSubstitutions,
7217 llvm::SMLoc outputFileLoc, formatStringLoc;
7221 result.getOrAddProperties<FPrintFOp::Properties>().outputFile,
7222 outputFileSubstitutions) ||
7223 parser.parseComma() ||
7226 result.getOrAddProperties<FPrintFOp::Properties>().formatString,
7234 Type clockType, condType;
7235 SmallVector<Type> restTypes;
7237 if (parser.parseColon() || parser.parseType(clockType) ||
7238 parser.parseComma() || parser.parseType(condType))
7241 if (succeeded(parser.parseOptionalComma())) {
7242 if (parser.parseTypeList(restTypes))
7247 result.getOrAddProperties<FPrintFOp::Properties>().operandSegmentSizes = {
7248 1, 1,
static_cast<int32_t
>(outputFileSubstitutions.size()),
7249 static_cast<int32_t
>(substitutions.size())};
7252 if (parser.resolveOperand(clock, clockType, result.operands) ||
7253 parser.resolveOperand(cond, condType, result.operands) ||
7254 parser.resolveOperands(
7255 outputFileSubstitutions,
7256 ArrayRef(restTypes).take_front(outputFileSubstitutions.size()),
7257 outputFileLoc, result.operands) ||
7258 parser.resolveOperands(
7260 ArrayRef(restTypes).drop_front(outputFileSubstitutions.size()),
7261 formatStringLoc, result.operands))
7267void FPrintFOp::print(OpAsmPrinter &p) {
7268 p <<
" " << getClock() <<
", " << getCond() <<
", ";
7269 p.printAttributeWithoutType(getOutputFileAttr());
7270 if (!getOutputFileSubstitutions().
empty()) {
7272 p.printOperands(getOutputFileSubstitutions());
7276 p.printAttributeWithoutType(getFormatStringAttr());
7277 if (!getSubstitutions().
empty()) {
7279 p.printOperands(getSubstitutions());
7283 p <<
" : " << getClock().getType() <<
", " << getCond().getType();
7284 if (!getOutputFileSubstitutions().
empty() || !getSubstitutions().
empty()) {
7285 for (
auto type : getOperands().drop_front(2).getTypes()) {
7296LogicalResult FFlushOp::verify() {
7297 if (!getOutputFileAttr() && !getOutputFileSubstitutions().
empty())
7298 return emitOpError(
"substitutions without output file are not allowed");
7307 auto ref = getInstanceAttr();
7308 auto target = ns.
lookup(ref);
7310 return emitError() <<
"target " << ref <<
" cannot be resolved";
7312 if (!target.isOpOnly())
7313 return emitError() <<
"target " << ref <<
" is not an operation";
7315 auto instance = dyn_cast<InstanceOp>(target.getOp());
7317 return emitError() <<
"target " << ref <<
" is not an instance";
7319 if (!instance.getDoNotPrint())
7320 return emitError() <<
"target " << ref <<
" is not marked doNotPrint";
7329void DomainCreateAnonOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
7334DomainCreateAnonOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7335 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
7336 auto domainAttr = getDomainAttr();
7338 auto *symbol = symbolTable.lookupSymbolIn(circuitOp, domainAttr);
7340 return emitOpError() <<
"references undefined symbol '" << domainAttr
7343 if (!isa<DomainOp>(symbol))
7344 return emitOpError() <<
"references symbol '" << domainAttr
7345 <<
"' which is not a domain";
7348 auto domainType = getResult().getType();
7349 return domainType.verifySymbolUses(getOperation(), symbolTable);
7352void DomainCreateOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
7357DomainCreateOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7358 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
7359 auto domainAttr = getDomainAttr();
7361 auto *symbol = symbolTable.lookupSymbolIn(circuitOp, domainAttr);
7363 return emitOpError() <<
"references undefined symbol '" << domainAttr
7366 if (!isa<DomainOp>(symbol))
7367 return emitOpError() <<
"references symbol '" << domainAttr
7368 <<
"' which is not a domain";
7371 auto domainType = getResult().getType();
7372 return domainType.verifySymbolUses(getOperation(), symbolTable);
7375LogicalResult DomainCreateOp::verify() {
7377 auto domainType = getResult().getType();
7378 auto fields = domainType.getFields();
7379 auto fieldValues = getFieldValues();
7382 if (fieldValues.size() != fields.size())
7383 return emitOpError() <<
"has " << fieldValues.size()
7384 <<
" field value(s) but domain '"
7385 << domainType.getName() <<
"' expects "
7386 << fields.size() <<
" field(s)";
7389 for (
size_t i = 0; i < fields.size(); ++i) {
7390 auto fieldAttr = cast<DomainFieldAttr>(fields[i]);
7391 auto expectedType = fieldAttr.getType();
7392 auto actualType = fieldValues[i].getType();
7394 if (expectedType == actualType)
7397 return emitOpError() <<
"field value " << i <<
" has type " << actualType
7398 <<
" but domain field '" << fieldAttr.getName()
7399 <<
"' expects type " << expectedType;
7409StringAttr DomainSubfieldOp::getFieldName() {
7410 auto domainType = getInput().getType();
7411 auto fields = domainType.getFields();
7412 auto index = getFieldIndex();
7414 if (index >= fields.size())
7417 return cast<DomainFieldAttr>(fields[index]).getName();
7420Type DomainSubfieldOp::inferReturnType(Type inType, uint32_t fieldIndex,
7421 std::optional<Location> loc) {
7422 auto domainType = dyn_cast<DomainType>(inType);
7426 auto fields = domainType.getFields();
7427 if (fieldIndex >= fields.size())
7429 loc,
"field index ", fieldIndex,
7430 +
" is greater than the number of fields in the domain");
7432 return cast<DomainFieldAttr>(fields[fieldIndex]).getType();
7435Type DomainSubfieldOp::inferReturnType(ValueRange operands,
7436 mlir::DictionaryAttr attrs,
7437 mlir::OpaqueProperties properties,
7438 mlir::RegionRange regions,
7439 std::optional<Location> loc) {
7440 Adaptor adaptor(operands, attrs, properties, regions);
7441 return inferReturnType(adaptor.getInput().getType(), adaptor.getFieldIndex(),
7445DomainSubfieldOp DomainSubfieldOp::create(OpBuilder &builder, Type resultType,
7446 Value base,
unsigned fieldIndex) {
7447 OperationState state(builder.getUnknownLoc(),
7448 DomainSubfieldOp::getOperationName());
7449 state.addOperands(base);
7450 state.addAttribute(
"fieldIndex", builder.getI32IntegerAttr(fieldIndex));
7451 state.addTypes(resultType);
7452 return cast<DomainSubfieldOp>(builder.create(state));
7455LogicalResult DomainSubfieldOp::inferReturnTypes(
7456 MLIRContext *
context, std::optional<Location> location, ValueRange operands,
7457 DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
7458 SmallVectorImpl<Type> &inferredReturnTypes) {
7459 Adaptor adaptor(operands, attributes, properties, regions);
7460 auto resultType = inferReturnType(adaptor.getInput().getType(),
7461 adaptor.getFieldIndex(), location);
7464 inferredReturnTypes.push_back(resultType);
7468void DomainSubfieldOp::print(OpAsmPrinter &p) {
7469 p <<
' ' << getInput() <<
"[";
7472 p.printOptionalAttrDict((*this)->getAttrs(), {
"fieldIndex"});
7473 p <<
" : " << getInput().getType();
7476ParseResult DomainSubfieldOp::parse(OpAsmParser &parser,
7477 OperationState &result) {
7478 auto *
context = parser.getContext();
7480 OpAsmParser::UnresolvedOperand input;
7481 std::string fieldName;
7482 DomainType inputType;
7484 if (parser.parseOperand(input) || parser.parseLSquare() ||
7485 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
7486 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
7487 parser.parseType(inputType) ||
7488 parser.resolveOperand(input, inputType, result.operands))
7492 auto fieldIndex = inputType.getFieldIndex(fieldName);
7494 return parser.emitError(parser.getNameLoc(),
7495 "unknown field '" + fieldName +
"' in domain type");
7498 result.addAttribute(
7500 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
7503 auto resultType = inferReturnType(inputType, *fieldIndex, std::nullopt);
7507 result.addTypes(resultType);
7516#define GET_OP_CLASSES
7517#include "circt/Dialect/FIRRTL/FIRRTL.cpp.inc"
static void printNameKind(OpAsmPrinter &p, Operation *op, firrtl::NameKindEnumAttr attr, ArrayRef< StringRef > extraElides={})
static ParseResult parseNameKind(OpAsmParser &parser, firrtl::NameKindEnumAttr &result)
assert(baseType &&"element must be base type")
MlirType uint64_t numElements
static std::unique_ptr< Context > context
static Attribute fixDomainInfoInsertions(MLIRContext *context, Attribute domainInfoAttr, ArrayRef< unsigned > indexMap)
Return an updated domain info Attribute with domain indices updated based on port insertions.
static LogicalResult verifyProbeType(RefType refType, Location loc, CircuitOp circuitOp, SymbolTableCollection &symbolTable, Twine start)
static ArrayAttr fixDomainInfoDeletions(MLIRContext *context, ArrayAttr domainInfoAttr, const llvm::BitVector &portIndices, bool supportsEmptyAttr)
static SmallVector< PortInfo > getPortImpl(FModuleLike module)
static void buildClass(OpBuilder &builder, OperationState &result, StringAttr name, ArrayRef< PortInfo > ports)
static FlatSymbolRefAttr getDomainTypeName(Value value)
static void printStopAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
static void buildModule(OpBuilder &builder, OperationState &result, StringAttr name, ArrayRef< PortInfo > ports, ArrayAttr annotations, ArrayAttr layers)
static LayerSet getLayersFor(Value value)
Get the effective layer requirements for the given value.
static SmallVector< hw::PortInfo > getPortListImpl(FModuleLike module)
ParseResult parseSubfieldLikeOp(OpAsmParser &parser, OperationState &result)
static bool isSameIntTypeKind(Type lhs, Type rhs, int32_t &lhsWidth, int32_t &rhsWidth, bool &isConstResult, std::optional< Location > loc)
If LHS and RHS are both UInt or SInt types, the return true and fill in the width of them if known.
static LogicalResult verifySubfieldLike(OpTy op)
static void printFPrintfAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
static LogicalResult checkSingleConnect(FConnectLike connect)
Returns success if the given connect is the sole driver of its dest operand.
static bool isConstFieldDriven(FIRRTLBaseType type, bool isFlip=false, bool outerTypeIsConst=false)
Checks if the type has any 'const' leaf elements .
static ParseResult parsePrintfAttrs(OpAsmParser &p, NamedAttrList &resultAttrs)
static ParseResult parseParameterList(OpAsmParser &parser, ArrayAttr ¶meters)
Shim to use with assemblyFormat, custom<ParameterList>.
static RetTy emitInferRetTypeError(std::optional< Location > loc, const Twine &message, Args &&...args)
Emit an error if optional location is non-null, return null of return type.
static SmallVector< T > removeElementsAtIndices(ArrayRef< T > input, const llvm::BitVector &indicesToDrop)
Remove elements from the input array corresponding to set bits in indicesToDrop, returning the elemen...
static LogicalResult checkLayerCompatibility(Operation *op, const LayerSet &src, const LayerSet &dst, const Twine &errorMsg, const Twine ¬eMsg=Twine("missing layer requirements"))
static ParseResult parseModulePorts(OpAsmParser &parser, bool hasSSAIdentifiers, bool supportsSymbols, bool supportsDomains, SmallVectorImpl< OpAsmParser::Argument > &entryArgs, SmallVectorImpl< Direction > &portDirections, SmallVectorImpl< Attribute > &portNames, SmallVectorImpl< Attribute > &portTypes, SmallVectorImpl< Attribute > &portAnnotations, SmallVectorImpl< Attribute > &portSyms, SmallVectorImpl< Attribute > &portLocs, SmallVectorImpl< Attribute > &domains)
Parse a list of module ports.
static LogicalResult checkConnectConditionality(FConnectLike connect)
Checks that connections to 'const' destinations are not dependent on non-'const' conditions in when b...
static void erasePorts(FModuleLike op, const llvm::BitVector &portIndices)
Erases the ports that have their corresponding bit set in portIndices.
static ParseResult parseClassInterface(OpAsmParser &parser, Type &result)
static void printElidePortAnnotations(OpAsmPrinter &p, Operation *op, DictionaryAttr attr, ArrayRef< StringRef > extraElides={})
static ParseResult parseStopAttrs(OpAsmParser &p, NamedAttrList &resultAttrs)
static ParseResult parseNameKind(OpAsmParser &parser, firrtl::NameKindEnumAttr &result)
A forward declaration for NameKind attribute parser.
static 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 printFieldsFromDomain(OpAsmPrinter &p, Operation *op, OperandRange fieldValues, TypeRange fieldTypes, Type resultType)
static void printFModuleLikeOp(OpAsmPrinter &p, FModuleLike op)
static void printSubfieldLikeOp(OpTy op, ::mlir::OpAsmPrinter &printer)
static bool checkAggConstant(Operation *op, Attribute attr, FIRRTLBaseType type)
static void printClassLike(OpAsmPrinter &p, ClassLike op)
static hw::ModulePort::Direction dirFtoH(Direction dir)
static ParseResult parseOptionalParameters(OpAsmParser &parser, SmallVectorImpl< Attribute > ¶meters)
Parse an parameter list if present.
static MemOp::PortKind getMemPortKindFromType(FIRRTLType type)
Return the kind of port this is given the port type from a 'mem' decl.
static void genericAsmResultNames(Operation *op, OpAsmSetValueNameFn setNameFn)
static void printClassInterface(OpAsmPrinter &p, Operation *, ClassType type)
static void printPrintfAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
const char * toString(Flow flow)
static void replaceUsesRespectingInsertedPorts(Operation *op1, Operation *op2, ArrayRef< std::pair< unsigned, PortInfo > > insertions)
static bool isLayerSetCompatibleWith(const LayerSet &src, const LayerSet &dst, SmallVectorImpl< SymbolRefAttr > &missing)
Check that the source layers are all present in the destination layers.
static bool isLayerCompatibleWith(mlir::SymbolRefAttr srcLayer, mlir::SymbolRefAttr dstLayer)
Check that the source layer is compatible with the destination layer.
static LayerSet getAmbientLayersFor(Value value)
Get the ambient layer requirements at the definition site of the value.
void buildModuleLike(OpBuilder &builder, OperationState &result, StringAttr name, ArrayRef< PortInfo > ports)
static LayerSet getAmbientLayersAt(Operation *op)
Get the ambient layers active at the given op.
static void printFIRRTLImplicitSSAName(OpAsmPrinter &p, Operation *op, DictionaryAttr attrs)
static ParseResult parseFIRRTLImplicitSSAName(OpAsmParser &parser, NamedAttrList &resultAttrs)
static FIRRTLBaseType inferMuxReturnType(FIRRTLBaseType high, FIRRTLBaseType low, bool isConstCondition, std::optional< Location > loc)
Infer the result type for a multiplexer given its two operand types, which may be aggregates.
static ParseResult parseCircuitOpAttrs(OpAsmParser &parser, NamedAttrList &resultAttrs)
void getAsmBlockArgumentNamesImpl(Operation *op, mlir::Region ®ion, OpAsmSetValueNameFn setNameFn)
Get a special name to use when printing the entry block arguments of the region contained by an opera...
static void printElideAnnotations(OpAsmPrinter &p, Operation *op, DictionaryAttr attr, ArrayRef< StringRef > extraElides={})
static ParseResult parseElidePortAnnotations(OpAsmParser &parser, NamedAttrList &resultAttrs)
Parse an optional attribute dictionary, adding empty 'annotations' and 'portAnnotations' attributes i...
static void insertPorts(FModuleLike op, ArrayRef< std::pair< unsigned, PortInfo > > ports)
Inserts the given ports.
static ParseResult parseFPrintfAttrs(OpAsmParser &p, NamedAttrList &resultAttrs)
static ParseResult parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs)
static void replaceUsesRespectingErasedPorts(Operation *op1, Operation *op2, const llvm::BitVector &erasures)
static LogicalResult checkConnectFlow(Operation *connect)
Check if the source and sink are of appropriate flow.
static void printParameterList(OpAsmPrinter &p, Operation *op, ArrayAttr parameters)
Print a paramter list for a module or instance.
static ParseResult parseVerifAttrs(OpAsmParser &p, NamedAttrList &resultAttrs)
static ParseResult parseElideAnnotations(OpAsmParser &parser, NamedAttrList &resultAttrs)
Parse an optional attribute dictionary, adding an empty 'annotations' attribute if not specified.
ParseResult parseClassLike(OpAsmParser &parser, OperationState &result, bool hasSSAIdentifiers)
static void printCircuitOpAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
static LogicalResult verifyPortSymbolUses(FModuleLike module, SymbolTableCollection &symbolTable)
static void printVerifAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
static void printMemOp(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
Always elide "ruw" and elide "annotations" if it exists or if it is empty.
static bool isTypeAllowedForDPI(Operation *op, Type type)
static ParseResult parseElideEmptyName(OpAsmParser &p, NamedAttrList &resultAttrs)
static bool printModulePorts(OpAsmPrinter &p, Block *block, ArrayRef< bool > portDirections, ArrayRef< Attribute > portNames, ArrayRef< Attribute > portTypes, ArrayRef< Attribute > portAnnotations, ArrayRef< Attribute > portSyms, ArrayRef< Attribute > portLocs, ArrayRef< Attribute > domainInfo)
Print a list of module ports in the following form: in x: !firrtl.uint<1> [{class = "DontTouch}],...
static void printElideEmptyName(OpAsmPrinter &p, Operation *op, DictionaryAttr attr, ArrayRef< StringRef > extraElides={})
static ParseResult parseFModuleLikeOp(OpAsmParser &parser, OperationState &result, bool hasSSAIdentifiers)
static bool isAncestor(Block *block, Block *other)
static Location getLoc(DefSlot slot)
static StringAttr append(StringAttr base, const Twine &suffix)
Return a attribute with the specified suffix appended.
static std::optional< APInt > getInt(Value value)
Helper to convert a value to a constant integer if it is one.
static Block * getBodyBlock(FModuleLike mod)
static InstancePath empty
This class represents a reference to a specific field or element of an aggregate value.
Value getValue() const
Get the Value which created this location.
This class provides a read-only projection over the MLIR attributes that represent a set of annotatio...
bool hasDontTouch() const
firrtl.transforms.DontTouchAnnotation
static AnnotationSet forPort(FModuleLike op, size_t portNo)
Get an annotation set for the specified port.
ExprVisitor is a visitor for FIRRTL expression nodes.
ResultType dispatchExprVisitor(Operation *op, ExtraArgs... args)
FIRRTLBaseType getConstType(bool isConst) const
Return a 'const' or non-'const' version of this type.
FIRRTLBaseType getMaskType()
Return this type with all ground types replaced with UInt<1>.
int32_t getBitWidthOrSentinel()
If this is an IntType, AnalogType, or sugar type for a single bit (Clock, Reset, etc) then return the...
FIRRTLBaseType getAllConstDroppedType()
Return this type with a 'const' modifiers dropped.
bool isPassive() const
Return true if this is a "passive" type - one that contains no "flip" types recursively within itself...
bool isConst() const
Returns true if this is a 'const' type that can only hold compile-time constant values.
bool isConst() const
Returns true if this is a 'const' type that can only hold compile-time constant values.
Caching version of getFieldRefFromValue.
FieldRef getFieldRefFromValue(Value value, bool lookThroughCasts=false)
Caching version of getFieldRefFromValue.
This is the common base class between SIntType and UIntType.
int32_t getWidthOrSentinel() const
Return the width of this type, or -1 if it has none specified.
static IntType get(MLIRContext *context, bool isSigned, int32_t widthOrSentinel=-1, bool isConst=false)
Return an SIntType or UIntType with the specified signedness, width, and constness.
bool hasWidth() const
Return true if this integer type has a known width.
std::optional< int32_t > getWidth() const
Return an optional containing the width, if the width is known (or empty if width is unknown).
static StringRef getInnerSymbolAttrName()
Return the name of the attribute used for inner symbol names.
int main(int argc, char **argv)
connect(destination, source)
ClassType getInstanceTypeForClassLike(ClassLike classOp)
LogicalResult verifyTypeAgainstClassLike(ClassLike classOp, ClassType type, function_ref< InFlightDiagnostic()> emitError)
Assuming that the classOp is the source of truth, verify that the type accurately matches the signatu...
RefType getForceableResultType(bool forceable, Type type)
Return null or forceable reference result type.
mlir::DenseBoolArrayAttr packAttribute(MLIRContext *context, ArrayRef< Direction > directions)
Return a DenseBoolArrayAttr containing the packed representation of an array of directions.
static bool unGet(Direction dir)
Convert from Direction to bool. The opposite of get;.
SmallVector< Direction > unpackAttribute(mlir::DenseBoolArrayAttr directions)
Turn a packed representation of port attributes into a vector that can be worked with.
static Direction get(bool isOutput)
Return an output direction if isOutput is true, otherwise return an input direction.
static StringRef toString(Direction direction)
FIRRTLType inferElementwiseResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
FIRRTLType inferBitwiseResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
FIRRTLType inferAddSubResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
FIRRTLType inferComparisonResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
FIRRTLType inferReductionResult(FIRRTLType arg, std::optional< Location > loc)
LogicalResult verifySameOperandsIntTypeKind(Operation *op)
LogicalResult verifyReferencedModule(Operation *instanceOp, SymbolTableCollection &symbolTable, mlir::FlatSymbolRefAttr moduleName)
Verify that the instance refers to a valid FIRRTL module.
BaseTy type_cast(Type type)
Flow swapFlow(Flow flow)
Get a flow's reverse.
Direction
This represents the direction of a single port.
FieldRef getFieldRefFromValue(Value value, bool lookThroughCasts=false)
Get the FieldRef from a value.
void walkGroundTypes(FIRRTLType firrtlType, llvm::function_ref< void(uint64_t, FIRRTLBaseType, bool)> fn)
Walk leaf ground types in the firrtlType and apply the function fn.
bool isConstant(Operation *op)
Return true if the specified operation has a constant value.
bool areAnonymousTypesEquivalent(FIRRTLBaseType lhs, FIRRTLBaseType rhs)
Return true if anonymous types of given arguments are equivalent by pointer comparison.
constexpr bool isValidDst(Flow flow)
Flow foldFlow(Value val, Flow accumulatedFlow=Flow::Source)
Compute the flow for a Value, val, as determined by the FIRRTL specification.
bool areTypesEquivalent(FIRRTLType destType, FIRRTLType srcType, bool destOuterTypeIsConst=false, bool srcOuterTypeIsConst=false, bool requireSameWidths=false)
Returns whether the two types are equivalent.
bool hasDontTouch(Value value)
Check whether a block argument ("port") or the operation defining a value has a DontTouch annotation,...
size_t getNumPorts(Operation *op)
Return the number of ports in a module-like thing (modules, memories, etc)
mlir::Type getPassiveType(mlir::Type anyBaseFIRRTLType)
bool isTypeLarger(FIRRTLBaseType dstType, FIRRTLBaseType srcType)
Returns true if the destination is at least as wide as a source.
bool containsConst(Type type)
Returns true if the type is or contains a 'const' type whose value is guaranteed to be unchanging at ...
bool isDuplexValue(Value val)
Returns true if the value results from an expression with duplex flow.
mlir::ParseResult parseFormatString(mlir::OpBuilder &builder, mlir::Location loc, llvm::StringRef formatString, llvm::ArrayRef< mlir::Value > specOperands, mlir::StringAttr &formatStringResult, llvm::SmallVectorImpl< mlir::Value > &operands)
SmallSet< SymbolRefAttr, 4, LayerSetCompare > LayerSet
constexpr bool isValidSrc(Flow flow)
Value getModuleScopedDriver(Value val, bool lookThroughWires, bool lookThroughNodes, bool lookThroughCasts)
Return the value that drives another FIRRTL value within module scope.
std::pair< std::string, bool > getFieldName(const FieldRef &fieldRef, bool nameSafe=false)
Get a string identifier representing the FieldRef.
BaseTy type_dyn_cast(Type type)
bool isConst(Type type)
Returns true if this is a 'const' type whose value is guaranteed to be unchanging at circuit executio...
bool areTypesConstCastable(FIRRTLType destType, FIRRTLType srcType, bool srcOuterTypeIsConst=false)
Returns whether the srcType can be const-casted to the destType.
bool isExpression(Operation *op)
Return true if the specified operation is a firrtl expression.
DeclKind getDeclarationKind(Value val)
std::optional< int64_t > getBitWidth(FIRRTLBaseType type, bool ignoreFlip=false)
::mlir::Type getFinalTypeByFieldID(Type type, uint64_t fieldID)
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
int64_t getBitWidth(mlir::Type type)
Return the hardware bit width of a type.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
void elideImplicitSSAName(OpAsmPrinter &printer, Operation *op, DictionaryAttr attrs, SmallVectorImpl< StringRef > &elides)
Check if the name attribute in attrs matches the SSA name of the operation's first result.
bool isAncestorOfValueOwner(Operation *op, Value value)
Return true if a Value is created "underneath" an operation.
bool inferImplicitSSAName(OpAsmParser &parser, NamedAttrList &attrs)
Ensure that attrs contains a name attribute by inferring its value from the SSA name of the operation...
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn
StringAttr getFirMemoryName() const
Compares two SymbolRefAttr lexicographically, returning true if LHS should be ordered before RHS.
This class represents the namespace in which InnerRef's can be resolved.
InnerSymTarget lookup(hw::InnerRefAttr inner) const
Resolve the InnerRef to its target within this namespace, returning empty target if no such name exis...
This holds the name, type, direction of a module's ports.