28#include "mlir/IR/BuiltinTypes.h"
29#include "mlir/IR/Diagnostics.h"
30#include "mlir/IR/DialectImplementation.h"
31#include "mlir/IR/PatternMatch.h"
32#include "mlir/IR/SymbolTable.h"
33#include "mlir/Interfaces/FunctionImplementation.h"
34#include "llvm/ADT/BitVector.h"
35#include "llvm/ADT/DenseMap.h"
36#include "llvm/ADT/DenseSet.h"
37#include "llvm/ADT/STLExtras.h"
38#include "llvm/ADT/SmallSet.h"
39#include "llvm/ADT/StringExtras.h"
40#include "llvm/ADT/TypeSwitch.h"
41#include "llvm/Support/Casting.h"
42#include "llvm/Support/FormatVariadic.h"
44using llvm::SmallDenseSet;
45using mlir::RegionRange;
47using namespace firrtl;
48using namespace chirrtl;
56 p <<
" of " << domainKind;
61 FlatSymbolRefAttr &domainKind) {
62 StringAttr domainName;
63 if (parser.parseKeyword(
"of") || parser.parseSymbolName(domainName))
65 domainKind = FlatSymbolRefAttr::get(domainName);
74 const llvm::BitVector &indicesToDrop) {
77 int lastIndex = indicesToDrop.find_last();
79 assert((
size_t)lastIndex < input.size() &&
"index out of range");
89 size_t lastCopied = 0;
90 SmallVector<T> result;
91 result.reserve(input.size() - indicesToDrop.count());
93 for (
unsigned indexToDrop : indicesToDrop.set_bits()) {
95 if (indexToDrop > lastCopied) {
96 result.append(input.begin() + lastCopied, input.begin() + indexToDrop);
97 lastCopied = indexToDrop;
104 if (lastCopied < input.size())
105 result.append(input.begin() + lastCopied, input.end());
111template <
typename RetTy =
FIRRTLType,
typename... Args>
113 const Twine &message, Args &&...args) {
115 (mlir::emitError(*loc, message) << ... << std::forward<Args>(args));
121 while (Operation *op = val.getDefiningOp()) {
123 TypeSwitch<Operation *, std::optional<bool>>(op)
124 .Case<SubfieldOp, SubindexOp, SubaccessOp>([&val](
auto op) {
128 .Case<RegOp, RegResetOp, WireOp>([](
auto) {
return true; })
129 .Default([](
auto) {
return false; });
136SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
137MemOp::computeDataFlow() {
140 if (getReadLatency() > 0)
142 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
144 for (
auto memPort : getResults())
145 if (auto type =
type_dyn_cast<BundleType>(memPort.getType())) {
146 auto enableFieldId = type.getFieldID((
unsigned)ReadPortSubfield::en);
147 auto addressFieldId = type.getFieldID((
unsigned)ReadPortSubfield::addr);
148 auto dataFieldId = type.getFieldID((
unsigned)ReadPortSubfield::data);
150 FieldRef(memPort,
static_cast<unsigned>(dataFieldId)),
151 FieldRef(memPort,
static_cast<unsigned>(enableFieldId)));
153 FieldRef(memPort,
static_cast<unsigned>(dataFieldId)),
154 FieldRef(memPort,
static_cast<unsigned>(addressFieldId)));
161 constexpr unsigned int addr = 1 << 0;
162 constexpr unsigned int en = 1 << 1;
163 constexpr unsigned int clk = 1 << 2;
164 constexpr unsigned int data = 1 << 3;
165 constexpr unsigned int mask = 1 << 4;
166 constexpr unsigned int rdata = 1 << 5;
167 constexpr unsigned int wdata = 1 << 6;
168 constexpr unsigned int wmask = 1 << 7;
169 constexpr unsigned int wmode = 1 << 8;
170 constexpr unsigned int def = 1 << 9;
172 auto portType = type_dyn_cast<BundleType>(type);
174 return MemOp::PortKind::Debug;
177 for (
auto elem : portType.getElements()) {
178 fields |= llvm::StringSwitch<unsigned>(elem.name.getValue())
184 .Case(
"rdata",
rdata)
185 .Case(
"wdata",
wdata)
186 .Case(
"wmask",
wmask)
187 .Case(
"wmode",
wmode)
191 return MemOp::PortKind::Read;
193 return MemOp::PortKind::Write;
195 return MemOp::PortKind::ReadWrite;
196 return MemOp::PortKind::Debug;
211 llvm_unreachable(
"Unsupported Flow type.");
219 return "source flow";
223 return "duplex flow";
226 llvm_unreachable(
"Unsupported Flow type.");
231 if (
auto blockArg = dyn_cast<BlockArgument>(val)) {
232 auto *op = val.getParentBlock()->getParentOp();
233 if (
auto moduleLike = dyn_cast<FModuleLike>(op)) {
234 auto direction = moduleLike.getPortDirection(blockArg.getArgNumber());
235 if (direction == Direction::Out)
238 return accumulatedFlow;
241 Operation *op = val.getDefiningOp();
243 return TypeSwitch<Operation *, Flow>(op)
244 .Case<SubfieldOp, OpenSubfieldOp>([&](
auto op) {
245 return foldFlow(op.getInput(), op.isFieldFlipped()
249 .Case<SubindexOp, SubaccessOp, OpenSubindexOp, RefSubOp>(
250 [&](
auto op) {
return foldFlow(op.getInput(), accumulatedFlow); })
252 .Case<RegOp, RegResetOp, WireOp, MemoryPortOp>(
253 [](
auto) {
return Flow::Duplex; })
254 .Case<InstanceOp, InstanceChoiceOp>([&](
auto inst) {
255 auto resultNo = cast<OpResult>(val).getResultNumber();
256 if (inst.getPortDirection(resultNo) == Direction::Out)
257 return accumulatedFlow;
260 .Case<MemOp>([&](
auto op) {
262 if (type_isa<RefType>(val.getType()))
266 .Case<ObjectSubfieldOp>([&](ObjectSubfieldOp op) {
267 auto input = op.getInput();
268 auto *inputOp = input.getDefiningOp();
271 if (
auto objectOp = dyn_cast_or_null<ObjectOp>(inputOp)) {
272 auto classType = input.getType();
273 auto direction = classType.getElement(op.getIndex()).direction;
274 if (direction == Direction::In)
285 auto classType = input.getType();
286 auto direction = classType.getElement(op.getIndex()).direction;
287 if (direction == Direction::In)
290 op = dyn_cast_or_null<ObjectSubfieldOp>(inputOp);
292 input = op.getInput();
293 inputOp = input.getDefiningOp();
297 return accumulatedFlow;
301 .Default([&](
auto) {
return accumulatedFlow; });
307 Operation *op = val.getDefiningOp();
309 return DeclKind::Port;
311 return TypeSwitch<Operation *, DeclKind>(op)
312 .Case<InstanceOp>([](
auto) {
return DeclKind::Instance; })
313 .Case<SubfieldOp, SubindexOp, SubaccessOp, OpenSubfieldOp, OpenSubindexOp,
315 .Default([](
auto) {
return DeclKind::Other; });
319 if (
auto module = dyn_cast<FModuleLike>(op))
320 return module.getNumPorts();
321 return op->getNumResults();
335 if (
auto *op = value.getDefiningOp())
337 auto arg = dyn_cast<BlockArgument>(value);
338 auto module = dyn_cast<FModuleOp>(arg.getOwner()->getParentOp());
341 return (module.getPortSymbolAttr(arg.getArgNumber())) ||
348 OpAsmSetValueNameFn setNameFn) {
352 auto *block = ®ion.front();
355 auto argAttr = parentOp->getAttrOfType<ArrayAttr>(
"portNames");
357 if (!argAttr || argAttr.size() != block->getNumArguments())
360 for (
size_t i = 0, e = block->getNumArguments(); i != e; ++i) {
361 auto str = cast<StringAttr>(argAttr[i]).getValue();
363 setNameFn(block->getArgument(i), str);
369 firrtl::NameKindEnumAttr &result);
380 for (; op !=
nullptr; op = op->getParentOp()) {
381 if (
auto module = dyn_cast<FModuleLike>(op)) {
382 auto layers =
module.getLayersAttr().getAsRange<SymbolRefAttr>();
383 result.insert(layers.begin(), layers.end());
386 if (
auto layerblock = dyn_cast<LayerBlockOp>(op)) {
387 result.insert(layerblock.getLayerName());
405 if (
auto type = dyn_cast<RefType>(value.getType()))
406 if (
auto layer = type.getLayer())
407 result.insert(type.getLayer());
416 mlir::SymbolRefAttr dstLayer) {
426 if (srcLayer.getRootReference() != dstLayer.getRootReference())
429 auto srcNames = srcLayer.getNestedReferences();
430 auto dstNames = dstLayer.getNestedReferences();
431 if (dstNames.size() < srcNames.size())
434 return llvm::all_of(llvm::zip_first(srcNames, dstNames),
435 [](
auto x) {
return std::get<0>(x) == std::get<1>(x); });
442 if (dstLayers.contains(srcLayer))
447 return any_of(dstLayers, [=](SymbolRefAttr dstLayer) {
456 SmallVectorImpl<SymbolRefAttr> &missing) {
457 for (
auto srcLayer : src)
459 missing.push_back(srcLayer);
462 return missing.empty();
467 const Twine &errorMsg,
468 const Twine ¬eMsg = Twine(
"missing layer requirements")) {
469 SmallVector<SymbolRefAttr> missing;
472 interleaveComma(missing, op->emitOpError(errorMsg).attachNote()
481void CircuitOp::build(OpBuilder &builder, OperationState &result,
482 StringAttr name, ArrayAttr annotations) {
484 result.getOrAddProperties<Properties>().setName(name);
487 annotations = builder.getArrayAttr({});
488 result.getOrAddProperties<Properties>().setAnnotations(annotations);
491 Region *bodyRegion = result.addRegion();
493 bodyRegion->push_back(body);
497 NamedAttrList &resultAttrs) {
498 auto result = parser.parseOptionalAttrDictWithKeyword(resultAttrs);
499 if (!resultAttrs.get(
"annotations"))
500 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
506 DictionaryAttr attr) {
508 SmallVector<StringRef> elidedAttrs = {
"name"};
510 auto annotationsAttr = op->getAttrOfType<ArrayAttr>(
"annotations");
511 if (annotationsAttr.empty())
512 elidedAttrs.push_back(
"annotations");
514 p.printOptionalAttrDictWithKeyword(op->getAttrs(), elidedAttrs);
517LogicalResult CircuitOp::verifyRegions() {
522 emitOpError(
"must have a non-empty name");
526 mlir::SymbolTable symtbl(getOperation());
528 auto *mainModule = symtbl.lookup(
main);
530 return emitOpError().append(
531 "does not contain module with same name as circuit");
532 if (!isa<FModuleLike>(mainModule))
533 return mainModule->emitError(
534 "entity with name of circuit must be a module");
535 if (symtbl.getSymbolVisibility(mainModule) !=
536 mlir::SymbolTable::Visibility::Public)
537 return mainModule->emitError(
"main module must be public");
542 llvm::DenseMap<Attribute, FExtModuleOp> defnameMap;
544 auto verifyExtModule = [&](FExtModuleOp extModule) -> LogicalResult {
548 auto defname = extModule.getDefnameAttr();
554 if (
auto collidingModule = symtbl.lookup<FModuleOp>(defname.getValue()))
555 return extModule.emitOpError()
556 .append(
"attribute 'defname' with value ", defname,
557 " conflicts with the name of another module in the circuit")
558 .attachNote(collidingModule.getLoc())
559 .append(
"previous module declared here");
567 FExtModuleOp collidingExtModule;
568 if (
auto &value = defnameMap[defname]) {
569 collidingExtModule = value;
570 if (!value.getParameters().empty() && extModule.getParameters().empty())
580 SmallVector<PortInfo> ports = extModule.getPorts();
581 SmallVector<PortInfo> collidingPorts = collidingExtModule.getPorts();
583 if (ports.size() != collidingPorts.size())
584 return extModule.emitOpError()
585 .append(
"with 'defname' attribute ", defname,
" has ", ports.size(),
586 " ports which is different from a previously defined "
587 "extmodule with the same 'defname' which has ",
588 collidingPorts.size(),
" ports")
589 .attachNote(collidingExtModule.getLoc())
590 .append(
"previous extmodule definition occurred here");
596 for (
auto p :
llvm::zip(ports, collidingPorts)) {
597 StringAttr aName = std::get<0>(p).name, bName = std::get<1>(p).name;
598 Type aType = std::get<0>(p).type, bType = std::get<1>(p).type;
601 return extModule.emitOpError()
602 .append(
"with 'defname' attribute ", defname,
603 " has a port with name ", aName,
604 " which does not match the name of the port in the same "
605 "position of a previously defined extmodule with the same "
606 "'defname', expected port to have name ",
608 .attachNote(collidingExtModule.getLoc())
609 .append(
"previous extmodule definition occurred here");
611 if (!extModule.getParameters().empty() ||
612 !collidingExtModule.getParameters().empty()) {
614 if (
auto base = type_dyn_cast<FIRRTLBaseType>(aType))
615 aType = base.getWidthlessType();
616 if (
auto base = type_dyn_cast<FIRRTLBaseType>(bType))
617 bType = base.getWidthlessType();
620 return extModule.emitOpError()
621 .append(
"with 'defname' attribute ", defname,
622 " has a port with name ", aName,
623 " which has a different type ", aType,
624 " which does not match the type of the port in the same "
625 "position of a previously defined extmodule with the same "
626 "'defname', expected port to have type ",
628 .attachNote(collidingExtModule.getLoc())
629 .append(
"previous extmodule definition occurred here");
634 SmallVector<FModuleOp, 1> dutModules;
637 if (
auto moduleOp = dyn_cast<FModuleOp>(op)) {
639 dutModules.push_back(moduleOp);
644 if (
auto extModule = dyn_cast<FExtModuleOp>(op)) {
645 if (verifyExtModule(extModule).failed())
651 if (dutModules.size() > 1) {
652 auto diag = dutModules[0]->emitOpError()
653 <<
"is annotated as the design-under-test (DUT), but other "
654 "modules are also annotated";
655 for (
auto moduleOp : ArrayRef(dutModules).drop_front())
656 diag.attachNote(moduleOp.
getLoc()) <<
"is also annotated as the DUT";
663Block *CircuitOp::getBodyBlock() {
return &getBody().front(); }
670 SmallVector<PortInfo> results;
671 ArrayRef<Attribute> domains =
module.getDomainInfo();
672 for (
unsigned i = 0, e = module.getNumPorts(); i < e; ++i) {
673 results.push_back({
module.getPortNameAttr(i), module.getPortType(i),
674 module.getPortDirection(i), module.getPortSymbolAttr(i),
675 module.getPortLocation(i),
676 AnnotationSet::forPort(module, i),
677 domains.empty() ? Attribute{} : domains[i]});
682SmallVector<PortInfo> FModuleOp::getPorts() { return ::getPortImpl(*
this); }
684SmallVector<PortInfo> FExtModuleOp::getPorts() { return ::getPortImpl(*
this); }
686SmallVector<PortInfo> FIntModuleOp::getPorts() { return ::getPortImpl(*
this); }
688SmallVector<PortInfo> FMemModuleOp::getPorts() { return ::getPortImpl(*
this); }
691 if (dir == Direction::In)
692 return hw::ModulePort::Direction::Input;
693 if (dir == Direction::Out)
694 return hw::ModulePort::Direction::Output;
695 assert(0 &&
"invalid direction");
700 SmallVector<hw::PortInfo> results;
701 auto aname = StringAttr::get(module.getContext(),
702 hw::HWModuleLike::getPortSymbolAttrName());
703 auto emptyDict = DictionaryAttr::get(module.getContext());
704 for (
unsigned i = 0, e =
getNumPorts(module); i < e; ++i) {
705 auto sym =
module.getPortSymbolAttr(i);
707 {{
module.getPortNameAttr(i), module.getPortType(i),
708 dirFtoH(module.getPortDirection(i))},
710 sym ? DictionaryAttr::get(
712 ArrayRef<mlir::NamedAttribute>{NamedAttribute{aname, sym}})
714 module.getPortLocation(i)});
719SmallVector<::circt::hw::PortInfo> FModuleOp::getPortList() {
720 return ::getPortListImpl(*
this);
723SmallVector<::circt::hw::PortInfo> FExtModuleOp::getPortList() {
724 return ::getPortListImpl(*
this);
727SmallVector<::circt::hw::PortInfo> FIntModuleOp::getPortList() {
728 return ::getPortListImpl(*
this);
731SmallVector<::circt::hw::PortInfo> FMemModuleOp::getPortList() {
732 return ::getPortListImpl(*
this);
736 auto sym =
module.getPortSymbolAttr(idx);
737 auto attrs = sym ? DictionaryAttr::getWithSorted(
739 ArrayRef(mlir::NamedAttribute(
740 hw::HWModuleLike::getPortSymbolAttrName(), sym)))
741 : DictionaryAttr::get(module.getContext());
742 return {{
module.getPortNameAttr(idx), module.getPortType(idx),
743 dirFtoH(module.getPortDirection(idx))},
746 module.getPortLocation(idx)};
750 return ::getPortImpl(*
this, idx);
754 return ::getPortImpl(*
this, idx);
758 return ::getPortImpl(*
this, idx);
762 return ::getPortImpl(*
this, idx);
766BlockArgument FModuleOp::getArgument(
size_t portNumber) {
773 Attribute domainInfoAttr,
774 ArrayRef<unsigned> indexMap) {
776 auto di = dyn_cast_or_null<ArrayAttr>(domainInfoAttr);
777 if (!di || di.empty())
778 return domainInfoAttr;
781 SmallVector<Attribute> domainInfo;
782 for (
auto attr : di) {
783 auto oldIdx = cast<IntegerAttr>(attr).getUInt();
784 auto newIdx = indexMap[oldIdx];
785 if (oldIdx == newIdx)
786 domainInfo.push_back(attr);
788 domainInfo.push_back(IntegerAttr::get(
789 IntegerType::get(
context, 32, IntegerType::Unsigned), newIdx));
791 return ArrayAttr::get(
context, domainInfo);
798 ArrayRef<std::pair<unsigned, PortInfo>> ports) {
801 unsigned oldNumArgs = op.getNumPorts();
802 unsigned newNumArgs = oldNumArgs + ports.size();
805 SmallVector<unsigned> indexMap(oldNumArgs);
807 for (
size_t i = 0; i < oldNumArgs; ++i) {
808 while (inserted < ports.size() && ports[inserted].first == i)
810 indexMap[i] = i + inserted;
814 auto existingDirections = op.getPortDirectionsAttr();
815 ArrayRef<Attribute> existingNames = op.getPortNames();
816 ArrayRef<Attribute> existingTypes = op.getPortTypes();
817 ArrayRef<Attribute> existingLocs = op.getPortLocations();
818 assert(existingDirections.size() == oldNumArgs);
819 assert(existingNames.size() == oldNumArgs);
820 assert(existingTypes.size() == oldNumArgs);
821 assert(existingLocs.size() == oldNumArgs);
823 SmallVector<bool> newDirections;
824 SmallVector<Attribute> newNames, newTypes, newDomains, newAnnos, newSyms,
826 newDirections.reserve(newNumArgs);
827 newNames.reserve(newNumArgs);
828 newTypes.reserve(newNumArgs);
829 newDomains.reserve(newNumArgs);
830 newAnnos.reserve(newNumArgs);
831 newSyms.reserve(newNumArgs);
832 newLocs.reserve(newNumArgs);
834 auto emptyArray = ArrayAttr::get(op.getContext(), {});
837 auto migrateOldPorts = [&](
unsigned untilOldIdx) {
838 while (oldIdx < oldNumArgs && oldIdx < untilOldIdx) {
839 newDirections.push_back(existingDirections[oldIdx]);
840 newNames.push_back(existingNames[oldIdx]);
841 newTypes.push_back(existingTypes[oldIdx]);
843 op.getContext(), op.getDomainInfoAttrForPort(oldIdx), indexMap));
844 newAnnos.push_back(op.getAnnotationsAttrForPort(oldIdx));
845 newSyms.push_back(op.getPortSymbolAttr(oldIdx));
846 newLocs.push_back(existingLocs[oldIdx]);
851 for (
auto [idx, port] : ports) {
852 migrateOldPorts(idx);
854 newNames.push_back(port.name);
855 newTypes.push_back(TypeAttr::get(port.type));
858 port.domains ? port.domains : ArrayAttr::get(op.getContext(), {}),
860 auto annos = port.annotations.getArrayAttr();
861 newAnnos.push_back(annos ? annos : emptyArray);
862 newSyms.push_back(port.sym);
863 newLocs.push_back(port.loc);
866 migrateOldPorts(oldNumArgs);
870 if (llvm::all_of(newAnnos, [](Attribute attr) {
871 return cast<ArrayAttr>(attr).empty();
877 if (llvm::all_of(newDomains, [](Attribute attr) {
880 if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr))
881 return arrayAttr.empty();
887 op->setAttr(
"portDirections",
889 op->setAttr(
"portNames", ArrayAttr::get(op.getContext(), newNames));
890 op->setAttr(
"portTypes", ArrayAttr::get(op.getContext(), newTypes));
891 op->setAttr(
"domainInfo", ArrayAttr::get(op.getContext(), newDomains));
892 op->setAttr(
"portAnnotations", ArrayAttr::get(op.getContext(), newAnnos));
893 FModuleLike::fixupPortSymsArray(newSyms, op.getContext());
894 op.setPortSymbols(newSyms);
895 op->setAttr(
"portLocations", ArrayAttr::get(op.getContext(), newLocs));
906 ArrayAttr domainInfoAttr,
907 const llvm::BitVector &portIndices,
908 bool supportsEmptyAttr) {
909 if (supportsEmptyAttr && domainInfoAttr.empty())
910 return domainInfoAttr;
913 SmallVector<unsigned> indexMap(portIndices.size());
915 for (
size_t i = 0, e = portIndices.size(); i != e; ++i) {
916 indexMap[i] = i - deleted;
923 auto getEmpty = [&]() {
925 eEmpty = ArrayAttr::get(
context, {});
930 SmallVector<Attribute> newDomainInfo;
931 newDomainInfo.reserve(portIndices.size() - portIndices.count());
932 for (
size_t i = 0, e = portIndices.size(); i != e; ++i) {
934 if (portIndices.test(i))
937 if (domainInfoAttr.empty()) {
938 newDomainInfo.push_back(getEmpty());
941 auto attr = domainInfoAttr[i];
943 auto domains = dyn_cast<ArrayAttr>(attr);
944 if (!domains || domains.empty()) {
945 newDomainInfo.push_back(attr);
949 SmallVector<Attribute> newDomains;
950 for (
auto domain : domains) {
952 auto oldIdx = cast<IntegerAttr>(domain).getUInt();
953 if (portIndices.test(oldIdx))
956 auto newIdx = indexMap[oldIdx];
957 if (oldIdx == newIdx) {
958 newDomains.push_back(domain);
962 newDomains.push_back(IntegerAttr::get(
963 IntegerType::get(
context, 32, IntegerType::Unsigned), newIdx));
965 newDomainInfo.push_back(ArrayAttr::get(
context, newDomains));
968 return ArrayAttr::get(
context, newDomainInfo);
972static void erasePorts(FModuleLike op,
const llvm::BitVector &portIndices) {
973 if (portIndices.none())
977 ArrayRef<bool> portDirections = op.getPortDirectionsAttr().asArrayRef();
978 ArrayRef<Attribute> portNames = op.getPortNames();
979 ArrayRef<Attribute> portTypes = op.getPortTypes();
980 ArrayRef<Attribute> portAnnos = op.getPortAnnotations();
981 ArrayRef<Attribute> portSyms = op.getPortSymbols();
982 ArrayRef<Attribute> portLocs = op.getPortLocations();
983 ArrayRef<Attribute> portDomains = op.getDomainInfo();
984 auto numPorts = op.getNumPorts();
986 assert(portDirections.size() == numPorts);
987 assert(portNames.size() == numPorts);
988 assert(portAnnos.size() == numPorts || portAnnos.empty());
989 assert(portTypes.size() == numPorts);
990 assert(portSyms.size() == numPorts || portSyms.empty());
991 assert(portLocs.size() == numPorts);
992 assert(portDomains.size() == numPorts || portDomains.empty());
994 SmallVector<bool> newPortDirections =
995 removeElementsAtIndices<bool>(portDirections, portIndices);
996 SmallVector<Attribute> newPortNames, newPortTypes, newPortAnnos, newPortSyms,
1004 op->setAttr(
"portDirections",
1006 op->setAttr(
"portNames", ArrayAttr::get(op.getContext(), newPortNames));
1007 op->setAttr(
"portAnnotations", ArrayAttr::get(op.getContext(), newPortAnnos));
1008 op->setAttr(
"portTypes", ArrayAttr::get(op.getContext(), newPortTypes));
1009 FModuleLike::fixupPortSymsArray(newPortSyms, op.getContext());
1010 op->setAttr(
"portSymbols", ArrayAttr::get(op.getContext(), newPortSyms));
1011 op->setAttr(
"portLocations", ArrayAttr::get(op.getContext(), newPortLocs));
1012 op->setAttr(
"domainInfo",
1014 portIndices,
true));
1017void FExtModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1018 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1021void FIntModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1022 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1025void FMemModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1026 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1029void FModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1030 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1037void FModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1038 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1042 for (
size_t i = 0, e = ports.size(); i < e; ++i) {
1045 auto &[index, port] = ports[i];
1046 body->insertArgument(index + i, port.type, port.loc);
1050void FExtModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1051 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1054void FIntModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1055 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1061void FMemModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1062 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1065template <
typename OpTy>
1067 StringAttr name, ArrayRef<PortInfo> ports) {
1069 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
1070 properties.setSymName(name);
1073 SmallVector<Direction, 4> portDirections;
1074 SmallVector<Attribute, 4> portNames;
1075 SmallVector<Attribute, 4> portTypes;
1076 SmallVector<Attribute, 4> portSyms;
1077 SmallVector<Attribute, 4> portLocs;
1078 SmallVector<Attribute, 4> portDomains;
1079 for (
const auto &port : ports) {
1080 portDirections.push_back(port.direction);
1081 portNames.push_back(port.name);
1082 portTypes.push_back(TypeAttr::get(port.type));
1083 portSyms.push_back(port.sym);
1084 portLocs.push_back(port.loc);
1085 portDomains.push_back(port.domains);
1087 if (llvm::all_of(portDomains, [](Attribute attr) {
1090 if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr))
1091 return arrayAttr.empty();
1094 portDomains.clear();
1096 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1099 properties.setPortDirections(
1101 properties.setPortNames(builder.getArrayAttr(portNames));
1102 properties.setPortTypes(builder.getArrayAttr(portTypes));
1103 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1104 properties.setPortLocations(builder.getArrayAttr(portLocs));
1105 properties.setDomainInfo(builder.getArrayAttr(portDomains));
1110template <
typename OpTy>
1112 StringAttr name, ArrayRef<PortInfo> ports,
1113 ArrayAttr annotations, ArrayAttr layers) {
1114 buildModuleLike<OpTy>(builder, result, name, ports);
1115 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
1118 annotations = builder.getArrayAttr({});
1119 properties.setAnnotations(annotations);
1123 SmallVector<Attribute, 4> portAnnotations;
1124 for (
const auto &port : ports)
1125 portAnnotations.push_back(port.annotations.getArrayAttr());
1126 if (llvm::all_of(portAnnotations, [](Attribute attr) {
1127 return cast<ArrayAttr>(attr).empty();
1129 portAnnotations.clear();
1130 properties.setPortAnnotations(builder.getArrayAttr(portAnnotations));
1134 layers = builder.getArrayAttr({});
1135 properties.setLayers(layers);
1138template <
typename OpTy>
1139static void buildClass(OpBuilder &builder, OperationState &result,
1140 StringAttr name, ArrayRef<PortInfo> ports) {
1141 return buildModuleLike<OpTy>(builder, result, name, ports);
1144void FModuleOp::build(OpBuilder &builder, OperationState &result,
1145 StringAttr name, ConventionAttr convention,
1146 ArrayRef<PortInfo> ports, ArrayAttr annotations,
1148 buildModule<FModuleOp>(builder, result, name, ports, annotations, layers);
1149 auto &properties = result.getOrAddProperties<Properties>();
1150 properties.setConvention(convention);
1153 auto *bodyRegion = result.regions[0].get();
1155 bodyRegion->push_back(body);
1158 for (
auto &elt : ports)
1159 body->addArgument(elt.type, elt.loc);
1162void FExtModuleOp::build(OpBuilder &builder, OperationState &result,
1163 StringAttr name, ConventionAttr convention,
1164 ArrayRef<PortInfo> ports, ArrayAttr knownLayers,
1165 StringRef defnameAttr, ArrayAttr annotations,
1166 ArrayAttr parameters, ArrayAttr layers,
1167 ArrayAttr externalRequirements) {
1168 buildModule<FExtModuleOp>(builder, result, name, ports, annotations, layers);
1169 auto &properties = result.getOrAddProperties<Properties>();
1170 properties.setConvention(convention);
1172 knownLayers = builder.getArrayAttr({});
1173 properties.setKnownLayers(knownLayers);
1174 if (!defnameAttr.empty())
1175 properties.setDefname(builder.getStringAttr(defnameAttr));
1177 parameters = builder.getArrayAttr({});
1178 properties.setParameters(parameters);
1179 if (externalRequirements)
1180 properties.setExternalRequirements(externalRequirements);
1183void FIntModuleOp::build(OpBuilder &builder, OperationState &result,
1184 StringAttr name, ArrayRef<PortInfo> ports,
1185 StringRef intrinsicNameStr, ArrayAttr annotations,
1186 ArrayAttr parameters, ArrayAttr layers) {
1187 buildModule<FIntModuleOp>(builder, result, name, ports, annotations, layers);
1188 auto &properties = result.getOrAddProperties<Properties>();
1189 properties.setIntrinsic(builder.getStringAttr(intrinsicNameStr));
1191 parameters = builder.getArrayAttr({});
1192 properties.setParameters(parameters);
1195void FMemModuleOp::build(OpBuilder &builder, OperationState &result,
1196 StringAttr name, ArrayRef<PortInfo> ports,
1197 uint32_t numReadPorts, uint32_t numWritePorts,
1198 uint32_t numReadWritePorts, uint32_t dataWidth,
1199 uint32_t maskBits, uint32_t readLatency,
1200 uint32_t writeLatency, uint64_t depth, RUWBehavior ruw,
1201 ArrayAttr annotations, ArrayAttr layers) {
1202 auto *
context = builder.getContext();
1203 buildModule<FMemModuleOp>(builder, result, name, ports, annotations, layers);
1204 auto ui32Type = IntegerType::get(
context, 32, IntegerType::Unsigned);
1205 auto ui64Type = IntegerType::get(
context, 64, IntegerType::Unsigned);
1206 auto &properties = result.getOrAddProperties<Properties>();
1207 properties.setNumReadPorts(IntegerAttr::get(ui32Type, numReadPorts));
1208 properties.setNumWritePorts(IntegerAttr::get(ui32Type, numWritePorts));
1209 properties.setNumReadWritePorts(
1210 IntegerAttr::get(ui32Type, numReadWritePorts));
1211 properties.setDataWidth(IntegerAttr::get(ui32Type, dataWidth));
1212 properties.setMaskBits(IntegerAttr::get(ui32Type, maskBits));
1213 properties.setReadLatency(IntegerAttr::get(ui32Type, readLatency));
1214 properties.setWriteLatency(IntegerAttr::get(ui32Type, writeLatency));
1215 properties.setDepth(IntegerAttr::get(ui64Type, depth));
1216 properties.setExtraPorts(ArrayAttr::get(
context, {}));
1217 properties.setRuw(RUWBehaviorAttr::get(
context, ruw));
1234 ArrayRef<Attribute> portNames, ArrayRef<Attribute> portTypes,
1235 ArrayRef<Attribute> portAnnotations,
1236 ArrayRef<Attribute> portSyms, ArrayRef<Attribute> portLocs,
1237 ArrayRef<Attribute> domainInfo) {
1240 bool printedNamesDontMatch =
false;
1242 mlir::OpPrintingFlags flags;
1245 DenseMap<unsigned, std::string> ssaNames;
1246 auto getSsaName = [&](
unsigned idx) -> StringRef {
1248 auto itr = ssaNames.find(idx);
1249 if (itr != ssaNames.end())
1250 return itr->getSecond();
1254 SmallString<32> resultNameStr;
1256 llvm::raw_svector_ostream tmpStream(resultNameStr);
1257 p.printOperand(block->getArgument(idx), tmpStream);
1260 auto portName = cast<StringAttr>(portNames[idx]).getValue();
1261 if (tmpStream.str().drop_front() != portName)
1262 printedNamesDontMatch =
true;
1263 return ssaNames.insert({idx, tmpStream.str().str()}).first->getSecond();
1266 auto name = cast<StringAttr>(portNames[idx]).getValue();
1267 return ssaNames.insert({idx, name.str()}).first->getSecond();
1273 for (
unsigned i = 0, e = portTypes.size(); i < e; ++i) {
1282 auto portType = cast<TypeAttr>(portTypes[i]).getValue();
1286 p.printKeywordOrString(getSsaName(i));
1291 p.printType(portType);
1294 if (!portSyms.empty()) {
1295 if (!cast<hw::InnerSymAttr>(portSyms[i]).
empty()) {
1297 cast<hw::InnerSymAttr>(portSyms[i]).print(p);
1302 if (!domainInfo.empty()) {
1303 if (
auto domainKind = dyn_cast<FlatSymbolRefAttr>(domainInfo[i])) {
1306 auto domains = cast<ArrayAttr>(domainInfo[i]);
1307 if (!domains.empty()) {
1309 llvm::interleaveComma(domains, p, [&](Attribute attr) {
1310 p << getSsaName(cast<IntegerAttr>(attr).getUInt());
1319 if (!portAnnotations.empty() &&
1320 !cast<ArrayAttr>(portAnnotations[i]).empty()) {
1322 p.printAttribute(portAnnotations[i]);
1329 if (flags.shouldPrintDebugInfo() && !portLocs.empty())
1330 p.printOptionalLocationSpecifier(cast<LocationAttr>(portLocs[i]));
1334 return printedNamesDontMatch;
1340 OpAsmParser &parser,
bool hasSSAIdentifiers,
bool supportsSymbols,
1341 bool supportsDomains, SmallVectorImpl<OpAsmParser::Argument> &entryArgs,
1342 SmallVectorImpl<Direction> &portDirections,
1343 SmallVectorImpl<Attribute> &portNames,
1344 SmallVectorImpl<Attribute> &portTypes,
1345 SmallVectorImpl<Attribute> &portAnnotations,
1346 SmallVectorImpl<Attribute> &portSyms, SmallVectorImpl<Attribute> &portLocs,
1347 SmallVectorImpl<Attribute> &domains) {
1348 auto *
context = parser.getContext();
1351 DenseMap<Attribute, size_t> domainIndex;
1354 using DomainAndLoc = std::pair<Attribute, llvm::SMLoc>;
1355 DenseMap<size_t, SmallVector<DomainAndLoc>> domainStrings;
1357 auto parseArgument = [&]() -> ParseResult {
1359 if (succeeded(parser.parseOptionalKeyword(
"out")))
1360 portDirections.push_back(Direction::Out);
1361 else if (succeeded(parser.parseKeyword(
"in",
" or 'out'")))
1362 portDirections.push_back(Direction::In);
1369 auto portIdx = portNames.size();
1371 if (hasSSAIdentifiers) {
1372 OpAsmParser::Argument arg;
1373 if (parser.parseArgument(arg))
1375 entryArgs.push_back(arg);
1379 assert(arg.ssaName.name.size() > 1 && arg.ssaName.name[0] ==
'%' &&
1380 "Unknown MLIR name");
1381 if (
isdigit(arg.ssaName.name[1]))
1382 portNames.push_back(StringAttr::get(
context,
""));
1384 portNames.push_back(
1385 StringAttr::get(
context, arg.ssaName.name.drop_front()));
1388 irLoc = arg.ssaName.location;
1392 irLoc = parser.getCurrentLocation();
1393 std::string portName;
1394 if (parser.parseKeywordOrString(&portName))
1396 portNames.push_back(StringAttr::get(
context, portName));
1401 if (parser.parseColonType(portType))
1403 portTypes.push_back(TypeAttr::get(portType));
1404 if (isa<DomainType>(portType))
1405 domainIndex[portNames.back()] = portIdx;
1407 if (hasSSAIdentifiers)
1408 entryArgs.back().type = portType;
1411 if (supportsSymbols) {
1412 hw::InnerSymAttr innerSymAttr;
1413 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
1414 NamedAttrList dummyAttrs;
1415 if (parser.parseCustomAttributeWithFallback(
1416 innerSymAttr, ::mlir::Type{},
1418 return ::mlir::failure();
1421 portSyms.push_back(innerSymAttr);
1429 Attribute domainInfo;
1430 if (supportsDomains) {
1431 if (isa<DomainType>(portType)) {
1432 FlatSymbolRefAttr domainKind;
1435 domainInfo = domainKind;
1436 }
else if (succeeded(parser.parseOptionalKeyword(
"domains"))) {
1437 auto result = parser.parseCommaSeparatedList(
1438 OpAsmParser::Delimiter::Square, [&]() -> ParseResult {
1440 if (hasSSAIdentifiers) {
1441 OpAsmParser::Argument arg;
1442 if (parser.parseArgument(arg))
1445 StringAttr::get(
context, arg.ssaName.name.drop_front());
1447 std::string portName;
1448 if (parser.parseKeywordOrString(&portName))
1450 argName = StringAttr::get(
context, portName);
1452 domainStrings[portIdx].push_back({argName, irLoc});
1459 domains.push_back(domainInfo);
1463 auto parseResult = parser.parseOptionalAttribute(annos);
1464 if (!parseResult.has_value())
1465 annos = parser.getBuilder().getArrayAttr({});
1466 else if (failed(*parseResult))
1468 portAnnotations.push_back(annos);
1471 std::optional<Location> maybeLoc;
1472 if (failed(parser.parseOptionalLocationSpecifier(maybeLoc)))
1474 Location loc = maybeLoc ? *maybeLoc : parser.getEncodedSourceLoc(irLoc);
1475 portLocs.push_back(loc);
1476 if (hasSSAIdentifiers)
1477 entryArgs.back().sourceLoc = loc;
1486 if (failed(parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
1492 for (
auto [portIdx, domainInfo] : llvm::enumerate(domains)) {
1497 SmallVector<Attribute> portDomains;
1498 for (
auto [domainName, loc] : domainStrings[portIdx]) {
1499 auto index = domainIndex.find(domainName);
1500 if (index == domainIndex.end()) {
1501 parser.emitError(loc) <<
"domain name '" << domainName <<
"' not found";
1504 portDomains.push_back(IntegerAttr::get(
1505 IntegerType::get(
context, 32, IntegerType::Unsigned), index->second));
1507 domains[portIdx] = parser.getBuilder().getArrayAttr(portDomains);
1515 ArrayAttr parameters) {
1516 if (!parameters || parameters.empty())
1520 llvm::interleaveComma(parameters, p, [&](Attribute param) {
1521 auto paramAttr = cast<ParamDeclAttr>(param);
1522 p << paramAttr.getName().getValue() <<
": " << paramAttr.getType();
1523 if (
auto value = paramAttr.getValue()) {
1525 p.printAttributeWithoutType(value);
1535 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
1536 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
1537 p << visibility.getValue() <<
' ';
1540 p.printSymbolName(op.getModuleName());
1547 Block *body =
nullptr;
1548 if (!op->getRegion(0).empty())
1549 body = &op->getRegion(0).front();
1552 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
1553 op.getPortAnnotations(), op.getPortSymbols(), op.getPortLocations(),
1554 op.getDomainInfo());
1556 SmallVector<StringRef, 13> omittedAttrs = {
1557 "sym_name",
"portDirections",
"portTypes",
1558 "portAnnotations",
"portSymbols",
"portLocations",
1559 "parameters", visibilityAttrName,
"domainInfo"};
1561 if (op.getConvention() == Convention::Internal)
1562 omittedAttrs.push_back(
"convention");
1566 if (!needPortNamesAttr)
1567 omittedAttrs.push_back(
"portNames");
1570 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
1571 omittedAttrs.push_back(
"annotations");
1574 if (
auto knownLayers = op->getAttrOfType<ArrayAttr>(
"knownLayers"))
1575 if (knownLayers.empty())
1576 omittedAttrs.push_back(
"knownLayers");
1579 if (
auto layers = op->getAttrOfType<ArrayAttr>(
"layers"))
1581 omittedAttrs.push_back(
"layers");
1584 if (
auto extReqs = op->getAttrOfType<ArrayAttr>(
"externalRequirements"))
1585 if (extReqs.empty())
1586 omittedAttrs.push_back(
"externalRequirements");
1588 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
1597void FModuleOp::print(OpAsmPrinter &p) {
1603 Region &fbody = getBody();
1604 if (!fbody.empty()) {
1606 p.printRegion(fbody,
false,
1618 SmallVectorImpl<Attribute> ¶meters) {
1620 return parser.parseCommaSeparatedList(
1621 OpAsmParser::Delimiter::OptionalLessGreater, [&]() {
1626 if (parser.parseKeywordOrString(&name) || parser.parseColonType(type))
1630 if (succeeded(parser.parseOptionalEqual())) {
1631 if (parser.parseAttribute(value, type))
1635 auto &builder = parser.getBuilder();
1636 parameters.push_back(ParamDeclAttr::get(
1637 builder.getContext(), builder.getStringAttr(name), type, value));
1644 ArrayAttr ¶meters) {
1645 SmallVector<Attribute> parseParameters;
1649 parameters = ArrayAttr::get(parser.getContext(), parseParameters);
1654template <
typename Properties,
typename =
void>
1657template <
typename Properties>
1659 Properties, std::void_t<decltype(std::declval<Properties>().parameters)>>
1660 : std::true_type {};
1662template <
typename OpTy>
1664 OperationState &result,
1665 bool hasSSAIdentifiers) {
1666 auto *
context = result.getContext();
1667 auto &builder = parser.getBuilder();
1668 using Properties =
typename OpTy::Properties;
1669 auto &properties = result.getOrAddProperties<Properties>();
1673 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
1676 StringAttr nameAttr;
1677 if (parser.parseSymbolName(nameAttr))
1679 properties.setSymName(nameAttr);
1683 SmallVector<Attribute, 4> parameters;
1686 properties.setParameters(builder.getArrayAttr(parameters));
1690 SmallVector<OpAsmParser::Argument> entryArgs;
1691 SmallVector<Direction, 4> portDirections;
1692 SmallVector<Attribute, 4> portNames;
1693 SmallVector<Attribute, 4> portTypes;
1694 SmallVector<Attribute, 4> portAnnotations;
1695 SmallVector<Attribute, 4> portSyms;
1696 SmallVector<Attribute, 4> portLocs;
1697 SmallVector<Attribute, 4> domains;
1699 true, entryArgs, portDirections,
1700 portNames, portTypes, portAnnotations, portSyms,
1705 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
1708 assert(portNames.size() == portTypes.size());
1714 properties.setPortDirections(
1718 properties.setPortNames(builder.getArrayAttr(portNames));
1721 properties.setPortTypes(ArrayAttr::get(
context, portTypes));
1725 if (llvm::any_of(portAnnotations, [&](Attribute anno) {
1726 return !cast<ArrayAttr>(anno).empty();
1728 properties.setPortAnnotations(ArrayAttr::get(
context, portAnnotations));
1730 properties.setPortAnnotations(builder.getArrayAttr({}));
1733 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1734 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1737 properties.setPortLocations(ArrayAttr::get(
context, portLocs));
1740 properties.setAnnotations(builder.getArrayAttr({}));
1743 if (llvm::all_of(domains, [&](Attribute attr) {
1744 auto arrayAttr = dyn_cast<ArrayAttr>(attr);
1745 return arrayAttr && arrayAttr.empty();
1747 properties.setDomainInfo(ArrayAttr::get(
context, {}));
1749 properties.setDomainInfo(ArrayAttr::get(
context, domains));
1752 auto *body = result.addRegion();
1754 if (hasSSAIdentifiers) {
1755 if (parser.parseRegion(*body, entryArgs))
1758 body->push_back(
new Block());
1763ParseResult FModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1764 if (parseFModuleLikeOp<FModuleOp>(parser, result,
1767 auto &properties = result.getOrAddProperties<Properties>();
1768 properties.setConvention(
1769 ConventionAttr::get(result.getContext(), Convention::Internal));
1770 properties.setLayers(ArrayAttr::get(parser.getContext(), {}));
1774ParseResult FExtModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1775 if (parseFModuleLikeOp<FExtModuleOp>(parser, result,
1778 auto &properties = result.getOrAddProperties<Properties>();
1779 properties.setConvention(
1780 ConventionAttr::get(result.getContext(), Convention::Internal));
1781 properties.setKnownLayers(ArrayAttr::get(result.getContext(), {}));
1785ParseResult FIntModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1786 return parseFModuleLikeOp<FIntModuleOp>(parser, result,
1790ParseResult FMemModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1791 return parseFModuleLikeOp<FMemModuleOp>(parser, result,
1795LogicalResult FModuleOp::verify() {
1798 auto portTypes = getPortTypes();
1799 auto portLocs = getPortLocations();
1800 auto numPorts = portTypes.size();
1803 if (body->getNumArguments() != numPorts)
1804 return emitOpError(
"entry block must have ")
1805 << numPorts <<
" arguments to match module signature";
1808 for (
auto [arg, type, loc] : zip(body->getArguments(), portTypes, portLocs)) {
1809 if (arg.getType() != cast<TypeAttr>(type).getValue())
1810 return emitOpError(
"block argument types should match signature types");
1811 if (arg.getLoc() != cast<LocationAttr>(loc))
1813 "block argument locations should match signature locations");
1819LogicalResult FExtModuleOp::verify() {
1820 auto params = getParameters();
1822 auto checkParmValue = [&](Attribute elt) ->
bool {
1823 auto param = cast<ParamDeclAttr>(elt);
1824 auto value = param.getValue();
1825 if (isa<IntegerAttr, StringAttr, FloatAttr, hw::ParamVerbatimAttr>(value))
1827 emitError() <<
"has unknown extmodule parameter value '"
1828 << param.getName().getValue() <<
"' = " << value;
1832 if (!llvm::all_of(params, checkParmValue))
1837 known.insert_range(getKnownLayersAttr().getAsRange<SymbolRefAttr>());
1840 referenced.insert_range(getLayersAttr().getAsRange<SymbolRefAttr>());
1841 for (
auto attr : getPortTypes()) {
1842 auto type = cast<TypeAttr>(attr).getValue();
1843 if (
auto refType = type_dyn_cast<RefType>(type))
1844 if (
auto layer = refType.getLayer())
1845 referenced.insert(layer);
1849 "references unknown layers",
"unknown layers");
1852LogicalResult FIntModuleOp::verify() {
1853 auto params = getParameters();
1857 auto checkParmValue = [&](Attribute elt) ->
bool {
1858 auto param = cast<ParamDeclAttr>(elt);
1859 auto value = param.getValue();
1860 if (isa<IntegerAttr, StringAttr, FloatAttr>(value))
1862 emitError() <<
"has unknown intmodule parameter value '"
1863 << param.getName().getValue() <<
"' = " << value;
1867 if (!llvm::all_of(params, checkParmValue))
1874 CircuitOp circuitOp,
1875 SymbolTableCollection &symbolTable,
1877 auto layer = refType.getLayer();
1880 auto *layerOp = symbolTable.lookupSymbolIn(circuitOp, layer);
1882 return emitError(loc) << start <<
" associated with layer '" << layer
1883 <<
"', but this layer was not defined";
1884 if (!isa<LayerOp>(layerOp)) {
1885 auto diag = emitError(loc)
1886 << start <<
" associated with layer '" << layer
1887 <<
"', but symbol '" << layer <<
"' does not refer to a '"
1888 << LayerOp::getOperationName() <<
"' op";
1889 return diag.attachNote(layerOp->getLoc()) <<
"symbol refers to this op";
1895 SymbolTableCollection &symbolTable) {
1897 auto circuitOp =
module->getParentOfType<CircuitOp>();
1898 for (
size_t i = 0, e = module.getNumPorts(); i < e; ++i) {
1899 auto type =
module.getPortType(i);
1901 if (
auto refType = type_dyn_cast<RefType>(type)) {
1903 refType, module.getPortLocation(i), circuitOp, symbolTable,
1904 Twine(
"probe port '") + module.getPortName(i) +
"' is")))
1909 if (
auto classType = dyn_cast<ClassType>(type)) {
1910 auto className = classType.getNameAttr();
1911 auto classOp = dyn_cast_or_null<ClassLike>(
1912 symbolTable.lookupSymbolIn(circuitOp, className));
1914 return module.emitOpError() << "references unknown class " << className;
1917 if (failed(classOp.verifyType(classType,
1918 [&]() { return module.emitOpError(); })))
1923 if (isa<DomainType>(type)) {
1924 auto domainInfo =
module.getDomainInfoAttrForPort(i);
1925 if (
auto kind = dyn_cast<FlatSymbolRefAttr>(domainInfo))
1926 if (!dyn_cast_or_null<DomainOp>(
1927 symbolTable.lookupSymbolIn(circuitOp, kind)))
1928 return mlir::emitError(module.getPortLocation(i))
1929 <<
"domain port '" <<
module.getPortName(i)
1930 << "' has undefined domain kind '" << kind.getValue() << "'";
1937LogicalResult FModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1941 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
1942 for (
auto layer : getLayers()) {
1943 if (!symbolTable.lookupSymbolIn(circuitOp, cast<SymbolRefAttr>(layer)))
1944 return emitOpError() <<
"enables undefined layer '" << layer <<
"'";
1951FExtModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1955 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
1956 for (
auto layer : getKnownLayersAttr().getAsRange<SymbolRefAttr>()) {
1957 if (!symbolTable.lookupSymbolIn(circuitOp, layer))
1958 return emitOpError() <<
"knows undefined layer '" << layer <<
"'";
1960 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>()) {
1961 if (!symbolTable.lookupSymbolIn(circuitOp, layer))
1962 return emitOpError() <<
"enables undefined layer '" << layer <<
"'";
1969FIntModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1974FMemModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1978void FModuleOp::getAsmBlockArgumentNames(mlir::Region ®ion,
1983void FExtModuleOp::getAsmBlockArgumentNames(
1988StringAttr FExtModuleOp::getExtModuleNameAttr() {
1989 if (
auto defnameAttr = getDefnameAttr(); defnameAttr && !defnameAttr.empty())
1991 return getNameAttr();
1994StringRef FExtModuleOp::getExtModuleName() {
1995 if (
auto defname = getDefname(); defname && !defname->empty())
2000void FIntModuleOp::getAsmBlockArgumentNames(
2005void FMemModuleOp::getAsmBlockArgumentNames(
2010ArrayAttr FMemModuleOp::getParameters() {
return {}; }
2012ArrayAttr FModuleOp::getParameters() {
return {}; }
2014Convention FIntModuleOp::getConvention() {
return Convention::Internal; }
2016ConventionAttr FIntModuleOp::getConventionAttr() {
2017 return ConventionAttr::get(getContext(), getConvention());
2020Convention FMemModuleOp::getConvention() {
return Convention::Internal; }
2022ConventionAttr FMemModuleOp::getConventionAttr() {
2023 return ConventionAttr::get(getContext(), getConvention());
2031 ClassLike classOp, ClassType type,
2032 function_ref<InFlightDiagnostic()> emitError) {
2034 auto name = type.getNameAttr().getAttr();
2035 auto expectedName = classOp.getModuleNameAttr();
2036 if (name != expectedName)
2037 return emitError() <<
"type has wrong name, got " << name <<
", expected "
2040 auto elements = type.getElements();
2042 auto expectedNumElements = classOp.getNumPorts();
2044 return emitError() <<
"has wrong number of ports, got " <<
numElements
2045 <<
", expected " << expectedNumElements;
2047 auto portNames = classOp.getPortNames();
2048 auto portDirections = classOp.getPortDirections();
2049 auto portTypes = classOp.getPortTypes();
2052 auto element = elements[i];
2054 auto name = element.name;
2055 auto expectedName = portNames[i];
2056 if (name != expectedName)
2057 return emitError() <<
"port #" << i <<
" has wrong name, got " << name
2058 <<
", expected " << expectedName;
2060 auto direction = element.direction;
2061 auto expectedDirection =
Direction(portDirections[i]);
2062 if (direction != expectedDirection)
2063 return emitError() <<
"port " << name <<
" has wrong direction, got "
2067 auto type = element.type;
2068 auto expectedType = cast<TypeAttr>(portTypes[i]).getValue();
2069 if (type != expectedType)
2070 return emitError() <<
"port " << name <<
" has wrong type, got " << type
2071 <<
", expected " << expectedType;
2078 auto n = classOp.getNumPorts();
2079 SmallVector<ClassElement> elements;
2080 elements.reserve(n);
2081 for (
size_t i = 0; i < n; ++i)
2082 elements.push_back({classOp.getPortNameAttr(i), classOp.getPortType(i),
2083 classOp.getPortDirection(i)});
2084 auto name = FlatSymbolRefAttr::get(classOp.getNameAttr());
2085 return ClassType::get(name, elements);
2088template <
typename OpTy>
2090 bool hasSSAIdentifiers) {
2091 auto *
context = result.getContext();
2092 auto &builder = parser.getBuilder();
2093 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
2097 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
2100 StringAttr nameAttr;
2101 if (parser.parseSymbolName(nameAttr))
2103 properties.setSymName(nameAttr);
2106 SmallVector<OpAsmParser::Argument> entryArgs;
2107 SmallVector<Direction, 4> portDirections;
2108 SmallVector<Attribute, 4> portNames;
2109 SmallVector<Attribute, 4> portTypes;
2110 SmallVector<Attribute, 4> portAnnotations;
2111 SmallVector<Attribute, 4> portSyms;
2112 SmallVector<Attribute, 4> portLocs;
2113 SmallVector<Attribute, 4> domains;
2116 entryArgs, portDirections, portNames, portTypes,
2117 portAnnotations, portSyms, portLocs, domains))
2121 for (
auto annos : portAnnotations)
2122 if (!cast<ArrayAttr>(annos).empty())
2126 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
2129 assert(portNames.size() == portTypes.size());
2135 properties.setPortDirections(
2139 properties.setPortNames(builder.getArrayAttr(portNames));
2142 properties.setPortTypes(builder.getArrayAttr(portTypes));
2145 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
2146 properties.setPortSymbols(builder.getArrayAttr(portSyms));
2149 properties.setPortLocations(ArrayAttr::get(
context, portLocs));
2155 auto *bodyRegion = result.addRegion();
2157 if (hasSSAIdentifiers) {
2158 if (parser.parseRegion(*bodyRegion, entryArgs))
2160 if (bodyRegion->empty())
2161 bodyRegion->push_back(
new Block());
2171 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
2172 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
2173 p << visibility.getValue() <<
' ';
2176 p.printSymbolName(op.getName());
2180 Region ®ion = op->getRegion(0);
2181 Block *body =
nullptr;
2182 if (!region.empty())
2183 body = ®ion.front();
2186 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
2187 {}, op.getPortSymbols(), op.getPortLocations(), {});
2190 SmallVector<StringRef, 8> omittedAttrs = {
2191 "sym_name",
"portNames",
"portTypes",
"portDirections",
2192 "portSymbols",
"portLocations", visibilityAttrName,
"domainInfo"};
2196 if (!needPortNamesAttr)
2197 omittedAttrs.push_back(
"portNames");
2199 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
2202 if (!region.empty()) {
2204 auto printEntryBlockArgs =
false;
2205 auto printBlockTerminators =
false;
2206 p.printRegion(region, printEntryBlockArgs, printBlockTerminators);
2214void ClassOp::build(OpBuilder &builder, OperationState &result, StringAttr name,
2215 ArrayRef<PortInfo> ports) {
2218 [](
const auto &port) {
return port.annotations.empty(); }) &&
2219 "class ports may not have annotations");
2221 buildClass<ClassOp>(builder, result, name, ports);
2224 auto *bodyRegion = result.regions[0].get();
2226 bodyRegion->push_back(body);
2229 for (
auto &elt : ports)
2230 body->addArgument(elt.type, elt.loc);
2233void ClassOp::build(::mlir::OpBuilder &odsBuilder,
2234 ::mlir::OperationState &odsState, Twine name,
2235 mlir::ArrayRef<mlir::StringRef> fieldNames,
2236 mlir::ArrayRef<mlir::Type> fieldTypes) {
2238 SmallVector<PortInfo, 10> ports;
2239 for (
auto [fieldName, fieldType] :
llvm::zip(fieldNames, fieldTypes)) {
2240 ports.emplace_back(odsBuilder.getStringAttr(fieldName +
"_in"), fieldType,
2242 ports.emplace_back(odsBuilder.getStringAttr(fieldName), fieldType,
2245 build(odsBuilder, odsState, odsBuilder.getStringAttr(name), ports);
2247 auto &body = odsState.regions[0]->getBlocks().front();
2248 auto prevLoc = odsBuilder.saveInsertionPoint();
2249 odsBuilder.setInsertionPointToEnd(&body);
2250 auto args = body.getArguments();
2251 auto loc = odsState.location;
2252 for (
unsigned i = 0, e = ports.size(); i != e; i += 2)
2253 PropAssignOp::create(odsBuilder, loc, args[i + 1], args[i]);
2255 odsBuilder.restoreInsertionPoint(prevLoc);
2257void ClassOp::print(OpAsmPrinter &p) {
2261ParseResult ClassOp::parse(OpAsmParser &parser, OperationState &result) {
2262 auto hasSSAIdentifiers =
true;
2263 return parseClassLike<ClassOp>(parser, result, hasSSAIdentifiers);
2266LogicalResult ClassOp::verify() {
2268 auto type = operand.getType();
2269 if (!isa<PropertyType>(type)) {
2270 emitOpError(
"ports on a class must be properties");
2279ClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2283void ClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2288SmallVector<PortInfo> ClassOp::getPorts() {
2289 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2292void ClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2293 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2297void ClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2298 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2301Convention ClassOp::getConvention() {
return Convention::Internal; }
2303ConventionAttr ClassOp::getConventionAttr() {
2304 return ConventionAttr::get(getContext(), getConvention());
2307ArrayAttr ClassOp::getParameters() {
return {}; }
2309ArrayAttr ClassOp::getPortAnnotationsAttr() {
2310 return ArrayAttr::get(getContext(), {});
2313ArrayRef<Attribute> ClassOp::getPortAnnotations() {
return {}; }
2315void ClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2316 llvm_unreachable(
"classes do not support annotations");
2319ArrayAttr ClassOp::getLayersAttr() {
return ArrayAttr::get(getContext(), {}); }
2321ArrayRef<Attribute> ClassOp::getLayers() {
return {}; }
2323SmallVector<::circt::hw::PortInfo> ClassOp::getPortList() {
2324 return ::getPortListImpl(*
this);
2328 return ::getPortImpl(*
this, idx);
2331BlockArgument ClassOp::getArgument(
size_t portNumber) {
2335bool ClassOp::canDiscardOnUseEmpty() {
2346void ExtClassOp::build(OpBuilder &builder, OperationState &result,
2347 StringAttr name, ArrayRef<PortInfo> ports) {
2350 [](
const auto &port) {
return port.annotations.empty(); }) &&
2351 "class ports may not have annotations");
2352 buildClass<ClassOp>(builder, result, name, ports);
2355void ExtClassOp::print(OpAsmPrinter &p) {
2359ParseResult ExtClassOp::parse(OpAsmParser &parser, OperationState &result) {
2360 auto hasSSAIdentifiers =
false;
2361 return parseClassLike<ExtClassOp>(parser, result, hasSSAIdentifiers);
2365ExtClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2369void ExtClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2374SmallVector<PortInfo> ExtClassOp::getPorts() {
2375 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2378void ExtClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2379 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2382void ExtClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2383 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2386Convention ExtClassOp::getConvention() {
return Convention::Internal; }
2388ConventionAttr ExtClassOp::getConventionAttr() {
2389 return ConventionAttr::get(getContext(), getConvention());
2392ArrayAttr ExtClassOp::getLayersAttr() {
2393 return ArrayAttr::get(getContext(), {});
2396ArrayRef<Attribute> ExtClassOp::getLayers() {
return {}; }
2398ArrayAttr ExtClassOp::getParameters() {
return {}; }
2400ArrayAttr ExtClassOp::getPortAnnotationsAttr() {
2401 return ArrayAttr::get(getContext(), {});
2404ArrayRef<Attribute> ExtClassOp::getPortAnnotations() {
return {}; }
2406void ExtClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2407 llvm_unreachable(
"classes do not support annotations");
2410SmallVector<::circt::hw::PortInfo> ExtClassOp::getPortList() {
2411 return ::getPortListImpl(*
this);
2415 return ::getPortImpl(*
this, idx);
2418bool ExtClassOp::canDiscardOnUseEmpty() {
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, StringAttr innerSym) {
2436 build(builder, result, resultTypes, moduleName, name, nameKind,
2437 portDirections, portNames, domainInfo, annotations, portAnnotations,
2438 layers, lowerToBind, doNotPrint,
2439 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr());
2442void InstanceOp::build(
2443 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2444 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2445 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2446 ArrayRef<Attribute> domainInfo, ArrayRef<Attribute> annotations,
2447 ArrayRef<Attribute> portAnnotations, ArrayRef<Attribute> layers,
2448 bool lowerToBind,
bool doNotPrint, hw::InnerSymAttr innerSym) {
2449 result.addTypes(resultTypes);
2450 result.getOrAddProperties<Properties>().setModuleName(
2451 SymbolRefAttr::get(builder.getContext(), moduleName));
2452 result.getOrAddProperties<Properties>().setName(builder.getStringAttr(name));
2453 result.getOrAddProperties<Properties>().setPortDirections(
2455 result.getOrAddProperties<Properties>().setPortNames(
2456 builder.getArrayAttr(portNames));
2458 if (domainInfo.empty()) {
2459 SmallVector<Attribute, 16> domainInfoVec(resultTypes.size(),
2460 builder.getArrayAttr({}));
2461 result.getOrAddProperties<Properties>().setDomainInfo(
2462 builder.getArrayAttr(domainInfoVec));
2464 assert(domainInfo.size() == resultTypes.size());
2465 result.getOrAddProperties<Properties>().setDomainInfo(
2466 builder.getArrayAttr(domainInfo));
2469 result.getOrAddProperties<Properties>().setAnnotations(
2470 builder.getArrayAttr(annotations));
2471 result.getOrAddProperties<Properties>().setLayers(
2472 builder.getArrayAttr(layers));
2474 result.getOrAddProperties<Properties>().setLowerToBind(
2475 builder.getUnitAttr());
2477 result.getOrAddProperties<Properties>().setDoNotPrint(
2478 builder.getUnitAttr());
2480 result.getOrAddProperties<Properties>().setInnerSym(innerSym);
2482 result.getOrAddProperties<Properties>().setNameKind(
2483 NameKindEnumAttr::get(builder.getContext(), nameKind));
2485 if (portAnnotations.empty()) {
2486 SmallVector<Attribute, 16> portAnnotationsVec(resultTypes.size(),
2487 builder.getArrayAttr({}));
2488 result.getOrAddProperties<Properties>().setPortAnnotations(
2489 builder.getArrayAttr(portAnnotationsVec));
2491 assert(portAnnotations.size() == resultTypes.size());
2492 result.getOrAddProperties<Properties>().setPortAnnotations(
2493 builder.getArrayAttr(portAnnotations));
2497void InstanceOp::build(OpBuilder &builder, OperationState &result,
2498 FModuleLike module, StringRef name,
2499 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2500 ArrayRef<Attribute> portAnnotations,
bool lowerToBind,
2501 bool doNotPrint, hw::InnerSymAttr innerSym) {
2504 SmallVector<Type> resultTypes;
2505 resultTypes.reserve(module.getNumPorts());
2507 module.getPortTypes(), std::back_inserter(resultTypes),
2508 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2513 ArrayAttr portAnnotationsAttr;
2514 if (portAnnotations.empty()) {
2515 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2516 resultTypes.size(), builder.getArrayAttr({})));
2518 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2520 ArrayAttr domainInfoAttr =
module.getDomainInfoAttr();
2521 if (domainInfoAttr.empty()) {
2522 domainInfoAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2523 resultTypes.size(), builder.getArrayAttr({})));
2527 builder, result, resultTypes,
2528 SymbolRefAttr::get(builder.getContext(), module.getModuleNameAttr()),
2529 builder.getStringAttr(name),
2530 NameKindEnumAttr::get(builder.getContext(), nameKind),
2531 module.getPortDirectionsAttr(), module.getPortNamesAttr(), domainInfoAttr,
2532 builder.getArrayAttr(annotations), portAnnotationsAttr,
2533 module.getLayersAttr(), lowerToBind ? builder.getUnitAttr() : UnitAttr(),
2534 doNotPrint ? builder.getUnitAttr() : UnitAttr(), innerSym);
2537void InstanceOp::build(OpBuilder &builder, OperationState &odsState,
2538 ArrayRef<PortInfo> ports, StringRef moduleName,
2539 StringRef name, NameKindEnum nameKind,
2540 ArrayRef<Attribute> annotations,
2541 ArrayRef<Attribute> layers,
bool lowerToBind,
2542 bool doNotPrint, hw::InnerSymAttr innerSym) {
2544 SmallVector<Type> newResultTypes;
2545 SmallVector<Direction> newPortDirections;
2546 SmallVector<Attribute> newPortNames;
2547 SmallVector<Attribute> newPortAnnotations;
2548 SmallVector<Attribute> newDomainInfo;
2549 for (
auto &p : ports) {
2550 newResultTypes.push_back(p.type);
2551 newPortDirections.push_back(p.direction);
2552 newPortNames.push_back(p.name);
2553 newPortAnnotations.push_back(p.annotations.getArrayAttr());
2555 newDomainInfo.push_back(p.domains);
2557 newDomainInfo.push_back(builder.getArrayAttr({}));
2560 return build(builder, odsState, newResultTypes, moduleName, name, nameKind,
2561 newPortDirections, newPortNames, newDomainInfo, annotations,
2562 newPortAnnotations, layers, lowerToBind, doNotPrint, innerSym);
2565LogicalResult InstanceOp::verify() {
2568 SmallVector<SymbolRefAttr> missingLayers;
2569 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
2571 missingLayers.push_back(layer);
2573 if (missingLayers.empty())
2577 emitOpError(
"ambient layers are insufficient to instantiate module");
2578 auto ¬e = diag.attachNote();
2579 note <<
"missing layer requirements: ";
2580 interleaveComma(missingLayers, note);
2585 Operation *op1, Operation *op2,
2586 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2588 size_t n = insertions.size();
2589 size_t inserted = 0;
2590 for (
size_t i = 0, e = op1->getNumResults(); i < e; ++i) {
2591 while (inserted < n) {
2592 auto &[index, portInfo] = insertions[inserted];
2597 auto r1 = op1->getResult(i);
2598 auto r2 = op2->getResult(i + inserted);
2599 r1.replaceAllUsesWith(r2);
2604 const llvm::BitVector &erasures) {
2607 for (
size_t i = 0, e = op1->getNumResults(); i < e; ++i) {
2608 auto r1 = op1->getResult(i);
2610 assert(r1.use_empty() &&
"removed instance port has uses");
2614 auto r2 = op2->getResult(i - erased);
2615 r1.replaceAllUsesWith(r2);
2619InstanceOp InstanceOp::cloneWithErasedPorts(
const llvm::BitVector &erasures) {
2620 assert(erasures.size() >= getNumResults() &&
2621 "erasures is not at least as large as getNumResults()");
2623 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
2624 SmallVector<Type>(result_type_begin(), result_type_end()), erasures);
2625 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
2627 SmallVector<Attribute> newPortNames =
2629 SmallVector<Attribute> newPortAnnotations =
2631 ArrayAttr newDomainInfo =
2635 OpBuilder builder(*
this);
2636 auto clone = InstanceOp::create(
2637 builder,
getLoc(), newResultTypes, getModuleName(),
getName(),
2638 getNameKind(), newPortDirections, newPortNames, newDomainInfo.getValue(),
2639 getAnnotations().getValue(), newPortAnnotations, getLayers(),
2640 getLowerToBind(), getDoNotPrint(), getInnerSymAttr());
2642 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2643 clone->setAttr(
"output_file", outputFile);
2648InstanceOp InstanceOp::cloneWithErasedPortsAndReplaceUses(
2649 const llvm::BitVector &erasures) {
2650 auto clone = cloneWithErasedPorts(erasures);
2655ArrayAttr InstanceOp::getPortAnnotation(
unsigned portIdx) {
2656 assert(portIdx < getNumResults() &&
2657 "index should be smaller than result number");
2658 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
2661void InstanceOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
2662 assert(annotations.size() == getNumResults() &&
2663 "number of annotations is not equal to result number");
2664 (*this)->setAttr(
"portAnnotations",
2665 ArrayAttr::get(getContext(), annotations));
2668Attribute InstanceOp::getPortDomain(
unsigned portIdx) {
2669 assert(portIdx < getNumResults() &&
2670 "index should be smaller than result number");
2671 return getDomainInfo()[portIdx];
2674InstanceOp InstanceOp::cloneWithInsertedPorts(
2675 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2679 auto oldPortCount = getNumResults();
2680 auto numInsertions = insertions.size();
2681 auto newPortCount = oldPortCount + numInsertions;
2683 SmallVector<Direction> newPortDirections;
2684 SmallVector<Attribute> newPortNames;
2685 SmallVector<Type> newPortTypes;
2686 SmallVector<Attribute> newPortAnnos;
2687 SmallVector<Attribute> newDomainInfo;
2689 newPortDirections.reserve(newPortCount);
2690 newPortNames.reserve(newPortCount);
2691 newPortTypes.reserve(newPortCount);
2692 newPortAnnos.reserve(newPortCount);
2693 newDomainInfo.reserve(newPortCount);
2695 SmallVector<unsigned> indexMap(oldPortCount);
2697 size_t inserted = 0;
2698 for (
size_t i = 0; i < oldPortCount; ++i) {
2699 while (inserted < numInsertions) {
2700 auto &[index,
info] = insertions[inserted];
2706 newPortDirections.push_back(
info.direction);
2707 newPortNames.push_back(
info.name);
2708 newPortTypes.push_back(
info.type);
2709 newPortAnnos.push_back(
info.annotations.getArrayAttr());
2710 newDomainInfo.push_back(domains);
2714 newPortDirections.push_back(getPortDirection(i));
2715 newPortNames.push_back(getPortNameAttr(i));
2716 newPortTypes.push_back(getType(i));
2717 newPortAnnos.push_back(getPortAnnotation(i));
2718 newDomainInfo.push_back(getDomainInfo()[i]);
2719 indexMap[i] = i + inserted;
2722 while (inserted < numInsertions) {
2723 auto &[index,
info] = insertions[inserted];
2726 newPortDirections.push_back(
info.direction);
2727 newPortNames.push_back(
info.name);
2728 newPortTypes.push_back(
info.type);
2729 newPortAnnos.push_back(
info.annotations.getArrayAttr());
2730 newDomainInfo.push_back(domains);
2734 OpBuilder builder(*
this);
2735 auto clone = InstanceOp::create(
2736 builder,
getLoc(), newPortTypes, getModuleName(),
getName(),
2737 getNameKind(), newPortDirections, newPortNames, newDomainInfo,
2738 getAnnotations().getValue(), newPortAnnos, getLayers(), getLowerToBind(),
2739 getDoNotPrint(), getInnerSymAttr());
2741 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2742 clone->setAttr(
"output_file", outputFile);
2747InstanceOp InstanceOp::cloneWithInsertedPortsAndReplaceUses(
2748 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2749 auto clone = cloneWithInsertedPorts(insertions);
2754LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2756 getModuleNameAttr());
2759StringRef InstanceOp::getInstanceName() {
return getName(); }
2761StringAttr InstanceOp::getInstanceNameAttr() {
return getNameAttr(); }
2763void InstanceOp::print(OpAsmPrinter &p) {
2766 p.printKeywordOrString(
getName());
2767 if (
auto attr = getInnerSymAttr()) {
2769 p.printSymbolName(attr.getSymName());
2771 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2772 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2775 SmallVector<StringRef, 10> omittedAttrs = {
2776 "moduleName",
"name",
"portDirections",
2777 "portNames",
"portTypes",
"portAnnotations",
2778 "inner_sym",
"nameKind",
"domainInfo"};
2779 if (getAnnotations().
empty())
2780 omittedAttrs.push_back(
"annotations");
2781 if (getLayers().
empty())
2782 omittedAttrs.push_back(
"layers");
2783 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2787 p.printSymbolName(getModuleName());
2790 SmallVector<Attribute> portTypes;
2791 portTypes.reserve(getNumResults());
2792 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2796 getPortNames().getValue(), portTypes,
2797 getPortAnnotations().getValue(), {}, {},
2798 getDomainInfo().getValue());
2801ParseResult InstanceOp::parse(OpAsmParser &parser, OperationState &result) {
2802 auto *
context = parser.getContext();
2803 auto &properties = result.getOrAddProperties<Properties>();
2806 hw::InnerSymAttr innerSymAttr;
2807 FlatSymbolRefAttr moduleName;
2808 SmallVector<OpAsmParser::Argument> entryArgs;
2809 SmallVector<Direction, 4> portDirections;
2810 SmallVector<Attribute, 4> portNames;
2811 SmallVector<Attribute, 4> portTypes;
2812 SmallVector<Attribute, 4> portAnnotations;
2813 SmallVector<Attribute, 4> portSyms;
2814 SmallVector<Attribute, 4> portLocs;
2815 SmallVector<Attribute, 4> domains;
2816 NameKindEnumAttr nameKind;
2818 if (parser.parseKeywordOrString(&name))
2820 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
2821 if (parser.parseCustomAttributeWithFallback(
2822 innerSymAttr, ::mlir::Type{},
2824 result.attributes)) {
2825 return ::mlir::failure();
2829 parser.parseOptionalAttrDict(result.attributes) ||
2830 parser.parseAttribute(moduleName) ||
2833 entryArgs, portDirections, portNames, portTypes,
2834 portAnnotations, portSyms, portLocs, domains))
2840 properties.setModuleName(moduleName);
2841 properties.setName(StringAttr::get(
context, name));
2842 properties.setNameKind(nameKind);
2843 properties.setPortDirections(
2845 properties.setPortNames(ArrayAttr::get(
context, portNames));
2846 properties.setPortAnnotations(ArrayAttr::get(
context, portAnnotations));
2850 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
2851 properties.setLayers(parser.getBuilder().getArrayAttr({}));
2854 properties.setDomainInfo(ArrayAttr::get(
context, domains));
2857 result.types.reserve(portTypes.size());
2859 portTypes, std::back_inserter(result.types),
2860 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2865void InstanceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
2870 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
2871 setNameFn(getResult(i), (base +
"_" + getPortName(i)).str());
2875std::optional<size_t> InstanceOp::getTargetResultIndex() {
2877 return std::nullopt;
2884void InstanceChoiceOp::build(
2885 OpBuilder &builder, OperationState &result, FModuleLike defaultModule,
2886 ArrayRef<std::pair<OptionCaseOp, FModuleLike>> cases, StringRef name,
2887 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2888 ArrayRef<Attribute> portAnnotations, StringAttr innerSym) {
2890 SmallVector<Type> resultTypes;
2891 for (Attribute portType : defaultModule.getPortTypes())
2892 resultTypes.push_back(cast<TypeAttr>(portType).getValue());
2895 ArrayAttr portAnnotationsAttr;
2896 if (portAnnotations.empty()) {
2897 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2898 resultTypes.size(), builder.getArrayAttr({})));
2900 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2904 ArrayAttr domainInfoAttr = defaultModule.getDomainInfoAttr();
2905 if (domainInfoAttr.empty()) {
2906 domainInfoAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2907 resultTypes.size(), builder.getArrayAttr({})));
2911 SmallVector<Attribute> moduleNames, caseNames;
2912 moduleNames.push_back(SymbolRefAttr::get(defaultModule.getModuleNameAttr()));
2913 for (
auto [caseOption, caseModule] : cases) {
2914 auto caseGroup = caseOption->getParentOfType<OptionOp>();
2915 caseNames.push_back(SymbolRefAttr::get(caseGroup.getSymNameAttr(),
2916 {SymbolRefAttr::get(caseOption)}));
2917 moduleNames.push_back(SymbolRefAttr::get(caseModule.getModuleNameAttr()));
2920 return build(builder, result, resultTypes, builder.getArrayAttr(moduleNames),
2921 builder.getArrayAttr(caseNames), builder.getStringAttr(name),
2922 NameKindEnumAttr::get(builder.getContext(), nameKind),
2923 defaultModule.getPortDirectionsAttr(),
2924 defaultModule.getPortNamesAttr(), domainInfoAttr,
2925 builder.getArrayAttr(annotations), portAnnotationsAttr,
2926 defaultModule.getLayersAttr(),
2927 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr());
2930std::optional<size_t> InstanceChoiceOp::getTargetResultIndex() {
2931 return std::nullopt;
2934void InstanceChoiceOp::print(OpAsmPrinter &p) {
2937 p.printKeywordOrString(
getName());
2938 if (
auto attr = getInnerSymAttr()) {
2940 p.printSymbolName(attr.getSymName());
2942 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2943 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2946 SmallVector<StringRef, 11> omittedAttrs = {
2947 "moduleNames",
"caseNames",
"name",
2948 "portDirections",
"portNames",
"portTypes",
2949 "portAnnotations",
"inner_sym",
"nameKind",
2951 if (getAnnotations().
empty())
2952 omittedAttrs.push_back(
"annotations");
2953 if (getLayers().
empty())
2954 omittedAttrs.push_back(
"layers");
2955 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2960 auto moduleNames = getModuleNamesAttr();
2961 auto caseNames = getCaseNamesAttr();
2963 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[0]).getValue());
2965 p <<
" alternatives ";
2967 cast<SymbolRefAttr>(caseNames[0]).getRootReference().getValue());
2969 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
2973 auto symbol = cast<SymbolRefAttr>(caseNames[i]);
2974 p.printSymbolName(symbol.getNestedReferences()[0].getValue());
2976 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[i + 1]).getValue());
2982 SmallVector<Attribute> portTypes;
2983 portTypes.reserve(getNumResults());
2984 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2987 getPortNames().getValue(), portTypes,
2988 getPortAnnotations().getValue(), {}, {},
2989 getDomainInfo().getValue());
2992ParseResult InstanceChoiceOp::parse(OpAsmParser &parser,
2993 OperationState &result) {
2994 auto *
context = parser.getContext();
2995 auto &properties = result.getOrAddProperties<Properties>();
2998 hw::InnerSymAttr innerSymAttr;
2999 SmallVector<Attribute> moduleNames;
3000 SmallVector<Attribute> caseNames;
3001 SmallVector<OpAsmParser::Argument> entryArgs;
3002 SmallVector<Direction, 4> portDirections;
3003 SmallVector<Attribute, 4> portNames;
3004 SmallVector<Attribute, 4> portTypes;
3005 SmallVector<Attribute, 4> portAnnotations;
3006 SmallVector<Attribute, 4> portSyms;
3007 SmallVector<Attribute, 4> portLocs;
3008 SmallVector<Attribute, 4> domains;
3009 NameKindEnumAttr nameKind;
3011 if (parser.parseKeywordOrString(&name))
3013 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
3014 if (parser.parseCustomAttributeWithFallback(
3015 innerSymAttr, Type{},
3017 result.attributes)) {
3022 parser.parseOptionalAttrDict(result.attributes))
3025 FlatSymbolRefAttr defaultModuleName;
3026 if (parser.parseAttribute(defaultModuleName))
3028 moduleNames.push_back(defaultModuleName);
3032 FlatSymbolRefAttr optionName;
3033 if (parser.parseKeyword(
"alternatives") ||
3034 parser.parseAttribute(optionName) || parser.parseLBrace())
3037 FlatSymbolRefAttr moduleName;
3038 StringAttr caseName;
3039 while (succeeded(parser.parseOptionalSymbolName(caseName))) {
3040 if (parser.parseArrow() || parser.parseAttribute(moduleName))
3042 moduleNames.push_back(moduleName);
3043 caseNames.push_back(SymbolRefAttr::get(
3044 optionName.getAttr(), {FlatSymbolRefAttr::get(caseName)}));
3045 if (failed(parser.parseOptionalComma()))
3048 if (parser.parseRBrace())
3054 entryArgs, portDirections, portNames, portTypes,
3055 portAnnotations, portSyms, portLocs, domains))
3060 properties.setModuleNames(ArrayAttr::get(
context, moduleNames));
3061 properties.setCaseNames(ArrayAttr::get(
context, caseNames));
3062 properties.setName(StringAttr::get(
context, name));
3063 properties.setNameKind(nameKind);
3064 properties.setPortDirections(
3066 properties.setPortNames(ArrayAttr::get(
context, portNames));
3067 properties.setDomainInfo(ArrayAttr::get(
context, domains));
3068 properties.setPortAnnotations(ArrayAttr::get(
context, portAnnotations));
3072 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
3073 properties.setLayers(parser.getBuilder().getArrayAttr({}));
3076 result.types.reserve(portTypes.size());
3078 portTypes, std::back_inserter(result.types),
3079 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
3084void InstanceChoiceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3086 for (
auto [result, name] :
llvm::zip(getResults(), getPortNames()))
3087 setNameFn(result, (base +
"_" + cast<StringAttr>(name).getValue()).str());
3090LogicalResult InstanceChoiceOp::verify() {
3091 if (getCaseNamesAttr().
empty())
3092 return emitOpError() <<
"must have at least one case";
3093 if (getModuleNamesAttr().size() != getCaseNamesAttr().size() + 1)
3094 return emitOpError() <<
"number of referenced modules does not match the "
3095 "number of options";
3100 SmallVector<SymbolRefAttr> missingLayers;
3101 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
3103 missingLayers.push_back(layer);
3105 if (missingLayers.empty())
3109 emitOpError(
"ambient layers are insufficient to instantiate module");
3110 auto ¬e = diag.attachNote();
3111 note <<
"missing layer requirements: ";
3112 interleaveComma(missingLayers, note);
3117InstanceChoiceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3118 auto caseNames = getCaseNamesAttr();
3119 for (
auto moduleName : getModuleNamesAttr()) {
3121 *
this, symbolTable, cast<FlatSymbolRefAttr>(moduleName))))
3125 auto root = cast<SymbolRefAttr>(caseNames[0]).getRootReference();
3126 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3127 auto ref = cast<SymbolRefAttr>(caseNames[i]);
3128 auto refRoot = ref.getRootReference();
3129 if (ref.getRootReference() != root)
3130 return emitOpError() <<
"case " << ref
3131 <<
" is not in the same option group as "
3134 if (!symbolTable.lookupNearestSymbolFrom<OptionOp>(*
this, refRoot))
3135 return emitOpError() <<
"option " << refRoot <<
" does not exist";
3137 if (!symbolTable.lookupNearestSymbolFrom<OptionCaseOp>(*
this, ref))
3138 return emitOpError() <<
"option " << refRoot
3139 <<
" does not contain option case " << ref;
3146InstanceChoiceOp::getTargetOrDefaultAttr(OptionCaseOp option) {
3147 auto caseNames = getCaseNamesAttr();
3148 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3149 StringAttr caseSym = cast<SymbolRefAttr>(caseNames[i]).getLeafReference();
3150 if (caseSym == option.getSymName())
3151 return cast<FlatSymbolRefAttr>(getModuleNamesAttr()[i + 1]);
3153 return getDefaultTargetAttr();
3156SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1>
3157InstanceChoiceOp::getTargetChoices() {
3158 auto caseNames = getCaseNamesAttr();
3159 auto moduleNames = getModuleNamesAttr();
3160 SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1> choices;
3161 for (
size_t i = 0; i < caseNames.size(); ++i) {
3162 choices.emplace_back(cast<SymbolRefAttr>(caseNames[i]),
3163 cast<FlatSymbolRefAttr>(moduleNames[i + 1]));
3169InstanceChoiceOp InstanceChoiceOp::cloneWithInsertedPorts(
3170 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
3174 auto oldPortCount = getNumResults();
3175 auto numInsertions = insertions.size();
3176 auto newPortCount = oldPortCount + numInsertions;
3178 SmallVector<Direction> newPortDirections;
3179 SmallVector<Attribute> newPortNames;
3180 SmallVector<Type> newPortTypes;
3181 SmallVector<Attribute> newPortAnnos;
3182 SmallVector<Attribute> newDomainInfo;
3184 newPortDirections.reserve(newPortCount);
3185 newPortNames.reserve(newPortCount);
3186 newPortTypes.reserve(newPortCount);
3187 newPortAnnos.reserve(newPortCount);
3188 newDomainInfo.reserve(newPortCount);
3190 SmallVector<unsigned> indexMap(oldPortCount);
3192 size_t inserted = 0;
3193 for (
size_t i = 0; i < oldPortCount; ++i) {
3194 while (inserted < numInsertions) {
3195 auto &[index,
info] = insertions[inserted];
3201 newPortDirections.push_back(
info.direction);
3202 newPortNames.push_back(
info.name);
3203 newPortTypes.push_back(
info.type);
3204 newPortAnnos.push_back(
info.annotations.getArrayAttr());
3205 newDomainInfo.push_back(domains);
3209 newPortDirections.push_back(getPortDirection(i));
3210 newPortNames.push_back(getPortNameAttr(i));
3211 newPortTypes.push_back(getType(i));
3212 newPortAnnos.push_back(getPortAnnotations()[i]);
3213 newDomainInfo.push_back(getDomainInfo()[i]);
3214 indexMap[i] = i + inserted;
3217 while (inserted < numInsertions) {
3218 auto &[index,
info] = insertions[inserted];
3221 newPortDirections.push_back(
info.direction);
3222 newPortNames.push_back(
info.name);
3223 newPortTypes.push_back(
info.type);
3224 newPortAnnos.push_back(
info.annotations.getArrayAttr());
3225 newDomainInfo.push_back(domains);
3229 OpBuilder builder(*
this);
3230 auto clone = InstanceChoiceOp::create(
3231 builder,
getLoc(), newPortTypes, getModuleNames(), getCaseNames(),
3234 ArrayAttr::get(
context, newPortNames),
3235 ArrayAttr::get(
context, newDomainInfo), getAnnotationsAttr(),
3236 ArrayAttr::get(
context, newPortAnnos), getLayers(), getInnerSymAttr());
3238 if (
auto outputFile = (*this)->getAttr(
"output_file"))
3239 clone->setAttr(
"output_file", outputFile);
3244InstanceChoiceOp InstanceChoiceOp::cloneWithInsertedPortsAndReplaceUses(
3245 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
3246 auto clone = cloneWithInsertedPorts(insertions);
3252InstanceChoiceOp::cloneWithErasedPorts(
const llvm::BitVector &erasures) {
3253 assert(erasures.size() >= getNumResults() &&
3254 "erasures is not at least as large as getNumResults()");
3256 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
3257 SmallVector<Type>(result_type_begin(), result_type_end()), erasures);
3258 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
3260 SmallVector<Attribute> newPortNames =
3262 SmallVector<Attribute> newPortAnnotations =
3264 ArrayAttr newPortDomains =
3268 OpBuilder builder(*
this);
3269 auto clone = InstanceChoiceOp::create(
3270 builder,
getLoc(), newResultTypes, getModuleNames(), getCaseNames(),
3273 ArrayAttr::get(getContext(), newPortNames), newPortDomains,
3274 getAnnotationsAttr(), ArrayAttr::get(getContext(), newPortAnnotations),
3275 getLayers(), getInnerSymAttr());
3277 if (
auto outputFile = (*this)->getAttr(
"output_file"))
3278 clone->setAttr(
"output_file", outputFile);
3283InstanceChoiceOp InstanceChoiceOp::cloneWithErasedPortsAndReplaceUses(
3284 const llvm::BitVector &erasures) {
3285 auto clone = cloneWithErasedPorts(erasures);
3294ArrayAttr MemOp::getPortAnnotation(
unsigned portIdx) {
3295 assert(portIdx < getNumResults() &&
3296 "index should be smaller than result number");
3297 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
3300void MemOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
3301 assert(annotations.size() == getNumResults() &&
3302 "number of annotations is not equal to result number");
3303 (*this)->setAttr(
"portAnnotations",
3304 ArrayAttr::get(getContext(), annotations));
3308void MemOp::getNumPorts(
size_t &numReadPorts,
size_t &numWritePorts,
3309 size_t &numReadWritePorts,
size_t &numDbgsPorts) {
3312 numReadWritePorts = 0;
3314 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3315 auto portKind = getPortKind(i);
3316 if (portKind == MemOp::PortKind::Debug)
3318 else if (portKind == MemOp::PortKind::Read)
3320 else if (portKind == MemOp::PortKind::Write) {
3323 ++numReadWritePorts;
3328LogicalResult MemOp::verify() {
3332 llvm::SmallDenseSet<Attribute, 8> portNamesSet;
3338 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3339 auto portName = getPortNameAttr(i);
3344 BundleType portBundleType =
3345 type_dyn_cast<BundleType>(getResult(i).getType());
3348 if (!portNamesSet.insert(portName).second) {
3349 emitOpError() <<
"has non-unique port name " << portName;
3357 auto elt = getPortNamed(portName);
3359 emitOpError() <<
"could not get port with name " << portName;
3362 auto firrtlType = type_cast<FIRRTLType>(elt.getType());
3365 if (portKind == MemOp::PortKind::Debug &&
3366 !type_isa<RefType>(getResult(i).getType()))
3367 return emitOpError() <<
"has an invalid type on port " << portName
3368 <<
" (expected Read/Write/ReadWrite/Debug)";
3369 if (type_isa<RefType>(firrtlType) && e == 1)
3370 return emitOpError()
3371 <<
"cannot have only one port of debug type. Debug port can only "
3372 "exist alongside other read/write/read-write port";
3377 if (portKind == MemOp::PortKind::Debug) {
3378 auto resType = type_cast<RefType>(getResult(i).getType());
3379 if (!(resType && type_isa<FVectorType>(resType.getType())))
3380 return emitOpError() <<
"debug ports must be a RefType of FVectorType";
3381 dataType = type_cast<FVectorType>(resType.getType()).getElementType();
3383 auto dataTypeOption = portBundleType.getElement(
"data");
3384 if (!dataTypeOption && portKind == MemOp::PortKind::ReadWrite)
3385 dataTypeOption = portBundleType.getElement(
"wdata");
3386 if (!dataTypeOption) {
3387 emitOpError() <<
"has no data field on port " << portName
3388 <<
" (expected to see \"data\" for a read or write "
3389 "port or \"rdata\" for a read/write port)";
3392 dataType = dataTypeOption->type;
3394 if (portKind == MemOp::PortKind::Read) {
3401 emitOpError() <<
"has non-passive data type on port " << portName
3402 <<
" (memory types must be passive)";
3407 if (dataType.containsAnalog()) {
3408 emitOpError() <<
"has a data type that contains an analog type on port "
3410 <<
" (memory types cannot contain analog types)";
3418 getTypeForPort(getDepth(), dataType, portKind,
3419 dataType.isGround() ? getMaskBits() : 0);
3422 auto originalType = getResult(i).getType();
3423 if (originalType != expectedType) {
3424 StringRef portKindName;
3426 case MemOp::PortKind::Read:
3427 portKindName =
"read";
3429 case MemOp::PortKind::Write:
3430 portKindName =
"write";
3432 case MemOp::PortKind::ReadWrite:
3433 portKindName =
"readwrite";
3435 case MemOp::PortKind::Debug:
3436 portKindName =
"dbg";
3439 emitOpError() <<
"has an invalid type for port " << portName
3440 <<
" of determined kind \"" << portKindName
3441 <<
"\" (expected " << expectedType <<
", but got "
3442 << originalType <<
")";
3448 if (oldDataType && oldDataType != dataType) {
3449 emitOpError() <<
"port " << getPortNameAttr(i)
3450 <<
" has a different type than port "
3451 << getPortNameAttr(i - 1) <<
" (expected " << oldDataType
3452 <<
", but got " << dataType <<
")";
3456 oldDataType = dataType;
3459 auto maskWidth = getMaskBits();
3461 auto dataWidth = getDataType().getBitWidthOrSentinel();
3462 if (dataWidth > 0 && maskWidth > (
size_t)dataWidth)
3463 return emitOpError(
"the mask width cannot be greater than "
3466 if (getPortAnnotations().size() != getNumResults())
3467 return emitOpError(
"the number of result annotations should be "
3468 "equal to the number of results");
3474 return std::max(1U, llvm::Log2_64_Ceil(depth));
3480 PortKind portKind,
size_t maskBits) {
3482 auto *
context = dataType.getContext();
3483 if (portKind == PortKind::Debug)
3484 return RefType::get(FVectorType::get(dataType, depth));
3490 maskType = UIntType::get(
context, maskBits);
3492 auto getId = [&](StringRef name) -> StringAttr {
3493 return StringAttr::get(
context, name);
3496 SmallVector<BundleType::BundleElement, 7> portFields;
3500 portFields.push_back({getId(
"addr"),
false, addressType});
3501 portFields.push_back({getId(
"en"),
false, UIntType::get(
context, 1)});
3502 portFields.push_back({getId(
"clk"),
false, ClockType::get(
context)});
3505 case PortKind::Read:
3506 portFields.push_back({getId(
"data"),
true, dataType});
3509 case PortKind::Write:
3510 portFields.push_back({getId(
"data"),
false, dataType});
3511 portFields.push_back({getId(
"mask"),
false, maskType});
3514 case PortKind::ReadWrite:
3515 portFields.push_back({getId(
"rdata"),
true, dataType});
3516 portFields.push_back({getId(
"wmode"),
false, UIntType::get(
context, 1)});
3517 portFields.push_back({getId(
"wdata"),
false, dataType});
3518 portFields.push_back({getId(
"wmask"),
false, maskType});
3521 llvm::report_fatal_error(
"memory port kind not handled");
3525 return BundleType::get(
context, portFields);
3529SmallVector<MemOp::NamedPort> MemOp::getPorts() {
3530 SmallVector<MemOp::NamedPort> result;
3532 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3534 auto portType = type_cast<FIRRTLType>(getResult(i).getType());
3541MemOp::PortKind MemOp::getPortKind(StringRef portName) {
3543 type_cast<FIRRTLType>(getPortNamed(portName).getType()));
3547MemOp::PortKind MemOp::getPortKind(
size_t resultNo) {
3549 type_cast<FIRRTLType>(getResult(resultNo).getType()));
3553size_t MemOp::getMaskBits() {
3555 for (
auto res : getResults()) {
3556 if (type_isa<RefType>(res.getType()))
3558 auto firstPortType = type_cast<FIRRTLBaseType>(res.getType());
3565 if (t.name.getValue().contains(
"mask"))
3568 if (type_isa<UIntType>(mType))
3578 assert(getNumResults() != 0 &&
"Mems with no read/write ports are illegal");
3580 if (
auto refType = type_dyn_cast<RefType>(getResult(0).getType()))
3581 return type_cast<FVectorType>(refType.getType()).getElementType();
3582 auto firstPortType = type_cast<FIRRTLBaseType>(getResult(0).getType());
3584 StringRef dataFieldName =
"data";
3586 dataFieldName =
"rdata";
3588 return type_cast<BundleType>(firstPortType.getPassiveType())
3589 .getElementType(dataFieldName);
3592StringAttr MemOp::getPortNameAttr(
size_t resultNo) {
3593 return cast<StringAttr>(getPortNames()[resultNo]);
3597 return type_cast<FIRRTLBaseType>(getResults()[resultNo].getType());
3600Value MemOp::getPortNamed(StringAttr name) {
3601 auto namesArray = getPortNames();
3602 for (
size_t i = 0, e = namesArray.size(); i != e; ++i) {
3603 if (namesArray[i] == name) {
3604 assert(i < getNumResults() &&
" names array out of sync with results");
3605 return getResult(i);
3614 size_t numReadPorts = 0;
3615 size_t numWritePorts = 0;
3616 size_t numReadWritePorts = 0;
3618 SmallVector<int32_t> writeClockIDs;
3620 for (
size_t i = 0, e = op.getNumResults(); i != e; ++i) {
3621 auto portKind = op.getPortKind(i);
3622 if (portKind == MemOp::PortKind::Read)
3624 else if (portKind == MemOp::PortKind::Write) {
3625 for (
auto *a : op.getResult(i).getUsers()) {
3626 auto subfield = dyn_cast<SubfieldOp>(a);
3627 if (!subfield || subfield.getFieldIndex() != 2)
3629 auto clockPort = a->getResult(0);
3630 for (
auto *b : clockPort.getUsers()) {
3631 if (
auto connect = dyn_cast<FConnectLike>(b)) {
3632 if (
connect.getDest() == clockPort) {
3635 connect.getSrc(),
true,
true,
true),
3637 if (result.second) {
3638 writeClockIDs.push_back(numWritePorts);
3640 writeClockIDs.push_back(result.first->second);
3649 ++numReadWritePorts;
3656 op.emitError(
"'firrtl.mem' should have simple type and known width");
3657 MemoryInitAttr init = op->getAttrOfType<MemoryInitAttr>(
"init");
3659 if (op->hasAttr(
"modName"))
3660 modName = op->getAttrOfType<StringAttr>(
"modName");
3662 SmallString<8> clocks;
3663 for (
auto a : writeClockIDs)
3664 clocks.
append(Twine((char)(a +
'a')).str());
3665 SmallString<32> initStr;
3670 for (
auto c : init.getFilename().getValue())
3671 if ((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') ||
3672 (c >=
'0' && c <=
'9'))
3673 initStr.push_back(c);
3674 initStr.push_back(
'_');
3675 initStr.push_back(init.getIsBinary() ?
't' :
'f');
3676 initStr.push_back(
'_');
3677 initStr.push_back(init.getIsInline() ?
't' :
'f');
3679 modName = StringAttr::get(
3682 "{0}FIRRTLMem_{1}_{2}_{3}_{4}_{5}_{6}_{7}_{8}_{9}_{10}{11}{12}",
3683 op.getPrefix().value_or(
""), numReadPorts, numWritePorts,
3684 numReadWritePorts, (
size_t)width, op.getDepth(),
3685 op.getReadLatency(), op.getWriteLatency(), op.getMaskBits(),
3686 (
unsigned)op.getRuw(), (
unsigned)seq::WUW::PortOrder,
3687 clocks.empty() ?
"" :
"_" + clocks, init ? initStr.str() :
""));
3689 return {numReadPorts,
3694 op.getReadLatency(),
3695 op.getWriteLatency(),
3697 *seq::symbolizeRUW(
unsigned(op.getRuw())),
3698 seq::WUW::PortOrder,
3701 op.getMaskBits() > 1,
3707void MemOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3712 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
3713 setNameFn(getResult(i), (base +
"_" + getPortName(i)).str());
3717std::optional<size_t> MemOp::getTargetResultIndex() {
3719 return std::nullopt;
3727 OpAsmSetValueNameFn setNameFn) {
3730 setNameFn(op.getDataRaw(), name);
3731 if (op.isForceable())
3732 setNameFn(op.getDataRef(), (name +
"_ref").str());
3735void NodeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3739LogicalResult NodeOp::inferReturnTypes(
3740 mlir::MLIRContext *
context, std::optional<mlir::Location> location,
3741 ::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes,
3742 ::mlir::OpaqueProperties properties, ::mlir::RegionRange regions,
3743 ::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
3744 if (operands.empty())
3746 Adaptor adaptor(operands, attributes, properties, regions);
3747 inferredReturnTypes.push_back(adaptor.getInput().getType());
3748 if (adaptor.getForceable()) {
3750 true, adaptor.getInput().getType());
3751 if (!forceableType) {
3753 ::mlir::emitError(*location,
"cannot force a node of type ")
3754 << operands[0].getType();
3757 inferredReturnTypes.push_back(forceableType);
3762std::optional<size_t> NodeOp::getTargetResultIndex() {
return 0; }
3764void RegOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3768std::optional<size_t> RegOp::getTargetResultIndex() {
return 0; }
3770SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3771RegOp::computeDataFlow() {
3776LogicalResult RegResetOp::verify() {
3777 auto reset = getResetValue();
3784 return emitError(
"type mismatch between register ")
3785 << regType <<
" and reset value " << resetType;
3790std::optional<size_t> RegResetOp::getTargetResultIndex() {
return 0; }
3792void RegResetOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3801FormalOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3802 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3804 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3806 if (!isa<FModuleLike>(op)) {
3807 auto d = emitOpError() <<
"target " << getModuleNameAttr()
3808 <<
" is not a module";
3809 d.attachNote(op->getLoc()) <<
"target defined here";
3821SimulationOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3822 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3824 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3826 auto complain = [&] {
3827 auto d = emitOpError() <<
"target " << getModuleNameAttr() <<
" ";
3828 d.attachNote(op->getLoc()) <<
"target defined here";
3832 auto module = dyn_cast<FModuleLike>(op);
3834 return complain() <<
"is not a module";
3836 auto numPorts =
module.getNumPorts();
3838 return complain() <<
"must have at least 4 ports, got " << numPorts
3842 auto checkPort = [&](
unsigned idx, StringRef expName,
Direction expDir,
3843 llvm::function_ref<bool(Type)> checkType,
3844 StringRef expType) {
3845 auto name =
module.getPortNameAttr(idx);
3846 if (name != expName) {
3847 complain() <<
"port " << idx <<
" must be called \"" << expName
3848 <<
"\", got " << name <<
" instead";
3851 if (
auto dir = module.getPortDirection(idx); dir != expDir) {
3855 complain() <<
"port " << name <<
" must be " << stringify(expDir)
3856 <<
", got " << stringify(dir) <<
" instead";
3859 if (
auto type = module.getPortType(idx); !checkType(type)) {
3860 complain() <<
"port " << name <<
" must be a '!firrtl." << expType
3861 <<
"', got " << type <<
" instead";
3867 auto isClock = [](Type type) {
return isa<ClockType>(type); };
3868 auto isBool = [](Type type) {
3869 if (
auto uintType = dyn_cast<UIntType>(type))
3870 return uintType.getWidth() == 1;
3874 if (!checkPort(0,
"clock",
Direction::In, isClock,
"clock") ||
3881 for (
unsigned i = 4; i < numPorts; ++i) {
3882 auto type =
module.getPortType(i);
3883 if (!isa<PropertyType>(type))
3884 return complain() <<
"port " << i <<
" may only be a property type, got "
3885 << type <<
" instead";
3895void WireOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3899SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3900RegResetOp::computeDataFlow() {
3905std::optional<size_t> WireOp::getTargetResultIndex() {
return 0; }
3907LogicalResult WireOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3908 auto refType = type_dyn_cast<RefType>(getType(0));
3913 refType,
getLoc(), getOperation()->getParentOfType<CircuitOp>(),
3914 symbolTable, Twine(
"'") + getOperationName() +
"' op is");
3921LogicalResult ContractOp::verify() {
3922 if (getBody().getArgumentTypes() != getInputs().getType())
3923 return emitOpError(
"result types and region argument types must match");
3931void ObjectOp::build(OpBuilder &builder, OperationState &state, ClassLike klass,
3933 build(builder, state, klass.getInstanceType(),
3934 StringAttr::get(builder.getContext(), name));
3937LogicalResult ObjectOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3938 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
3939 auto classType = getType();
3940 auto className = classType.getNameAttr();
3943 auto classOp = dyn_cast_or_null<ClassLike>(
3944 symbolTable.lookupSymbolIn(circuitOp, className));
3946 return emitOpError() <<
"references unknown class " << className;
3949 if (failed(classOp.verifyType(classType, [&]() { return emitOpError(); })))
3955StringAttr ObjectOp::getClassNameAttr() {
3956 return getType().getNameAttr().getAttr();
3959StringRef ObjectOp::getClassName() {
return getType().getName(); }
3961ClassLike ObjectOp::getReferencedClass(
const SymbolTable &symbolTable) {
3962 auto symRef = getType().getNameAttr();
3963 return symbolTable.lookup<ClassLike>(symRef.getLeafReference());
3966Operation *ObjectOp::getReferencedOperation(
const SymbolTable &symtbl) {
3967 return getReferencedClass(symtbl);
3970StringRef ObjectOp::getInstanceName() {
return getName(); }
3972StringAttr ObjectOp::getInstanceNameAttr() {
return getNameAttr(); }
3974StringRef ObjectOp::getReferencedModuleName() {
return getClassName(); }
3976StringAttr ObjectOp::getReferencedModuleNameAttr() {
3977 return getClassNameAttr();
3980void ObjectOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3981 setNameFn(getResult(),
getName());
3988LogicalResult AttachOp::verify() {
3990 std::optional<int32_t> commonWidth;
3991 for (
auto operand : getOperands()) {
3992 auto thisWidth = type_cast<AnalogType>(operand.getType()).getWidth();
3996 commonWidth = thisWidth;
3999 if (commonWidth != thisWidth)
4000 return emitOpError(
"is inavlid as not all known operand widths match");
4007 Value dst = connect->getOperand(0);
4008 Value src = connect->getOperand(1);
4017 if (isa<PropertyType>(src.getType()) ||
4021 auto diag = emitError(connect->getLoc());
4022 diag <<
"connect has invalid flow: the source expression ";
4024 diag <<
"\"" << srcName <<
"\" ";
4025 diag <<
"has " <<
toString(srcFlow) <<
", expected source or duplex flow";
4026 return diag.attachNote(srcRef.getLoc()) <<
"the source was defined here";
4034 auto diag = emitError(connect->getLoc());
4035 diag <<
"connect has invalid flow: the destination expression ";
4037 diag <<
"\"" << dstName <<
"\" ";
4038 diag <<
"has " <<
toString(dstFlow) <<
", expected sink or duplex flow";
4039 return diag.attachNote(dstRef.getLoc())
4040 <<
"the destination was defined here";
4049 bool outerTypeIsConst =
false) {
4050 auto typeIsConst = outerTypeIsConst || type.
isConst();
4055 if (
auto bundleType = type_dyn_cast<BundleType>(type))
4056 return llvm::any_of(bundleType.getElements(), [&](
auto &element) {
4057 return isConstFieldDriven(element.type, isFlip ^ element.isFlip,
4061 if (
auto vectorType = type_dyn_cast<FVectorType>(type))
4073 auto dest = connect.getDest();
4074 auto destType = type_dyn_cast<FIRRTLBaseType>(dest.getType());
4075 auto src = connect.getSrc();
4076 auto srcType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4077 if (!destType || !srcType)
4080 auto destRefinedType = destType;
4081 auto srcRefinedType = srcType;
4086 auto findFieldDeclarationRefiningFieldType =
4088 while (
auto *definingOp = value.getDefiningOp()) {
4089 bool shouldContinue =
true;
4090 TypeSwitch<Operation *>(definingOp)
4091 .Case<SubfieldOp, SubindexOp>([&](
auto op) { value = op.getInput(); })
4092 .Case<SubaccessOp>([&](SubaccessOp op) {
4096 .getElementTypePreservingConst()
4098 originalFieldType = originalFieldType.getConstType(
true);
4099 value = op.getInput();
4101 .Default([&](Operation *) { shouldContinue =
false; });
4102 if (!shouldContinue)
4108 auto destDeclaration =
4109 findFieldDeclarationRefiningFieldType(dest, destRefinedType);
4110 auto srcDeclaration =
4111 findFieldDeclarationRefiningFieldType(src, srcRefinedType);
4113 auto checkConstConditionality = [&](Value value,
FIRRTLBaseType type,
4114 Value declaration) -> LogicalResult {
4115 auto *declarationBlock = declaration.getParentBlock();
4116 auto *block = connect->getBlock();
4117 while (block && block != declarationBlock) {
4118 auto *parentOp = block->getParentOp();
4120 if (
auto whenOp = dyn_cast<WhenOp>(parentOp);
4121 whenOp && !whenOp.getCondition().getType().isConst()) {
4123 return connect.emitOpError()
4124 <<
"assignment to 'const' type " << type
4125 <<
" is dependent on a non-'const' condition";
4126 return connect->emitOpError()
4127 <<
"assignment to nested 'const' member of type " << type
4128 <<
" is dependent on a non-'const' condition";
4131 block = parentOp->getBlock();
4136 auto emitSubaccessError = [&] {
4137 return connect.emitError(
4138 "assignment to non-'const' subaccess of 'const' type is disallowed");
4144 if (destType != destRefinedType)
4145 return emitSubaccessError();
4147 if (failed(checkConstConditionality(dest, destType, destDeclaration)))
4152 if (srcRefinedType.containsConst() &&
4155 if (srcType != srcRefinedType)
4156 return emitSubaccessError();
4157 if (failed(checkConstConditionality(src, srcType, srcDeclaration)))
4174 auto dest = connect.getDest();
4175 for (
auto *user : dest.getUsers()) {
4176 if (
auto c = dyn_cast<FConnectLike>(user);
4177 c && c.getDest() == dest && c != connect) {
4178 auto diag = connect.emitError(
"destination cannot be driven by multiple "
4180 diag.attachNote(c->getLoc()) <<
"other driver is here";
4187LogicalResult ConnectOp::verify() {
4188 auto dstType = getDest().getType();
4189 auto srcType = getSrc().getType();
4190 auto dstBaseType = type_dyn_cast<FIRRTLBaseType>(dstType);
4191 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(srcType);
4192 if (!dstBaseType || !srcBaseType) {
4193 if (dstType != srcType)
4194 return emitError(
"may not connect different non-base types");
4197 if (dstBaseType.containsAnalog() || srcBaseType.containsAnalog())
4198 return emitError(
"analog types may not be connected");
4202 return emitError(
"type mismatch between destination ")
4203 << dstBaseType <<
" and source " << srcBaseType;
4208 return emitError(
"destination ")
4209 << dstBaseType <<
" is not as wide as the source " << srcBaseType;
4222LogicalResult MatchingConnectOp::verify() {
4223 if (
auto type = type_dyn_cast<FIRRTLType>(getDest().getType())) {
4224 auto baseType = type_cast<FIRRTLBaseType>(type);
4227 if (baseType && baseType.containsAnalog())
4228 return emitError(
"analog types may not be connected");
4233 "`SameAnonTypeOperands` trait should have already rejected "
4234 "structurally non-equivalent types");
4247LogicalResult RefDefineOp::verify() {
4254 if (
auto *op = getDest().getDefiningOp()) {
4256 if (isa<RefSubOp>(op))
4258 "destination reference cannot be a sub-element of a reference");
4259 if (isa<RefCastOp>(op))
4261 "destination reference cannot be a cast of another reference");
4269 SmallVector<SymbolRefAttr> missingLayers;
4272 "has more layer requirements than destination",
4273 "additional layers required");
4276LogicalResult PropAssignOp::verify() {
4286template <
typename T>
4288 auto info = op.getDomainInfo();
4291 return dyn_cast<FlatSymbolRefAttr>(info[i]);
4295 if (!isa<DomainType>(value.getType()))
4298 if (
auto arg = dyn_cast<BlockArgument>(value)) {
4299 auto *parent = arg.getOwner()->getParentOp();
4300 if (
auto module = dyn_cast<FModuleLike>(parent)) {
4301 auto info =
module.getDomainInfo();
4304 auto attr = info[arg.getArgNumber()];
4305 return dyn_cast<FlatSymbolRefAttr>(attr);
4311 if (
auto result = dyn_cast<OpResult>(value)) {
4312 auto *op = result.getDefiningOp();
4313 if (
auto instance = dyn_cast<InstanceOp>(op))
4315 if (
auto instance = dyn_cast<InstanceChoiceOp>(op))
4317 if (
auto anonDomain = dyn_cast<DomainCreateAnonOp>(op))
4318 return anonDomain.getDomainAttr();
4325LogicalResult DomainDefineOp::verify() {
4332 auto dst = getDest();
4333 auto src = getSrc();
4341 if (
auto *srcDefOp = src.getDefiningOp())
4342 if (isa<WireOp>(srcDefOp))
4344 if (
auto *dstDefOp = dst.getDefiningOp())
4345 if (isa<WireOp>(dstDefOp))
4350 return emitError(
"could not determine domain-type of destination");
4354 return emitError(
"could not determine domain-type of source");
4356 if (dstDomain != srcDomain) {
4357 auto diag = emitError()
4358 <<
"source domain type " << srcDomain
4359 <<
" does not match destination domain type " << dstDomain;
4366void WhenOp::createElseRegion() {
4367 assert(!hasElseRegion() &&
"already has an else region");
4368 getElseRegion().push_back(
new Block());
4371void WhenOp::build(OpBuilder &builder, OperationState &result, Value condition,
4372 bool withElseRegion, std::function<
void()> thenCtor,
4373 std::function<
void()> elseCtor) {
4374 OpBuilder::InsertionGuard guard(builder);
4375 result.addOperands(condition);
4378 builder.createBlock(result.addRegion());
4383 Region *elseRegion = result.addRegion();
4384 if (withElseRegion) {
4385 builder.createBlock(elseRegion);
4395LogicalResult MatchOp::verify() {
4396 FEnumType type = getInput().getType();
4399 auto numCases = getTags().size();
4400 auto numRegions = getNumRegions();
4401 if (numRegions != numCases)
4402 return emitOpError(
"expected ")
4403 << numRegions <<
" tags but got " << numCases;
4405 auto numTags = type.getNumElements();
4407 SmallDenseSet<int64_t> seen;
4408 for (
const auto &[tag, region] :
llvm::zip(getTags(), getRegions())) {
4409 auto tagIndex = size_t(cast<IntegerAttr>(tag).
getInt());
4412 if (region.getNumArguments() != 1)
4413 return emitOpError(
"region should have exactly one argument");
4416 if (tagIndex >= numTags)
4417 return emitOpError(
"the tag index ")
4418 << tagIndex <<
" is out of the range of valid tags in " << type;
4421 auto [it, inserted] = seen.insert(tagIndex);
4423 return emitOpError(
"the tag ") << type.getElementNameAttr(tagIndex)
4424 <<
" is matched more than once";
4427 auto expectedType = type.getElementTypePreservingConst(tagIndex);
4428 auto regionType = region.getArgument(0).getType();
4429 if (regionType != expectedType)
4430 return emitOpError(
"region type ")
4431 << regionType <<
" does not match the expected type "
4436 for (
size_t i = 0, e = type.getNumElements(); i < e; ++i)
4437 if (!seen.contains(i))
4438 return emitOpError(
"missing case for tag ") << type.getElementNameAttr(i);
4443void MatchOp::print(OpAsmPrinter &p) {
4444 auto input = getInput();
4445 FEnumType type = input.getType();
4446 auto regions = getRegions();
4447 p <<
" " << input <<
" : " << type;
4448 SmallVector<StringRef> elided = {
"tags"};
4449 p.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elided);
4452 for (
const auto &[tag, region] :
llvm::zip(getTags(), regions)) {
4455 p.printKeywordOrString(
4456 type.getElementName(cast<IntegerAttr>(tag).getInt()));
4458 p.printRegionArgument(region.front().getArgument(0), {},
4461 p.printRegion(region,
false);
4468ParseResult MatchOp::parse(OpAsmParser &parser, OperationState &result) {
4469 auto *
context = parser.getContext();
4470 auto &properties = result.getOrAddProperties<Properties>();
4471 OpAsmParser::UnresolvedOperand input;
4472 if (parser.parseOperand(input) || parser.parseColon())
4475 auto loc = parser.getCurrentLocation();
4477 if (parser.parseType(type))
4479 auto enumType = type_dyn_cast<FEnumType>(type);
4481 return parser.emitError(loc,
"expected enumeration type but got") << type;
4483 if (parser.resolveOperand(input, type, result.operands) ||
4484 parser.parseOptionalAttrDictWithKeyword(result.attributes) ||
4485 parser.parseLBrace())
4488 auto i32Type = IntegerType::get(
context, 32);
4489 SmallVector<Attribute> tags;
4492 if (failed(parser.parseOptionalKeyword(
"case")))
4496 auto nameLoc = parser.getCurrentLocation();
4498 OpAsmParser::Argument arg;
4499 auto *region = result.addRegion();
4500 if (parser.parseKeywordOrString(&name) || parser.parseLParen() ||
4501 parser.parseArgument(arg) || parser.parseRParen())
4505 auto index = enumType.getElementIndex(name);
4507 return parser.emitError(nameLoc,
"the tag \"")
4508 << name <<
"\" is not a member of the enumeration " << enumType;
4509 tags.push_back(IntegerAttr::get(i32Type, *index));
4512 arg.type = enumType.getElementTypePreservingConst(*index);
4513 if (parser.parseRegion(*region, arg))
4516 properties.setTags(ArrayAttr::get(
context, tags));
4518 return parser.parseRBrace();
4521void MatchOp::build(OpBuilder &builder, OperationState &result, Value input,
4523 MutableArrayRef<std::unique_ptr<Region>> regions) {
4524 auto &properties = result.getOrAddProperties<Properties>();
4525 result.addOperands(input);
4526 properties.setTags(tags);
4527 result.addRegions(regions);
4536 struct IsExprClassifier :
public ExprVisitor<IsExprClassifier, bool> {
4537 bool visitInvalidExpr(Operation *op) {
return false; }
4538 bool visitUnhandledExpr(Operation *op) {
return true; }
4544void InvalidValueOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4547 if (
auto ty = type_dyn_cast<IntType>(getType())) {
4548 const char *base = ty.isSigned() ?
"invalid_si" :
"invalid_ui";
4549 auto width = ty.getWidthOrSentinel();
4553 name = (Twine(base) + Twine(width)).str();
4554 }
else if (
auto ty = type_dyn_cast<AnalogType>(getType())) {
4555 auto width = ty.getWidthOrSentinel();
4557 name =
"invalid_analog";
4559 name = (
"invalid_analog" + Twine(width)).str();
4560 }
else if (type_isa<AsyncResetType>(getType()))
4561 name =
"invalid_asyncreset";
4562 else if (type_isa<ResetType>(getType()))
4563 name =
"invalid_reset";
4564 else if (type_isa<ClockType>(getType()))
4565 name =
"invalid_clock";
4569 setNameFn(getResult(), name);
4572void ConstantOp::print(OpAsmPrinter &p) {
4574 p.printAttributeWithoutType(getValueAttr());
4576 p.printType(getType());
4577 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4580ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
4581 auto &properties = result.getOrAddProperties<Properties>();
4584 auto loc = parser.getCurrentLocation();
4585 auto valueResult = parser.parseOptionalInteger(value);
4586 if (!valueResult.has_value())
4587 return parser.emitError(loc,
"expected integer value");
4591 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4592 parser.parseOptionalAttrDict(result.attributes))
4594 result.addTypes(resultType);
4600 if (width > value.getBitWidth()) {
4604 value = value.sext(width);
4605 }
else if (width < value.getBitWidth()) {
4608 unsigned neededBits = value.isNegative() ? value.getSignificantBits()
4609 : value.getActiveBits();
4610 if (width < neededBits)
4611 return parser.emitError(loc,
"constant out of range for result type ")
4613 value = value.trunc(width);
4617 auto intType = parser.getBuilder().getIntegerType(value.getBitWidth(),
4619 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4620 properties.setValue(valueAttr);
4624LogicalResult ConstantOp::verify() {
4628 if (width != -1 && (
int)getValue().
getBitWidth() != width)
4630 "firrtl.constant attribute bitwidth doesn't match return type");
4633 auto attrType = type_cast<IntegerType>(getValueAttr().getType());
4634 if (attrType.isSignless() || attrType.isSigned() != intType.
isSigned())
4635 return emitError(
"firrtl.constant attribute has wrong sign");
4642void ConstantOp::build(OpBuilder &builder, OperationState &result,
IntType type,
4643 const APInt &value) {
4646 assert((width == -1 || (int32_t)value.getBitWidth() == width) &&
4647 "incorrect attribute bitwidth for firrtl.constant");
4650 IntegerAttr::get(type.getContext(), APSInt(value, !type.
isSigned()));
4651 return build(builder, result, type, attr);
4656void ConstantOp::build(OpBuilder &builder, OperationState &result,
4657 const APSInt &value) {
4658 auto attr = IntegerAttr::get(builder.getContext(), value);
4660 IntType::get(builder.getContext(), value.isSigned(), value.getBitWidth());
4661 return build(builder, result, type, attr);
4664void ConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4671 SmallString<32> specialNameBuffer;
4672 llvm::raw_svector_ostream specialName(specialNameBuffer);
4674 getValue().print(specialName, intTy.
isSigned());
4676 specialName << (intTy.
isSigned() ?
"_si" :
"_ui");
4679 specialName << width;
4680 setNameFn(getResult(), specialName.str());
4683void SpecialConstantOp::print(OpAsmPrinter &p) {
4686 p << static_cast<unsigned>(getValue());
4688 p.printType(getType());
4689 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4692ParseResult SpecialConstantOp::parse(OpAsmParser &parser,
4693 OperationState &result) {
4694 auto &properties = result.getOrAddProperties<Properties>();
4698 auto loc = parser.getCurrentLocation();
4699 auto valueResult = parser.parseOptionalInteger(value);
4700 if (!valueResult.has_value())
4701 return parser.emitError(loc,
"expected integer value");
4704 if (value != 0 && value != 1)
4705 return parser.emitError(loc,
"special constants can only be 0 or 1.");
4709 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4710 parser.parseOptionalAttrDict(result.attributes))
4712 result.addTypes(resultType);
4715 auto valueAttr = parser.getBuilder().getBoolAttr(value == 1);
4716 properties.setValue(valueAttr);
4720void SpecialConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4721 SmallString<32> specialNameBuffer;
4722 llvm::raw_svector_ostream specialName(specialNameBuffer);
4724 specialName << static_cast<unsigned>(getValue());
4725 auto type = getType();
4726 if (type_isa<ClockType>(type)) {
4727 specialName <<
"_clock";
4728 }
else if (type_isa<ResetType>(type)) {
4729 specialName <<
"_reset";
4730 }
else if (type_isa<AsyncResetType>(type)) {
4731 specialName <<
"_asyncreset";
4733 setNameFn(getResult(), specialName.str());
4740 if (type.isGround()) {
4741 if (!isa<IntegerAttr>(attr)) {
4742 op->emitOpError(
"Ground type is not an integer attribute");
4747 auto attrlist = dyn_cast<ArrayAttr>(attr);
4749 op->emitOpError(
"expected array attribute for aggregate constant");
4752 if (
auto array = type_dyn_cast<FVectorType>(type)) {
4753 if (array.getNumElements() != attrlist.size()) {
4754 op->emitOpError(
"array attribute (")
4755 << attrlist.size() <<
") has wrong size for vector constant ("
4756 << array.getNumElements() <<
")";
4759 return llvm::all_of(attrlist, [&array, op](Attribute attr) {
4763 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4764 if (bundle.getNumElements() != attrlist.size()) {
4765 op->emitOpError(
"array attribute (")
4766 << attrlist.size() <<
") has wrong size for bundle constant ("
4767 << bundle.getNumElements() <<
")";
4770 for (
size_t i = 0; i < bundle.getNumElements(); ++i) {
4771 if (bundle.getElement(i).isFlip) {
4772 op->emitOpError(
"Cannot have constant bundle type with flip");
4780 op->emitOpError(
"Unknown aggregate type");
4784LogicalResult AggregateConstantOp::verify() {
4790Attribute AggregateConstantOp::getAttributeFromFieldID(uint64_t fieldID) {
4792 Attribute value = getFields();
4793 while (fieldID != 0) {
4794 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4795 auto index = bundle.getIndexForFieldID(fieldID);
4796 fieldID -= bundle.getFieldID(index);
4797 type = bundle.getElementType(index);
4798 value = cast<ArrayAttr>(value)[index];
4800 auto vector = type_cast<FVectorType>(type);
4801 auto index = vector.getIndexForFieldID(fieldID);
4802 fieldID -= vector.getFieldID(index);
4803 type = vector.getElementType();
4804 value = cast<ArrayAttr>(value)[index];
4810void FIntegerConstantOp::print(OpAsmPrinter &p) {
4812 p.printAttributeWithoutType(getValueAttr());
4813 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4816ParseResult FIntegerConstantOp::parse(OpAsmParser &parser,
4817 OperationState &result) {
4818 auto *
context = parser.getContext();
4819 auto &properties = result.getOrAddProperties<Properties>();
4821 if (parser.parseInteger(value) ||
4822 parser.parseOptionalAttrDict(result.attributes))
4824 result.addTypes(FIntegerType::get(
context));
4826 IntegerType::get(
context, value.getBitWidth(), IntegerType::Signed);
4827 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4828 properties.setValue(valueAttr);
4832ParseResult ListCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4833 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
4836 if (parser.parseOperandList(operands) ||
4837 parser.parseOptionalAttrDict(result.attributes) ||
4838 parser.parseColonType(type))
4840 result.addTypes(type);
4842 return parser.resolveOperands(operands, type.getElementType(),
4846void ListCreateOp::print(OpAsmPrinter &p) {
4848 p.printOperands(getElements());
4849 p.printOptionalAttrDict((*this)->getAttrs());
4850 p <<
" : " << getType();
4853LogicalResult ListCreateOp::verify() {
4854 if (getElements().
empty())
4857 auto elementType = getElements().front().getType();
4858 auto listElementType = getType().getElementType();
4860 return emitOpError(
"has elements of type ")
4861 <<
elementType <<
" instead of " << listElementType;
4866LogicalResult BundleCreateOp::verify() {
4867 BundleType resultType = getType();
4868 if (resultType.getNumElements() != getFields().size())
4869 return emitOpError(
"number of fields doesn't match type");
4870 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4872 resultType.getElementTypePreservingConst(i),
4873 type_cast<FIRRTLBaseType>(getOperand(i).getType())))
4874 return emitOpError(
"type of element doesn't match bundle for field ")
4875 << resultType.getElement(i).name;
4880LogicalResult VectorCreateOp::verify() {
4881 FVectorType resultType = getType();
4882 if (resultType.getNumElements() != getFields().size())
4883 return emitOpError(
"number of fields doesn't match type");
4884 auto elemTy = resultType.getElementTypePreservingConst();
4885 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4887 elemTy, type_cast<FIRRTLBaseType>(getOperand(i).getType())))
4888 return emitOpError(
"type of element doesn't match vector element");
4894UnknownValueOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
4896 auto classType = dyn_cast<ClassType>(getType());
4900 auto className = classType.getNameAttr();
4902 Operation *op = symbolTable.lookupNearestSymbolFrom(*
this, className);
4904 return emitOpError() <<
"refers to non-existent class ("
4905 << className.getAttr() <<
")";
4908 if (!isa<ClassLike>(op))
4909 return emitOpError() <<
"refers to a non-class type ("
4910 << className.getAttr() <<
")";
4919LogicalResult FEnumCreateOp::verify() {
4920 FEnumType resultType = getResult().getType();
4921 auto elementIndex = resultType.getElementIndex(
getFieldName());
4923 return emitOpError(
"label ")
4924 <<
getFieldName() <<
" is not a member of the enumeration type "
4927 resultType.getElementTypePreservingConst(*elementIndex),
4928 getInput().getType()))
4929 return emitOpError(
"type of element doesn't match enum element");
4933void FEnumCreateOp::print(OpAsmPrinter &printer) {
4936 printer <<
'(' << getInput() <<
')';
4937 SmallVector<StringRef> elidedAttrs = {
"fieldIndex"};
4938 printer.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elidedAttrs);
4940 printer.printFunctionalType(ArrayRef<Type>{getInput().getType()},
4941 ArrayRef<Type>{getResult().getType()});
4944ParseResult FEnumCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4945 auto *
context = parser.getContext();
4946 auto &properties = result.getOrAddProperties<Properties>();
4948 OpAsmParser::UnresolvedOperand input;
4949 std::string fieldName;
4950 mlir::FunctionType functionType;
4951 if (parser.parseKeywordOrString(&fieldName) || parser.parseLParen() ||
4952 parser.parseOperand(input) || parser.parseRParen() ||
4953 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4954 parser.parseType(functionType))
4957 if (functionType.getNumInputs() != 1)
4958 return parser.emitError(parser.getNameLoc(),
"single input type required");
4959 if (functionType.getNumResults() != 1)
4960 return parser.emitError(parser.getNameLoc(),
"single result type required");
4962 auto inputType = functionType.getInput(0);
4963 if (parser.resolveOperand(input, inputType, result.operands))
4966 auto outputType = functionType.getResult(0);
4967 auto enumType = type_dyn_cast<FEnumType>(outputType);
4969 return parser.emitError(parser.getNameLoc(),
4970 "output must be enum type, got ")
4972 auto fieldIndex = enumType.getElementIndex(fieldName);
4974 return parser.emitError(parser.getNameLoc(),
4975 "unknown field " + fieldName +
" in enum type ")
4978 properties.setFieldIndex(
4979 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
4981 result.addTypes(enumType);
4990LogicalResult IsTagOp::verify() {
4991 if (getFieldIndex() >= getInput().getType().base().getNumElements())
4992 return emitOpError(
"element index is greater than the number of fields in "
4997void IsTagOp::print(::mlir::OpAsmPrinter &printer) {
4998 printer <<
' ' << getInput() <<
' ';
5000 SmallVector<::llvm::StringRef, 1> elidedAttrs = {
"fieldIndex"};
5001 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
5002 printer <<
" : " << getInput().getType();
5005ParseResult IsTagOp::parse(OpAsmParser &parser, OperationState &result) {
5006 auto *
context = parser.getContext();
5007 auto &properties = result.getOrAddProperties<Properties>();
5009 OpAsmParser::UnresolvedOperand input;
5010 std::string fieldName;
5012 if (parser.parseOperand(input) || parser.parseKeywordOrString(&fieldName) ||
5013 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5014 parser.parseType(inputType))
5017 if (parser.resolveOperand(input, inputType, result.operands))
5020 auto enumType = type_dyn_cast<FEnumType>(inputType);
5022 return parser.emitError(parser.getNameLoc(),
5023 "input must be enum type, got ")
5025 auto fieldIndex = enumType.getElementIndex(fieldName);
5027 return parser.emitError(parser.getNameLoc(),
5028 "unknown field " + fieldName +
" in enum type ")
5031 properties.setFieldIndex(
5032 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5034 result.addTypes(UIntType::get(
context, 1,
false));
5039FIRRTLType IsTagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5040 OpaqueProperties properties,
5041 mlir::RegionRange regions,
5042 std::optional<Location> loc) {
5043 Adaptor adaptor(operands, attrs, properties, regions);
5044 return UIntType::get(attrs.getContext(), 1,
5045 isConst(adaptor.getInput().getType()));
5048template <
typename OpTy>
5050 auto *
context = parser.getContext();
5052 OpAsmParser::UnresolvedOperand input;
5053 std::string fieldName;
5055 if (parser.parseOperand(input) || parser.parseLSquare() ||
5056 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5057 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5058 parser.parseType(inputType))
5061 if (parser.resolveOperand(input, inputType, result.operands))
5064 auto bundleType = type_dyn_cast<typename OpTy::InputType>(inputType);
5066 return parser.emitError(parser.getNameLoc(),
5067 "input must be bundle type, got ")
5069 auto fieldIndex = bundleType.getElementIndex(fieldName);
5071 return parser.emitError(parser.getNameLoc(),
5072 "unknown field " + fieldName +
" in bundle type ")
5075 result.getOrAddProperties<
typename OpTy::Properties>().setFieldIndex(
5076 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5078 auto type = OpTy::inferReturnType(inputType, *fieldIndex, {});
5081 result.addTypes(type);
5086ParseResult SubtagOp::parse(OpAsmParser &parser, OperationState &result) {
5087 auto *
context = parser.getContext();
5089 OpAsmParser::UnresolvedOperand input;
5090 std::string fieldName;
5092 if (parser.parseOperand(input) || parser.parseLSquare() ||
5093 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5094 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5095 parser.parseType(inputType))
5098 if (parser.resolveOperand(input, inputType, result.operands))
5101 auto enumType = type_dyn_cast<FEnumType>(inputType);
5103 return parser.emitError(parser.getNameLoc(),
5104 "input must be enum type, got ")
5106 auto fieldIndex = enumType.getElementIndex(fieldName);
5108 return parser.emitError(parser.getNameLoc(),
5109 "unknown field " + fieldName +
" in enum type ")
5112 result.getOrAddProperties<Properties>().setFieldIndex(
5113 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5115 SmallVector<Type> inferredReturnTypes;
5116 if (failed(SubtagOp::inferReturnTypes(
5117 context, result.location, result.operands,
5118 result.attributes.getDictionary(
context), result.getRawProperties(),
5119 result.regions, inferredReturnTypes)))
5121 result.addTypes(inferredReturnTypes);
5126ParseResult SubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
5127 return parseSubfieldLikeOp<SubfieldOp>(parser, result);
5129ParseResult OpenSubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
5130 return parseSubfieldLikeOp<OpenSubfieldOp>(parser, result);
5133template <
typename OpTy>
5135 printer <<
' ' << op.getInput() <<
'[';
5136 printer.printKeywordOrString(op.getFieldName());
5138 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
5139 elidedAttrs.push_back(
"fieldIndex");
5140 printer.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
5141 printer <<
" : " << op.getInput().getType();
5143void SubfieldOp::print(::mlir::OpAsmPrinter &printer) {
5144 return printSubfieldLikeOp<SubfieldOp>(*
this, printer);
5146void OpenSubfieldOp::print(::mlir::OpAsmPrinter &printer) {
5147 return printSubfieldLikeOp<OpenSubfieldOp>(*
this, printer);
5150void SubtagOp::print(::mlir::OpAsmPrinter &printer) {
5151 printer <<
' ' << getInput() <<
'[';
5154 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
5155 elidedAttrs.push_back(
"fieldIndex");
5156 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
5157 printer <<
" : " << getInput().getType();
5160template <
typename OpTy>
5162 if (op.getFieldIndex() >=
5163 firrtl::type_cast<typename OpTy::InputType>(op.getInput().getType())
5165 return op.emitOpError(
"subfield element index is greater than the number "
5166 "of fields in the bundle type");
5169LogicalResult SubfieldOp::verify() {
5170 return verifySubfieldLike<SubfieldOp>(*
this);
5172LogicalResult OpenSubfieldOp::verify() {
5173 return verifySubfieldLike<OpenSubfieldOp>(*
this);
5176LogicalResult SubtagOp::verify() {
5177 if (getFieldIndex() >= getInput().getType().base().getNumElements())
5178 return emitOpError(
"subfield element index is greater than the number "
5179 "of fields in the bundle type");
5189 SmallVector<Operation *, 8> worklist({op});
5193 bool constant =
true;
5199 while (constant && !(worklist.empty()))
5200 TypeSwitch<Operation *>(worklist.pop_back_val())
5201 .Case<NodeOp, AsSIntPrimOp, AsUIntPrimOp>([&](
auto op) {
5202 if (
auto definingOp = op.getInput().getDefiningOp())
5203 worklist.push_back(definingOp);
5206 .Case<WireOp, SubindexOp, SubfieldOp>([&](
auto op) {
5207 for (
auto &use : op.getResult().getUses())
5208 worklist.push_back(use.getOwner());
5210 .Case<ConstantOp, SpecialConstantOp, AggregateConstantOp>([](
auto) {})
5211 .Default([&](
auto) { constant =
false; });
5220 if (
auto *op = value.getDefiningOp())
5225LogicalResult ConstCastOp::verify() {
5227 return emitOpError() << getInput().getType()
5228 <<
" is not 'const'-castable to "
5229 << getResult().getType();
5233FIRRTLType SubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
5234 std::optional<Location> loc) {
5235 auto inType = type_cast<BundleType>(type);
5237 if (fieldIndex >= inType.getNumElements())
5239 "subfield element index is greater than the "
5240 "number of fields in the bundle type");
5244 return inType.getElementTypePreservingConst(fieldIndex);
5247FIRRTLType OpenSubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
5248 std::optional<Location> loc) {
5249 auto inType = type_cast<OpenBundleType>(type);
5251 if (fieldIndex >= inType.getNumElements())
5253 "subfield element index is greater than the "
5254 "number of fields in the bundle type");
5258 return inType.getElementTypePreservingConst(fieldIndex);
5261bool SubfieldOp::isFieldFlipped() {
5262 BundleType bundle = getInput().getType();
5263 return bundle.getElement(getFieldIndex()).isFlip;
5265bool OpenSubfieldOp::isFieldFlipped() {
5266 auto bundle = getInput().getType();
5267 return bundle.getElement(getFieldIndex()).isFlip;
5270FIRRTLType SubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
5271 std::optional<Location> loc) {
5272 if (
auto vectorType = type_dyn_cast<FVectorType>(type)) {
5273 if (fieldIndex < vectorType.getNumElements())
5274 return vectorType.getElementTypePreservingConst();
5276 "' in vector type ", type);
5281FIRRTLType OpenSubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
5282 std::optional<Location> loc) {
5283 if (
auto vectorType = type_dyn_cast<OpenVectorType>(type)) {
5284 if (fieldIndex < vectorType.getNumElements())
5285 return vectorType.getElementTypePreservingConst();
5287 "' in vector type ", type);
5293FIRRTLType SubtagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5294 OpaqueProperties properties,
5295 mlir::RegionRange regions,
5296 std::optional<Location> loc) {
5297 Adaptor adaptor(operands, attrs, properties, regions);
5298 auto inType = type_cast<FEnumType>(adaptor.getInput().getType());
5299 auto fieldIndex = adaptor.getFieldIndex();
5301 if (fieldIndex >= inType.getNumElements())
5303 "subtag element index is greater than the "
5304 "number of fields in the enum type");
5308 auto elementType = inType.getElement(fieldIndex).type;
5312FIRRTLType SubaccessOp::inferReturnType(Type inType, Type indexType,
5313 std::optional<Location> loc) {
5314 if (!type_isa<UIntType>(indexType))
5318 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
5320 return vectorType.getElementTypePreservingConst();
5321 return vectorType.getElementType().getAllConstDroppedType();
5329 std::optional<Location> loc) {
5330 auto inType = type_cast<FEnumType>(input);
5331 return UIntType::get(inType.getContext(), inType.getTagWidth());
5334ParseResult MultibitMuxOp::parse(OpAsmParser &parser, OperationState &result) {
5335 OpAsmParser::UnresolvedOperand index;
5336 SmallVector<OpAsmParser::UnresolvedOperand, 16> inputs;
5337 Type indexType, elemType;
5339 if (parser.parseOperand(index) || parser.parseComma() ||
5340 parser.parseOperandList(inputs) ||
5341 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5342 parser.parseType(indexType) || parser.parseComma() ||
5343 parser.parseType(elemType))
5346 if (parser.resolveOperand(index, indexType, result.operands))
5349 result.addTypes(elemType);
5351 return parser.resolveOperands(inputs, elemType, result.operands);
5354void MultibitMuxOp::print(OpAsmPrinter &p) {
5355 p <<
" " << getIndex() <<
", ";
5356 p.printOperands(getInputs());
5357 p.printOptionalAttrDict((*this)->getAttrs());
5358 p <<
" : " << getIndex().getType() <<
", " << getType();
5361FIRRTLType MultibitMuxOp::inferReturnType(ValueRange operands,
5362 DictionaryAttr attrs,
5363 OpaqueProperties properties,
5364 mlir::RegionRange regions,
5365 std::optional<Location> loc) {
5366 if (operands.size() < 2)
5370 if (!llvm::all_of(operands.drop_front(2), [&](
auto op) {
5371 return operands[1].getType() == op.getType();
5375 return type_cast<FIRRTLType>(operands[1].getType());
5382LogicalResult ObjectSubfieldOp::inferReturnTypes(
5383 MLIRContext *
context, std::optional<mlir::Location> location,
5384 ValueRange operands, DictionaryAttr attributes, OpaqueProperties properties,
5385 RegionRange regions, llvm::SmallVectorImpl<Type> &inferredReturnTypes) {
5387 inferReturnType(operands, attributes, properties, regions, location);
5390 inferredReturnTypes.push_back(type);
5394Type ObjectSubfieldOp::inferReturnType(Type inType, uint32_t fieldIndex,
5395 std::optional<Location> loc) {
5396 auto classType = dyn_cast<ClassType>(inType);
5400 if (classType.getNumElements() <= fieldIndex)
5402 "number of fields in the object");
5403 return classType.getElement(fieldIndex).type;
5406void ObjectSubfieldOp::print(OpAsmPrinter &p) {
5407 auto input = getInput();
5408 auto classType = input.getType();
5409 p <<
' ' << input <<
"[";
5410 p.printKeywordOrString(classType.getElement(getIndex()).name);
5412 p.printOptionalAttrDict((*this)->getAttrs(), std::array{StringRef(
"index")});
5413 p <<
" : " << classType;
5416ParseResult ObjectSubfieldOp::parse(OpAsmParser &parser,
5417 OperationState &result) {
5418 auto *
context = parser.getContext();
5420 OpAsmParser::UnresolvedOperand input;
5421 std::string fieldName;
5422 ClassType inputType;
5423 if (parser.parseOperand(input) || parser.parseLSquare() ||
5424 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5425 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5426 parser.parseType(inputType) ||
5427 parser.resolveOperand(input, inputType, result.operands))
5430 auto index = inputType.getElementIndex(fieldName);
5432 return parser.emitError(parser.getNameLoc(),
5433 "unknown field " + fieldName +
" in class type ")
5435 result.getOrAddProperties<Properties>().setIndex(
5436 IntegerAttr::get(IntegerType::get(
context, 32), *index));
5438 SmallVector<Type> inferredReturnTypes;
5439 if (failed(inferReturnTypes(
context, result.location, result.operands,
5440 result.attributes.getDictionary(
context),
5441 result.getRawProperties(), result.regions,
5442 inferredReturnTypes)))
5444 result.addTypes(inferredReturnTypes);
5461 int32_t &rhsWidth,
bool &isConstResult,
5462 std::optional<Location> loc) {
5464 auto lhsi = type_dyn_cast<IntType>(lhs);
5465 auto rhsi = type_dyn_cast<IntType>(rhs);
5466 if (!lhsi || !rhsi || lhsi.isSigned() != rhsi.isSigned()) {
5469 mlir::emitError(*loc,
"second operand must be an integer type, not ")
5471 else if (!lhsi && rhsi)
5472 mlir::emitError(*loc,
"first operand must be an integer type, not ")
5474 else if (!lhsi && !rhsi)
5475 mlir::emitError(*loc,
"operands must be integer types, not ")
5476 << lhs <<
" and " << rhs;
5478 mlir::emitError(*loc,
"operand signedness must match");
5483 lhsWidth = lhsi.getWidthOrSentinel();
5484 rhsWidth = rhsi.getWidthOrSentinel();
5485 isConstResult = lhsi.isConst() && rhsi.isConst();
5490 assert(op->getNumOperands() == 2 &&
5491 "SameOperandsIntTypeKind on non-binary op");
5492 int32_t lhsWidth, rhsWidth;
5495 op->getOperand(1).getType(), lhsWidth,
5496 rhsWidth, isConstResult, op->getLoc()));
5500 std::optional<Location> loc) {
5501 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5502 bool isConstResult =
false;
5506 if (lhsWidth != -1 && rhsWidth != -1)
5507 resultWidth = std::max(lhsWidth, rhsWidth) + 1;
5508 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5513 std::optional<Location> loc) {
5514 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5515 bool isConstResult =
false;
5519 if (lhsWidth != -1 && rhsWidth != -1)
5520 resultWidth = lhsWidth + rhsWidth;
5522 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5527 std::optional<Location> loc) {
5528 int32_t lhsWidth, rhsWidth;
5529 bool isConstResult =
false;
5534 if (type_isa<UIntType>(lhs))
5535 return UIntType::get(lhs.getContext(), lhsWidth, isConstResult);
5538 int32_t resultWidth = lhsWidth != -1 ? lhsWidth + 1 : -1;
5539 return SIntType::get(lhs.getContext(), resultWidth, isConstResult);
5543 std::optional<Location> loc) {
5544 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5545 bool isConstResult =
false;
5549 if (lhsWidth != -1 && rhsWidth != -1)
5550 resultWidth = std::min(lhsWidth, rhsWidth);
5551 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5556 std::optional<Location> loc) {
5557 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5558 bool isConstResult =
false;
5562 if (lhsWidth != -1 && rhsWidth != -1) {
5563 resultWidth = std::max(lhsWidth, rhsWidth);
5564 if (lhsWidth == resultWidth && lhs.
isConst() == isConstResult &&
5567 if (rhsWidth == resultWidth && rhs.
isConst() == isConstResult &&
5571 return UIntType::get(lhs.getContext(), resultWidth, isConstResult);
5575 std::optional<Location> loc) {
5576 if (!type_isa<FVectorType>(lhs) || !type_isa<FVectorType>(rhs))
5579 auto lhsVec = type_cast<FVectorType>(lhs);
5580 auto rhsVec = type_cast<FVectorType>(rhs);
5582 if (lhsVec.getNumElements() != rhsVec.getNumElements())
5587 rhsVec.getElementTypePreservingConst(), loc);
5590 auto elemBaseType = type_cast<FIRRTLBaseType>(elemType);
5591 return FVectorType::get(elemBaseType, lhsVec.getNumElements(),
5592 lhsVec.isConst() && rhsVec.isConst() &&
5593 elemBaseType.isConst());
5597 std::optional<Location> loc) {
5598 return UIntType::get(lhs.getContext(), 1,
isConst(lhs) &&
isConst(rhs));
5601FIRRTLType CatPrimOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5602 OpaqueProperties properties,
5603 mlir::RegionRange regions,
5604 std::optional<Location> loc) {
5606 if (operands.empty())
5607 return UIntType::get(attrs.getContext(), 0);
5610 bool isSigned = type_isa<SIntType>(operands[0].getType());
5611 for (
auto operand : operands) {
5612 auto type = type_dyn_cast<IntType>(operand.getType());
5615 if (type.isSigned() != isSigned)
5617 "all operands must have same signedness");
5621 int32_t resultWidth = 0;
5622 bool isConstResult =
true;
5624 for (
auto operand : operands) {
5625 auto type = type_cast<IntType>(operand.getType());
5626 int32_t width = type.getWidthOrSentinel();
5633 if (resultWidth != -1)
5634 resultWidth += width;
5637 isConstResult &= type.isConst();
5641 return UIntType::get(attrs.getContext(), resultWidth, isConstResult);
5645 std::optional<Location> loc) {
5646 auto lhsi = type_dyn_cast<IntType>(lhs);
5647 auto rhsui = type_dyn_cast<UIntType>(rhs);
5648 if (!rhsui || !lhsi)
5650 loc,
"first operand should be integer, second unsigned int");
5654 auto width = lhsi.getWidthOrSentinel();
5655 if (width == -1 || !rhsui.getWidth().has_value()) {
5658 auto amount = *rhsui.getWidth();
5661 "shift amount too large: second operand of "
5662 "dshl is wider than 31 bits");
5663 int64_t newWidth = (int64_t)width + ((int64_t)1 << amount) - 1;
5664 if (newWidth > INT32_MAX)
5666 loc,
"shift amount too large: first operand shifted by maximum "
5667 "amount exceeds maximum width");
5670 return IntType::get(lhs.getContext(), lhsi.isSigned(), width,
5671 lhsi.
isConst() && rhsui.isConst());
5675 std::optional<Location> loc) {
5676 auto lhsi = type_dyn_cast<IntType>(lhs);
5677 auto rhsu = type_dyn_cast<UIntType>(rhs);
5680 loc,
"first operand should be integer, second unsigned int");
5681 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5685 std::optional<Location> loc) {
5686 auto lhsi = type_dyn_cast<IntType>(lhs);
5687 auto rhsu = type_dyn_cast<UIntType>(rhs);
5690 loc,
"first operand should be integer, second unsigned int");
5691 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5699 std::optional<Location> loc) {
5700 return UIntType::get(input.getContext(), 32);
5704 std::optional<Location> loc) {
5705 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5708 int32_t width = base.getBitWidthOrSentinel();
5711 return SIntType::get(input.getContext(), width, base.
isConst());
5715 std::optional<Location> loc) {
5716 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5719 int32_t width = base.getBitWidthOrSentinel();
5722 return UIntType::get(input.getContext(), width, base.
isConst());
5726 std::optional<Location> loc) {
5727 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5730 "operand must be single bit scalar base type");
5731 int32_t width = base.getBitWidthOrSentinel();
5732 if (width == -2 || width == 0 || width > 1)
5734 return AsyncResetType::get(input.getContext(), base.
isConst());
5738 std::optional<Location> loc) {
5739 return ClockType::get(input.getContext(),
isConst(input));
5743 std::optional<Location> loc) {
5744 if (
auto uiType = type_dyn_cast<UIntType>(input)) {
5745 auto width = uiType.getWidthOrSentinel();
5748 return SIntType::get(input.getContext(), width, uiType.
isConst());
5751 if (type_isa<SIntType>(input))
5758 std::optional<Location> loc) {
5759 auto inputi = type_dyn_cast<IntType>(input);
5762 int32_t width = inputi.getWidthOrSentinel();
5765 return SIntType::get(input.getContext(), width, inputi.
isConst());
5769 std::optional<Location> loc) {
5770 auto inputi = type_dyn_cast<IntType>(input);
5773 if (isa<UIntType>(inputi))
5775 return UIntType::get(input.getContext(), inputi.getWidthOrSentinel(),
5780 std::optional<Location> loc) {
5781 return UIntType::get(input.getContext(), 1,
isConst(input));
5790 std::optional<Location> loc) {
5791 auto inputi = type_dyn_cast<IntType>(input);
5794 loc,
"input type should be the int type but got ", input);
5799 loc,
"high must be equal or greater than low, but got high = ", high,
5807 int32_t width = inputi.getWidthOrSentinel();
5808 if (width != -1 && high >= width)
5811 "high must be smaller than the width of input, but got high = ", high,
5812 ", width = ", width);
5814 return UIntType::get(input.getContext(), high - low + 1, inputi.
isConst());
5818 std::optional<Location> loc) {
5820 auto inputi = type_dyn_cast<IntType>(input);
5821 if (amount < 0 || !inputi)
5823 loc,
"operand must have integer type and amount must be >= 0");
5825 int32_t width = inputi.getWidthOrSentinel();
5826 if (width != -1 && amount > width)
5829 return UIntType::get(input.getContext(), amount, inputi.
isConst());
5844 bool isConstCondition,
5845 std::optional<Location> loc) {
5851 if (high.getTypeID() != low.getTypeID())
5852 return emitInferRetTypeError<FIRRTLBaseType>(
5853 loc,
"incompatible mux operand types, true value type: ", high,
5854 ", false value type: ", low);
5856 bool outerTypeIsConst = isConstCondition && low.
isConst() && high.
isConst();
5861 if (type_isa<IntType>(low)) {
5866 if (highWidth == -1)
5868 return (lowWidth > highWidth ? low : high).getConstType(outerTypeIsConst);
5873 auto highEnum = type_dyn_cast<FEnumType>(high);
5874 auto lowEnum = type_dyn_cast<FEnumType>(low);
5875 if (lowEnum && highEnum) {
5876 if (lowEnum.getNumElements() != highEnum.getNumElements())
5877 return emitInferRetTypeError<FIRRTLBaseType>(
5878 loc,
"incompatible mux operand types, true value type: ", high,
5879 ", false value type: ", low);
5880 SmallVector<FEnumType::EnumElement> elements;
5881 for (
auto [high, low] : llvm::zip_equal(highEnum, lowEnum)) {
5883 if (high.name != low.name || high.value != low.value)
5884 return emitInferRetTypeError<FIRRTLBaseType>(
5885 loc,
"incompatible mux operand types, true value type: ", highEnum,
5886 ", false value type: ", lowEnum);
5893 elements.emplace_back(high.name, high.value, inner);
5895 return FEnumType::get(high.getContext(), elements, outerTypeIsConst);
5899 auto highVector = type_dyn_cast<FVectorType>(high);
5900 auto lowVector = type_dyn_cast<FVectorType>(low);
5901 if (highVector && lowVector &&
5902 highVector.getNumElements() == lowVector.getNumElements()) {
5904 lowVector.getElementTypePreservingConst(),
5905 isConstCondition, loc);
5908 return FVectorType::get(inner, lowVector.getNumElements(),
5913 auto highBundle = type_dyn_cast<BundleType>(high);
5914 auto lowBundle = type_dyn_cast<BundleType>(low);
5915 if (highBundle && lowBundle) {
5916 auto highElements = highBundle.getElements();
5917 auto lowElements = lowBundle.getElements();
5920 SmallVector<BundleType::BundleElement> newElements;
5922 bool failed =
false;
5924 if (highElements[i].name != lowElements[i].name ||
5925 highElements[i].isFlip != lowElements[i].isFlip) {
5929 auto element = highElements[i];
5931 highBundle.getElementTypePreservingConst(i),
5932 lowBundle.getElementTypePreservingConst(i), isConstCondition, loc);
5935 newElements.push_back(element);
5938 return BundleType::get(low.getContext(), newElements, outerTypeIsConst);
5940 return emitInferRetTypeError<FIRRTLBaseType>(
5941 loc,
"incompatible mux operand bundle fields, true value type: ", high,
5942 ", false value type: ", low);
5947 return emitInferRetTypeError<FIRRTLBaseType>(
5948 loc,
"invalid mux operand types, true value type: ", high,
5949 ", false value type: ", low);
5954 std::optional<Location> loc) {
5955 auto highType = type_dyn_cast<FIRRTLBaseType>(high);
5956 auto lowType = type_dyn_cast<FIRRTLBaseType>(low);
5957 if (!highType || !lowType)
5962FIRRTLType Mux2CellIntrinsicOp::inferReturnType(ValueRange operands,
5963 DictionaryAttr attrs,
5964 OpaqueProperties properties,
5965 mlir::RegionRange regions,
5966 std::optional<Location> loc) {
5967 auto highType = type_dyn_cast<FIRRTLBaseType>(operands[1].getType());
5968 auto lowType = type_dyn_cast<FIRRTLBaseType>(operands[2].getType());
5969 if (!highType || !lowType)
5975FIRRTLType Mux4CellIntrinsicOp::inferReturnType(ValueRange operands,
5976 DictionaryAttr attrs,
5977 OpaqueProperties properties,
5978 mlir::RegionRange regions,
5979 std::optional<Location> loc) {
5980 SmallVector<FIRRTLBaseType> types;
5982 for (
unsigned i = 1; i < 5; i++) {
5983 types.push_back(type_dyn_cast<FIRRTLBaseType>(operands[i].getType()));
5988 isConst(operands[0].getType()), loc);
5992 result = types.back();
5999 std::optional<Location> loc) {
6000 auto inputi = type_dyn_cast<IntType>(input);
6001 if (amount < 0 || !inputi)
6003 loc,
"pad input must be integer and amount must be >= 0");
6005 int32_t width = inputi.getWidthOrSentinel();
6009 width = std::max<int32_t>(width, amount);
6010 return IntType::get(input.getContext(), inputi.isSigned(), width,
6015 std::optional<Location> loc) {
6016 auto inputi = type_dyn_cast<IntType>(input);
6017 if (amount < 0 || !inputi)
6019 loc,
"shl input must be integer and amount must be >= 0");
6021 int32_t width = inputi.getWidthOrSentinel();
6025 return IntType::get(input.getContext(), inputi.isSigned(), width,
6030 std::optional<Location> loc) {
6031 auto inputi = type_dyn_cast<IntType>(input);
6032 if (amount < 0 || !inputi)
6034 loc,
"shr input must be integer and amount must be >= 0");
6036 int32_t width = inputi.getWidthOrSentinel();
6039 int32_t minWidth = inputi.isUnsigned() ? 0 : 1;
6040 width = std::max<int32_t>(minWidth, width - amount);
6043 return IntType::get(input.getContext(), inputi.isSigned(), width,
6048 std::optional<Location> loc) {
6050 auto inputi = type_dyn_cast<IntType>(input);
6051 if (amount < 0 || !inputi)
6053 loc,
"tail input must be integer and amount must be >= 0");
6055 int32_t width = inputi.getWidthOrSentinel();
6059 loc,
"amount must be less than or equal operand width");
6070void VerbatimExprOp::getAsmResultNames(
6071 function_ref<
void(Value, StringRef)> setNameFn) {
6075 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
6076 auto name = getText();
6078 if (name.starts_with(
"`"))
6079 name = name.drop_front();
6080 name = name.take_while(isOkCharacter);
6082 setNameFn(getResult(), name);
6089void VerbatimWireOp::getAsmResultNames(
6090 function_ref<
void(Value, StringRef)> setNameFn) {
6094 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
6095 auto name = getText();
6097 if (name.starts_with(
"`"))
6098 name = name.drop_front();
6099 name = name.take_while(isOkCharacter);
6101 setNameFn(getResult(), name);
6112 op->emitError() <<
"unknown width is not allowed for DPI";
6113 return WalkResult::interrupt();
6115 if (width == 1 || width == 8 || width == 16 || width == 32 ||
6117 return WalkResult::advance();
6119 <<
"integer types used by DPI functions must have a "
6120 "specific bit width; "
6121 "it must be equal to 1(bit), 8(byte), 16(shortint), "
6122 "32(int), 64(longint) "
6123 "or greater than 64, but got "
6125 return WalkResult::interrupt();
6130LogicalResult DPICallIntrinsicOp::verify() {
6131 if (
auto inputNames = getInputNames()) {
6132 if (getInputs().size() != inputNames->size())
6133 return emitError() <<
"inputNames has " << inputNames->size()
6134 <<
" elements but there are " << getInputs().size()
6135 <<
" input arguments";
6137 if (
auto outputName = getOutputName())
6138 if (getNumResults() == 0)
6139 return emitError() <<
"output name is given but there is no result";
6141 auto checkType = [
this](Type type) {
6144 return success(llvm::all_of(this->getResultTypes(), checkType) &&
6145 llvm::all_of(this->getOperandTypes(), checkType));
6148SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
6149DPICallIntrinsicOp::computeDataFlow() {
6153 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
6155 for (
auto operand : getOperands()) {
6156 auto type = type_cast<FIRRTLBaseType>(operand.getType());
6158 SmallVector<circt::FieldRef> operandFields;
6161 operandFields.push_back(baseFieldRef.getSubField(dstIndex));
6165 for (
auto result : getResults())
6168 for (
auto field : operandFields)
6169 deps.emplace_back(
circt::
FieldRef(result, dstIndex), field);
6179LogicalResult HWStructCastOp::verify() {
6181 BundleType bundleType;
6182 hw::StructType structType;
6183 if ((bundleType = type_dyn_cast<BundleType>(getOperand().getType()))) {
6184 structType = dyn_cast<hw::StructType>(getType());
6186 return emitError(
"result type must be a struct");
6187 }
else if ((bundleType = type_dyn_cast<BundleType>(getType()))) {
6188 structType = dyn_cast<hw::StructType>(getOperand().getType());
6190 return emitError(
"operand type must be a struct");
6192 return emitError(
"either source or result type must be a bundle type");
6195 auto firFields = bundleType.getElements();
6196 auto hwFields = structType.getElements();
6197 if (firFields.size() != hwFields.size())
6198 return emitError(
"bundle and struct have different number of fields");
6200 for (
size_t findex = 0, fend = firFields.size(); findex < fend; ++findex) {
6201 if (firFields[findex].name.getValue() != hwFields[findex].name)
6202 return emitError(
"field names don't match '")
6203 << firFields[findex].name.getValue() <<
"', '"
6204 << hwFields[findex].name.getValue() <<
"'";
6208 if (firWidth > 0 && hwWidth > 0 && firWidth != hwWidth)
6209 return emitError(
"size of field '")
6210 << hwFields[findex].name.getValue() <<
"' don't match " << firWidth
6217LogicalResult BitCastOp::verify() {
6218 auto inTypeBits =
getBitWidth(getInput().getType(),
true);
6220 if (inTypeBits.has_value() && resTypeBits.has_value()) {
6222 if (*inTypeBits == *resTypeBits) {
6225 return emitError(
"cannot cast non-'const' input type ")
6226 << getOperand().getType() <<
" to 'const' result type "
6230 return emitError(
"the bitwidth of input (")
6231 << *inTypeBits <<
") and result (" << *resTypeBits
6234 if (!inTypeBits.has_value())
6235 return emitError(
"bitwidth cannot be determined for input operand type ")
6236 << getInput().getType();
6237 return emitError(
"bitwidth cannot be determined for result type ")
6248 NamedAttrList &resultAttrs) {
6249 auto result = parser.parseOptionalAttrDict(resultAttrs);
6250 if (!resultAttrs.get(
"annotations"))
6251 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
6257 DictionaryAttr attr,
6258 ArrayRef<StringRef> extraElides = {}) {
6259 SmallVector<StringRef> elidedAttrs(extraElides.begin(), extraElides.end());
6261 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
6262 elidedAttrs.push_back(
"annotations");
6264 elidedAttrs.push_back(
"nameKind");
6266 p.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
6272 NamedAttrList &resultAttrs) {
6275 if (!resultAttrs.get(
"portAnnotations")) {
6276 SmallVector<Attribute, 16> portAnnotations(
6277 parser.getNumResults(), parser.getBuilder().getArrayAttr({}));
6278 resultAttrs.append(
"portAnnotations",
6279 parser.getBuilder().getArrayAttr(portAnnotations));
6286 DictionaryAttr attr,
6287 ArrayRef<StringRef> extraElides = {}) {
6288 SmallVector<StringRef, 2> elidedAttrs(extraElides.begin(), extraElides.end());
6290 if (llvm::all_of(op->getAttrOfType<ArrayAttr>(
"portAnnotations"),
6291 [&](Attribute a) { return cast<ArrayAttr>(a).empty(); }))
6292 elidedAttrs.push_back(
"portAnnotations");
6301 firrtl::NameKindEnumAttr &result) {
6304 if (!parser.parseOptionalKeyword(&keyword,
6305 {
"interesting_name",
"droppable_name"})) {
6306 auto kind = symbolizeNameKindEnum(keyword);
6307 result = NameKindEnumAttr::get(parser.getContext(), kind.value());
6313 NameKindEnumAttr::get(parser.getContext(), NameKindEnum::DroppableName);
6318 firrtl::NameKindEnumAttr attr,
6319 ArrayRef<StringRef> extraElides = {}) {
6320 if (attr.getValue() != NameKindEnum::DroppableName)
6321 p <<
" " << stringifyNameKindEnum(attr.getValue());
6329 NamedAttrList &resultAttrs) {
6337 DictionaryAttr attrs) {
6338 SmallVector<StringRef, 4> elides;
6340 elides.push_back(Forceable::getForceableAttrName());
6349static ParseResult
parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs) {
6354static void printMemOp(OpAsmPrinter &p, Operation *op, DictionaryAttr attr) {
6365 if (ClassType::parseInterface(parser, type))
6372 type.printInterface(p);
6380 NamedAttrList &resultAttrs) {
6381 auto result = p.parseOptionalAttrDict(resultAttrs);
6382 if (!resultAttrs.get(
"name"))
6383 resultAttrs.append(
"name", p.getBuilder().getStringAttr(
""));
6389 DictionaryAttr attr,
6390 ArrayRef<StringRef> extraElides = {}) {
6391 SmallVector<StringRef> elides(extraElides.begin(), extraElides.end());
6392 if (op->getAttrOfType<StringAttr>(
"name").getValue().empty())
6393 elides.push_back(
"name");
6395 p.printOptionalAttrDict(op->getAttrs(), elides);
6399 NamedAttrList &resultAttrs) {
6404 DictionaryAttr attr) {
6409 NamedAttrList &resultAttrs) {
6414 DictionaryAttr attr) {
6416 {
"formatString",
"outputFile",
"operandSegmentSizes"});
6424 DictionaryAttr attr) {
6433 DictionaryAttr attr) {
6442 OpAsmSetValueNameFn setNameFn) {
6445 if (op->getNumResults() == 1)
6446 if (
auto nameAttr = op->getAttrOfType<StringAttr>(
"name"))
6447 setNameFn(op->getResult(0), nameAttr.getValue());
6450void AddPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6454void AndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6458void AndRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6462void SizeOfIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6465void AsAsyncResetPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6468void AsClockPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6471void AsSIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6474void AsUIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6477void BitsPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6480void CatPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6483void CvtPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6486void DShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6489void DShlwPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6492void DShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6495void DivPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6498void EQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6501void GEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6504void GTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6507void GenericIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6510void HeadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6513void IntegerAddOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6516void IntegerMulOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6519void IntegerShrOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6522void IntegerShlOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6525void IsTagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6528void IsXIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6531void PlusArgsValueIntrinsicOp::getAsmResultNames(
6532 OpAsmSetValueNameFn setNameFn) {
6535void PlusArgsTestIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6538void LEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6541void LTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6544void MulPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6547void MultibitMuxOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6550void MuxPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6553void Mux4CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6556void Mux2CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6559void NEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6562void NegPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6565void NotPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6568void OrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6571void OrRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6574void PadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6577void RemPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6580void ShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6583void ShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6587void SubPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6591void SubaccessOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6595void SubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6599void OpenSubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6603void SubtagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6607void SubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6611void OpenSubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6615void TagExtractOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6619void TailPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6623void XorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6627void XorRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6631void UninferredResetCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6635void ConstCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6639void ElementwiseXorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6643void ElementwiseOrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6647void ElementwiseAndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6655void RefCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6659void RefResolveOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6663void RefSendOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6667void RefSubOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6671void RWProbeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6675FIRRTLType RefResolveOp::inferReturnType(ValueRange operands,
6676 DictionaryAttr attrs,
6677 OpaqueProperties properties,
6678 mlir::RegionRange regions,
6679 std::optional<Location> loc) {
6680 Type inType = operands[0].getType();
6681 auto inRefType = type_dyn_cast<RefType>(inType);
6684 loc,
"ref.resolve operand must be ref type, not ", inType);
6685 return inRefType.getType();
6688FIRRTLType RefSendOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
6689 OpaqueProperties properties,
6690 mlir::RegionRange regions,
6691 std::optional<Location> loc) {
6692 Type inType = operands[0].getType();
6693 auto inBaseType = type_dyn_cast<FIRRTLBaseType>(inType);
6696 loc,
"ref.send operand must be base type, not ", inType);
6697 return RefType::get(inBaseType.getPassiveType());
6700FIRRTLType RefSubOp::inferReturnType(Type type, uint32_t fieldIndex,
6701 std::optional<Location> loc) {
6702 auto refType = type_dyn_cast<RefType>(type);
6705 auto inType = refType.getType();
6711 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
6712 if (fieldIndex < vectorType.getNumElements())
6713 return RefType::get(
6714 vectorType.getElementType().getConstType(
6715 vectorType.isConst() || vectorType.getElementType().isConst()),
6716 refType.getForceable(), refType.getLayer());
6718 "' in RefType of vector type ", refType);
6720 if (
auto bundleType = type_dyn_cast<BundleType>(inType)) {
6721 if (fieldIndex >= bundleType.getNumElements()) {
6723 "subfield element index is greater than "
6724 "the number of fields in the bundle type");
6726 return RefType::get(
6727 bundleType.getElement(fieldIndex)
6729 bundleType.isConst() ||
6730 bundleType.getElement(fieldIndex).type.isConst()),
6731 refType.getForceable(), refType.getLayer());
6735 loc,
"ref.sub op requires a RefType of vector or bundle base type");
6738LogicalResult RefCastOp::verify() {
6742 getOperation(), srcLayers, dstLayers,
6743 "cannot discard layer requirements of input reference",
6744 "discarding layer requirements");
6747LogicalResult RefResolveOp::verify() {
6751 getOperation(), srcLayers, dstLayers,
6752 "ambient layers are insufficient to resolve reference");
6756 auto targetRef = getTarget();
6757 if (targetRef.getModule() !=
6758 (*this)->getParentOfType<FModuleLike>().getModuleNameAttr())
6759 return emitOpError() <<
"has non-local target";
6761 auto target = ns.
lookup(targetRef);
6763 return emitOpError() <<
"has target that cannot be resolved: " << targetRef;
6765 auto checkFinalType = [&](
auto type, Location loc) -> LogicalResult {
6770 auto baseType = type_dyn_cast<FIRRTLBaseType>(fType);
6771 if (!baseType || baseType.getPassiveType() != getType().getType()) {
6772 auto diag = emitOpError(
"has type mismatch: target resolves to ")
6773 << fType <<
" instead of expected " << getType().getType();
6774 diag.attachNote(loc) <<
"target resolves here";
6779 if (target.isPort()) {
6780 auto mod = cast<FModuleLike>(target.getOp());
6781 return checkFinalType(mod.getPortType(target.getPort()),
6782 mod.getPortLocation(target.getPort()));
6784 hw::InnerSymbolOpInterface symOp =
6785 cast<hw::InnerSymbolOpInterface>(target.getOp());
6786 if (!symOp.getTargetResult())
6787 return emitOpError(
"has target that cannot be probed")
6788 .attachNote(symOp.getLoc())
6789 .append(
"target resolves here");
6791 symOp.getTargetResult().getParentBlock()->findAncestorOpInBlock(**
this);
6792 if (!ancestor || !symOp->isBeforeInBlock(ancestor))
6793 return emitOpError(
"is not dominated by target")
6794 .attachNote(symOp.getLoc())
6795 .append(
"target here");
6796 return checkFinalType(symOp.getTargetResult().getType(), symOp.getLoc());
6799LogicalResult RefForceOp::verify() {
6803 getOperation(), destLayers, ambientLayers,
6804 "has insufficient ambient layers to force its reference");
6807LogicalResult RefForceInitialOp::verify() {
6811 getOperation(), destLayers, ambientLayers,
6812 "has insufficient ambient layers to force its reference");
6815LogicalResult RefReleaseOp::verify() {
6819 getOperation(), destLayers, ambientLayers,
6820 "has insufficient ambient layers to release its reference");
6823LogicalResult RefReleaseInitialOp::verify() {
6827 getOperation(), destLayers, ambientLayers,
6828 "has insufficient ambient layers to release its reference");
6831LogicalResult XMRRefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6832 auto *target = symbolTable.lookupNearestSymbolFrom(*
this, getRefAttr());
6834 return emitOpError(
"has an invalid symbol reference");
6836 if (!isa<hw::HierPathOp>(target))
6837 return emitOpError(
"does not target a hierpath op");
6843LogicalResult XMRDerefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6844 auto *target = symbolTable.lookupNearestSymbolFrom(*
this, getRefAttr());
6846 return emitOpError(
"has an invalid symbol reference");
6848 if (!isa<hw::HierPathOp>(target))
6849 return emitOpError(
"does not target a hierpath op");
6859LogicalResult LayerBlockOp::verify() {
6860 auto layerName = getLayerName();
6861 auto *parentOp = (*this)->getParentOp();
6864 while (isa<WhenOp, MatchOp>(parentOp))
6865 parentOp = parentOp->getParentOp();
6869 auto nestedReferences = layerName.getNestedReferences();
6870 if (nestedReferences.empty()) {
6871 if (!isa<FModuleOp>(parentOp)) {
6872 auto diag = emitOpError() <<
"has an un-nested layer symbol, but does "
6873 "not have a 'firrtl.module' op as a parent";
6874 return diag.attachNote(parentOp->getLoc())
6875 <<
"illegal parent op defined here";
6878 auto parentLayerBlock = dyn_cast<LayerBlockOp>(parentOp);
6879 if (!parentLayerBlock) {
6880 auto diag = emitOpError()
6881 <<
"has a nested layer symbol, but does not have a '"
6882 << getOperationName() <<
"' op as a parent'";
6883 return diag.attachNote(parentOp->getLoc())
6884 <<
"illegal parent op defined here";
6886 auto parentLayerBlockName = parentLayerBlock.getLayerName();
6887 if (parentLayerBlockName.getRootReference() !=
6888 layerName.getRootReference() ||
6889 parentLayerBlockName.getNestedReferences() !=
6890 layerName.getNestedReferences().drop_back()) {
6891 auto diag = emitOpError() <<
"is nested under an illegal layer block";
6892 return diag.attachNote(parentLayerBlock->getLoc())
6893 <<
"illegal parent layer block defined here";
6899 auto result = getBody(0)->walk<mlir::WalkOrder::PreOrder>(
6900 [&](Operation *op) -> WalkResult {
6902 if (isa<LayerBlockOp>(op))
6903 return WalkResult::skip();
6907 for (
auto operand : op->getOperands()) {
6909 if (
auto *definingOp = operand.getDefiningOp())
6913 auto type = operand.getType();
6916 if (isa<PropertyType>(type)) {
6917 auto diag = emitOpError() <<
"captures a property operand";
6918 diag.attachNote(operand.getLoc()) <<
"operand is defined here";
6919 diag.attachNote(op->getLoc()) <<
"operand is used here";
6920 return WalkResult::interrupt();
6925 if (
auto connect = dyn_cast<FConnectLike>(op)) {
6927 if (isa<RefDefineOp>(connect))
6928 return WalkResult::advance();
6935 bool passive =
true;
6937 type_dyn_cast<FIRRTLBaseType>(
connect.getDest().getType()))
6938 passive = type.isPassive();
6947 return WalkResult::advance();
6950 return WalkResult::advance();
6954 <<
"connects to a destination which is defined outside its "
6955 "enclosing layer block";
6956 diag.attachNote(
getLoc()) <<
"enclosing layer block is defined here";
6957 diag.attachNote(dest.getLoc()) <<
"destination is defined here";
6958 return WalkResult::interrupt();
6961 return WalkResult::advance();
6964 return failure(result.wasInterrupted());
6968LayerBlockOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6970 symbolTable.lookupNearestSymbolFrom<LayerOp>(*
this, getLayerNameAttr());
6972 return emitOpError(
"invalid symbol reference");
6982void TimeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6983 setNameFn(getResult(),
"time");
6986void HierarchicalModuleNameOp::getAsmResultNames(
6987 OpAsmSetValueNameFn setNameFn) {
6988 setNameFn(getResult(),
"hierarchicalmodulename");
6991ParseResult FPrintFOp::parse(::mlir::OpAsmParser &parser,
6992 ::mlir::OperationState &result) {
6994 OpAsmParser::UnresolvedOperand clock, cond;
6995 if (parser.parseOperand(clock) || parser.parseComma() ||
6996 parser.parseOperand(cond) || parser.parseComma())
7000 [&parser](llvm::SMLoc &loc, StringAttr &result,
7001 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &operands)
7003 loc = parser.getCurrentLocation();
7006 std::string resultStr;
7007 if (parser.parseString(&resultStr))
7009 result = parser.getBuilder().getStringAttr(resultStr);
7012 if (parser.parseOperandList(operands, AsmParser::Delimiter::OptionalParen))
7018 SmallVector<OpAsmParser::UnresolvedOperand> outputFileSubstitutions,
7020 llvm::SMLoc outputFileLoc, formatStringLoc;
7024 result.getOrAddProperties<FPrintFOp::Properties>().outputFile,
7025 outputFileSubstitutions) ||
7026 parser.parseComma() ||
7029 result.getOrAddProperties<FPrintFOp::Properties>().formatString,
7037 Type clockType, condType;
7038 SmallVector<Type> restTypes;
7040 if (parser.parseColon() || parser.parseType(clockType) ||
7041 parser.parseComma() || parser.parseType(condType))
7044 if (succeeded(parser.parseOptionalComma())) {
7045 if (parser.parseTypeList(restTypes))
7050 result.getOrAddProperties<FPrintFOp::Properties>().operandSegmentSizes = {
7051 1, 1,
static_cast<int32_t
>(outputFileSubstitutions.size()),
7052 static_cast<int32_t
>(substitutions.size())};
7055 if (parser.resolveOperand(clock, clockType, result.operands) ||
7056 parser.resolveOperand(cond, condType, result.operands) ||
7057 parser.resolveOperands(
7058 outputFileSubstitutions,
7059 ArrayRef(restTypes).take_front(outputFileSubstitutions.size()),
7060 outputFileLoc, result.operands) ||
7061 parser.resolveOperands(
7063 ArrayRef(restTypes).drop_front(outputFileSubstitutions.size()),
7064 formatStringLoc, result.operands))
7070void FPrintFOp::print(OpAsmPrinter &p) {
7071 p <<
" " << getClock() <<
", " << getCond() <<
", ";
7072 p.printAttributeWithoutType(getOutputFileAttr());
7073 if (!getOutputFileSubstitutions().
empty()) {
7075 p.printOperands(getOutputFileSubstitutions());
7079 p.printAttributeWithoutType(getFormatStringAttr());
7080 if (!getSubstitutions().
empty()) {
7082 p.printOperands(getSubstitutions());
7086 p <<
" : " << getClock().getType() <<
", " << getCond().getType();
7087 if (!getOutputFileSubstitutions().
empty() || !getSubstitutions().
empty()) {
7088 for (
auto type : getOperands().drop_front(2).getTypes()) {
7099LogicalResult FFlushOp::verify() {
7100 if (!getOutputFileAttr() && !getOutputFileSubstitutions().
empty())
7101 return emitOpError(
"substitutions without output file are not allowed");
7110 auto ref = getInstanceAttr();
7111 auto target = ns.
lookup(ref);
7113 return emitError() <<
"target " << ref <<
" cannot be resolved";
7115 if (!target.isOpOnly())
7116 return emitError() <<
"target " << ref <<
" is not an operation";
7118 auto instance = dyn_cast<InstanceOp>(target.getOp());
7120 return emitError() <<
"target " << ref <<
" is not an instance";
7122 if (!instance.getDoNotPrint())
7123 return emitError() <<
"target " << ref <<
" is not marked doNotPrint";
7133DomainCreateAnonOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7134 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
7135 auto domain = getDomainAttr();
7136 if (!symbolTable.lookupSymbolIn<DomainOp>(circuitOp, domain))
7137 return emitOpError() <<
"references undefined domain '" << domain <<
"'";
7147#define GET_OP_CLASSES
7148#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 ParseResult parseDomainKind(OpAsmParser &parser, FlatSymbolRefAttr &domainKind)
Helper to parse domain kind: "of @Symbol".
static LogicalResult checkSingleConnect(FConnectLike connect)
Returns success if the given connect is the sole driver of its dest operand.
static bool isConstFieldDriven(FIRRTLBaseType type, bool isFlip=false, bool outerTypeIsConst=false)
Checks if the type has any 'const' leaf elements .
static ParseResult parsePrintfAttrs(OpAsmParser &p, NamedAttrList &resultAttrs)
static ParseResult parseParameterList(OpAsmParser &parser, ArrayAttr ¶meters)
Shim to use with assemblyFormat, custom<ParameterList>.
static RetTy emitInferRetTypeError(std::optional< Location > loc, const Twine &message, Args &&...args)
Emit an error if optional location is non-null, return null of return type.
static SmallVector< T > removeElementsAtIndices(ArrayRef< T > input, const llvm::BitVector &indicesToDrop)
Remove elements from the input array corresponding to set bits in indicesToDrop, returning the elemen...
static LogicalResult checkLayerCompatibility(Operation *op, const LayerSet &src, const LayerSet &dst, const Twine &errorMsg, const Twine ¬eMsg=Twine("missing layer requirements"))
static ParseResult parseModulePorts(OpAsmParser &parser, bool hasSSAIdentifiers, bool supportsSymbols, bool supportsDomains, SmallVectorImpl< OpAsmParser::Argument > &entryArgs, SmallVectorImpl< Direction > &portDirections, SmallVectorImpl< Attribute > &portNames, SmallVectorImpl< Attribute > &portTypes, SmallVectorImpl< Attribute > &portAnnotations, SmallVectorImpl< Attribute > &portSyms, SmallVectorImpl< Attribute > &portLocs, SmallVectorImpl< Attribute > &domains)
Parse a list of module ports.
static LogicalResult checkConnectConditionality(FConnectLike connect)
Checks that connections to 'const' destinations are not dependent on non-'const' conditions in when b...
static void erasePorts(FModuleLike op, const llvm::BitVector &portIndices)
Erases the ports that have their corresponding bit set in portIndices.
static ParseResult parseClassInterface(OpAsmParser &parser, Type &result)
static void printElidePortAnnotations(OpAsmPrinter &p, Operation *op, DictionaryAttr attr, ArrayRef< StringRef > extraElides={})
static ParseResult parseStopAttrs(OpAsmParser &p, NamedAttrList &resultAttrs)
static ParseResult parseNameKind(OpAsmParser &parser, firrtl::NameKindEnumAttr &result)
A forward declaration for NameKind attribute parser.
static size_t getAddressWidth(size_t depth)
static void forceableAsmResultNames(Forceable op, StringRef name, OpAsmSetValueNameFn setNameFn)
Helper for naming forceable declarations (and their optional ref result).
static void printFModuleLikeOp(OpAsmPrinter &p, FModuleLike op)
static void printSubfieldLikeOp(OpTy op, ::mlir::OpAsmPrinter &printer)
static FlatSymbolRefAttr getDomainTypeNameOfResult(T op, size_t i)
static bool checkAggConstant(Operation *op, Attribute attr, FIRRTLBaseType type)
static void printClassLike(OpAsmPrinter &p, ClassLike op)
static hw::ModulePort::Direction dirFtoH(Direction dir)
static ParseResult parseOptionalParameters(OpAsmParser &parser, SmallVectorImpl< Attribute > ¶meters)
Parse an parameter list if present.
static MemOp::PortKind getMemPortKindFromType(FIRRTLType type)
Return the kind of port this is given the port type from a 'mem' decl.
static void genericAsmResultNames(Operation *op, OpAsmSetValueNameFn setNameFn)
static void printClassInterface(OpAsmPrinter &p, Operation *, ClassType type)
static void printDomainKind(OpAsmPrinter &p, FlatSymbolRefAttr domainKind)
Helper to print domain kind: " of @Symbol".
static void printPrintfAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
const char * toString(Flow flow)
static void replaceUsesRespectingInsertedPorts(Operation *op1, Operation *op2, ArrayRef< std::pair< unsigned, PortInfo > > insertions)
static bool isLayerSetCompatibleWith(const LayerSet &src, const LayerSet &dst, SmallVectorImpl< SymbolRefAttr > &missing)
Check that the source layers are all present in the destination layers.
static bool isLayerCompatibleWith(mlir::SymbolRefAttr srcLayer, mlir::SymbolRefAttr dstLayer)
Check that the source layer is compatible with the destination layer.
static LayerSet getAmbientLayersFor(Value value)
Get the ambient layer requirements at the definition site of the value.
void buildModuleLike(OpBuilder &builder, OperationState &result, StringAttr name, ArrayRef< PortInfo > ports)
static LayerSet getAmbientLayersAt(Operation *op)
Get the ambient layers active at the given op.
static void printFIRRTLImplicitSSAName(OpAsmPrinter &p, Operation *op, DictionaryAttr attrs)
static ParseResult parseFIRRTLImplicitSSAName(OpAsmParser &parser, NamedAttrList &resultAttrs)
static FIRRTLBaseType inferMuxReturnType(FIRRTLBaseType high, FIRRTLBaseType low, bool isConstCondition, std::optional< Location > loc)
Infer the result type for a multiplexer given its two operand types, which may be aggregates.
static ParseResult parseCircuitOpAttrs(OpAsmParser &parser, NamedAttrList &resultAttrs)
void getAsmBlockArgumentNamesImpl(Operation *op, mlir::Region ®ion, OpAsmSetValueNameFn setNameFn)
Get a special name to use when printing the entry block arguments of the region contained by an opera...
static void printElideAnnotations(OpAsmPrinter &p, Operation *op, DictionaryAttr attr, ArrayRef< StringRef > extraElides={})
static ParseResult parseElidePortAnnotations(OpAsmParser &parser, NamedAttrList &resultAttrs)
Parse an optional attribute dictionary, adding empty 'annotations' and 'portAnnotations' attributes i...
static void insertPorts(FModuleLike op, ArrayRef< std::pair< unsigned, PortInfo > > ports)
Inserts the given ports.
static ParseResult parseFPrintfAttrs(OpAsmParser &p, NamedAttrList &resultAttrs)
static ParseResult parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs)
static void replaceUsesRespectingErasedPorts(Operation *op1, Operation *op2, const llvm::BitVector &erasures)
static LogicalResult checkConnectFlow(Operation *connect)
Check if the source and sink are of appropriate flow.
static void printParameterList(OpAsmPrinter &p, Operation *op, ArrayAttr parameters)
Print a paramter list for a module or instance.
static ParseResult parseVerifAttrs(OpAsmParser &p, NamedAttrList &resultAttrs)
static ParseResult parseElideAnnotations(OpAsmParser &parser, NamedAttrList &resultAttrs)
Parse an optional attribute dictionary, adding an empty 'annotations' attribute if not specified.
ParseResult parseClassLike(OpAsmParser &parser, OperationState &result, bool hasSSAIdentifiers)
static void printCircuitOpAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
static LogicalResult verifyPortSymbolUses(FModuleLike module, SymbolTableCollection &symbolTable)
static void printVerifAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
static void printMemOp(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
Always elide "ruw" and elide "annotations" if it exists or if it is empty.
static bool isTypeAllowedForDPI(Operation *op, Type type)
static ParseResult parseElideEmptyName(OpAsmParser &p, NamedAttrList &resultAttrs)
static bool printModulePorts(OpAsmPrinter &p, Block *block, ArrayRef< bool > portDirections, ArrayRef< Attribute > portNames, ArrayRef< Attribute > portTypes, ArrayRef< Attribute > portAnnotations, ArrayRef< Attribute > portSyms, ArrayRef< Attribute > portLocs, ArrayRef< Attribute > domainInfo)
Print a list of module ports in the following form: in x: !firrtl.uint<1> [{class = "DontTouch}],...
static void printElideEmptyName(OpAsmPrinter &p, Operation *op, DictionaryAttr attr, ArrayRef< StringRef > extraElides={})
static ParseResult parseFModuleLikeOp(OpAsmParser &parser, OperationState &result, bool hasSSAIdentifiers)
static bool isAncestor(Block *block, Block *other)
static Location getLoc(DefSlot slot)
static StringAttr append(StringAttr base, const Twine &suffix)
Return a attribute with the specified suffix appended.
static std::optional< APInt > getInt(Value value)
Helper to convert a value to a constant integer if it is one.
static Block * getBodyBlock(FModuleLike mod)
static InstancePath empty
This class represents a reference to a specific field or element of an aggregate value.
Value getValue() const
Get the Value which created this location.
This class provides a read-only projection over the MLIR attributes that represent a set of annotatio...
bool hasDontTouch() const
firrtl.transforms.DontTouchAnnotation
static AnnotationSet forPort(FModuleLike op, size_t portNo)
Get an annotation set for the specified port.
ExprVisitor is a visitor for FIRRTL expression nodes.
ResultType dispatchExprVisitor(Operation *op, ExtraArgs... args)
FIRRTLBaseType getConstType(bool isConst) const
Return a 'const' or non-'const' version of this type.
FIRRTLBaseType getMaskType()
Return this type with all ground types replaced with UInt<1>.
int32_t getBitWidthOrSentinel()
If this is an IntType, AnalogType, or sugar type for a single bit (Clock, Reset, etc) then return the...
FIRRTLBaseType getAllConstDroppedType()
Return this type with a 'const' modifiers dropped.
bool isPassive() const
Return true if this is a "passive" type - one that contains no "flip" types recursively within itself...
bool isConst() const
Returns true if this is a 'const' type that can only hold compile-time constant values.
bool isConst() const
Returns true if this is a 'const' type that can only hold compile-time constant values.
Caching version of getFieldRefFromValue.
FieldRef getFieldRefFromValue(Value value, bool lookThroughCasts=false)
Caching version of getFieldRefFromValue.
This is the common base class between SIntType and UIntType.
int32_t getWidthOrSentinel() const
Return the width of this type, or -1 if it has none specified.
static IntType get(MLIRContext *context, bool isSigned, int32_t widthOrSentinel=-1, bool isConst=false)
Return an SIntType or UIntType with the specified signedness, width, and constness.
bool hasWidth() const
Return true if this integer type has a known width.
std::optional< int32_t > getWidth() const
Return an optional containing the width, if the width is known (or empty if width is unknown).
static StringRef getInnerSymbolAttrName()
Return the name of the attribute used for inner symbol names.
int main(int argc, char **argv)
connect(destination, source)
ClassType getInstanceTypeForClassLike(ClassLike classOp)
LogicalResult verifyTypeAgainstClassLike(ClassLike classOp, ClassType type, function_ref< InFlightDiagnostic()> emitError)
Assuming that the classOp is the source of truth, verify that the type accurately matches the signatu...
RefType getForceableResultType(bool forceable, Type type)
Return null or forceable reference result type.
mlir::DenseBoolArrayAttr packAttribute(MLIRContext *context, ArrayRef< Direction > directions)
Return a DenseBoolArrayAttr containing the packed representation of an array of directions.
static bool unGet(Direction dir)
Convert from Direction to bool. The opposite of get;.
SmallVector< Direction > unpackAttribute(mlir::DenseBoolArrayAttr directions)
Turn a packed representation of port attributes into a vector that can be worked with.
static Direction get(bool isOutput)
Return an output direction if isOutput is true, otherwise return an input direction.
static StringRef toString(Direction direction)
FIRRTLType inferElementwiseResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
FIRRTLType inferBitwiseResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
FIRRTLType inferAddSubResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
FIRRTLType inferComparisonResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
FIRRTLType inferReductionResult(FIRRTLType arg, std::optional< Location > loc)
LogicalResult verifySameOperandsIntTypeKind(Operation *op)
LogicalResult verifyReferencedModule(Operation *instanceOp, SymbolTableCollection &symbolTable, mlir::FlatSymbolRefAttr moduleName)
Verify that the instance refers to a valid FIRRTL module.
BaseTy type_cast(Type type)
Flow swapFlow(Flow flow)
Get a flow's reverse.
Direction
This represents the direction of a single port.
FieldRef getFieldRefFromValue(Value value, bool lookThroughCasts=false)
Get the FieldRef from a value.
void walkGroundTypes(FIRRTLType firrtlType, llvm::function_ref< void(uint64_t, FIRRTLBaseType, bool)> fn)
Walk leaf ground types in the firrtlType and apply the function fn.
bool isConstant(Operation *op)
Return true if the specified operation has a constant value.
bool areAnonymousTypesEquivalent(FIRRTLBaseType lhs, FIRRTLBaseType rhs)
Return true if anonymous types of given arguments are equivalent by pointer comparison.
constexpr bool isValidDst(Flow flow)
Flow foldFlow(Value val, Flow accumulatedFlow=Flow::Source)
Compute the flow for a Value, val, as determined by the FIRRTL specification.
constexpr const char * dutAnnoClass
bool areTypesEquivalent(FIRRTLType destType, FIRRTLType srcType, bool destOuterTypeIsConst=false, bool srcOuterTypeIsConst=false, bool requireSameWidths=false)
Returns whether the two types are equivalent.
bool hasDontTouch(Value value)
Check whether a block argument ("port") or the operation defining a value has a DontTouch annotation,...
size_t getNumPorts(Operation *op)
Return the number of ports in a module-like thing (modules, memories, etc)
mlir::Type getPassiveType(mlir::Type anyBaseFIRRTLType)
bool isTypeLarger(FIRRTLBaseType dstType, FIRRTLBaseType srcType)
Returns true if the destination is at least as wide as a source.
bool containsConst(Type type)
Returns true if the type is or contains a 'const' type whose value is guaranteed to be unchanging at ...
bool isDuplexValue(Value val)
Returns true if the value results from an expression with duplex flow.
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.