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 auto existingDirections = op.getPortDirectionsAttr();
806 ArrayRef<Attribute> existingNames = op.getPortNames();
807 ArrayRef<Attribute> existingTypes = op.getPortTypes();
808 ArrayRef<Attribute> existingLocs = op.getPortLocations();
809 assert(existingDirections.size() == oldNumArgs);
810 assert(existingNames.size() == oldNumArgs);
811 assert(existingTypes.size() == oldNumArgs);
812 assert(existingLocs.size() == oldNumArgs);
814 SmallVector<bool> newDirections;
815 SmallVector<Attribute> newNames, newTypes, newDomains, newAnnos, newSyms,
817 newDirections.reserve(newNumArgs);
818 newNames.reserve(newNumArgs);
819 newTypes.reserve(newNumArgs);
820 newDomains.reserve(newNumArgs);
821 newAnnos.reserve(newNumArgs);
822 newSyms.reserve(newNumArgs);
823 newLocs.reserve(newNumArgs);
825 SmallVector<unsigned> indexMap(oldNumArgs);
827 auto emptyArray = ArrayAttr::get(op.getContext(), {});
830 unsigned inserted = 0;
831 auto migrateOldPorts = [&](
unsigned untilOldIdx) {
832 while (oldIdx < oldNumArgs && oldIdx < untilOldIdx) {
833 newDirections.push_back(existingDirections[oldIdx]);
834 newNames.push_back(existingNames[oldIdx]);
835 newTypes.push_back(existingTypes[oldIdx]);
837 op.getContext(), op.getDomainInfoAttrForPort(oldIdx), indexMap));
838 newAnnos.push_back(op.getAnnotationsAttrForPort(oldIdx));
839 newSyms.push_back(op.getPortSymbolAttr(oldIdx));
840 newLocs.push_back(existingLocs[oldIdx]);
842 indexMap[oldIdx] = oldIdx + inserted;
847 for (
auto [idx, port] : ports) {
848 migrateOldPorts(idx);
850 newNames.push_back(port.name);
851 newTypes.push_back(TypeAttr::get(port.type));
854 port.domains ? port.domains : ArrayAttr::get(op.getContext(), {}),
856 auto annos = port.annotations.getArrayAttr();
857 newAnnos.push_back(annos ? annos : emptyArray);
858 newSyms.push_back(port.sym);
859 newLocs.push_back(port.loc);
862 migrateOldPorts(oldNumArgs);
866 if (llvm::all_of(newAnnos, [](Attribute attr) {
867 return cast<ArrayAttr>(attr).empty();
873 if (llvm::all_of(newDomains, [](Attribute attr) {
876 if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr))
877 return arrayAttr.empty();
883 op->setAttr(
"portDirections",
885 op->setAttr(
"portNames", ArrayAttr::get(op.getContext(), newNames));
886 op->setAttr(
"portTypes", ArrayAttr::get(op.getContext(), newTypes));
887 op->setAttr(
"domainInfo", ArrayAttr::get(op.getContext(), newDomains));
888 op->setAttr(
"portAnnotations", ArrayAttr::get(op.getContext(), newAnnos));
889 FModuleLike::fixupPortSymsArray(newSyms, op.getContext());
890 op.setPortSymbols(newSyms);
891 op->setAttr(
"portLocations", ArrayAttr::get(op.getContext(), newLocs));
902 ArrayAttr domainInfoAttr,
903 const llvm::BitVector &portIndices,
904 bool supportsEmptyAttr) {
905 if (supportsEmptyAttr && domainInfoAttr.empty())
906 return domainInfoAttr;
910 SmallVector<unsigned> numDeleted;
911 numDeleted.resize(portIndices.size());
912 size_t deletionIndex = portIndices.find_first();
913 for (
size_t i = 0, e = portIndices.size(); i != e; ++i) {
914 if (i == deletionIndex) {
918 numDeleted[i] = numDeleted[i - 1] + 1;
919 deletionIndex = portIndices.find_next(i);
925 numDeleted[i] = numDeleted[i - 1];
930 auto getEmpty = [&]() {
932 eEmpty = ArrayAttr::get(
context, {});
937 SmallVector<Attribute> newDomainInfo;
938 newDomainInfo.reserve(portIndices.size() - portIndices.count());
939 for (
size_t i = 0, e = portIndices.size(); i != e; ++i) {
941 if (portIndices.test(i))
944 if (domainInfoAttr.empty()) {
945 newDomainInfo.push_back(getEmpty());
948 auto attr = domainInfoAttr[i];
950 auto domains = dyn_cast<ArrayAttr>(attr);
951 if (!domains || domains.empty()) {
952 newDomainInfo.push_back(attr);
956 SmallVector<Attribute> newDomains;
957 for (
auto domain : domains) {
959 auto oldIdx = cast<IntegerAttr>(domain).getUInt();
960 if (portIndices.test(oldIdx))
963 auto newIdx = oldIdx - numDeleted[oldIdx];
964 if (oldIdx == newIdx) {
965 newDomainInfo.push_back(attr);
969 newDomains.push_back(IntegerAttr::get(
970 IntegerType::get(
context, 32, IntegerType::Unsigned), newIdx));
972 newDomainInfo.push_back(ArrayAttr::get(
context, newDomains));
975 return ArrayAttr::get(
context, newDomainInfo);
979static void erasePorts(FModuleLike op,
const llvm::BitVector &portIndices) {
980 if (portIndices.none())
984 ArrayRef<bool> portDirections = op.getPortDirectionsAttr().asArrayRef();
985 ArrayRef<Attribute> portNames = op.getPortNames();
986 ArrayRef<Attribute> portTypes = op.getPortTypes();
987 ArrayRef<Attribute> portAnnos = op.getPortAnnotations();
988 ArrayRef<Attribute> portSyms = op.getPortSymbols();
989 ArrayRef<Attribute> portLocs = op.getPortLocations();
990 ArrayRef<Attribute> portDomains = op.getDomainInfo();
991 auto numPorts = op.getNumPorts();
993 assert(portDirections.size() == numPorts);
994 assert(portNames.size() == numPorts);
995 assert(portAnnos.size() == numPorts || portAnnos.empty());
996 assert(portTypes.size() == numPorts);
997 assert(portSyms.size() == numPorts || portSyms.empty());
998 assert(portLocs.size() == numPorts);
999 assert(portDomains.size() == numPorts || portDomains.empty());
1001 SmallVector<bool> newPortDirections =
1002 removeElementsAtIndices<bool>(portDirections, portIndices);
1003 SmallVector<Attribute> newPortNames, newPortTypes, newPortAnnos, newPortSyms,
1011 op->setAttr(
"portDirections",
1013 op->setAttr(
"portNames", ArrayAttr::get(op.getContext(), newPortNames));
1014 op->setAttr(
"portAnnotations", ArrayAttr::get(op.getContext(), newPortAnnos));
1015 op->setAttr(
"portTypes", ArrayAttr::get(op.getContext(), newPortTypes));
1016 FModuleLike::fixupPortSymsArray(newPortSyms, op.getContext());
1017 op->setAttr(
"portSymbols", ArrayAttr::get(op.getContext(), newPortSyms));
1018 op->setAttr(
"portLocations", ArrayAttr::get(op.getContext(), newPortLocs));
1019 op->setAttr(
"domainInfo",
1021 portIndices,
true));
1024void FExtModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1025 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1028void FIntModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1029 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1032void FMemModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1033 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1036void FModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1037 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1044void FModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1045 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1049 for (
size_t i = 0, e = ports.size(); i < e; ++i) {
1052 auto &[index, port] = ports[i];
1053 body->insertArgument(index + i, port.type, port.loc);
1057void FExtModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1058 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1061void FIntModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1062 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1068void FMemModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1069 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1072template <
typename OpTy>
1074 StringAttr name, ArrayRef<PortInfo> ports) {
1076 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
1077 properties.setSymName(name);
1080 SmallVector<Direction, 4> portDirections;
1081 SmallVector<Attribute, 4> portNames;
1082 SmallVector<Attribute, 4> portTypes;
1083 SmallVector<Attribute, 4> portSyms;
1084 SmallVector<Attribute, 4> portLocs;
1085 SmallVector<Attribute, 4> portDomains;
1086 for (
const auto &port : ports) {
1087 portDirections.push_back(port.direction);
1088 portNames.push_back(port.name);
1089 portTypes.push_back(TypeAttr::get(port.type));
1090 portSyms.push_back(port.sym);
1091 portLocs.push_back(port.loc);
1092 portDomains.push_back(port.domains);
1094 if (llvm::all_of(portDomains, [](Attribute attr) {
1097 if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr))
1098 return arrayAttr.empty();
1101 portDomains.clear();
1103 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1106 properties.setPortDirections(
1108 properties.setPortNames(builder.getArrayAttr(portNames));
1109 properties.setPortTypes(builder.getArrayAttr(portTypes));
1110 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1111 properties.setPortLocations(builder.getArrayAttr(portLocs));
1112 properties.setDomainInfo(builder.getArrayAttr(portDomains));
1117template <
typename OpTy>
1119 StringAttr name, ArrayRef<PortInfo> ports,
1120 ArrayAttr annotations, ArrayAttr layers) {
1121 buildModuleLike<OpTy>(builder, result, name, ports);
1122 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
1125 annotations = builder.getArrayAttr({});
1126 properties.setAnnotations(annotations);
1130 SmallVector<Attribute, 4> portAnnotations;
1131 for (
const auto &port : ports)
1132 portAnnotations.push_back(port.annotations.getArrayAttr());
1133 if (llvm::all_of(portAnnotations, [](Attribute attr) {
1134 return cast<ArrayAttr>(attr).empty();
1136 portAnnotations.clear();
1137 properties.setPortAnnotations(builder.getArrayAttr(portAnnotations));
1141 layers = builder.getArrayAttr({});
1142 properties.setLayers(layers);
1145template <
typename OpTy>
1146static void buildClass(OpBuilder &builder, OperationState &result,
1147 StringAttr name, ArrayRef<PortInfo> ports) {
1148 return buildModuleLike<OpTy>(builder, result, name, ports);
1151void FModuleOp::build(OpBuilder &builder, OperationState &result,
1152 StringAttr name, ConventionAttr convention,
1153 ArrayRef<PortInfo> ports, ArrayAttr annotations,
1155 buildModule<FModuleOp>(builder, result, name, ports, annotations, layers);
1156 auto &properties = result.getOrAddProperties<Properties>();
1157 properties.setConvention(convention);
1160 auto *bodyRegion = result.regions[0].get();
1162 bodyRegion->push_back(body);
1165 for (
auto &elt : ports)
1166 body->addArgument(elt.type, elt.loc);
1169void FExtModuleOp::build(OpBuilder &builder, OperationState &result,
1170 StringAttr name, ConventionAttr convention,
1171 ArrayRef<PortInfo> ports, ArrayAttr knownLayers,
1172 StringRef defnameAttr, ArrayAttr annotations,
1173 ArrayAttr parameters, ArrayAttr layers) {
1174 buildModule<FExtModuleOp>(builder, result, name, ports, annotations, layers);
1175 auto &properties = result.getOrAddProperties<Properties>();
1176 properties.setConvention(convention);
1178 knownLayers = builder.getArrayAttr({});
1179 properties.setKnownLayers(knownLayers);
1180 if (!defnameAttr.empty())
1181 properties.setDefname(builder.getStringAttr(defnameAttr));
1183 parameters = builder.getArrayAttr({});
1184 properties.setParameters(parameters);
1187void FIntModuleOp::build(OpBuilder &builder, OperationState &result,
1188 StringAttr name, ArrayRef<PortInfo> ports,
1189 StringRef intrinsicNameStr, ArrayAttr annotations,
1190 ArrayAttr parameters, ArrayAttr layers) {
1191 buildModule<FIntModuleOp>(builder, result, name, ports, annotations, layers);
1192 auto &properties = result.getOrAddProperties<Properties>();
1193 properties.setIntrinsic(builder.getStringAttr(intrinsicNameStr));
1195 parameters = builder.getArrayAttr({});
1196 properties.setParameters(parameters);
1199void FMemModuleOp::build(OpBuilder &builder, OperationState &result,
1200 StringAttr name, ArrayRef<PortInfo> ports,
1201 uint32_t numReadPorts, uint32_t numWritePorts,
1202 uint32_t numReadWritePorts, uint32_t dataWidth,
1203 uint32_t maskBits, uint32_t readLatency,
1204 uint32_t writeLatency, uint64_t depth, RUWBehavior ruw,
1205 ArrayAttr annotations, ArrayAttr layers) {
1206 auto *
context = builder.getContext();
1207 buildModule<FMemModuleOp>(builder, result, name, ports, annotations, layers);
1208 auto ui32Type = IntegerType::get(
context, 32, IntegerType::Unsigned);
1209 auto ui64Type = IntegerType::get(
context, 64, IntegerType::Unsigned);
1210 auto &properties = result.getOrAddProperties<Properties>();
1211 properties.setNumReadPorts(IntegerAttr::get(ui32Type, numReadPorts));
1212 properties.setNumWritePorts(IntegerAttr::get(ui32Type, numWritePorts));
1213 properties.setNumReadWritePorts(
1214 IntegerAttr::get(ui32Type, numReadWritePorts));
1215 properties.setDataWidth(IntegerAttr::get(ui32Type, dataWidth));
1216 properties.setMaskBits(IntegerAttr::get(ui32Type, maskBits));
1217 properties.setReadLatency(IntegerAttr::get(ui32Type, readLatency));
1218 properties.setWriteLatency(IntegerAttr::get(ui32Type, writeLatency));
1219 properties.setDepth(IntegerAttr::get(ui64Type, depth));
1220 properties.setExtraPorts(ArrayAttr::get(
context, {}));
1221 properties.setRuw(RUWBehaviorAttr::get(
context, ruw));
1238 ArrayRef<Attribute> portNames, ArrayRef<Attribute> portTypes,
1239 ArrayRef<Attribute> portAnnotations,
1240 ArrayRef<Attribute> portSyms, ArrayRef<Attribute> portLocs,
1241 ArrayRef<Attribute> domainInfo) {
1244 bool printedNamesDontMatch =
false;
1246 mlir::OpPrintingFlags flags;
1249 DenseMap<unsigned, std::string> ssaNames;
1250 auto getSsaName = [&](
unsigned idx) -> StringRef {
1252 auto itr = ssaNames.find(idx);
1253 if (itr != ssaNames.end())
1254 return itr->getSecond();
1258 SmallString<32> resultNameStr;
1260 llvm::raw_svector_ostream tmpStream(resultNameStr);
1261 p.printOperand(block->getArgument(idx), tmpStream);
1264 auto portName = cast<StringAttr>(portNames[idx]).getValue();
1265 if (tmpStream.str().drop_front() != portName)
1266 printedNamesDontMatch =
true;
1267 return ssaNames.insert({idx, tmpStream.str().str()}).first->getSecond();
1270 auto name = cast<StringAttr>(portNames[idx]).getValue();
1271 return ssaNames.insert({idx, name.str()}).first->getSecond();
1277 for (
unsigned i = 0, e = portTypes.size(); i < e; ++i) {
1286 auto portType = cast<TypeAttr>(portTypes[i]).getValue();
1290 p.printKeywordOrString(getSsaName(i));
1295 p.printType(portType);
1298 if (!portSyms.empty()) {
1299 if (!cast<hw::InnerSymAttr>(portSyms[i]).
empty()) {
1301 cast<hw::InnerSymAttr>(portSyms[i]).print(p);
1306 if (!domainInfo.empty()) {
1307 if (
auto domainKind = dyn_cast<FlatSymbolRefAttr>(domainInfo[i])) {
1310 auto domains = cast<ArrayAttr>(domainInfo[i]);
1311 if (!domains.empty()) {
1313 llvm::interleaveComma(domains, p, [&](Attribute attr) {
1314 p << getSsaName(cast<IntegerAttr>(attr).getUInt());
1323 if (!portAnnotations.empty() &&
1324 !cast<ArrayAttr>(portAnnotations[i]).empty()) {
1326 p.printAttribute(portAnnotations[i]);
1333 if (flags.shouldPrintDebugInfo() && !portLocs.empty())
1334 p.printOptionalLocationSpecifier(cast<LocationAttr>(portLocs[i]));
1338 return printedNamesDontMatch;
1344 OpAsmParser &parser,
bool hasSSAIdentifiers,
bool supportsSymbols,
1345 bool supportsDomains, SmallVectorImpl<OpAsmParser::Argument> &entryArgs,
1346 SmallVectorImpl<Direction> &portDirections,
1347 SmallVectorImpl<Attribute> &portNames,
1348 SmallVectorImpl<Attribute> &portTypes,
1349 SmallVectorImpl<Attribute> &portAnnotations,
1350 SmallVectorImpl<Attribute> &portSyms, SmallVectorImpl<Attribute> &portLocs,
1351 SmallVectorImpl<Attribute> &domains) {
1352 auto *
context = parser.getContext();
1355 DenseMap<Attribute, size_t> domainIndex;
1358 using DomainAndLoc = std::pair<Attribute, llvm::SMLoc>;
1359 DenseMap<size_t, SmallVector<DomainAndLoc>> domainStrings;
1361 auto parseArgument = [&]() -> ParseResult {
1363 if (succeeded(parser.parseOptionalKeyword(
"out")))
1364 portDirections.push_back(Direction::Out);
1365 else if (succeeded(parser.parseKeyword(
"in",
" or 'out'")))
1366 portDirections.push_back(Direction::In);
1373 auto portIdx = portNames.size();
1375 if (hasSSAIdentifiers) {
1376 OpAsmParser::Argument arg;
1377 if (parser.parseArgument(arg))
1379 entryArgs.push_back(arg);
1383 assert(arg.ssaName.name.size() > 1 && arg.ssaName.name[0] ==
'%' &&
1384 "Unknown MLIR name");
1385 if (
isdigit(arg.ssaName.name[1]))
1386 portNames.push_back(StringAttr::get(
context,
""));
1388 portNames.push_back(
1389 StringAttr::get(
context, arg.ssaName.name.drop_front()));
1392 irLoc = arg.ssaName.location;
1396 irLoc = parser.getCurrentLocation();
1397 std::string portName;
1398 if (parser.parseKeywordOrString(&portName))
1400 portNames.push_back(StringAttr::get(
context, portName));
1405 if (parser.parseColonType(portType))
1407 portTypes.push_back(TypeAttr::get(portType));
1408 if (isa<DomainType>(portType))
1409 domainIndex[portNames.back()] = portIdx;
1411 if (hasSSAIdentifiers)
1412 entryArgs.back().type = portType;
1415 if (supportsSymbols) {
1416 hw::InnerSymAttr innerSymAttr;
1417 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
1418 NamedAttrList dummyAttrs;
1419 if (parser.parseCustomAttributeWithFallback(
1420 innerSymAttr, ::mlir::Type{},
1422 return ::mlir::failure();
1425 portSyms.push_back(innerSymAttr);
1433 Attribute domainInfo;
1434 if (supportsDomains) {
1435 if (isa<DomainType>(portType)) {
1436 FlatSymbolRefAttr domainKind;
1439 domainInfo = domainKind;
1440 }
else if (succeeded(parser.parseOptionalKeyword(
"domains"))) {
1441 auto result = parser.parseCommaSeparatedList(
1442 OpAsmParser::Delimiter::Square, [&]() -> ParseResult {
1444 if (hasSSAIdentifiers) {
1445 OpAsmParser::Argument arg;
1446 if (parser.parseArgument(arg))
1449 StringAttr::get(
context, arg.ssaName.name.drop_front());
1451 std::string portName;
1452 if (parser.parseKeywordOrString(&portName))
1454 argName = StringAttr::get(
context, portName);
1456 domainStrings[portIdx].push_back({argName, irLoc});
1463 domains.push_back(domainInfo);
1467 auto parseResult = parser.parseOptionalAttribute(annos);
1468 if (!parseResult.has_value())
1469 annos = parser.getBuilder().getArrayAttr({});
1470 else if (failed(*parseResult))
1472 portAnnotations.push_back(annos);
1475 std::optional<Location> maybeLoc;
1476 if (failed(parser.parseOptionalLocationSpecifier(maybeLoc)))
1478 Location loc = maybeLoc ? *maybeLoc : parser.getEncodedSourceLoc(irLoc);
1479 portLocs.push_back(loc);
1480 if (hasSSAIdentifiers)
1481 entryArgs.back().sourceLoc = loc;
1490 if (failed(parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
1496 for (
auto [portIdx, domainInfo] : llvm::enumerate(domains)) {
1501 SmallVector<Attribute> portDomains;
1502 for (
auto [domainName, loc] : domainStrings[portIdx]) {
1503 auto index = domainIndex.find(domainName);
1504 if (index == domainIndex.end()) {
1505 parser.emitError(loc) <<
"domain name '" << domainName <<
"' not found";
1508 portDomains.push_back(IntegerAttr::get(
1509 IntegerType::get(
context, 32, IntegerType::Unsigned), index->second));
1511 domains[portIdx] = parser.getBuilder().getArrayAttr(portDomains);
1519 ArrayAttr parameters) {
1520 if (!parameters || parameters.empty())
1524 llvm::interleaveComma(parameters, p, [&](Attribute param) {
1525 auto paramAttr = cast<ParamDeclAttr>(param);
1526 p << paramAttr.getName().getValue() <<
": " << paramAttr.getType();
1527 if (
auto value = paramAttr.getValue()) {
1529 p.printAttributeWithoutType(value);
1539 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
1540 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
1541 p << visibility.getValue() <<
' ';
1544 p.printSymbolName(op.getModuleName());
1551 Block *body =
nullptr;
1552 if (!op->getRegion(0).empty())
1553 body = &op->getRegion(0).front();
1556 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
1557 op.getPortAnnotations(), op.getPortSymbols(), op.getPortLocations(),
1558 op.getDomainInfo());
1560 SmallVector<StringRef, 13> omittedAttrs = {
1561 "sym_name",
"portDirections",
"portTypes",
1562 "portAnnotations",
"portSymbols",
"portLocations",
1563 "parameters", visibilityAttrName,
"domainInfo"};
1565 if (op.getConvention() == Convention::Internal)
1566 omittedAttrs.push_back(
"convention");
1570 if (!needPortNamesAttr)
1571 omittedAttrs.push_back(
"portNames");
1574 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
1575 omittedAttrs.push_back(
"annotations");
1578 if (
auto knownLayers = op->getAttrOfType<ArrayAttr>(
"knownLayers"))
1579 if (knownLayers.empty())
1580 omittedAttrs.push_back(
"knownLayers");
1583 if (
auto layers = op->getAttrOfType<ArrayAttr>(
"layers"))
1585 omittedAttrs.push_back(
"layers");
1587 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
1596void FModuleOp::print(OpAsmPrinter &p) {
1602 Region &fbody = getBody();
1603 if (!fbody.empty()) {
1605 p.printRegion(fbody,
false,
1617 SmallVectorImpl<Attribute> ¶meters) {
1619 return parser.parseCommaSeparatedList(
1620 OpAsmParser::Delimiter::OptionalLessGreater, [&]() {
1625 if (parser.parseKeywordOrString(&name) || parser.parseColonType(type))
1629 if (succeeded(parser.parseOptionalEqual())) {
1630 if (parser.parseAttribute(value, type))
1634 auto &builder = parser.getBuilder();
1635 parameters.push_back(ParamDeclAttr::get(
1636 builder.getContext(), builder.getStringAttr(name), type, value));
1643 ArrayAttr ¶meters) {
1644 SmallVector<Attribute> parseParameters;
1648 parameters = ArrayAttr::get(parser.getContext(), parseParameters);
1653template <
typename Properties,
typename =
void>
1656template <
typename Properties>
1658 Properties, std::void_t<decltype(std::declval<Properties>().parameters)>>
1659 : std::true_type {};
1661template <
typename OpTy>
1663 OperationState &result,
1664 bool hasSSAIdentifiers) {
1665 auto *
context = result.getContext();
1666 auto &builder = parser.getBuilder();
1667 using Properties =
typename OpTy::Properties;
1668 auto &properties = result.getOrAddProperties<Properties>();
1672 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
1675 StringAttr nameAttr;
1676 if (parser.parseSymbolName(nameAttr))
1678 properties.setSymName(nameAttr);
1682 SmallVector<Attribute, 4> parameters;
1685 properties.setParameters(builder.getArrayAttr(parameters));
1689 SmallVector<OpAsmParser::Argument> entryArgs;
1690 SmallVector<Direction, 4> portDirections;
1691 SmallVector<Attribute, 4> portNames;
1692 SmallVector<Attribute, 4> portTypes;
1693 SmallVector<Attribute, 4> portAnnotations;
1694 SmallVector<Attribute, 4> portSyms;
1695 SmallVector<Attribute, 4> portLocs;
1696 SmallVector<Attribute, 4> domains;
1698 true, entryArgs, portDirections,
1699 portNames, portTypes, portAnnotations, portSyms,
1704 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
1707 assert(portNames.size() == portTypes.size());
1713 properties.setPortDirections(
1717 properties.setPortNames(builder.getArrayAttr(portNames));
1720 properties.setPortTypes(ArrayAttr::get(
context, portTypes));
1724 if (llvm::any_of(portAnnotations, [&](Attribute anno) {
1725 return !cast<ArrayAttr>(anno).empty();
1727 properties.setPortAnnotations(ArrayAttr::get(
context, portAnnotations));
1729 properties.setPortAnnotations(builder.getArrayAttr({}));
1732 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1733 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1736 properties.setPortLocations(ArrayAttr::get(
context, portLocs));
1739 properties.setAnnotations(builder.getArrayAttr({}));
1742 if (llvm::all_of(domains, [&](Attribute attr) {
1743 auto arrayAttr = dyn_cast<ArrayAttr>(attr);
1744 return arrayAttr && arrayAttr.empty();
1746 properties.setDomainInfo(ArrayAttr::get(
context, {}));
1748 properties.setDomainInfo(ArrayAttr::get(
context, domains));
1751 auto *body = result.addRegion();
1753 if (hasSSAIdentifiers) {
1754 if (parser.parseRegion(*body, entryArgs))
1757 body->push_back(
new Block());
1762ParseResult FModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1763 if (parseFModuleLikeOp<FModuleOp>(parser, result,
1766 auto &properties = result.getOrAddProperties<Properties>();
1767 properties.setConvention(
1768 ConventionAttr::get(result.getContext(), Convention::Internal));
1769 properties.setLayers(ArrayAttr::get(parser.getContext(), {}));
1773ParseResult FExtModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1774 if (parseFModuleLikeOp<FExtModuleOp>(parser, result,
1777 auto &properties = result.getOrAddProperties<Properties>();
1778 properties.setConvention(
1779 ConventionAttr::get(result.getContext(), Convention::Internal));
1780 properties.setKnownLayers(ArrayAttr::get(result.getContext(), {}));
1784ParseResult FIntModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1785 return parseFModuleLikeOp<FIntModuleOp>(parser, result,
1789ParseResult FMemModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1790 return parseFModuleLikeOp<FMemModuleOp>(parser, result,
1794LogicalResult FModuleOp::verify() {
1797 auto portTypes = getPortTypes();
1798 auto portLocs = getPortLocations();
1799 auto numPorts = portTypes.size();
1802 if (body->getNumArguments() != numPorts)
1803 return emitOpError(
"entry block must have ")
1804 << numPorts <<
" arguments to match module signature";
1807 for (
auto [arg, type, loc] : zip(body->getArguments(), portTypes, portLocs)) {
1808 if (arg.getType() != cast<TypeAttr>(type).getValue())
1809 return emitOpError(
"block argument types should match signature types");
1810 if (arg.getLoc() != cast<LocationAttr>(loc))
1812 "block argument locations should match signature locations");
1818LogicalResult FExtModuleOp::verify() {
1819 auto params = getParameters();
1821 auto checkParmValue = [&](Attribute elt) ->
bool {
1822 auto param = cast<ParamDeclAttr>(elt);
1823 auto value = param.getValue();
1824 if (isa<IntegerAttr, StringAttr, FloatAttr, hw::ParamVerbatimAttr>(value))
1826 emitError() <<
"has unknown extmodule parameter value '"
1827 << param.getName().getValue() <<
"' = " << value;
1831 if (!llvm::all_of(params, checkParmValue))
1836 known.insert_range(getKnownLayersAttr().getAsRange<SymbolRefAttr>());
1839 referenced.insert_range(getLayersAttr().getAsRange<SymbolRefAttr>());
1840 for (
auto attr : getPortTypes()) {
1841 auto type = cast<TypeAttr>(attr).getValue();
1842 if (
auto refType = type_dyn_cast<RefType>(type))
1843 if (
auto layer = refType.getLayer())
1844 referenced.insert(layer);
1848 "references unknown layers",
"unknown layers");
1851LogicalResult FIntModuleOp::verify() {
1852 auto params = getParameters();
1856 auto checkParmValue = [&](Attribute elt) ->
bool {
1857 auto param = cast<ParamDeclAttr>(elt);
1858 auto value = param.getValue();
1859 if (isa<IntegerAttr, StringAttr, FloatAttr>(value))
1861 emitError() <<
"has unknown intmodule parameter value '"
1862 << param.getName().getValue() <<
"' = " << value;
1866 if (!llvm::all_of(params, checkParmValue))
1873 CircuitOp circuitOp,
1874 SymbolTableCollection &symbolTable,
1876 auto layer = refType.getLayer();
1879 auto *layerOp = symbolTable.lookupSymbolIn(circuitOp, layer);
1881 return emitError(loc) << start <<
" associated with layer '" << layer
1882 <<
"', but this layer was not defined";
1883 if (!isa<LayerOp>(layerOp)) {
1884 auto diag = emitError(loc)
1885 << start <<
" associated with layer '" << layer
1886 <<
"', but symbol '" << layer <<
"' does not refer to a '"
1887 << LayerOp::getOperationName() <<
"' op";
1888 return diag.attachNote(layerOp->getLoc()) <<
"symbol refers to this op";
1894 SymbolTableCollection &symbolTable) {
1896 auto circuitOp =
module->getParentOfType<CircuitOp>();
1897 for (
size_t i = 0, e = module.getNumPorts(); i < e; ++i) {
1898 auto type =
module.getPortType(i);
1900 if (
auto refType = type_dyn_cast<RefType>(type)) {
1902 refType, module.getPortLocation(i), circuitOp, symbolTable,
1903 Twine(
"probe port '") + module.getPortName(i) +
"' is")))
1908 if (
auto classType = dyn_cast<ClassType>(type)) {
1909 auto className = classType.getNameAttr();
1910 auto classOp = dyn_cast_or_null<ClassLike>(
1911 symbolTable.lookupSymbolIn(circuitOp, className));
1913 return module.emitOpError() << "references unknown class " << className;
1916 if (failed(classOp.verifyType(classType,
1917 [&]() { return module.emitOpError(); })))
1922 if (isa<DomainType>(type)) {
1923 auto domainInfo =
module.getDomainInfoAttrForPort(i);
1924 if (
auto kind = dyn_cast<FlatSymbolRefAttr>(domainInfo))
1925 if (!dyn_cast_or_null<DomainOp>(
1926 symbolTable.lookupSymbolIn(circuitOp, kind)))
1927 return mlir::emitError(module.getPortLocation(i))
1928 <<
"domain port '" <<
module.getPortName(i)
1929 << "' has undefined domain kind '" << kind.getValue() << "'";
1936LogicalResult FModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1940 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
1941 for (
auto layer : getLayers()) {
1942 if (!symbolTable.lookupSymbolIn(circuitOp, cast<SymbolRefAttr>(layer)))
1943 return emitOpError() <<
"enables undefined layer '" << layer <<
"'";
1950FExtModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1954 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
1955 for (
auto layer : getKnownLayersAttr().getAsRange<SymbolRefAttr>()) {
1956 if (!symbolTable.lookupSymbolIn(circuitOp, layer))
1957 return emitOpError() <<
"knows undefined layer '" << layer <<
"'";
1959 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>()) {
1960 if (!symbolTable.lookupSymbolIn(circuitOp, layer))
1961 return emitOpError() <<
"enables undefined layer '" << layer <<
"'";
1968FIntModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1973FMemModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1977void FModuleOp::getAsmBlockArgumentNames(mlir::Region ®ion,
1982void FExtModuleOp::getAsmBlockArgumentNames(
1987StringRef FExtModuleOp::getExtModuleName() {
1988 if (
auto defname = getDefname(); defname && !defname->empty())
1993void FIntModuleOp::getAsmBlockArgumentNames(
1998void FMemModuleOp::getAsmBlockArgumentNames(
2003ArrayAttr FMemModuleOp::getParameters() {
return {}; }
2005ArrayAttr FModuleOp::getParameters() {
return {}; }
2007Convention FIntModuleOp::getConvention() {
return Convention::Internal; }
2009ConventionAttr FIntModuleOp::getConventionAttr() {
2010 return ConventionAttr::get(getContext(), getConvention());
2013Convention FMemModuleOp::getConvention() {
return Convention::Internal; }
2015ConventionAttr FMemModuleOp::getConventionAttr() {
2016 return ConventionAttr::get(getContext(), getConvention());
2024 ClassLike classOp, ClassType type,
2025 function_ref<InFlightDiagnostic()> emitError) {
2027 auto name = type.getNameAttr().getAttr();
2028 auto expectedName = classOp.getModuleNameAttr();
2029 if (name != expectedName)
2030 return emitError() <<
"type has wrong name, got " << name <<
", expected "
2033 auto elements = type.getElements();
2035 auto expectedNumElements = classOp.getNumPorts();
2037 return emitError() <<
"has wrong number of ports, got " <<
numElements
2038 <<
", expected " << expectedNumElements;
2040 auto portNames = classOp.getPortNames();
2041 auto portDirections = classOp.getPortDirections();
2042 auto portTypes = classOp.getPortTypes();
2045 auto element = elements[i];
2047 auto name = element.name;
2048 auto expectedName = portNames[i];
2049 if (name != expectedName)
2050 return emitError() <<
"port #" << i <<
" has wrong name, got " << name
2051 <<
", expected " << expectedName;
2053 auto direction = element.direction;
2054 auto expectedDirection =
Direction(portDirections[i]);
2055 if (direction != expectedDirection)
2056 return emitError() <<
"port " << name <<
" has wrong direction, got "
2060 auto type = element.type;
2061 auto expectedType = cast<TypeAttr>(portTypes[i]).getValue();
2062 if (type != expectedType)
2063 return emitError() <<
"port " << name <<
" has wrong type, got " << type
2064 <<
", expected " << expectedType;
2071 auto n = classOp.getNumPorts();
2072 SmallVector<ClassElement> elements;
2073 elements.reserve(n);
2074 for (
size_t i = 0; i < n; ++i)
2075 elements.push_back({classOp.getPortNameAttr(i), classOp.getPortType(i),
2076 classOp.getPortDirection(i)});
2077 auto name = FlatSymbolRefAttr::get(classOp.getNameAttr());
2078 return ClassType::get(name, elements);
2081template <
typename OpTy>
2083 bool hasSSAIdentifiers) {
2084 auto *
context = result.getContext();
2085 auto &builder = parser.getBuilder();
2086 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
2090 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
2093 StringAttr nameAttr;
2094 if (parser.parseSymbolName(nameAttr))
2096 properties.setSymName(nameAttr);
2099 SmallVector<OpAsmParser::Argument> entryArgs;
2100 SmallVector<Direction, 4> portDirections;
2101 SmallVector<Attribute, 4> portNames;
2102 SmallVector<Attribute, 4> portTypes;
2103 SmallVector<Attribute, 4> portAnnotations;
2104 SmallVector<Attribute, 4> portSyms;
2105 SmallVector<Attribute, 4> portLocs;
2106 SmallVector<Attribute, 4> domains;
2109 entryArgs, portDirections, portNames, portTypes,
2110 portAnnotations, portSyms, portLocs, domains))
2114 for (
auto annos : portAnnotations)
2115 if (!cast<ArrayAttr>(annos).empty())
2119 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
2122 assert(portNames.size() == portTypes.size());
2128 properties.setPortDirections(
2132 properties.setPortNames(builder.getArrayAttr(portNames));
2135 properties.setPortTypes(builder.getArrayAttr(portTypes));
2138 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
2139 properties.setPortSymbols(builder.getArrayAttr(portSyms));
2142 properties.setPortLocations(ArrayAttr::get(
context, portLocs));
2148 auto *bodyRegion = result.addRegion();
2150 if (hasSSAIdentifiers) {
2151 if (parser.parseRegion(*bodyRegion, entryArgs))
2153 if (bodyRegion->empty())
2154 bodyRegion->push_back(
new Block());
2164 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
2165 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
2166 p << visibility.getValue() <<
' ';
2169 p.printSymbolName(op.getName());
2173 Region ®ion = op->getRegion(0);
2174 Block *body =
nullptr;
2175 if (!region.empty())
2176 body = ®ion.front();
2179 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
2180 {}, op.getPortSymbols(), op.getPortLocations(), {});
2183 SmallVector<StringRef, 8> omittedAttrs = {
2184 "sym_name",
"portNames",
"portTypes",
"portDirections",
2185 "portSymbols",
"portLocations", visibilityAttrName,
"domainInfo"};
2189 if (!needPortNamesAttr)
2190 omittedAttrs.push_back(
"portNames");
2192 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
2195 if (!region.empty()) {
2197 auto printEntryBlockArgs =
false;
2198 auto printBlockTerminators =
false;
2199 p.printRegion(region, printEntryBlockArgs, printBlockTerminators);
2207void ClassOp::build(OpBuilder &builder, OperationState &result, StringAttr name,
2208 ArrayRef<PortInfo> ports) {
2211 [](
const auto &port) {
return port.annotations.empty(); }) &&
2212 "class ports may not have annotations");
2214 buildClass<ClassOp>(builder, result, name, ports);
2217 auto *bodyRegion = result.regions[0].get();
2219 bodyRegion->push_back(body);
2222 for (
auto &elt : ports)
2223 body->addArgument(elt.type, elt.loc);
2226void ClassOp::build(::mlir::OpBuilder &odsBuilder,
2227 ::mlir::OperationState &odsState, Twine name,
2228 mlir::ArrayRef<mlir::StringRef> fieldNames,
2229 mlir::ArrayRef<mlir::Type> fieldTypes) {
2231 SmallVector<PortInfo, 10> ports;
2232 for (
auto [fieldName, fieldType] :
llvm::zip(fieldNames, fieldTypes)) {
2233 ports.emplace_back(odsBuilder.getStringAttr(fieldName +
"_in"), fieldType,
2235 ports.emplace_back(odsBuilder.getStringAttr(fieldName), fieldType,
2238 build(odsBuilder, odsState, odsBuilder.getStringAttr(name), ports);
2240 auto &body = odsState.regions[0]->getBlocks().front();
2241 auto prevLoc = odsBuilder.saveInsertionPoint();
2242 odsBuilder.setInsertionPointToEnd(&body);
2243 auto args = body.getArguments();
2244 auto loc = odsState.location;
2245 for (
unsigned i = 0, e = ports.size(); i != e; i += 2)
2246 PropAssignOp::create(odsBuilder, loc, args[i + 1], args[i]);
2248 odsBuilder.restoreInsertionPoint(prevLoc);
2250void ClassOp::print(OpAsmPrinter &p) {
2254ParseResult ClassOp::parse(OpAsmParser &parser, OperationState &result) {
2255 auto hasSSAIdentifiers =
true;
2256 return parseClassLike<ClassOp>(parser, result, hasSSAIdentifiers);
2259LogicalResult ClassOp::verify() {
2261 auto type = operand.getType();
2262 if (!isa<PropertyType>(type)) {
2263 emitOpError(
"ports on a class must be properties");
2272ClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2276void ClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2281SmallVector<PortInfo> ClassOp::getPorts() {
2282 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2285void ClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2286 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2290void ClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2291 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2294Convention ClassOp::getConvention() {
return Convention::Internal; }
2296ConventionAttr ClassOp::getConventionAttr() {
2297 return ConventionAttr::get(getContext(), getConvention());
2300ArrayAttr ClassOp::getParameters() {
return {}; }
2302ArrayAttr ClassOp::getPortAnnotationsAttr() {
2303 return ArrayAttr::get(getContext(), {});
2306ArrayRef<Attribute> ClassOp::getPortAnnotations() {
return {}; }
2308void ClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2309 llvm_unreachable(
"classes do not support annotations");
2312ArrayAttr ClassOp::getLayersAttr() {
return ArrayAttr::get(getContext(), {}); }
2314ArrayRef<Attribute> ClassOp::getLayers() {
return {}; }
2316SmallVector<::circt::hw::PortInfo> ClassOp::getPortList() {
2317 return ::getPortListImpl(*
this);
2321 return ::getPortImpl(*
this, idx);
2324BlockArgument ClassOp::getArgument(
size_t portNumber) {
2328bool ClassOp::canDiscardOnUseEmpty() {
2339void ExtClassOp::build(OpBuilder &builder, OperationState &result,
2340 StringAttr name, ArrayRef<PortInfo> ports) {
2343 [](
const auto &port) {
return port.annotations.empty(); }) &&
2344 "class ports may not have annotations");
2345 buildClass<ClassOp>(builder, result, name, ports);
2348void ExtClassOp::print(OpAsmPrinter &p) {
2352ParseResult ExtClassOp::parse(OpAsmParser &parser, OperationState &result) {
2353 auto hasSSAIdentifiers =
false;
2354 return parseClassLike<ExtClassOp>(parser, result, hasSSAIdentifiers);
2358ExtClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2362void ExtClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2367SmallVector<PortInfo> ExtClassOp::getPorts() {
2368 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2371void ExtClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2372 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2375void ExtClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2376 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2379Convention ExtClassOp::getConvention() {
return Convention::Internal; }
2381ConventionAttr ExtClassOp::getConventionAttr() {
2382 return ConventionAttr::get(getContext(), getConvention());
2385ArrayAttr ExtClassOp::getLayersAttr() {
2386 return ArrayAttr::get(getContext(), {});
2389ArrayRef<Attribute> ExtClassOp::getLayers() {
return {}; }
2391ArrayAttr ExtClassOp::getParameters() {
return {}; }
2393ArrayAttr ExtClassOp::getPortAnnotationsAttr() {
2394 return ArrayAttr::get(getContext(), {});
2397ArrayRef<Attribute> ExtClassOp::getPortAnnotations() {
return {}; }
2399void ExtClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2400 llvm_unreachable(
"classes do not support annotations");
2403SmallVector<::circt::hw::PortInfo> ExtClassOp::getPortList() {
2404 return ::getPortListImpl(*
this);
2408 return ::getPortImpl(*
this, idx);
2411bool ExtClassOp::canDiscardOnUseEmpty() {
2422void InstanceOp::build(
2423 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2424 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2425 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2426 ArrayRef<Attribute> domainInfo, ArrayRef<Attribute> annotations,
2427 ArrayRef<Attribute> portAnnotations, ArrayRef<Attribute> layers,
2428 bool lowerToBind,
bool doNotPrint, StringAttr innerSym) {
2429 build(builder, result, resultTypes, moduleName, name, nameKind,
2430 portDirections, portNames, domainInfo, annotations, portAnnotations,
2431 layers, lowerToBind, doNotPrint,
2432 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr());
2435void InstanceOp::build(
2436 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2437 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2438 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2439 ArrayRef<Attribute> domainInfo, ArrayRef<Attribute> annotations,
2440 ArrayRef<Attribute> portAnnotations, ArrayRef<Attribute> layers,
2441 bool lowerToBind,
bool doNotPrint, hw::InnerSymAttr innerSym) {
2442 result.addTypes(resultTypes);
2443 result.getOrAddProperties<Properties>().setModuleName(
2444 SymbolRefAttr::get(builder.getContext(), moduleName));
2445 result.getOrAddProperties<Properties>().setName(builder.getStringAttr(name));
2446 result.getOrAddProperties<Properties>().setPortDirections(
2448 result.getOrAddProperties<Properties>().setPortNames(
2449 builder.getArrayAttr(portNames));
2451 if (domainInfo.empty()) {
2452 SmallVector<Attribute, 16> domainInfoVec(resultTypes.size(),
2453 builder.getArrayAttr({}));
2454 result.getOrAddProperties<Properties>().setDomainInfo(
2455 builder.getArrayAttr(domainInfoVec));
2457 assert(domainInfo.size() == resultTypes.size());
2458 result.getOrAddProperties<Properties>().setDomainInfo(
2459 builder.getArrayAttr(domainInfo));
2462 result.getOrAddProperties<Properties>().setAnnotations(
2463 builder.getArrayAttr(annotations));
2464 result.getOrAddProperties<Properties>().setLayers(
2465 builder.getArrayAttr(layers));
2467 result.getOrAddProperties<Properties>().setLowerToBind(
2468 builder.getUnitAttr());
2470 result.getOrAddProperties<Properties>().setDoNotPrint(
2471 builder.getUnitAttr());
2473 result.getOrAddProperties<Properties>().setInnerSym(innerSym);
2475 result.getOrAddProperties<Properties>().setNameKind(
2476 NameKindEnumAttr::get(builder.getContext(), nameKind));
2478 if (portAnnotations.empty()) {
2479 SmallVector<Attribute, 16> portAnnotationsVec(resultTypes.size(),
2480 builder.getArrayAttr({}));
2481 result.getOrAddProperties<Properties>().setPortAnnotations(
2482 builder.getArrayAttr(portAnnotationsVec));
2484 assert(portAnnotations.size() == resultTypes.size());
2485 result.getOrAddProperties<Properties>().setPortAnnotations(
2486 builder.getArrayAttr(portAnnotations));
2490void InstanceOp::build(OpBuilder &builder, OperationState &result,
2491 FModuleLike module, StringRef name,
2492 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2493 ArrayRef<Attribute> portAnnotations,
bool lowerToBind,
2494 bool doNotPrint, hw::InnerSymAttr innerSym) {
2497 SmallVector<Type> resultTypes;
2498 resultTypes.reserve(module.getNumPorts());
2500 module.getPortTypes(), std::back_inserter(resultTypes),
2501 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2506 ArrayAttr portAnnotationsAttr;
2507 if (portAnnotations.empty()) {
2508 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2509 resultTypes.size(), builder.getArrayAttr({})));
2511 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2513 ArrayAttr domainInfoAttr =
module.getDomainInfoAttr();
2514 if (domainInfoAttr.empty()) {
2515 domainInfoAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2516 resultTypes.size(), builder.getArrayAttr({})));
2520 builder, result, resultTypes,
2521 SymbolRefAttr::get(builder.getContext(), module.getModuleNameAttr()),
2522 builder.getStringAttr(name),
2523 NameKindEnumAttr::get(builder.getContext(), nameKind),
2524 module.getPortDirectionsAttr(), module.getPortNamesAttr(), domainInfoAttr,
2525 builder.getArrayAttr(annotations), portAnnotationsAttr,
2526 module.getLayersAttr(), lowerToBind ? builder.getUnitAttr() : UnitAttr(),
2527 doNotPrint ? builder.getUnitAttr() : UnitAttr(), innerSym);
2530void InstanceOp::build(OpBuilder &builder, OperationState &odsState,
2531 ArrayRef<PortInfo> ports, StringRef moduleName,
2532 StringRef name, NameKindEnum nameKind,
2533 ArrayRef<Attribute> annotations,
2534 ArrayRef<Attribute> layers,
bool lowerToBind,
2535 bool doNotPrint, hw::InnerSymAttr innerSym) {
2537 SmallVector<Type> newResultTypes;
2538 SmallVector<Direction> newPortDirections;
2539 SmallVector<Attribute> newPortNames;
2540 SmallVector<Attribute> newPortAnnotations;
2541 SmallVector<Attribute> newDomainInfo;
2542 for (
auto &p : ports) {
2543 newResultTypes.push_back(p.type);
2544 newPortDirections.push_back(p.direction);
2545 newPortNames.push_back(p.name);
2546 newPortAnnotations.push_back(p.annotations.getArrayAttr());
2548 newDomainInfo.push_back(p.domains);
2550 newDomainInfo.push_back(builder.getArrayAttr({}));
2553 return build(builder, odsState, newResultTypes, moduleName, name, nameKind,
2554 newPortDirections, newPortNames, newDomainInfo, annotations,
2555 newPortAnnotations, layers, lowerToBind, doNotPrint, innerSym);
2558LogicalResult InstanceOp::verify() {
2561 SmallVector<SymbolRefAttr> missingLayers;
2562 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
2564 missingLayers.push_back(layer);
2566 if (missingLayers.empty())
2570 emitOpError(
"ambient layers are insufficient to instantiate module");
2571 auto ¬e = diag.attachNote();
2572 note <<
"missing layer requirements: ";
2573 interleaveComma(missingLayers, note);
2578 Operation *op1, Operation *op2,
2579 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2581 size_t n = insertions.size();
2582 size_t inserted = 0;
2583 for (
size_t i = 0, e = op1->getNumResults(); i < e; ++i) {
2584 while (inserted < n) {
2585 auto &[index, portInfo] = insertions[inserted];
2590 auto r1 = op1->getResult(i);
2591 auto r2 = op2->getResult(i + inserted);
2592 r1.replaceAllUsesWith(r2);
2597 const llvm::BitVector &erasures) {
2600 for (
size_t i = 0, e = op1->getNumResults(); i < e; ++i) {
2601 auto r1 = op1->getResult(i);
2603 assert(r1.use_empty() &&
"removed instance port has uses");
2607 auto r2 = op2->getResult(i - erased);
2608 r1.replaceAllUsesWith(r2);
2612InstanceOp InstanceOp::cloneWithErasedPorts(
const llvm::BitVector &erasures) {
2613 assert(erasures.size() >= getNumResults() &&
2614 "erasures is not at least as large as getNumResults()");
2616 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
2617 SmallVector<Type>(result_type_begin(), result_type_end()), erasures);
2618 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
2620 SmallVector<Attribute> newPortNames =
2622 SmallVector<Attribute> newPortAnnotations =
2624 ArrayAttr newDomainInfo =
2628 OpBuilder builder(*
this);
2629 auto clone = InstanceOp::create(
2630 builder,
getLoc(), newResultTypes, getModuleName(),
getName(),
2631 getNameKind(), newPortDirections, newPortNames, newDomainInfo.getValue(),
2632 getAnnotations().getValue(), newPortAnnotations, getLayers(),
2633 getLowerToBind(), getDoNotPrint(), getInnerSymAttr());
2635 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2636 clone->setAttr(
"output_file", outputFile);
2641InstanceOp InstanceOp::cloneWithErasedPortsAndReplaceUses(
2642 const llvm::BitVector &erasures) {
2643 auto clone = cloneWithErasedPorts(erasures);
2648ArrayAttr InstanceOp::getPortAnnotation(
unsigned portIdx) {
2649 assert(portIdx < getNumResults() &&
2650 "index should be smaller than result number");
2651 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
2654void InstanceOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
2655 assert(annotations.size() == getNumResults() &&
2656 "number of annotations is not equal to result number");
2657 (*this)->setAttr(
"portAnnotations",
2658 ArrayAttr::get(getContext(), annotations));
2661ArrayAttr InstanceOp::getPortDomain(
unsigned portIdx) {
2662 assert(portIdx < getNumResults() &&
2663 "index should be smaller than result number");
2664 return cast<ArrayAttr>(getDomainInfo()[portIdx]);
2667InstanceOp InstanceOp::cloneWithInsertedPorts(
2668 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2672 auto oldPortCount = getNumResults();
2673 auto numInsertions = insertions.size();
2674 auto newPortCount = oldPortCount + numInsertions;
2676 SmallVector<Direction> newPortDirections;
2677 SmallVector<Attribute> newPortNames;
2678 SmallVector<Type> newPortTypes;
2679 SmallVector<Attribute> newPortAnnos;
2680 SmallVector<Attribute> newDomainInfo;
2682 newPortDirections.reserve(newPortCount);
2683 newPortNames.reserve(newPortCount);
2684 newPortTypes.reserve(newPortCount);
2685 newPortAnnos.reserve(newPortCount);
2686 newDomainInfo.reserve(newPortCount);
2688 SmallVector<unsigned> indexMap(oldPortCount);
2690 size_t inserted = 0;
2691 for (
size_t i = 0; i < oldPortCount; ++i) {
2692 while (inserted < numInsertions) {
2693 auto &[index,
info] = insertions[inserted];
2699 newPortDirections.push_back(
info.direction);
2700 newPortNames.push_back(
info.name);
2701 newPortTypes.push_back(
info.type);
2702 newPortAnnos.push_back(
info.annotations.getArrayAttr());
2703 newDomainInfo.push_back(domains);
2707 newPortDirections.push_back(getPortDirection(i));
2708 newPortNames.push_back(getPortNameAttr(i));
2709 newPortTypes.push_back(getType(i));
2710 newPortAnnos.push_back(getPortAnnotation(i));
2711 newDomainInfo.push_back(getDomainInfo()[i]);
2712 indexMap[i] = i + inserted;
2715 while (inserted < numInsertions) {
2716 auto &[index,
info] = insertions[inserted];
2719 newPortDirections.push_back(
info.direction);
2720 newPortNames.push_back(
info.name);
2721 newPortTypes.push_back(
info.type);
2722 newPortAnnos.push_back(
info.annotations.getArrayAttr());
2723 newDomainInfo.push_back(domains);
2727 OpBuilder builder(*
this);
2728 auto clone = InstanceOp::create(
2729 builder,
getLoc(), newPortTypes, getModuleName(),
getName(),
2730 getNameKind(), newPortDirections, newPortNames, newDomainInfo,
2731 getAnnotations().getValue(), newPortAnnos, getLayers(), getLowerToBind(),
2732 getDoNotPrint(), getInnerSymAttr());
2734 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2735 clone->setAttr(
"output_file", outputFile);
2740InstanceOp InstanceOp::cloneWithInsertedPortsAndReplaceUses(
2741 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2742 auto clone = cloneWithInsertedPorts(insertions);
2747LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2749 getModuleNameAttr());
2752StringRef InstanceOp::getInstanceName() {
return getName(); }
2754StringAttr InstanceOp::getInstanceNameAttr() {
return getNameAttr(); }
2756void InstanceOp::print(OpAsmPrinter &p) {
2759 p.printKeywordOrString(
getName());
2760 if (
auto attr = getInnerSymAttr()) {
2762 p.printSymbolName(attr.getSymName());
2764 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2765 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2768 SmallVector<StringRef, 10> omittedAttrs = {
2769 "moduleName",
"name",
"portDirections",
2770 "portNames",
"portTypes",
"portAnnotations",
2771 "inner_sym",
"nameKind",
"domainInfo"};
2772 if (getAnnotations().
empty())
2773 omittedAttrs.push_back(
"annotations");
2774 if (getLayers().
empty())
2775 omittedAttrs.push_back(
"layers");
2776 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2780 p.printSymbolName(getModuleName());
2783 SmallVector<Attribute> portTypes;
2784 portTypes.reserve(getNumResults());
2785 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2789 getPortNames().getValue(), portTypes,
2790 getPortAnnotations().getValue(), {}, {},
2791 getDomainInfo().getValue());
2794ParseResult InstanceOp::parse(OpAsmParser &parser, OperationState &result) {
2795 auto *
context = parser.getContext();
2796 auto &properties = result.getOrAddProperties<Properties>();
2799 hw::InnerSymAttr innerSymAttr;
2800 FlatSymbolRefAttr moduleName;
2801 SmallVector<OpAsmParser::Argument> entryArgs;
2802 SmallVector<Direction, 4> portDirections;
2803 SmallVector<Attribute, 4> portNames;
2804 SmallVector<Attribute, 4> portTypes;
2805 SmallVector<Attribute, 4> portAnnotations;
2806 SmallVector<Attribute, 4> portSyms;
2807 SmallVector<Attribute, 4> portLocs;
2808 SmallVector<Attribute, 4> domains;
2809 NameKindEnumAttr nameKind;
2811 if (parser.parseKeywordOrString(&name))
2813 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
2814 if (parser.parseCustomAttributeWithFallback(
2815 innerSymAttr, ::mlir::Type{},
2817 result.attributes)) {
2818 return ::mlir::failure();
2822 parser.parseOptionalAttrDict(result.attributes) ||
2823 parser.parseAttribute(moduleName) ||
2826 entryArgs, portDirections, portNames, portTypes,
2827 portAnnotations, portSyms, portLocs, domains))
2833 properties.setModuleName(moduleName);
2834 properties.setName(StringAttr::get(
context, name));
2835 properties.setNameKind(nameKind);
2836 properties.setPortDirections(
2838 properties.setPortNames(ArrayAttr::get(
context, portNames));
2839 properties.setPortAnnotations(ArrayAttr::get(
context, portAnnotations));
2843 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
2844 properties.setLayers(parser.getBuilder().getArrayAttr({}));
2847 properties.setDomainInfo(ArrayAttr::get(
context, domains));
2850 result.types.reserve(portTypes.size());
2852 portTypes, std::back_inserter(result.types),
2853 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2858void InstanceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
2863 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
2864 setNameFn(getResult(i), (base +
"_" + getPortName(i)).str());
2868std::optional<size_t> InstanceOp::getTargetResultIndex() {
2870 return std::nullopt;
2877void InstanceChoiceOp::build(
2878 OpBuilder &builder, OperationState &result, FModuleLike defaultModule,
2879 ArrayRef<std::pair<OptionCaseOp, FModuleLike>> cases, StringRef name,
2880 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2881 ArrayRef<Attribute> portAnnotations, StringAttr innerSym) {
2883 SmallVector<Type> resultTypes;
2884 for (Attribute portType : defaultModule.getPortTypes())
2885 resultTypes.push_back(cast<TypeAttr>(portType).getValue());
2888 ArrayAttr portAnnotationsAttr;
2889 if (portAnnotations.empty()) {
2890 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2891 resultTypes.size(), builder.getArrayAttr({})));
2893 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2897 ArrayAttr domainInfoAttr = defaultModule.getDomainInfoAttr();
2898 if (domainInfoAttr.empty()) {
2899 domainInfoAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2900 resultTypes.size(), builder.getArrayAttr({})));
2904 SmallVector<Attribute> moduleNames, caseNames;
2905 moduleNames.push_back(SymbolRefAttr::get(defaultModule.getModuleNameAttr()));
2906 for (
auto [caseOption, caseModule] : cases) {
2907 auto caseGroup = caseOption->getParentOfType<OptionOp>();
2908 caseNames.push_back(SymbolRefAttr::get(caseGroup.getSymNameAttr(),
2909 {SymbolRefAttr::get(caseOption)}));
2910 moduleNames.push_back(SymbolRefAttr::get(caseModule.getModuleNameAttr()));
2913 return build(builder, result, resultTypes, builder.getArrayAttr(moduleNames),
2914 builder.getArrayAttr(caseNames), builder.getStringAttr(name),
2915 NameKindEnumAttr::get(builder.getContext(), nameKind),
2916 defaultModule.getPortDirectionsAttr(),
2917 defaultModule.getPortNamesAttr(), domainInfoAttr,
2918 builder.getArrayAttr(annotations), portAnnotationsAttr,
2919 defaultModule.getLayersAttr(),
2920 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr());
2923std::optional<size_t> InstanceChoiceOp::getTargetResultIndex() {
2924 return std::nullopt;
2927void InstanceChoiceOp::print(OpAsmPrinter &p) {
2930 p.printKeywordOrString(
getName());
2931 if (
auto attr = getInnerSymAttr()) {
2933 p.printSymbolName(attr.getSymName());
2935 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2936 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2939 SmallVector<StringRef, 11> omittedAttrs = {
2940 "moduleNames",
"caseNames",
"name",
2941 "portDirections",
"portNames",
"portTypes",
2942 "portAnnotations",
"inner_sym",
"nameKind",
2944 if (getAnnotations().
empty())
2945 omittedAttrs.push_back(
"annotations");
2946 if (getLayers().
empty())
2947 omittedAttrs.push_back(
"layers");
2948 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2953 auto moduleNames = getModuleNamesAttr();
2954 auto caseNames = getCaseNamesAttr();
2956 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[0]).getValue());
2958 p <<
" alternatives ";
2960 cast<SymbolRefAttr>(caseNames[0]).getRootReference().getValue());
2962 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
2966 auto symbol = cast<SymbolRefAttr>(caseNames[i]);
2967 p.printSymbolName(symbol.getNestedReferences()[0].getValue());
2969 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[i + 1]).getValue());
2975 SmallVector<Attribute> portTypes;
2976 portTypes.reserve(getNumResults());
2977 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2980 getPortNames().getValue(), portTypes,
2981 getPortAnnotations().getValue(), {}, {},
2982 getDomainInfo().getValue());
2985ParseResult InstanceChoiceOp::parse(OpAsmParser &parser,
2986 OperationState &result) {
2987 auto *
context = parser.getContext();
2988 auto &properties = result.getOrAddProperties<Properties>();
2991 hw::InnerSymAttr innerSymAttr;
2992 SmallVector<Attribute> moduleNames;
2993 SmallVector<Attribute> caseNames;
2994 SmallVector<OpAsmParser::Argument> entryArgs;
2995 SmallVector<Direction, 4> portDirections;
2996 SmallVector<Attribute, 4> portNames;
2997 SmallVector<Attribute, 4> portTypes;
2998 SmallVector<Attribute, 4> portAnnotations;
2999 SmallVector<Attribute, 4> portSyms;
3000 SmallVector<Attribute, 4> portLocs;
3001 SmallVector<Attribute, 4> domains;
3002 NameKindEnumAttr nameKind;
3004 if (parser.parseKeywordOrString(&name))
3006 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
3007 if (parser.parseCustomAttributeWithFallback(
3008 innerSymAttr, Type{},
3010 result.attributes)) {
3015 parser.parseOptionalAttrDict(result.attributes))
3018 FlatSymbolRefAttr defaultModuleName;
3019 if (parser.parseAttribute(defaultModuleName))
3021 moduleNames.push_back(defaultModuleName);
3025 FlatSymbolRefAttr optionName;
3026 if (parser.parseKeyword(
"alternatives") ||
3027 parser.parseAttribute(optionName) || parser.parseLBrace())
3030 FlatSymbolRefAttr moduleName;
3031 StringAttr caseName;
3032 while (succeeded(parser.parseOptionalSymbolName(caseName))) {
3033 if (parser.parseArrow() || parser.parseAttribute(moduleName))
3035 moduleNames.push_back(moduleName);
3036 caseNames.push_back(SymbolRefAttr::get(
3037 optionName.getAttr(), {FlatSymbolRefAttr::get(caseName)}));
3038 if (failed(parser.parseOptionalComma()))
3041 if (parser.parseRBrace())
3047 entryArgs, portDirections, portNames, portTypes,
3048 portAnnotations, portSyms, portLocs, domains))
3053 properties.setModuleNames(ArrayAttr::get(
context, moduleNames));
3054 properties.setCaseNames(ArrayAttr::get(
context, caseNames));
3055 properties.setName(StringAttr::get(
context, name));
3056 properties.setNameKind(nameKind);
3057 properties.setPortDirections(
3059 properties.setPortNames(ArrayAttr::get(
context, portNames));
3060 properties.setDomainInfo(ArrayAttr::get(
context, domains));
3061 properties.setPortAnnotations(ArrayAttr::get(
context, portAnnotations));
3065 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
3066 properties.setLayers(parser.getBuilder().getArrayAttr({}));
3069 result.types.reserve(portTypes.size());
3071 portTypes, std::back_inserter(result.types),
3072 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
3077void InstanceChoiceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3079 for (
auto [result, name] :
llvm::zip(getResults(), getPortNames()))
3080 setNameFn(result, (base +
"_" + cast<StringAttr>(name).getValue()).str());
3083LogicalResult InstanceChoiceOp::verify() {
3084 if (getCaseNamesAttr().
empty())
3085 return emitOpError() <<
"must have at least one case";
3086 if (getModuleNamesAttr().size() != getCaseNamesAttr().size() + 1)
3087 return emitOpError() <<
"number of referenced modules does not match the "
3088 "number of options";
3093 SmallVector<SymbolRefAttr> missingLayers;
3094 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
3096 missingLayers.push_back(layer);
3098 if (missingLayers.empty())
3102 emitOpError(
"ambient layers are insufficient to instantiate module");
3103 auto ¬e = diag.attachNote();
3104 note <<
"missing layer requirements: ";
3105 interleaveComma(missingLayers, note);
3110InstanceChoiceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3111 auto caseNames = getCaseNamesAttr();
3112 for (
auto moduleName : getModuleNamesAttr()) {
3114 *
this, symbolTable, cast<FlatSymbolRefAttr>(moduleName))))
3118 auto root = cast<SymbolRefAttr>(caseNames[0]).getRootReference();
3119 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3120 auto ref = cast<SymbolRefAttr>(caseNames[i]);
3121 auto refRoot = ref.getRootReference();
3122 if (ref.getRootReference() != root)
3123 return emitOpError() <<
"case " << ref
3124 <<
" is not in the same option group as "
3127 if (!symbolTable.lookupNearestSymbolFrom<OptionOp>(*
this, refRoot))
3128 return emitOpError() <<
"option " << refRoot <<
" does not exist";
3130 if (!symbolTable.lookupNearestSymbolFrom<OptionCaseOp>(*
this, ref))
3131 return emitOpError() <<
"option " << refRoot
3132 <<
" does not contain option case " << ref;
3139InstanceChoiceOp::getTargetOrDefaultAttr(OptionCaseOp option) {
3140 auto caseNames = getCaseNamesAttr();
3141 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3142 StringAttr caseSym = cast<SymbolRefAttr>(caseNames[i]).getLeafReference();
3143 if (caseSym == option.getSymName())
3144 return cast<FlatSymbolRefAttr>(getModuleNamesAttr()[i + 1]);
3146 return getDefaultTargetAttr();
3149SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1>
3150InstanceChoiceOp::getTargetChoices() {
3151 auto caseNames = getCaseNamesAttr();
3152 auto moduleNames = getModuleNamesAttr();
3153 SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1> choices;
3154 for (
size_t i = 0; i < caseNames.size(); ++i) {
3155 choices.emplace_back(cast<SymbolRefAttr>(caseNames[i]),
3156 cast<FlatSymbolRefAttr>(moduleNames[i + 1]));
3162InstanceChoiceOp InstanceChoiceOp::cloneWithInsertedPorts(
3163 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
3167 auto oldPortCount = getNumResults();
3168 auto numInsertions = insertions.size();
3169 auto newPortCount = oldPortCount + numInsertions;
3171 SmallVector<Direction> newPortDirections;
3172 SmallVector<Attribute> newPortNames;
3173 SmallVector<Type> newPortTypes;
3174 SmallVector<Attribute> newPortAnnos;
3175 SmallVector<Attribute> newDomainInfo;
3177 newPortDirections.reserve(newPortCount);
3178 newPortNames.reserve(newPortCount);
3179 newPortTypes.reserve(newPortCount);
3180 newPortAnnos.reserve(newPortCount);
3181 newDomainInfo.reserve(newPortCount);
3183 SmallVector<unsigned> indexMap(oldPortCount);
3185 size_t inserted = 0;
3186 for (
size_t i = 0; i < oldPortCount; ++i) {
3187 while (inserted < numInsertions) {
3188 auto &[index,
info] = insertions[inserted];
3194 newPortDirections.push_back(
info.direction);
3195 newPortNames.push_back(
info.name);
3196 newPortTypes.push_back(
info.type);
3197 newPortAnnos.push_back(
info.annotations.getArrayAttr());
3198 newDomainInfo.push_back(domains);
3202 newPortDirections.push_back(getPortDirection(i));
3203 newPortNames.push_back(getPortNameAttr(i));
3204 newPortTypes.push_back(getType(i));
3205 newPortAnnos.push_back(getPortAnnotations()[i]);
3206 newDomainInfo.push_back(getDomainInfo()[i]);
3207 indexMap[i] = i + inserted;
3210 while (inserted < numInsertions) {
3211 auto &[index,
info] = insertions[inserted];
3214 newPortDirections.push_back(
info.direction);
3215 newPortNames.push_back(
info.name);
3216 newPortTypes.push_back(
info.type);
3217 newPortAnnos.push_back(
info.annotations.getArrayAttr());
3218 newDomainInfo.push_back(domains);
3222 OpBuilder builder(*
this);
3223 auto clone = InstanceChoiceOp::create(
3224 builder,
getLoc(), newPortTypes, getModuleNames(), getCaseNames(),
3227 ArrayAttr::get(
context, newPortNames),
3228 ArrayAttr::get(
context, newDomainInfo), getAnnotationsAttr(),
3229 ArrayAttr::get(
context, newPortAnnos), getLayers(), getInnerSymAttr());
3231 if (
auto outputFile = (*this)->getAttr(
"output_file"))
3232 clone->setAttr(
"output_file", outputFile);
3237InstanceChoiceOp InstanceChoiceOp::cloneWithInsertedPortsAndReplaceUses(
3238 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
3239 auto clone = cloneWithInsertedPorts(insertions);
3245InstanceChoiceOp::cloneWithErasedPorts(
const llvm::BitVector &erasures) {
3246 assert(erasures.size() >= getNumResults() &&
3247 "erasures is not at least as large as getNumResults()");
3249 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
3250 SmallVector<Type>(result_type_begin(), result_type_end()), erasures);
3251 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
3253 SmallVector<Attribute> newPortNames =
3255 SmallVector<Attribute> newPortAnnotations =
3257 ArrayAttr newPortDomains =
3261 OpBuilder builder(*
this);
3262 auto clone = InstanceChoiceOp::create(
3263 builder,
getLoc(), newResultTypes, getModuleNames(), getCaseNames(),
3266 ArrayAttr::get(getContext(), newPortNames), newPortDomains,
3267 getAnnotationsAttr(), ArrayAttr::get(getContext(), newPortAnnotations),
3268 getLayers(), getInnerSymAttr());
3270 if (
auto outputFile = (*this)->getAttr(
"output_file"))
3271 clone->setAttr(
"output_file", outputFile);
3276InstanceChoiceOp InstanceChoiceOp::cloneWithErasedPortsAndReplaceUses(
3277 const llvm::BitVector &erasures) {
3278 auto clone = cloneWithErasedPorts(erasures);
3287ArrayAttr MemOp::getPortAnnotation(
unsigned portIdx) {
3288 assert(portIdx < getNumResults() &&
3289 "index should be smaller than result number");
3290 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
3293void MemOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
3294 assert(annotations.size() == getNumResults() &&
3295 "number of annotations is not equal to result number");
3296 (*this)->setAttr(
"portAnnotations",
3297 ArrayAttr::get(getContext(), annotations));
3301void MemOp::getNumPorts(
size_t &numReadPorts,
size_t &numWritePorts,
3302 size_t &numReadWritePorts,
size_t &numDbgsPorts) {
3305 numReadWritePorts = 0;
3307 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3308 auto portKind = getPortKind(i);
3309 if (portKind == MemOp::PortKind::Debug)
3311 else if (portKind == MemOp::PortKind::Read)
3313 else if (portKind == MemOp::PortKind::Write) {
3316 ++numReadWritePorts;
3321LogicalResult MemOp::verify() {
3325 llvm::SmallDenseSet<Attribute, 8> portNamesSet;
3331 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3332 auto portName = getPortNameAttr(i);
3337 BundleType portBundleType =
3338 type_dyn_cast<BundleType>(getResult(i).getType());
3341 if (!portNamesSet.insert(portName).second) {
3342 emitOpError() <<
"has non-unique port name " << portName;
3350 auto elt = getPortNamed(portName);
3352 emitOpError() <<
"could not get port with name " << portName;
3355 auto firrtlType = type_cast<FIRRTLType>(elt.getType());
3358 if (portKind == MemOp::PortKind::Debug &&
3359 !type_isa<RefType>(getResult(i).getType()))
3360 return emitOpError() <<
"has an invalid type on port " << portName
3361 <<
" (expected Read/Write/ReadWrite/Debug)";
3362 if (type_isa<RefType>(firrtlType) && e == 1)
3363 return emitOpError()
3364 <<
"cannot have only one port of debug type. Debug port can only "
3365 "exist alongside other read/write/read-write port";
3370 if (portKind == MemOp::PortKind::Debug) {
3371 auto resType = type_cast<RefType>(getResult(i).getType());
3372 if (!(resType && type_isa<FVectorType>(resType.getType())))
3373 return emitOpError() <<
"debug ports must be a RefType of FVectorType";
3374 dataType = type_cast<FVectorType>(resType.getType()).getElementType();
3376 auto dataTypeOption = portBundleType.getElement(
"data");
3377 if (!dataTypeOption && portKind == MemOp::PortKind::ReadWrite)
3378 dataTypeOption = portBundleType.getElement(
"wdata");
3379 if (!dataTypeOption) {
3380 emitOpError() <<
"has no data field on port " << portName
3381 <<
" (expected to see \"data\" for a read or write "
3382 "port or \"rdata\" for a read/write port)";
3385 dataType = dataTypeOption->type;
3387 if (portKind == MemOp::PortKind::Read) {
3394 emitOpError() <<
"has non-passive data type on port " << portName
3395 <<
" (memory types must be passive)";
3400 if (dataType.containsAnalog()) {
3401 emitOpError() <<
"has a data type that contains an analog type on port "
3403 <<
" (memory types cannot contain analog types)";
3411 getTypeForPort(getDepth(), dataType, portKind,
3412 dataType.isGround() ? getMaskBits() : 0);
3415 auto originalType = getResult(i).getType();
3416 if (originalType != expectedType) {
3417 StringRef portKindName;
3419 case MemOp::PortKind::Read:
3420 portKindName =
"read";
3422 case MemOp::PortKind::Write:
3423 portKindName =
"write";
3425 case MemOp::PortKind::ReadWrite:
3426 portKindName =
"readwrite";
3428 case MemOp::PortKind::Debug:
3429 portKindName =
"dbg";
3432 emitOpError() <<
"has an invalid type for port " << portName
3433 <<
" of determined kind \"" << portKindName
3434 <<
"\" (expected " << expectedType <<
", but got "
3435 << originalType <<
")";
3441 if (oldDataType && oldDataType != dataType) {
3442 emitOpError() <<
"port " << getPortNameAttr(i)
3443 <<
" has a different type than port "
3444 << getPortNameAttr(i - 1) <<
" (expected " << oldDataType
3445 <<
", but got " << dataType <<
")";
3449 oldDataType = dataType;
3452 auto maskWidth = getMaskBits();
3454 auto dataWidth = getDataType().getBitWidthOrSentinel();
3455 if (dataWidth > 0 && maskWidth > (
size_t)dataWidth)
3456 return emitOpError(
"the mask width cannot be greater than "
3459 if (getPortAnnotations().size() != getNumResults())
3460 return emitOpError(
"the number of result annotations should be "
3461 "equal to the number of results");
3467 return std::max(1U, llvm::Log2_64_Ceil(depth));
3473 PortKind portKind,
size_t maskBits) {
3475 auto *
context = dataType.getContext();
3476 if (portKind == PortKind::Debug)
3477 return RefType::get(FVectorType::get(dataType, depth));
3483 maskType = UIntType::get(
context, maskBits);
3485 auto getId = [&](StringRef name) -> StringAttr {
3486 return StringAttr::get(
context, name);
3489 SmallVector<BundleType::BundleElement, 7> portFields;
3493 portFields.push_back({getId(
"addr"),
false, addressType});
3494 portFields.push_back({getId(
"en"),
false, UIntType::get(
context, 1)});
3495 portFields.push_back({getId(
"clk"),
false, ClockType::get(
context)});
3498 case PortKind::Read:
3499 portFields.push_back({getId(
"data"),
true, dataType});
3502 case PortKind::Write:
3503 portFields.push_back({getId(
"data"),
false, dataType});
3504 portFields.push_back({getId(
"mask"),
false, maskType});
3507 case PortKind::ReadWrite:
3508 portFields.push_back({getId(
"rdata"),
true, dataType});
3509 portFields.push_back({getId(
"wmode"),
false, UIntType::get(
context, 1)});
3510 portFields.push_back({getId(
"wdata"),
false, dataType});
3511 portFields.push_back({getId(
"wmask"),
false, maskType});
3514 llvm::report_fatal_error(
"memory port kind not handled");
3518 return BundleType::get(
context, portFields);
3522SmallVector<MemOp::NamedPort> MemOp::getPorts() {
3523 SmallVector<MemOp::NamedPort> result;
3525 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3527 auto portType = type_cast<FIRRTLType>(getResult(i).getType());
3534MemOp::PortKind MemOp::getPortKind(StringRef portName) {
3536 type_cast<FIRRTLType>(getPortNamed(portName).getType()));
3540MemOp::PortKind MemOp::getPortKind(
size_t resultNo) {
3542 type_cast<FIRRTLType>(getResult(resultNo).getType()));
3546size_t MemOp::getMaskBits() {
3548 for (
auto res : getResults()) {
3549 if (type_isa<RefType>(res.getType()))
3551 auto firstPortType = type_cast<FIRRTLBaseType>(res.getType());
3558 if (t.name.getValue().contains(
"mask"))
3561 if (type_isa<UIntType>(mType))
3571 assert(getNumResults() != 0 &&
"Mems with no read/write ports are illegal");
3573 if (
auto refType = type_dyn_cast<RefType>(getResult(0).getType()))
3574 return type_cast<FVectorType>(refType.getType()).getElementType();
3575 auto firstPortType = type_cast<FIRRTLBaseType>(getResult(0).getType());
3577 StringRef dataFieldName =
"data";
3579 dataFieldName =
"rdata";
3581 return type_cast<BundleType>(firstPortType.getPassiveType())
3582 .getElementType(dataFieldName);
3585StringAttr MemOp::getPortNameAttr(
size_t resultNo) {
3586 return cast<StringAttr>(getPortNames()[resultNo]);
3590 return type_cast<FIRRTLBaseType>(getResults()[resultNo].getType());
3593Value MemOp::getPortNamed(StringAttr name) {
3594 auto namesArray = getPortNames();
3595 for (
size_t i = 0, e = namesArray.size(); i != e; ++i) {
3596 if (namesArray[i] == name) {
3597 assert(i < getNumResults() &&
" names array out of sync with results");
3598 return getResult(i);
3607 size_t numReadPorts = 0;
3608 size_t numWritePorts = 0;
3609 size_t numReadWritePorts = 0;
3611 SmallVector<int32_t> writeClockIDs;
3613 for (
size_t i = 0, e = op.getNumResults(); i != e; ++i) {
3614 auto portKind = op.getPortKind(i);
3615 if (portKind == MemOp::PortKind::Read)
3617 else if (portKind == MemOp::PortKind::Write) {
3618 for (
auto *a : op.getResult(i).getUsers()) {
3619 auto subfield = dyn_cast<SubfieldOp>(a);
3620 if (!subfield || subfield.getFieldIndex() != 2)
3622 auto clockPort = a->getResult(0);
3623 for (
auto *b : clockPort.getUsers()) {
3624 if (
auto connect = dyn_cast<FConnectLike>(b)) {
3625 if (
connect.getDest() == clockPort) {
3628 connect.getSrc(),
true,
true,
true),
3630 if (result.second) {
3631 writeClockIDs.push_back(numWritePorts);
3633 writeClockIDs.push_back(result.first->second);
3642 ++numReadWritePorts;
3649 op.emitError(
"'firrtl.mem' should have simple type and known width");
3650 MemoryInitAttr init = op->getAttrOfType<MemoryInitAttr>(
"init");
3652 if (op->hasAttr(
"modName"))
3653 modName = op->getAttrOfType<StringAttr>(
"modName");
3655 SmallString<8> clocks;
3656 for (
auto a : writeClockIDs)
3657 clocks.
append(Twine((char)(a +
'a')).str());
3658 SmallString<32> initStr;
3663 for (
auto c : init.getFilename().getValue())
3664 if ((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') ||
3665 (c >=
'0' && c <=
'9'))
3666 initStr.push_back(c);
3667 initStr.push_back(
'_');
3668 initStr.push_back(init.getIsBinary() ?
't' :
'f');
3669 initStr.push_back(
'_');
3670 initStr.push_back(init.getIsInline() ?
't' :
'f');
3672 modName = StringAttr::get(
3675 "{0}FIRRTLMem_{1}_{2}_{3}_{4}_{5}_{6}_{7}_{8}_{9}_{10}{11}{12}",
3676 op.getPrefix().value_or(
""), numReadPorts, numWritePorts,
3677 numReadWritePorts, (
size_t)width, op.getDepth(),
3678 op.getReadLatency(), op.getWriteLatency(), op.getMaskBits(),
3679 (
unsigned)op.getRuw(), (
unsigned)seq::WUW::PortOrder,
3680 clocks.empty() ?
"" :
"_" + clocks, init ? initStr.str() :
""));
3682 return {numReadPorts,
3687 op.getReadLatency(),
3688 op.getWriteLatency(),
3690 *seq::symbolizeRUW(
unsigned(op.getRuw())),
3691 seq::WUW::PortOrder,
3694 op.getMaskBits() > 1,
3700void MemOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3705 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
3706 setNameFn(getResult(i), (base +
"_" + getPortName(i)).str());
3710std::optional<size_t> MemOp::getTargetResultIndex() {
3712 return std::nullopt;
3720 OpAsmSetValueNameFn setNameFn) {
3723 setNameFn(op.getDataRaw(), name);
3724 if (op.isForceable())
3725 setNameFn(op.getDataRef(), (name +
"_ref").str());
3728void NodeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3732LogicalResult NodeOp::inferReturnTypes(
3733 mlir::MLIRContext *
context, std::optional<mlir::Location> location,
3734 ::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes,
3735 ::mlir::OpaqueProperties properties, ::mlir::RegionRange regions,
3736 ::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
3737 if (operands.empty())
3739 Adaptor adaptor(operands, attributes, properties, regions);
3740 inferredReturnTypes.push_back(adaptor.getInput().getType());
3741 if (adaptor.getForceable()) {
3743 true, adaptor.getInput().getType());
3744 if (!forceableType) {
3746 ::mlir::emitError(*location,
"cannot force a node of type ")
3747 << operands[0].getType();
3750 inferredReturnTypes.push_back(forceableType);
3755std::optional<size_t> NodeOp::getTargetResultIndex() {
return 0; }
3757void RegOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3761std::optional<size_t> RegOp::getTargetResultIndex() {
return 0; }
3763SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3764RegOp::computeDataFlow() {
3769LogicalResult RegResetOp::verify() {
3770 auto reset = getResetValue();
3777 return emitError(
"type mismatch between register ")
3778 << regType <<
" and reset value " << resetType;
3783std::optional<size_t> RegResetOp::getTargetResultIndex() {
return 0; }
3785void RegResetOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3794FormalOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3795 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3797 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3799 if (!isa<FModuleLike>(op)) {
3800 auto d = emitOpError() <<
"target " << getModuleNameAttr()
3801 <<
" is not a module";
3802 d.attachNote(op->getLoc()) <<
"target defined here";
3814SimulationOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3815 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3817 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3819 auto complain = [&] {
3820 auto d = emitOpError() <<
"target " << getModuleNameAttr() <<
" ";
3821 d.attachNote(op->getLoc()) <<
"target defined here";
3825 auto module = dyn_cast<FModuleLike>(op);
3827 return complain() <<
"is not a module";
3829 auto numPorts =
module.getPortDirections().size();
3831 return complain() <<
"must have 4 ports, got " << numPorts <<
" instead";
3833 auto checkPort = [&](
unsigned idx, StringRef expName,
Direction expDir,
3834 llvm::function_ref<bool(Type)> checkType,
3835 StringRef expType) {
3836 auto name =
module.getPortNameAttr(idx);
3837 if (name != expName) {
3838 complain() <<
"port " << idx <<
" must be called \"" << expName
3839 <<
"\", got " << name <<
" instead";
3842 if (
auto dir = module.getPortDirection(idx); dir != expDir) {
3846 complain() <<
"port " << name <<
" must be " << stringify(expDir)
3847 <<
", got " << stringify(dir) <<
" instead";
3850 if (
auto type = module.getPortType(idx); !checkType(type)) {
3851 complain() <<
"port " << name <<
" must be a '!firrtl." << expType
3852 <<
"', got " << type <<
" instead";
3858 auto isClock = [](Type type) {
return isa<ClockType>(type); };
3859 auto isBool = [](Type type) {
3860 if (
auto uintType = dyn_cast<UIntType>(type))
3861 return uintType.getWidth() == 1;
3864 return success(checkPort(0,
"clock",
Direction::In, isClock,
"clock") &&
3874void WireOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3878SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3879RegResetOp::computeDataFlow() {
3884std::optional<size_t> WireOp::getTargetResultIndex() {
return 0; }
3886LogicalResult WireOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3887 auto refType = type_dyn_cast<RefType>(getType(0));
3892 refType,
getLoc(), getOperation()->getParentOfType<CircuitOp>(),
3893 symbolTable, Twine(
"'") + getOperationName() +
"' op is");
3900LogicalResult ContractOp::verify() {
3901 if (getBody().getArgumentTypes() != getInputs().getType())
3902 return emitOpError(
"result types and region argument types must match");
3910void ObjectOp::build(OpBuilder &builder, OperationState &state, ClassLike klass,
3912 build(builder, state, klass.getInstanceType(),
3913 StringAttr::get(builder.getContext(), name));
3916LogicalResult ObjectOp::verify() {
return success(); }
3918LogicalResult ObjectOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3919 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
3920 auto classType = getType();
3921 auto className = classType.getNameAttr();
3924 auto classOp = dyn_cast_or_null<ClassLike>(
3925 symbolTable.lookupSymbolIn(circuitOp, className));
3927 return emitOpError() <<
"references unknown class " << className;
3930 if (failed(classOp.verifyType(classType, [&]() { return emitOpError(); })))
3936StringAttr ObjectOp::getClassNameAttr() {
3937 return getType().getNameAttr().getAttr();
3940StringRef ObjectOp::getClassName() {
return getType().getName(); }
3942ClassLike ObjectOp::getReferencedClass(
const SymbolTable &symbolTable) {
3943 auto symRef = getType().getNameAttr();
3944 return symbolTable.lookup<ClassLike>(symRef.getLeafReference());
3947Operation *ObjectOp::getReferencedOperation(
const SymbolTable &symtbl) {
3948 return getReferencedClass(symtbl);
3951StringRef ObjectOp::getInstanceName() {
return getName(); }
3953StringAttr ObjectOp::getInstanceNameAttr() {
return getNameAttr(); }
3955StringRef ObjectOp::getReferencedModuleName() {
return getClassName(); }
3957StringAttr ObjectOp::getReferencedModuleNameAttr() {
3958 return getClassNameAttr();
3961void ObjectOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3962 setNameFn(getResult(),
getName());
3969LogicalResult AttachOp::verify() {
3971 std::optional<int32_t> commonWidth;
3972 for (
auto operand : getOperands()) {
3973 auto thisWidth = type_cast<AnalogType>(operand.getType()).getWidth();
3977 commonWidth = thisWidth;
3980 if (commonWidth != thisWidth)
3981 return emitOpError(
"is inavlid as not all known operand widths match");
3988 Value dst = connect->getOperand(0);
3989 Value src = connect->getOperand(1);
3998 if (isa<PropertyType>(src.getType()) ||
4002 auto diag = emitError(connect->getLoc());
4003 diag <<
"connect has invalid flow: the source expression ";
4005 diag <<
"\"" << srcName <<
"\" ";
4006 diag <<
"has " <<
toString(srcFlow) <<
", expected source or duplex flow";
4007 return diag.attachNote(srcRef.getLoc()) <<
"the source was defined here";
4015 auto diag = emitError(connect->getLoc());
4016 diag <<
"connect has invalid flow: the destination expression ";
4018 diag <<
"\"" << dstName <<
"\" ";
4019 diag <<
"has " <<
toString(dstFlow) <<
", expected sink or duplex flow";
4020 return diag.attachNote(dstRef.getLoc())
4021 <<
"the destination was defined here";
4030 bool outerTypeIsConst =
false) {
4031 auto typeIsConst = outerTypeIsConst || type.
isConst();
4036 if (
auto bundleType = type_dyn_cast<BundleType>(type))
4037 return llvm::any_of(bundleType.getElements(), [&](
auto &element) {
4038 return isConstFieldDriven(element.type, isFlip ^ element.isFlip,
4042 if (
auto vectorType = type_dyn_cast<FVectorType>(type))
4054 auto dest = connect.getDest();
4055 auto destType = type_dyn_cast<FIRRTLBaseType>(dest.getType());
4056 auto src = connect.getSrc();
4057 auto srcType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4058 if (!destType || !srcType)
4061 auto destRefinedType = destType;
4062 auto srcRefinedType = srcType;
4067 auto findFieldDeclarationRefiningFieldType =
4069 while (
auto *definingOp = value.getDefiningOp()) {
4070 bool shouldContinue =
true;
4071 TypeSwitch<Operation *>(definingOp)
4072 .Case<SubfieldOp, SubindexOp>([&](
auto op) { value = op.getInput(); })
4073 .Case<SubaccessOp>([&](SubaccessOp op) {
4077 .getElementTypePreservingConst()
4079 originalFieldType = originalFieldType.getConstType(
true);
4080 value = op.getInput();
4082 .Default([&](Operation *) { shouldContinue =
false; });
4083 if (!shouldContinue)
4089 auto destDeclaration =
4090 findFieldDeclarationRefiningFieldType(dest, destRefinedType);
4091 auto srcDeclaration =
4092 findFieldDeclarationRefiningFieldType(src, srcRefinedType);
4094 auto checkConstConditionality = [&](Value value,
FIRRTLBaseType type,
4095 Value declaration) -> LogicalResult {
4096 auto *declarationBlock = declaration.getParentBlock();
4097 auto *block = connect->getBlock();
4098 while (block && block != declarationBlock) {
4099 auto *parentOp = block->getParentOp();
4101 if (
auto whenOp = dyn_cast<WhenOp>(parentOp);
4102 whenOp && !whenOp.getCondition().getType().isConst()) {
4104 return connect.emitOpError()
4105 <<
"assignment to 'const' type " << type
4106 <<
" is dependent on a non-'const' condition";
4107 return connect->emitOpError()
4108 <<
"assignment to nested 'const' member of type " << type
4109 <<
" is dependent on a non-'const' condition";
4112 block = parentOp->getBlock();
4117 auto emitSubaccessError = [&] {
4118 return connect.emitError(
4119 "assignment to non-'const' subaccess of 'const' type is disallowed");
4125 if (destType != destRefinedType)
4126 return emitSubaccessError();
4128 if (failed(checkConstConditionality(dest, destType, destDeclaration)))
4133 if (srcRefinedType.containsConst() &&
4136 if (srcType != srcRefinedType)
4137 return emitSubaccessError();
4138 if (failed(checkConstConditionality(src, srcType, srcDeclaration)))
4155 auto dest = connect.getDest();
4156 for (
auto *user : dest.getUsers()) {
4157 if (
auto c = dyn_cast<FConnectLike>(user);
4158 c && c.getDest() == dest && c != connect) {
4159 auto diag = connect.emitError(
"destination cannot be driven by multiple "
4161 diag.attachNote(c->getLoc()) <<
"other driver is here";
4168LogicalResult ConnectOp::verify() {
4169 auto dstType = getDest().getType();
4170 auto srcType = getSrc().getType();
4171 auto dstBaseType = type_dyn_cast<FIRRTLBaseType>(dstType);
4172 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(srcType);
4173 if (!dstBaseType || !srcBaseType) {
4174 if (dstType != srcType)
4175 return emitError(
"may not connect different non-base types");
4178 if (dstBaseType.containsAnalog() || srcBaseType.containsAnalog())
4179 return emitError(
"analog types may not be connected");
4183 return emitError(
"type mismatch between destination ")
4184 << dstBaseType <<
" and source " << srcBaseType;
4189 return emitError(
"destination ")
4190 << dstBaseType <<
" is not as wide as the source " << srcBaseType;
4203LogicalResult MatchingConnectOp::verify() {
4204 if (
auto type = type_dyn_cast<FIRRTLType>(getDest().getType())) {
4205 auto baseType = type_cast<FIRRTLBaseType>(type);
4208 if (baseType && baseType.containsAnalog())
4209 return emitError(
"analog types may not be connected");
4214 "`SameAnonTypeOperands` trait should have already rejected "
4215 "structurally non-equivalent types");
4228LogicalResult RefDefineOp::verify() {
4235 if (
auto *op = getDest().getDefiningOp()) {
4237 if (isa<RefSubOp>(op))
4239 "destination reference cannot be a sub-element of a reference");
4240 if (isa<RefCastOp>(op))
4242 "destination reference cannot be a cast of another reference");
4250 SmallVector<SymbolRefAttr> missingLayers;
4253 "has more layer requirements than destination",
4254 "additional layers required");
4257LogicalResult PropAssignOp::verify() {
4267template <
typename T>
4269 auto info = op.getDomainInfo();
4272 return dyn_cast<FlatSymbolRefAttr>(info[i]);
4276 if (!isa<DomainType>(value.getType()))
4279 if (
auto arg = dyn_cast<BlockArgument>(value)) {
4280 auto *parent = arg.getOwner()->getParentOp();
4281 if (
auto module = dyn_cast<FModuleLike>(parent)) {
4282 auto info =
module.getDomainInfo();
4285 auto attr = info[arg.getArgNumber()];
4286 return dyn_cast<FlatSymbolRefAttr>(attr);
4292 if (
auto result = dyn_cast<OpResult>(value)) {
4293 auto *op = result.getDefiningOp();
4294 if (
auto instance = dyn_cast<InstanceOp>(op))
4296 if (
auto instance = dyn_cast<InstanceChoiceOp>(op))
4298 if (
auto anonDomain = dyn_cast<DomainCreateAnonOp>(op))
4299 return anonDomain.getDomainAttr();
4306LogicalResult DomainDefineOp::verify() {
4313 auto dst = getDest();
4314 auto src = getSrc();
4318 return emitError(
"could not determine domain-type of destination");
4322 return emitError(
"could not determine domain-type of source");
4324 if (dstDomain != srcDomain) {
4325 auto diag = emitError()
4326 <<
"source domain type " << srcDomain
4327 <<
" does not match destination domain type " << dstDomain;
4334void WhenOp::createElseRegion() {
4335 assert(!hasElseRegion() &&
"already has an else region");
4336 getElseRegion().push_back(
new Block());
4339void WhenOp::build(OpBuilder &builder, OperationState &result, Value condition,
4340 bool withElseRegion, std::function<
void()> thenCtor,
4341 std::function<
void()> elseCtor) {
4342 OpBuilder::InsertionGuard guard(builder);
4343 result.addOperands(condition);
4346 builder.createBlock(result.addRegion());
4351 Region *elseRegion = result.addRegion();
4352 if (withElseRegion) {
4353 builder.createBlock(elseRegion);
4363LogicalResult MatchOp::verify() {
4364 FEnumType type = getInput().getType();
4367 auto numCases = getTags().size();
4368 auto numRegions = getNumRegions();
4369 if (numRegions != numCases)
4370 return emitOpError(
"expected ")
4371 << numRegions <<
" tags but got " << numCases;
4373 auto numTags = type.getNumElements();
4375 SmallDenseSet<int64_t> seen;
4376 for (
const auto &[tag, region] :
llvm::zip(getTags(), getRegions())) {
4377 auto tagIndex = size_t(cast<IntegerAttr>(tag).
getInt());
4380 if (region.getNumArguments() != 1)
4381 return emitOpError(
"region should have exactly one argument");
4384 if (tagIndex >= numTags)
4385 return emitOpError(
"the tag index ")
4386 << tagIndex <<
" is out of the range of valid tags in " << type;
4389 auto [it, inserted] = seen.insert(tagIndex);
4391 return emitOpError(
"the tag ") << type.getElementNameAttr(tagIndex)
4392 <<
" is matched more than once";
4395 auto expectedType = type.getElementTypePreservingConst(tagIndex);
4396 auto regionType = region.getArgument(0).getType();
4397 if (regionType != expectedType)
4398 return emitOpError(
"region type ")
4399 << regionType <<
" does not match the expected type "
4404 for (
size_t i = 0, e = type.getNumElements(); i < e; ++i)
4405 if (!seen.contains(i))
4406 return emitOpError(
"missing case for tag ") << type.getElementNameAttr(i);
4411void MatchOp::print(OpAsmPrinter &p) {
4412 auto input = getInput();
4413 FEnumType type = input.getType();
4414 auto regions = getRegions();
4415 p <<
" " << input <<
" : " << type;
4416 SmallVector<StringRef> elided = {
"tags"};
4417 p.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elided);
4420 for (
const auto &[tag, region] :
llvm::zip(getTags(), regions)) {
4423 p.printKeywordOrString(
4424 type.getElementName(cast<IntegerAttr>(tag).getInt()));
4426 p.printRegionArgument(region.front().getArgument(0), {},
4429 p.printRegion(region,
false);
4436ParseResult MatchOp::parse(OpAsmParser &parser, OperationState &result) {
4437 auto *
context = parser.getContext();
4438 auto &properties = result.getOrAddProperties<Properties>();
4439 OpAsmParser::UnresolvedOperand input;
4440 if (parser.parseOperand(input) || parser.parseColon())
4443 auto loc = parser.getCurrentLocation();
4445 if (parser.parseType(type))
4447 auto enumType = type_dyn_cast<FEnumType>(type);
4449 return parser.emitError(loc,
"expected enumeration type but got") << type;
4451 if (parser.resolveOperand(input, type, result.operands) ||
4452 parser.parseOptionalAttrDictWithKeyword(result.attributes) ||
4453 parser.parseLBrace())
4456 auto i32Type = IntegerType::get(
context, 32);
4457 SmallVector<Attribute> tags;
4460 if (failed(parser.parseOptionalKeyword(
"case")))
4464 auto nameLoc = parser.getCurrentLocation();
4466 OpAsmParser::Argument arg;
4467 auto *region = result.addRegion();
4468 if (parser.parseKeywordOrString(&name) || parser.parseLParen() ||
4469 parser.parseArgument(arg) || parser.parseRParen())
4473 auto index = enumType.getElementIndex(name);
4475 return parser.emitError(nameLoc,
"the tag \"")
4476 << name <<
"\" is not a member of the enumeration " << enumType;
4477 tags.push_back(IntegerAttr::get(i32Type, *index));
4480 arg.type = enumType.getElementTypePreservingConst(*index);
4481 if (parser.parseRegion(*region, arg))
4484 properties.setTags(ArrayAttr::get(
context, tags));
4486 return parser.parseRBrace();
4489void MatchOp::build(OpBuilder &builder, OperationState &result, Value input,
4491 MutableArrayRef<std::unique_ptr<Region>> regions) {
4492 auto &properties = result.getOrAddProperties<Properties>();
4493 result.addOperands(input);
4494 properties.setTags(tags);
4495 result.addRegions(regions);
4504 struct IsExprClassifier :
public ExprVisitor<IsExprClassifier, bool> {
4505 bool visitInvalidExpr(Operation *op) {
return false; }
4506 bool visitUnhandledExpr(Operation *op) {
return true; }
4512void InvalidValueOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4515 if (
auto ty = type_dyn_cast<IntType>(getType())) {
4516 const char *base = ty.isSigned() ?
"invalid_si" :
"invalid_ui";
4517 auto width = ty.getWidthOrSentinel();
4521 name = (Twine(base) + Twine(width)).str();
4522 }
else if (
auto ty = type_dyn_cast<AnalogType>(getType())) {
4523 auto width = ty.getWidthOrSentinel();
4525 name =
"invalid_analog";
4527 name = (
"invalid_analog" + Twine(width)).str();
4528 }
else if (type_isa<AsyncResetType>(getType()))
4529 name =
"invalid_asyncreset";
4530 else if (type_isa<ResetType>(getType()))
4531 name =
"invalid_reset";
4532 else if (type_isa<ClockType>(getType()))
4533 name =
"invalid_clock";
4537 setNameFn(getResult(), name);
4540void ConstantOp::print(OpAsmPrinter &p) {
4542 p.printAttributeWithoutType(getValueAttr());
4544 p.printType(getType());
4545 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4548ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
4549 auto &properties = result.getOrAddProperties<Properties>();
4552 auto loc = parser.getCurrentLocation();
4553 auto valueResult = parser.parseOptionalInteger(value);
4554 if (!valueResult.has_value())
4555 return parser.emitError(loc,
"expected integer value");
4559 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4560 parser.parseOptionalAttrDict(result.attributes))
4562 result.addTypes(resultType);
4568 if (width > value.getBitWidth()) {
4572 value = value.sext(width);
4573 }
else if (width < value.getBitWidth()) {
4576 unsigned neededBits = value.isNegative() ? value.getSignificantBits()
4577 : value.getActiveBits();
4578 if (width < neededBits)
4579 return parser.emitError(loc,
"constant out of range for result type ")
4581 value = value.trunc(width);
4585 auto intType = parser.getBuilder().getIntegerType(value.getBitWidth(),
4587 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4588 properties.setValue(valueAttr);
4592LogicalResult ConstantOp::verify() {
4596 if (width != -1 && (
int)getValue().
getBitWidth() != width)
4598 "firrtl.constant attribute bitwidth doesn't match return type");
4601 auto attrType = type_cast<IntegerType>(getValueAttr().getType());
4602 if (attrType.isSignless() || attrType.isSigned() != intType.
isSigned())
4603 return emitError(
"firrtl.constant attribute has wrong sign");
4610void ConstantOp::build(OpBuilder &builder, OperationState &result,
IntType type,
4611 const APInt &value) {
4614 assert((width == -1 || (int32_t)value.getBitWidth() == width) &&
4615 "incorrect attribute bitwidth for firrtl.constant");
4618 IntegerAttr::get(type.getContext(), APSInt(value, !type.
isSigned()));
4619 return build(builder, result, type, attr);
4624void ConstantOp::build(OpBuilder &builder, OperationState &result,
4625 const APSInt &value) {
4626 auto attr = IntegerAttr::get(builder.getContext(), value);
4628 IntType::get(builder.getContext(), value.isSigned(), value.getBitWidth());
4629 return build(builder, result, type, attr);
4632void ConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4639 SmallString<32> specialNameBuffer;
4640 llvm::raw_svector_ostream specialName(specialNameBuffer);
4642 getValue().print(specialName, intTy.
isSigned());
4644 specialName << (intTy.
isSigned() ?
"_si" :
"_ui");
4647 specialName << width;
4648 setNameFn(getResult(), specialName.str());
4651void SpecialConstantOp::print(OpAsmPrinter &p) {
4654 p << static_cast<unsigned>(getValue());
4656 p.printType(getType());
4657 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4660ParseResult SpecialConstantOp::parse(OpAsmParser &parser,
4661 OperationState &result) {
4662 auto &properties = result.getOrAddProperties<Properties>();
4666 auto loc = parser.getCurrentLocation();
4667 auto valueResult = parser.parseOptionalInteger(value);
4668 if (!valueResult.has_value())
4669 return parser.emitError(loc,
"expected integer value");
4672 if (value != 0 && value != 1)
4673 return parser.emitError(loc,
"special constants can only be 0 or 1.");
4677 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4678 parser.parseOptionalAttrDict(result.attributes))
4680 result.addTypes(resultType);
4683 auto valueAttr = parser.getBuilder().getBoolAttr(value == 1);
4684 properties.setValue(valueAttr);
4688void SpecialConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4689 SmallString<32> specialNameBuffer;
4690 llvm::raw_svector_ostream specialName(specialNameBuffer);
4692 specialName << static_cast<unsigned>(getValue());
4693 auto type = getType();
4694 if (type_isa<ClockType>(type)) {
4695 specialName <<
"_clock";
4696 }
else if (type_isa<ResetType>(type)) {
4697 specialName <<
"_reset";
4698 }
else if (type_isa<AsyncResetType>(type)) {
4699 specialName <<
"_asyncreset";
4701 setNameFn(getResult(), specialName.str());
4708 if (type.isGround()) {
4709 if (!isa<IntegerAttr>(attr)) {
4710 op->emitOpError(
"Ground type is not an integer attribute");
4715 auto attrlist = dyn_cast<ArrayAttr>(attr);
4717 op->emitOpError(
"expected array attribute for aggregate constant");
4720 if (
auto array = type_dyn_cast<FVectorType>(type)) {
4721 if (array.getNumElements() != attrlist.size()) {
4722 op->emitOpError(
"array attribute (")
4723 << attrlist.size() <<
") has wrong size for vector constant ("
4724 << array.getNumElements() <<
")";
4727 return llvm::all_of(attrlist, [&array, op](Attribute attr) {
4731 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4732 if (bundle.getNumElements() != attrlist.size()) {
4733 op->emitOpError(
"array attribute (")
4734 << attrlist.size() <<
") has wrong size for bundle constant ("
4735 << bundle.getNumElements() <<
")";
4738 for (
size_t i = 0; i < bundle.getNumElements(); ++i) {
4739 if (bundle.getElement(i).isFlip) {
4740 op->emitOpError(
"Cannot have constant bundle type with flip");
4748 op->emitOpError(
"Unknown aggregate type");
4752LogicalResult AggregateConstantOp::verify() {
4758Attribute AggregateConstantOp::getAttributeFromFieldID(uint64_t fieldID) {
4760 Attribute value = getFields();
4761 while (fieldID != 0) {
4762 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4763 auto index = bundle.getIndexForFieldID(fieldID);
4764 fieldID -= bundle.getFieldID(index);
4765 type = bundle.getElementType(index);
4766 value = cast<ArrayAttr>(value)[index];
4768 auto vector = type_cast<FVectorType>(type);
4769 auto index = vector.getIndexForFieldID(fieldID);
4770 fieldID -= vector.getFieldID(index);
4771 type = vector.getElementType();
4772 value = cast<ArrayAttr>(value)[index];
4778void FIntegerConstantOp::print(OpAsmPrinter &p) {
4780 p.printAttributeWithoutType(getValueAttr());
4781 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4784ParseResult FIntegerConstantOp::parse(OpAsmParser &parser,
4785 OperationState &result) {
4786 auto *
context = parser.getContext();
4787 auto &properties = result.getOrAddProperties<Properties>();
4789 if (parser.parseInteger(value) ||
4790 parser.parseOptionalAttrDict(result.attributes))
4792 result.addTypes(FIntegerType::get(
context));
4794 IntegerType::get(
context, value.getBitWidth(), IntegerType::Signed);
4795 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4796 properties.setValue(valueAttr);
4800ParseResult ListCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4801 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
4804 if (parser.parseOperandList(operands) ||
4805 parser.parseOptionalAttrDict(result.attributes) ||
4806 parser.parseColonType(type))
4808 result.addTypes(type);
4810 return parser.resolveOperands(operands, type.getElementType(),
4814void ListCreateOp::print(OpAsmPrinter &p) {
4816 p.printOperands(getElements());
4817 p.printOptionalAttrDict((*this)->getAttrs());
4818 p <<
" : " << getType();
4821LogicalResult ListCreateOp::verify() {
4822 if (getElements().
empty())
4825 auto elementType = getElements().front().getType();
4826 auto listElementType = getType().getElementType();
4828 return emitOpError(
"has elements of type ")
4829 <<
elementType <<
" instead of " << listElementType;
4834LogicalResult BundleCreateOp::verify() {
4835 BundleType resultType = getType();
4836 if (resultType.getNumElements() != getFields().size())
4837 return emitOpError(
"number of fields doesn't match type");
4838 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4840 resultType.getElementTypePreservingConst(i),
4841 type_cast<FIRRTLBaseType>(getOperand(i).getType())))
4842 return emitOpError(
"type of element doesn't match bundle for field ")
4843 << resultType.getElement(i).name;
4848LogicalResult VectorCreateOp::verify() {
4849 FVectorType resultType = getType();
4850 if (resultType.getNumElements() != getFields().size())
4851 return emitOpError(
"number of fields doesn't match type");
4852 auto elemTy = resultType.getElementTypePreservingConst();
4853 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4855 elemTy, type_cast<FIRRTLBaseType>(getOperand(i).getType())))
4856 return emitOpError(
"type of element doesn't match vector element");
4865LogicalResult FEnumCreateOp::verify() {
4866 FEnumType resultType = getResult().getType();
4867 auto elementIndex = resultType.getElementIndex(
getFieldName());
4869 return emitOpError(
"label ")
4870 <<
getFieldName() <<
" is not a member of the enumeration type "
4873 resultType.getElementTypePreservingConst(*elementIndex),
4874 getInput().getType()))
4875 return emitOpError(
"type of element doesn't match enum element");
4879void FEnumCreateOp::print(OpAsmPrinter &printer) {
4882 printer <<
'(' << getInput() <<
')';
4883 SmallVector<StringRef> elidedAttrs = {
"fieldIndex"};
4884 printer.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elidedAttrs);
4886 printer.printFunctionalType(ArrayRef<Type>{getInput().getType()},
4887 ArrayRef<Type>{getResult().getType()});
4890ParseResult FEnumCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4891 auto *
context = parser.getContext();
4892 auto &properties = result.getOrAddProperties<Properties>();
4894 OpAsmParser::UnresolvedOperand input;
4895 std::string fieldName;
4896 mlir::FunctionType functionType;
4897 if (parser.parseKeywordOrString(&fieldName) || parser.parseLParen() ||
4898 parser.parseOperand(input) || parser.parseRParen() ||
4899 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4900 parser.parseType(functionType))
4903 if (functionType.getNumInputs() != 1)
4904 return parser.emitError(parser.getNameLoc(),
"single input type required");
4905 if (functionType.getNumResults() != 1)
4906 return parser.emitError(parser.getNameLoc(),
"single result type required");
4908 auto inputType = functionType.getInput(0);
4909 if (parser.resolveOperand(input, inputType, result.operands))
4912 auto outputType = functionType.getResult(0);
4913 auto enumType = type_dyn_cast<FEnumType>(outputType);
4915 return parser.emitError(parser.getNameLoc(),
4916 "output must be enum type, got ")
4918 auto fieldIndex = enumType.getElementIndex(fieldName);
4920 return parser.emitError(parser.getNameLoc(),
4921 "unknown field " + fieldName +
" in enum type ")
4924 properties.setFieldIndex(
4925 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
4927 result.addTypes(enumType);
4936LogicalResult IsTagOp::verify() {
4937 if (getFieldIndex() >= getInput().getType().base().getNumElements())
4938 return emitOpError(
"element index is greater than the number of fields in "
4943void IsTagOp::print(::mlir::OpAsmPrinter &printer) {
4944 printer <<
' ' << getInput() <<
' ';
4946 SmallVector<::llvm::StringRef, 1> elidedAttrs = {
"fieldIndex"};
4947 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
4948 printer <<
" : " << getInput().getType();
4951ParseResult IsTagOp::parse(OpAsmParser &parser, OperationState &result) {
4952 auto *
context = parser.getContext();
4953 auto &properties = result.getOrAddProperties<Properties>();
4955 OpAsmParser::UnresolvedOperand input;
4956 std::string fieldName;
4958 if (parser.parseOperand(input) || parser.parseKeywordOrString(&fieldName) ||
4959 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4960 parser.parseType(inputType))
4963 if (parser.resolveOperand(input, inputType, result.operands))
4966 auto enumType = type_dyn_cast<FEnumType>(inputType);
4968 return parser.emitError(parser.getNameLoc(),
4969 "input must be enum type, got ")
4971 auto fieldIndex = enumType.getElementIndex(fieldName);
4973 return parser.emitError(parser.getNameLoc(),
4974 "unknown field " + fieldName +
" in enum type ")
4977 properties.setFieldIndex(
4978 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
4980 result.addTypes(UIntType::get(
context, 1,
false));
4985FIRRTLType IsTagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
4986 OpaqueProperties properties,
4987 mlir::RegionRange regions,
4988 std::optional<Location> loc) {
4989 Adaptor adaptor(operands, attrs, properties, regions);
4990 return UIntType::get(attrs.getContext(), 1,
4991 isConst(adaptor.getInput().getType()));
4994template <
typename OpTy>
4996 auto *
context = parser.getContext();
4998 OpAsmParser::UnresolvedOperand input;
4999 std::string fieldName;
5001 if (parser.parseOperand(input) || parser.parseLSquare() ||
5002 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5003 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5004 parser.parseType(inputType))
5007 if (parser.resolveOperand(input, inputType, result.operands))
5010 auto bundleType = type_dyn_cast<typename OpTy::InputType>(inputType);
5012 return parser.emitError(parser.getNameLoc(),
5013 "input must be bundle type, got ")
5015 auto fieldIndex = bundleType.getElementIndex(fieldName);
5017 return parser.emitError(parser.getNameLoc(),
5018 "unknown field " + fieldName +
" in bundle type ")
5021 result.getOrAddProperties<
typename OpTy::Properties>().setFieldIndex(
5022 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5024 auto type = OpTy::inferReturnType(inputType, *fieldIndex, {});
5027 result.addTypes(type);
5032ParseResult SubtagOp::parse(OpAsmParser &parser, OperationState &result) {
5033 auto *
context = parser.getContext();
5035 OpAsmParser::UnresolvedOperand input;
5036 std::string fieldName;
5038 if (parser.parseOperand(input) || parser.parseLSquare() ||
5039 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5040 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5041 parser.parseType(inputType))
5044 if (parser.resolveOperand(input, inputType, result.operands))
5047 auto enumType = type_dyn_cast<FEnumType>(inputType);
5049 return parser.emitError(parser.getNameLoc(),
5050 "input must be enum type, got ")
5052 auto fieldIndex = enumType.getElementIndex(fieldName);
5054 return parser.emitError(parser.getNameLoc(),
5055 "unknown field " + fieldName +
" in enum type ")
5058 result.getOrAddProperties<Properties>().setFieldIndex(
5059 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5061 SmallVector<Type> inferredReturnTypes;
5062 if (failed(SubtagOp::inferReturnTypes(
5063 context, result.location, result.operands,
5064 result.attributes.getDictionary(
context), result.getRawProperties(),
5065 result.regions, inferredReturnTypes)))
5067 result.addTypes(inferredReturnTypes);
5072ParseResult SubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
5073 return parseSubfieldLikeOp<SubfieldOp>(parser, result);
5075ParseResult OpenSubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
5076 return parseSubfieldLikeOp<OpenSubfieldOp>(parser, result);
5079template <
typename OpTy>
5081 printer <<
' ' << op.getInput() <<
'[';
5082 printer.printKeywordOrString(op.getFieldName());
5084 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
5085 elidedAttrs.push_back(
"fieldIndex");
5086 printer.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
5087 printer <<
" : " << op.getInput().getType();
5089void SubfieldOp::print(::mlir::OpAsmPrinter &printer) {
5090 return printSubfieldLikeOp<SubfieldOp>(*
this, printer);
5092void OpenSubfieldOp::print(::mlir::OpAsmPrinter &printer) {
5093 return printSubfieldLikeOp<OpenSubfieldOp>(*
this, printer);
5096void SubtagOp::print(::mlir::OpAsmPrinter &printer) {
5097 printer <<
' ' << getInput() <<
'[';
5100 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
5101 elidedAttrs.push_back(
"fieldIndex");
5102 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
5103 printer <<
" : " << getInput().getType();
5106template <
typename OpTy>
5108 if (op.getFieldIndex() >=
5109 firrtl::type_cast<typename OpTy::InputType>(op.getInput().getType())
5111 return op.emitOpError(
"subfield element index is greater than the number "
5112 "of fields in the bundle type");
5115LogicalResult SubfieldOp::verify() {
5116 return verifySubfieldLike<SubfieldOp>(*
this);
5118LogicalResult OpenSubfieldOp::verify() {
5119 return verifySubfieldLike<OpenSubfieldOp>(*
this);
5122LogicalResult SubtagOp::verify() {
5123 if (getFieldIndex() >= getInput().getType().base().getNumElements())
5124 return emitOpError(
"subfield element index is greater than the number "
5125 "of fields in the bundle type");
5135 SmallVector<Operation *, 8> worklist({op});
5139 bool constant =
true;
5145 while (constant && !(worklist.empty()))
5146 TypeSwitch<Operation *>(worklist.pop_back_val())
5147 .Case<NodeOp, AsSIntPrimOp, AsUIntPrimOp>([&](
auto op) {
5148 if (
auto definingOp = op.getInput().getDefiningOp())
5149 worklist.push_back(definingOp);
5152 .Case<WireOp, SubindexOp, SubfieldOp>([&](
auto op) {
5153 for (
auto &use : op.getResult().getUses())
5154 worklist.push_back(use.getOwner());
5156 .Case<ConstantOp, SpecialConstantOp, AggregateConstantOp>([](
auto) {})
5157 .Default([&](
auto) { constant =
false; });
5166 if (
auto *op = value.getDefiningOp())
5171LogicalResult ConstCastOp::verify() {
5173 return emitOpError() << getInput().getType()
5174 <<
" is not 'const'-castable to "
5175 << getResult().getType();
5179FIRRTLType SubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
5180 std::optional<Location> loc) {
5181 auto inType = type_cast<BundleType>(type);
5183 if (fieldIndex >= inType.getNumElements())
5185 "subfield element index is greater than the "
5186 "number of fields in the bundle type");
5190 return inType.getElementTypePreservingConst(fieldIndex);
5193FIRRTLType OpenSubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
5194 std::optional<Location> loc) {
5195 auto inType = type_cast<OpenBundleType>(type);
5197 if (fieldIndex >= inType.getNumElements())
5199 "subfield element index is greater than the "
5200 "number of fields in the bundle type");
5204 return inType.getElementTypePreservingConst(fieldIndex);
5207bool SubfieldOp::isFieldFlipped() {
5208 BundleType bundle = getInput().getType();
5209 return bundle.getElement(getFieldIndex()).isFlip;
5211bool OpenSubfieldOp::isFieldFlipped() {
5212 auto bundle = getInput().getType();
5213 return bundle.getElement(getFieldIndex()).isFlip;
5216FIRRTLType SubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
5217 std::optional<Location> loc) {
5218 if (
auto vectorType = type_dyn_cast<FVectorType>(type)) {
5219 if (fieldIndex < vectorType.getNumElements())
5220 return vectorType.getElementTypePreservingConst();
5222 "' in vector type ", type);
5227FIRRTLType OpenSubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
5228 std::optional<Location> loc) {
5229 if (
auto vectorType = type_dyn_cast<OpenVectorType>(type)) {
5230 if (fieldIndex < vectorType.getNumElements())
5231 return vectorType.getElementTypePreservingConst();
5233 "' in vector type ", type);
5239FIRRTLType SubtagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5240 OpaqueProperties properties,
5241 mlir::RegionRange regions,
5242 std::optional<Location> loc) {
5243 Adaptor adaptor(operands, attrs, properties, regions);
5244 auto inType = type_cast<FEnumType>(adaptor.getInput().getType());
5245 auto fieldIndex = adaptor.getFieldIndex();
5247 if (fieldIndex >= inType.getNumElements())
5249 "subtag element index is greater than the "
5250 "number of fields in the enum type");
5254 auto elementType = inType.getElement(fieldIndex).type;
5258FIRRTLType SubaccessOp::inferReturnType(Type inType, Type indexType,
5259 std::optional<Location> loc) {
5260 if (!type_isa<UIntType>(indexType))
5264 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
5266 return vectorType.getElementTypePreservingConst();
5267 return vectorType.getElementType().getAllConstDroppedType();
5275 std::optional<Location> loc) {
5276 auto inType = type_cast<FEnumType>(input);
5277 return UIntType::get(inType.getContext(), inType.getTagWidth());
5280ParseResult MultibitMuxOp::parse(OpAsmParser &parser, OperationState &result) {
5281 OpAsmParser::UnresolvedOperand index;
5282 SmallVector<OpAsmParser::UnresolvedOperand, 16> inputs;
5283 Type indexType, elemType;
5285 if (parser.parseOperand(index) || parser.parseComma() ||
5286 parser.parseOperandList(inputs) ||
5287 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5288 parser.parseType(indexType) || parser.parseComma() ||
5289 parser.parseType(elemType))
5292 if (parser.resolveOperand(index, indexType, result.operands))
5295 result.addTypes(elemType);
5297 return parser.resolveOperands(inputs, elemType, result.operands);
5300void MultibitMuxOp::print(OpAsmPrinter &p) {
5301 p <<
" " << getIndex() <<
", ";
5302 p.printOperands(getInputs());
5303 p.printOptionalAttrDict((*this)->getAttrs());
5304 p <<
" : " << getIndex().getType() <<
", " << getType();
5307FIRRTLType MultibitMuxOp::inferReturnType(ValueRange operands,
5308 DictionaryAttr attrs,
5309 OpaqueProperties properties,
5310 mlir::RegionRange regions,
5311 std::optional<Location> loc) {
5312 if (operands.size() < 2)
5316 if (!llvm::all_of(operands.drop_front(2), [&](
auto op) {
5317 return operands[1].getType() == op.getType();
5321 return type_cast<FIRRTLType>(operands[1].getType());
5328LogicalResult ObjectSubfieldOp::inferReturnTypes(
5329 MLIRContext *
context, std::optional<mlir::Location> location,
5330 ValueRange operands, DictionaryAttr attributes, OpaqueProperties properties,
5331 RegionRange regions, llvm::SmallVectorImpl<Type> &inferredReturnTypes) {
5333 inferReturnType(operands, attributes, properties, regions, location);
5336 inferredReturnTypes.push_back(type);
5340Type ObjectSubfieldOp::inferReturnType(Type inType, uint32_t fieldIndex,
5341 std::optional<Location> loc) {
5342 auto classType = dyn_cast<ClassType>(inType);
5346 if (classType.getNumElements() <= fieldIndex)
5348 "number of fields in the object");
5349 return classType.getElement(fieldIndex).type;
5352void ObjectSubfieldOp::print(OpAsmPrinter &p) {
5353 auto input = getInput();
5354 auto classType = input.getType();
5355 p <<
' ' << input <<
"[";
5356 p.printKeywordOrString(classType.getElement(getIndex()).name);
5358 p.printOptionalAttrDict((*this)->getAttrs(), std::array{StringRef(
"index")});
5359 p <<
" : " << classType;
5362ParseResult ObjectSubfieldOp::parse(OpAsmParser &parser,
5363 OperationState &result) {
5364 auto *
context = parser.getContext();
5366 OpAsmParser::UnresolvedOperand input;
5367 std::string fieldName;
5368 ClassType inputType;
5369 if (parser.parseOperand(input) || parser.parseLSquare() ||
5370 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5371 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5372 parser.parseType(inputType) ||
5373 parser.resolveOperand(input, inputType, result.operands))
5376 auto index = inputType.getElementIndex(fieldName);
5378 return parser.emitError(parser.getNameLoc(),
5379 "unknown field " + fieldName +
" in class type ")
5381 result.getOrAddProperties<Properties>().setIndex(
5382 IntegerAttr::get(IntegerType::get(
context, 32), *index));
5384 SmallVector<Type> inferredReturnTypes;
5385 if (failed(inferReturnTypes(
context, result.location, result.operands,
5386 result.attributes.getDictionary(
context),
5387 result.getRawProperties(), result.regions,
5388 inferredReturnTypes)))
5390 result.addTypes(inferredReturnTypes);
5407 int32_t &rhsWidth,
bool &isConstResult,
5408 std::optional<Location> loc) {
5410 auto lhsi = type_dyn_cast<IntType>(lhs);
5411 auto rhsi = type_dyn_cast<IntType>(rhs);
5412 if (!lhsi || !rhsi || lhsi.isSigned() != rhsi.isSigned()) {
5415 mlir::emitError(*loc,
"second operand must be an integer type, not ")
5417 else if (!lhsi && rhsi)
5418 mlir::emitError(*loc,
"first operand must be an integer type, not ")
5420 else if (!lhsi && !rhsi)
5421 mlir::emitError(*loc,
"operands must be integer types, not ")
5422 << lhs <<
" and " << rhs;
5424 mlir::emitError(*loc,
"operand signedness must match");
5429 lhsWidth = lhsi.getWidthOrSentinel();
5430 rhsWidth = rhsi.getWidthOrSentinel();
5431 isConstResult = lhsi.isConst() && rhsi.isConst();
5436 assert(op->getNumOperands() == 2 &&
5437 "SameOperandsIntTypeKind on non-binary op");
5438 int32_t lhsWidth, rhsWidth;
5441 op->getOperand(1).getType(), lhsWidth,
5442 rhsWidth, isConstResult, op->getLoc()));
5446 std::optional<Location> loc) {
5447 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5448 bool isConstResult =
false;
5452 if (lhsWidth != -1 && rhsWidth != -1)
5453 resultWidth = std::max(lhsWidth, rhsWidth) + 1;
5454 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5459 std::optional<Location> loc) {
5460 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5461 bool isConstResult =
false;
5465 if (lhsWidth != -1 && rhsWidth != -1)
5466 resultWidth = lhsWidth + rhsWidth;
5468 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5473 std::optional<Location> loc) {
5474 int32_t lhsWidth, rhsWidth;
5475 bool isConstResult =
false;
5480 if (type_isa<UIntType>(lhs))
5481 return UIntType::get(lhs.getContext(), lhsWidth, isConstResult);
5484 int32_t resultWidth = lhsWidth != -1 ? lhsWidth + 1 : -1;
5485 return SIntType::get(lhs.getContext(), resultWidth, isConstResult);
5489 std::optional<Location> loc) {
5490 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5491 bool isConstResult =
false;
5495 if (lhsWidth != -1 && rhsWidth != -1)
5496 resultWidth = std::min(lhsWidth, rhsWidth);
5497 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5502 std::optional<Location> loc) {
5503 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5504 bool isConstResult =
false;
5508 if (lhsWidth != -1 && rhsWidth != -1) {
5509 resultWidth = std::max(lhsWidth, rhsWidth);
5510 if (lhsWidth == resultWidth && lhs.
isConst() == isConstResult &&
5513 if (rhsWidth == resultWidth && rhs.
isConst() == isConstResult &&
5517 return UIntType::get(lhs.getContext(), resultWidth, isConstResult);
5521 std::optional<Location> loc) {
5522 if (!type_isa<FVectorType>(lhs) || !type_isa<FVectorType>(rhs))
5525 auto lhsVec = type_cast<FVectorType>(lhs);
5526 auto rhsVec = type_cast<FVectorType>(rhs);
5528 if (lhsVec.getNumElements() != rhsVec.getNumElements())
5533 rhsVec.getElementTypePreservingConst(), loc);
5536 auto elemBaseType = type_cast<FIRRTLBaseType>(elemType);
5537 return FVectorType::get(elemBaseType, lhsVec.getNumElements(),
5538 lhsVec.isConst() && rhsVec.isConst() &&
5539 elemBaseType.isConst());
5543 std::optional<Location> loc) {
5544 return UIntType::get(lhs.getContext(), 1,
isConst(lhs) &&
isConst(rhs));
5547FIRRTLType CatPrimOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5548 OpaqueProperties properties,
5549 mlir::RegionRange regions,
5550 std::optional<Location> loc) {
5552 if (operands.empty())
5553 return UIntType::get(attrs.getContext(), 0);
5556 bool isSigned = type_isa<SIntType>(operands[0].getType());
5557 for (
auto operand : operands) {
5558 auto type = type_dyn_cast<IntType>(operand.getType());
5561 if (type.isSigned() != isSigned)
5563 "all operands must have same signedness");
5567 int32_t resultWidth = 0;
5568 bool isConstResult =
true;
5570 for (
auto operand : operands) {
5571 auto type = type_cast<IntType>(operand.getType());
5572 int32_t width = type.getWidthOrSentinel();
5579 if (resultWidth != -1)
5580 resultWidth += width;
5583 isConstResult &= type.isConst();
5587 return UIntType::get(attrs.getContext(), resultWidth, isConstResult);
5591 std::optional<Location> loc) {
5592 auto lhsi = type_dyn_cast<IntType>(lhs);
5593 auto rhsui = type_dyn_cast<UIntType>(rhs);
5594 if (!rhsui || !lhsi)
5596 loc,
"first operand should be integer, second unsigned int");
5600 auto width = lhsi.getWidthOrSentinel();
5601 if (width == -1 || !rhsui.getWidth().has_value()) {
5604 auto amount = *rhsui.getWidth();
5607 "shift amount too large: second operand of "
5608 "dshl is wider than 31 bits");
5609 int64_t newWidth = (int64_t)width + ((int64_t)1 << amount) - 1;
5610 if (newWidth > INT32_MAX)
5612 loc,
"shift amount too large: first operand shifted by maximum "
5613 "amount exceeds maximum width");
5616 return IntType::get(lhs.getContext(), lhsi.isSigned(), width,
5617 lhsi.
isConst() && rhsui.isConst());
5621 std::optional<Location> loc) {
5622 auto lhsi = type_dyn_cast<IntType>(lhs);
5623 auto rhsu = type_dyn_cast<UIntType>(rhs);
5626 loc,
"first operand should be integer, second unsigned int");
5627 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5631 std::optional<Location> loc) {
5632 auto lhsi = type_dyn_cast<IntType>(lhs);
5633 auto rhsu = type_dyn_cast<UIntType>(rhs);
5636 loc,
"first operand should be integer, second unsigned int");
5637 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5645 std::optional<Location> loc) {
5646 return UIntType::get(input.getContext(), 32);
5650 std::optional<Location> loc) {
5651 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5654 int32_t width = base.getBitWidthOrSentinel();
5657 return SIntType::get(input.getContext(), width, base.
isConst());
5661 std::optional<Location> loc) {
5662 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5665 int32_t width = base.getBitWidthOrSentinel();
5668 return UIntType::get(input.getContext(), width, base.
isConst());
5672 std::optional<Location> loc) {
5673 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5676 "operand must be single bit scalar base type");
5677 int32_t width = base.getBitWidthOrSentinel();
5678 if (width == -2 || width == 0 || width > 1)
5680 return AsyncResetType::get(input.getContext(), base.
isConst());
5684 std::optional<Location> loc) {
5685 return ClockType::get(input.getContext(),
isConst(input));
5689 std::optional<Location> loc) {
5690 if (
auto uiType = type_dyn_cast<UIntType>(input)) {
5691 auto width = uiType.getWidthOrSentinel();
5694 return SIntType::get(input.getContext(), width, uiType.
isConst());
5697 if (type_isa<SIntType>(input))
5704 std::optional<Location> loc) {
5705 auto inputi = type_dyn_cast<IntType>(input);
5708 int32_t width = inputi.getWidthOrSentinel();
5711 return SIntType::get(input.getContext(), width, inputi.
isConst());
5715 std::optional<Location> loc) {
5716 auto inputi = type_dyn_cast<IntType>(input);
5719 if (isa<UIntType>(inputi))
5721 return UIntType::get(input.getContext(), inputi.getWidthOrSentinel(),
5726 std::optional<Location> loc) {
5727 return UIntType::get(input.getContext(), 1,
isConst(input));
5736 std::optional<Location> loc) {
5737 auto inputi = type_dyn_cast<IntType>(input);
5740 loc,
"input type should be the int type but got ", input);
5745 loc,
"high must be equal or greater than low, but got high = ", high,
5753 int32_t width = inputi.getWidthOrSentinel();
5754 if (width != -1 && high >= width)
5757 "high must be smaller than the width of input, but got high = ", high,
5758 ", width = ", width);
5760 return UIntType::get(input.getContext(), high - low + 1, inputi.
isConst());
5764 std::optional<Location> loc) {
5766 auto inputi = type_dyn_cast<IntType>(input);
5767 if (amount < 0 || !inputi)
5769 loc,
"operand must have integer type and amount must be >= 0");
5771 int32_t width = inputi.getWidthOrSentinel();
5772 if (width != -1 && amount > width)
5775 return UIntType::get(input.getContext(), amount, inputi.
isConst());
5790 bool isConstCondition,
5791 std::optional<Location> loc) {
5797 if (high.getTypeID() != low.getTypeID())
5798 return emitInferRetTypeError<FIRRTLBaseType>(
5799 loc,
"incompatible mux operand types, true value type: ", high,
5800 ", false value type: ", low);
5802 bool outerTypeIsConst = isConstCondition && low.
isConst() && high.
isConst();
5807 if (type_isa<IntType>(low)) {
5812 if (highWidth == -1)
5814 return (lowWidth > highWidth ? low : high).getConstType(outerTypeIsConst);
5819 auto highEnum = type_dyn_cast<FEnumType>(high);
5820 auto lowEnum = type_dyn_cast<FEnumType>(low);
5821 if (lowEnum && highEnum) {
5822 if (lowEnum.getNumElements() != highEnum.getNumElements())
5823 return emitInferRetTypeError<FIRRTLBaseType>(
5824 loc,
"incompatible mux operand types, true value type: ", high,
5825 ", false value type: ", low);
5826 SmallVector<FEnumType::EnumElement> elements;
5827 for (
auto [high, low] : llvm::zip_equal(highEnum, lowEnum)) {
5829 if (high.name != low.name || high.value != low.value)
5830 return emitInferRetTypeError<FIRRTLBaseType>(
5831 loc,
"incompatible mux operand types, true value type: ", highEnum,
5832 ", false value type: ", lowEnum);
5839 elements.emplace_back(high.name, high.value, inner);
5841 return FEnumType::get(high.getContext(), elements, outerTypeIsConst);
5845 auto highVector = type_dyn_cast<FVectorType>(high);
5846 auto lowVector = type_dyn_cast<FVectorType>(low);
5847 if (highVector && lowVector &&
5848 highVector.getNumElements() == lowVector.getNumElements()) {
5850 lowVector.getElementTypePreservingConst(),
5851 isConstCondition, loc);
5854 return FVectorType::get(inner, lowVector.getNumElements(),
5859 auto highBundle = type_dyn_cast<BundleType>(high);
5860 auto lowBundle = type_dyn_cast<BundleType>(low);
5861 if (highBundle && lowBundle) {
5862 auto highElements = highBundle.getElements();
5863 auto lowElements = lowBundle.getElements();
5866 SmallVector<BundleType::BundleElement> newElements;
5868 bool failed =
false;
5870 if (highElements[i].name != lowElements[i].name ||
5871 highElements[i].isFlip != lowElements[i].isFlip) {
5875 auto element = highElements[i];
5877 highBundle.getElementTypePreservingConst(i),
5878 lowBundle.getElementTypePreservingConst(i), isConstCondition, loc);
5881 newElements.push_back(element);
5884 return BundleType::get(low.getContext(), newElements, outerTypeIsConst);
5886 return emitInferRetTypeError<FIRRTLBaseType>(
5887 loc,
"incompatible mux operand bundle fields, true value type: ", high,
5888 ", false value type: ", low);
5893 return emitInferRetTypeError<FIRRTLBaseType>(
5894 loc,
"invalid mux operand types, true value type: ", high,
5895 ", false value type: ", low);
5900 std::optional<Location> loc) {
5901 auto highType = type_dyn_cast<FIRRTLBaseType>(high);
5902 auto lowType = type_dyn_cast<FIRRTLBaseType>(low);
5903 if (!highType || !lowType)
5908FIRRTLType Mux2CellIntrinsicOp::inferReturnType(ValueRange operands,
5909 DictionaryAttr attrs,
5910 OpaqueProperties properties,
5911 mlir::RegionRange regions,
5912 std::optional<Location> loc) {
5913 auto highType = type_dyn_cast<FIRRTLBaseType>(operands[1].getType());
5914 auto lowType = type_dyn_cast<FIRRTLBaseType>(operands[2].getType());
5915 if (!highType || !lowType)
5921FIRRTLType Mux4CellIntrinsicOp::inferReturnType(ValueRange operands,
5922 DictionaryAttr attrs,
5923 OpaqueProperties properties,
5924 mlir::RegionRange regions,
5925 std::optional<Location> loc) {
5926 SmallVector<FIRRTLBaseType> types;
5928 for (
unsigned i = 1; i < 5; i++) {
5929 types.push_back(type_dyn_cast<FIRRTLBaseType>(operands[i].getType()));
5934 isConst(operands[0].getType()), loc);
5938 result = types.back();
5945 std::optional<Location> loc) {
5946 auto inputi = type_dyn_cast<IntType>(input);
5947 if (amount < 0 || !inputi)
5949 loc,
"pad input must be integer and amount must be >= 0");
5951 int32_t width = inputi.getWidthOrSentinel();
5955 width = std::max<int32_t>(width, amount);
5956 return IntType::get(input.getContext(), inputi.isSigned(), width,
5961 std::optional<Location> loc) {
5962 auto inputi = type_dyn_cast<IntType>(input);
5963 if (amount < 0 || !inputi)
5965 loc,
"shl input must be integer and amount must be >= 0");
5967 int32_t width = inputi.getWidthOrSentinel();
5971 return IntType::get(input.getContext(), inputi.isSigned(), width,
5976 std::optional<Location> loc) {
5977 auto inputi = type_dyn_cast<IntType>(input);
5978 if (amount < 0 || !inputi)
5980 loc,
"shr input must be integer and amount must be >= 0");
5982 int32_t width = inputi.getWidthOrSentinel();
5985 int32_t minWidth = inputi.isUnsigned() ? 0 : 1;
5986 width = std::max<int32_t>(minWidth, width - amount);
5989 return IntType::get(input.getContext(), inputi.isSigned(), width,
5994 std::optional<Location> loc) {
5996 auto inputi = type_dyn_cast<IntType>(input);
5997 if (amount < 0 || !inputi)
5999 loc,
"tail input must be integer and amount must be >= 0");
6001 int32_t width = inputi.getWidthOrSentinel();
6005 loc,
"amount must be less than or equal operand width");
6016void VerbatimExprOp::getAsmResultNames(
6017 function_ref<
void(Value, StringRef)> setNameFn) {
6021 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
6022 auto name = getText();
6024 if (name.starts_with(
"`"))
6025 name = name.drop_front();
6026 name = name.take_while(isOkCharacter);
6028 setNameFn(getResult(), name);
6035void VerbatimWireOp::getAsmResultNames(
6036 function_ref<
void(Value, StringRef)> setNameFn) {
6040 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
6041 auto name = getText();
6043 if (name.starts_with(
"`"))
6044 name = name.drop_front();
6045 name = name.take_while(isOkCharacter);
6047 setNameFn(getResult(), name);
6058 op->emitError() <<
"unknown width is not allowed for DPI";
6059 return WalkResult::interrupt();
6061 if (width == 1 || width == 8 || width == 16 || width == 32 ||
6063 return WalkResult::advance();
6065 <<
"integer types used by DPI functions must have a "
6066 "specific bit width; "
6067 "it must be equal to 1(bit), 8(byte), 16(shortint), "
6068 "32(int), 64(longint) "
6069 "or greater than 64, but got "
6071 return WalkResult::interrupt();
6076LogicalResult DPICallIntrinsicOp::verify() {
6077 if (
auto inputNames = getInputNames()) {
6078 if (getInputs().size() != inputNames->size())
6079 return emitError() <<
"inputNames has " << inputNames->size()
6080 <<
" elements but there are " << getInputs().size()
6081 <<
" input arguments";
6083 if (
auto outputName = getOutputName())
6084 if (getNumResults() == 0)
6085 return emitError() <<
"output name is given but there is no result";
6087 auto checkType = [
this](Type type) {
6090 return success(llvm::all_of(this->getResultTypes(), checkType) &&
6091 llvm::all_of(this->getOperandTypes(), checkType));
6094SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
6095DPICallIntrinsicOp::computeDataFlow() {
6099 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
6101 for (
auto operand : getOperands()) {
6102 auto type = type_cast<FIRRTLBaseType>(operand.getType());
6104 SmallVector<circt::FieldRef> operandFields;
6107 operandFields.push_back(baseFieldRef.getSubField(dstIndex));
6111 for (
auto result : getResults())
6114 for (
auto field : operandFields)
6115 deps.emplace_back(
circt::
FieldRef(result, dstIndex), field);
6125LogicalResult HWStructCastOp::verify() {
6127 BundleType bundleType;
6128 hw::StructType structType;
6129 if ((bundleType = type_dyn_cast<BundleType>(getOperand().getType()))) {
6130 structType = dyn_cast<hw::StructType>(getType());
6132 return emitError(
"result type must be a struct");
6133 }
else if ((bundleType = type_dyn_cast<BundleType>(getType()))) {
6134 structType = dyn_cast<hw::StructType>(getOperand().getType());
6136 return emitError(
"operand type must be a struct");
6138 return emitError(
"either source or result type must be a bundle type");
6141 auto firFields = bundleType.getElements();
6142 auto hwFields = structType.getElements();
6143 if (firFields.size() != hwFields.size())
6144 return emitError(
"bundle and struct have different number of fields");
6146 for (
size_t findex = 0, fend = firFields.size(); findex < fend; ++findex) {
6147 if (firFields[findex].name.getValue() != hwFields[findex].name)
6148 return emitError(
"field names don't match '")
6149 << firFields[findex].name.getValue() <<
"', '"
6150 << hwFields[findex].name.getValue() <<
"'";
6154 if (firWidth > 0 && hwWidth > 0 && firWidth != hwWidth)
6155 return emitError(
"size of field '")
6156 << hwFields[findex].name.getValue() <<
"' don't match " << firWidth
6163LogicalResult BitCastOp::verify() {
6164 auto inTypeBits =
getBitWidth(getInput().getType(),
true);
6166 if (inTypeBits.has_value() && resTypeBits.has_value()) {
6168 if (*inTypeBits == *resTypeBits) {
6171 return emitError(
"cannot cast non-'const' input type ")
6172 << getOperand().getType() <<
" to 'const' result type "
6176 return emitError(
"the bitwidth of input (")
6177 << *inTypeBits <<
") and result (" << *resTypeBits
6180 if (!inTypeBits.has_value())
6181 return emitError(
"bitwidth cannot be determined for input operand type ")
6182 << getInput().getType();
6183 return emitError(
"bitwidth cannot be determined for result type ")
6194 NamedAttrList &resultAttrs) {
6195 auto result = parser.parseOptionalAttrDict(resultAttrs);
6196 if (!resultAttrs.get(
"annotations"))
6197 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
6203 DictionaryAttr attr,
6204 ArrayRef<StringRef> extraElides = {}) {
6205 SmallVector<StringRef> elidedAttrs(extraElides.begin(), extraElides.end());
6207 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
6208 elidedAttrs.push_back(
"annotations");
6210 elidedAttrs.push_back(
"nameKind");
6212 p.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
6218 NamedAttrList &resultAttrs) {
6221 if (!resultAttrs.get(
"portAnnotations")) {
6222 SmallVector<Attribute, 16> portAnnotations(
6223 parser.getNumResults(), parser.getBuilder().getArrayAttr({}));
6224 resultAttrs.append(
"portAnnotations",
6225 parser.getBuilder().getArrayAttr(portAnnotations));
6232 DictionaryAttr attr,
6233 ArrayRef<StringRef> extraElides = {}) {
6234 SmallVector<StringRef, 2> elidedAttrs(extraElides.begin(), extraElides.end());
6236 if (llvm::all_of(op->getAttrOfType<ArrayAttr>(
"portAnnotations"),
6237 [&](Attribute a) { return cast<ArrayAttr>(a).empty(); }))
6238 elidedAttrs.push_back(
"portAnnotations");
6247 firrtl::NameKindEnumAttr &result) {
6250 if (!parser.parseOptionalKeyword(&keyword,
6251 {
"interesting_name",
"droppable_name"})) {
6252 auto kind = symbolizeNameKindEnum(keyword);
6253 result = NameKindEnumAttr::get(parser.getContext(), kind.value());
6259 NameKindEnumAttr::get(parser.getContext(), NameKindEnum::DroppableName);
6264 firrtl::NameKindEnumAttr attr,
6265 ArrayRef<StringRef> extraElides = {}) {
6266 if (attr.getValue() != NameKindEnum::DroppableName)
6267 p <<
" " << stringifyNameKindEnum(attr.getValue());
6275 NamedAttrList &resultAttrs) {
6283 DictionaryAttr attrs) {
6284 SmallVector<StringRef, 4> elides;
6286 elides.push_back(Forceable::getForceableAttrName());
6295static ParseResult
parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs) {
6300static void printMemOp(OpAsmPrinter &p, Operation *op, DictionaryAttr attr) {
6311 if (ClassType::parseInterface(parser, type))
6318 type.printInterface(p);
6326 NamedAttrList &resultAttrs) {
6327 auto result = p.parseOptionalAttrDict(resultAttrs);
6328 if (!resultAttrs.get(
"name"))
6329 resultAttrs.append(
"name", p.getBuilder().getStringAttr(
""));
6335 DictionaryAttr attr,
6336 ArrayRef<StringRef> extraElides = {}) {
6337 SmallVector<StringRef> elides(extraElides.begin(), extraElides.end());
6338 if (op->getAttrOfType<StringAttr>(
"name").getValue().empty())
6339 elides.push_back(
"name");
6341 p.printOptionalAttrDict(op->getAttrs(), elides);
6345 NamedAttrList &resultAttrs) {
6350 DictionaryAttr attr) {
6355 NamedAttrList &resultAttrs) {
6360 DictionaryAttr attr) {
6362 {
"formatString",
"outputFile",
"operandSegmentSizes"});
6370 DictionaryAttr attr) {
6379 DictionaryAttr attr) {
6388 OpAsmSetValueNameFn setNameFn) {
6391 if (op->getNumResults() == 1)
6392 if (
auto nameAttr = op->getAttrOfType<StringAttr>(
"name"))
6393 setNameFn(op->getResult(0), nameAttr.getValue());
6396void AddPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6400void AndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6404void AndRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6408void SizeOfIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6411void AsAsyncResetPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6414void AsClockPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6417void AsSIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6420void AsUIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6423void BitsPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6426void CatPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6429void CvtPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6432void DShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6435void DShlwPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6438void DShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6441void DivPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6444void EQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6447void GEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6450void GTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6453void GenericIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6456void HeadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6459void IntegerAddOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6462void IntegerMulOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6465void IntegerShrOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6468void IntegerShlOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6471void IsTagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6474void IsXIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6477void PlusArgsValueIntrinsicOp::getAsmResultNames(
6478 OpAsmSetValueNameFn setNameFn) {
6481void PlusArgsTestIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6484void LEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6487void LTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6490void MulPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6493void MultibitMuxOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6496void MuxPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6499void Mux4CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6502void Mux2CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6505void NEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6508void NegPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6511void NotPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6514void OrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6517void OrRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6520void PadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6523void RemPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6526void ShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6529void ShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6533void SubPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6537void SubaccessOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6541void SubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6545void OpenSubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6549void SubtagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6553void SubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6557void OpenSubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6561void TagExtractOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6565void TailPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6569void XorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6573void XorRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6577void UninferredResetCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6581void ConstCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6585void ElementwiseXorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6589void ElementwiseOrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6593void ElementwiseAndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6601void RefCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6605void RefResolveOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6609void RefSendOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6613void RefSubOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6617void RWProbeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6621FIRRTLType RefResolveOp::inferReturnType(ValueRange operands,
6622 DictionaryAttr attrs,
6623 OpaqueProperties properties,
6624 mlir::RegionRange regions,
6625 std::optional<Location> loc) {
6626 Type inType = operands[0].getType();
6627 auto inRefType = type_dyn_cast<RefType>(inType);
6630 loc,
"ref.resolve operand must be ref type, not ", inType);
6631 return inRefType.getType();
6634FIRRTLType RefSendOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
6635 OpaqueProperties properties,
6636 mlir::RegionRange regions,
6637 std::optional<Location> loc) {
6638 Type inType = operands[0].getType();
6639 auto inBaseType = type_dyn_cast<FIRRTLBaseType>(inType);
6642 loc,
"ref.send operand must be base type, not ", inType);
6643 return RefType::get(inBaseType.getPassiveType());
6646FIRRTLType RefSubOp::inferReturnType(Type type, uint32_t fieldIndex,
6647 std::optional<Location> loc) {
6648 auto refType = type_dyn_cast<RefType>(type);
6651 auto inType = refType.getType();
6657 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
6658 if (fieldIndex < vectorType.getNumElements())
6659 return RefType::get(
6660 vectorType.getElementType().getConstType(
6661 vectorType.isConst() || vectorType.getElementType().isConst()),
6662 refType.getForceable(), refType.getLayer());
6664 "' in RefType of vector type ", refType);
6666 if (
auto bundleType = type_dyn_cast<BundleType>(inType)) {
6667 if (fieldIndex >= bundleType.getNumElements()) {
6669 "subfield element index is greater than "
6670 "the number of fields in the bundle type");
6672 return RefType::get(
6673 bundleType.getElement(fieldIndex)
6675 bundleType.isConst() ||
6676 bundleType.getElement(fieldIndex).type.isConst()),
6677 refType.getForceable(), refType.getLayer());
6681 loc,
"ref.sub op requires a RefType of vector or bundle base type");
6684LogicalResult RefCastOp::verify() {
6688 getOperation(), srcLayers, dstLayers,
6689 "cannot discard layer requirements of input reference",
6690 "discarding layer requirements");
6693LogicalResult RefResolveOp::verify() {
6697 getOperation(), srcLayers, dstLayers,
6698 "ambient layers are insufficient to resolve reference");
6702 auto targetRef = getTarget();
6703 if (targetRef.getModule() !=
6704 (*this)->getParentOfType<FModuleLike>().getModuleNameAttr())
6705 return emitOpError() <<
"has non-local target";
6707 auto target = ns.
lookup(targetRef);
6709 return emitOpError() <<
"has target that cannot be resolved: " << targetRef;
6711 auto checkFinalType = [&](
auto type, Location loc) -> LogicalResult {
6716 auto baseType = type_dyn_cast<FIRRTLBaseType>(fType);
6717 if (!baseType || baseType.getPassiveType() != getType().getType()) {
6718 auto diag = emitOpError(
"has type mismatch: target resolves to ")
6719 << fType <<
" instead of expected " << getType().getType();
6720 diag.attachNote(loc) <<
"target resolves here";
6725 if (target.isPort()) {
6726 auto mod = cast<FModuleLike>(target.getOp());
6727 return checkFinalType(mod.getPortType(target.getPort()),
6728 mod.getPortLocation(target.getPort()));
6730 hw::InnerSymbolOpInterface symOp =
6731 cast<hw::InnerSymbolOpInterface>(target.getOp());
6732 if (!symOp.getTargetResult())
6733 return emitOpError(
"has target that cannot be probed")
6734 .attachNote(symOp.getLoc())
6735 .append(
"target resolves here");
6737 symOp.getTargetResult().getParentBlock()->findAncestorOpInBlock(**
this);
6738 if (!ancestor || !symOp->isBeforeInBlock(ancestor))
6739 return emitOpError(
"is not dominated by target")
6740 .attachNote(symOp.getLoc())
6741 .append(
"target here");
6742 return checkFinalType(symOp.getTargetResult().getType(), symOp.getLoc());
6745LogicalResult RefForceOp::verify() {
6749 getOperation(), destLayers, ambientLayers,
6750 "has insufficient ambient layers to force its reference");
6753LogicalResult RefForceInitialOp::verify() {
6757 getOperation(), destLayers, ambientLayers,
6758 "has insufficient ambient layers to force its reference");
6761LogicalResult RefReleaseOp::verify() {
6765 getOperation(), destLayers, ambientLayers,
6766 "has insufficient ambient layers to release its reference");
6769LogicalResult RefReleaseInitialOp::verify() {
6773 getOperation(), destLayers, ambientLayers,
6774 "has insufficient ambient layers to release its reference");
6777LogicalResult XMRRefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6778 auto *target = symbolTable.lookupNearestSymbolFrom(*
this, getRefAttr());
6780 return emitOpError(
"has an invalid symbol reference");
6782 if (!isa<hw::HierPathOp>(target))
6783 return emitOpError(
"does not target a hierpath op");
6789LogicalResult XMRDerefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6790 auto *target = symbolTable.lookupNearestSymbolFrom(*
this, getRefAttr());
6792 return emitOpError(
"has an invalid symbol reference");
6794 if (!isa<hw::HierPathOp>(target))
6795 return emitOpError(
"does not target a hierpath op");
6805LogicalResult LayerBlockOp::verify() {
6806 auto layerName = getLayerName();
6807 auto *parentOp = (*this)->getParentOp();
6810 while (isa<WhenOp, MatchOp>(parentOp))
6811 parentOp = parentOp->getParentOp();
6815 auto nestedReferences = layerName.getNestedReferences();
6816 if (nestedReferences.empty()) {
6817 if (!isa<FModuleOp>(parentOp)) {
6818 auto diag = emitOpError() <<
"has an un-nested layer symbol, but does "
6819 "not have a 'firrtl.module' op as a parent";
6820 return diag.attachNote(parentOp->getLoc())
6821 <<
"illegal parent op defined here";
6824 auto parentLayerBlock = dyn_cast<LayerBlockOp>(parentOp);
6825 if (!parentLayerBlock) {
6826 auto diag = emitOpError()
6827 <<
"has a nested layer symbol, but does not have a '"
6828 << getOperationName() <<
"' op as a parent'";
6829 return diag.attachNote(parentOp->getLoc())
6830 <<
"illegal parent op defined here";
6832 auto parentLayerBlockName = parentLayerBlock.getLayerName();
6833 if (parentLayerBlockName.getRootReference() !=
6834 layerName.getRootReference() ||
6835 parentLayerBlockName.getNestedReferences() !=
6836 layerName.getNestedReferences().drop_back()) {
6837 auto diag = emitOpError() <<
"is nested under an illegal layer block";
6838 return diag.attachNote(parentLayerBlock->getLoc())
6839 <<
"illegal parent layer block defined here";
6845 auto result = getBody(0)->walk<mlir::WalkOrder::PreOrder>(
6846 [&](Operation *op) -> WalkResult {
6848 if (isa<LayerBlockOp>(op))
6849 return WalkResult::skip();
6853 for (
auto operand : op->getOperands()) {
6855 if (
auto *definingOp = operand.getDefiningOp())
6859 auto type = operand.getType();
6862 if (isa<PropertyType>(type)) {
6863 auto diag = emitOpError() <<
"captures a property operand";
6864 diag.attachNote(operand.getLoc()) <<
"operand is defined here";
6865 diag.attachNote(op->getLoc()) <<
"operand is used here";
6866 return WalkResult::interrupt();
6871 if (
auto connect = dyn_cast<FConnectLike>(op)) {
6873 if (isa<RefDefineOp>(connect))
6874 return WalkResult::advance();
6881 bool passive =
true;
6883 type_dyn_cast<FIRRTLBaseType>(
connect.getDest().getType()))
6884 passive = type.isPassive();
6893 return WalkResult::advance();
6896 return WalkResult::advance();
6900 <<
"connects to a destination which is defined outside its "
6901 "enclosing layer block";
6902 diag.attachNote(
getLoc()) <<
"enclosing layer block is defined here";
6903 diag.attachNote(dest.getLoc()) <<
"destination is defined here";
6904 return WalkResult::interrupt();
6907 return WalkResult::advance();
6910 return failure(result.wasInterrupted());
6914LayerBlockOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6916 symbolTable.lookupNearestSymbolFrom<LayerOp>(*
this, getLayerNameAttr());
6918 return emitOpError(
"invalid symbol reference");
6928void TimeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6929 setNameFn(getResult(),
"time");
6932void HierarchicalModuleNameOp::getAsmResultNames(
6933 OpAsmSetValueNameFn setNameFn) {
6934 setNameFn(getResult(),
"hierarchicalmodulename");
6937ParseResult FPrintFOp::parse(::mlir::OpAsmParser &parser,
6938 ::mlir::OperationState &result) {
6940 OpAsmParser::UnresolvedOperand clock, cond;
6941 if (parser.parseOperand(clock) || parser.parseComma() ||
6942 parser.parseOperand(cond) || parser.parseComma())
6945 auto parseFormatString =
6946 [&parser](llvm::SMLoc &loc, StringAttr &result,
6947 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &operands)
6949 loc = parser.getCurrentLocation();
6952 std::string resultStr;
6953 if (parser.parseString(&resultStr))
6955 result = parser.getBuilder().getStringAttr(resultStr);
6958 if (parser.parseOperandList(operands, AsmParser::Delimiter::OptionalParen))
6964 SmallVector<OpAsmParser::UnresolvedOperand> outputFileSubstitutions,
6966 llvm::SMLoc outputFileLoc, formatStringLoc;
6968 if (parseFormatString(
6970 result.getOrAddProperties<FPrintFOp::Properties>().outputFile,
6971 outputFileSubstitutions) ||
6972 parser.parseComma() ||
6975 result.getOrAddProperties<FPrintFOp::Properties>().formatString,
6983 Type clockType, condType;
6984 SmallVector<Type> restTypes;
6986 if (parser.parseColon() || parser.parseType(clockType) ||
6987 parser.parseComma() || parser.parseType(condType))
6990 if (succeeded(parser.parseOptionalComma())) {
6991 if (parser.parseTypeList(restTypes))
6996 result.getOrAddProperties<FPrintFOp::Properties>().operandSegmentSizes = {
6997 1, 1,
static_cast<int32_t
>(outputFileSubstitutions.size()),
6998 static_cast<int32_t
>(substitutions.size())};
7001 if (parser.resolveOperand(clock, clockType, result.operands) ||
7002 parser.resolveOperand(cond, condType, result.operands) ||
7003 parser.resolveOperands(
7004 outputFileSubstitutions,
7005 ArrayRef(restTypes).take_front(outputFileSubstitutions.size()),
7006 outputFileLoc, result.operands) ||
7007 parser.resolveOperands(
7009 ArrayRef(restTypes).drop_front(outputFileSubstitutions.size()),
7010 formatStringLoc, result.operands))
7016void FPrintFOp::print(OpAsmPrinter &p) {
7017 p <<
" " << getClock() <<
", " << getCond() <<
", ";
7018 p.printAttributeWithoutType(getOutputFileAttr());
7019 if (!getOutputFileSubstitutions().
empty()) {
7021 p.printOperands(getOutputFileSubstitutions());
7025 p.printAttributeWithoutType(getFormatStringAttr());
7026 if (!getSubstitutions().
empty()) {
7028 p.printOperands(getSubstitutions());
7032 p <<
" : " << getClock().getType() <<
", " << getCond().getType();
7033 if (!getOutputFileSubstitutions().
empty() || !getSubstitutions().
empty()) {
7034 for (
auto type : getOperands().drop_front(2).getTypes()) {
7045LogicalResult FFlushOp::verify() {
7046 if (!getOutputFileAttr() && !getOutputFileSubstitutions().
empty())
7047 return emitOpError(
"substitutions without output file are not allowed");
7056 auto ref = getInstanceAttr();
7057 auto target = ns.
lookup(ref);
7059 return emitError() <<
"target " << ref <<
" cannot be resolved";
7061 if (!target.isOpOnly())
7062 return emitError() <<
"target " << ref <<
" is not an operation";
7064 auto instance = dyn_cast<InstanceOp>(target.getOp());
7066 return emitError() <<
"target " << ref <<
" is not an instance";
7068 if (!instance.getDoNotPrint())
7069 return emitError() <<
"target " << ref <<
" is not marked doNotPrint";
7079DomainCreateAnonOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7080 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
7081 auto domain = getDomainAttr();
7082 if (!symbolTable.lookupSymbolIn<DomainOp>(circuitOp, domain))
7083 return emitOpError() <<
"references undefined domain '" << domain <<
"'";
7093#define GET_OP_CLASSES
7094#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.
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.