28#include "mlir/IR/BuiltinTypes.h"
29#include "mlir/IR/Diagnostics.h"
30#include "mlir/IR/DialectImplementation.h"
31#include "mlir/IR/PatternMatch.h"
32#include "mlir/IR/SymbolTable.h"
33#include "mlir/Interfaces/FunctionImplementation.h"
34#include "llvm/ADT/BitVector.h"
35#include "llvm/ADT/DenseMap.h"
36#include "llvm/ADT/DenseSet.h"
37#include "llvm/ADT/STLExtras.h"
38#include "llvm/ADT/SmallSet.h"
39#include "llvm/ADT/StringExtras.h"
40#include "llvm/ADT/TypeSwitch.h"
41#include "llvm/Support/Casting.h"
42#include "llvm/Support/FormatVariadic.h"
44using llvm::SmallDenseSet;
45using mlir::RegionRange;
47using namespace firrtl;
48using namespace chirrtl;
56 p <<
" of " << domainKind;
61 FlatSymbolRefAttr &domainKind) {
62 StringAttr domainName;
63 if (parser.parseKeyword(
"of") || parser.parseSymbolName(domainName))
65 domainKind = FlatSymbolRefAttr::get(domainName);
74 const llvm::BitVector &indicesToDrop) {
77 int lastIndex = indicesToDrop.find_last();
79 assert((
size_t)lastIndex < input.size() &&
"index out of range");
89 size_t lastCopied = 0;
90 SmallVector<T> result;
91 result.reserve(input.size() - indicesToDrop.count());
93 for (
unsigned indexToDrop : indicesToDrop.set_bits()) {
95 if (indexToDrop > lastCopied) {
96 result.append(input.begin() + lastCopied, input.begin() + indexToDrop);
97 lastCopied = indexToDrop;
104 if (lastCopied < input.size())
105 result.append(input.begin() + lastCopied, input.end());
111template <
typename RetTy =
FIRRTLType,
typename... Args>
113 const Twine &message, Args &&...args) {
115 (mlir::emitError(*loc, message) << ... << std::forward<Args>(args));
121 while (Operation *op = val.getDefiningOp()) {
123 TypeSwitch<Operation *, std::optional<bool>>(op)
124 .Case<SubfieldOp, SubindexOp, SubaccessOp>([&val](
auto op) {
128 .Case<RegOp, RegResetOp, WireOp>([](
auto) {
return true; })
129 .Default([](
auto) {
return false; });
136SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
137MemOp::computeDataFlow() {
140 if (getReadLatency() > 0)
142 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
144 for (
auto memPort : getResults())
145 if (auto type =
type_dyn_cast<BundleType>(memPort.getType())) {
146 auto enableFieldId = type.getFieldID((
unsigned)ReadPortSubfield::en);
147 auto addressFieldId = type.getFieldID((
unsigned)ReadPortSubfield::addr);
148 auto dataFieldId = type.getFieldID((
unsigned)ReadPortSubfield::data);
150 FieldRef(memPort,
static_cast<unsigned>(dataFieldId)),
151 FieldRef(memPort,
static_cast<unsigned>(enableFieldId)));
153 FieldRef(memPort,
static_cast<unsigned>(dataFieldId)),
154 FieldRef(memPort,
static_cast<unsigned>(addressFieldId)));
161 constexpr unsigned int addr = 1 << 0;
162 constexpr unsigned int en = 1 << 1;
163 constexpr unsigned int clk = 1 << 2;
164 constexpr unsigned int data = 1 << 3;
165 constexpr unsigned int mask = 1 << 4;
166 constexpr unsigned int rdata = 1 << 5;
167 constexpr unsigned int wdata = 1 << 6;
168 constexpr unsigned int wmask = 1 << 7;
169 constexpr unsigned int wmode = 1 << 8;
170 constexpr unsigned int def = 1 << 9;
172 auto portType = type_dyn_cast<BundleType>(type);
174 return MemOp::PortKind::Debug;
177 for (
auto elem : portType.getElements()) {
178 fields |= llvm::StringSwitch<unsigned>(elem.name.getValue())
184 .Case(
"rdata",
rdata)
185 .Case(
"wdata",
wdata)
186 .Case(
"wmask",
wmask)
187 .Case(
"wmode",
wmode)
191 return MemOp::PortKind::Read;
193 return MemOp::PortKind::Write;
195 return MemOp::PortKind::ReadWrite;
196 return MemOp::PortKind::Debug;
211 llvm_unreachable(
"Unsupported Flow type.");
219 return "source flow";
223 return "duplex flow";
226 llvm_unreachable(
"Unsupported Flow type.");
231 if (
auto blockArg = dyn_cast<BlockArgument>(val)) {
232 auto *op = val.getParentBlock()->getParentOp();
233 if (
auto moduleLike = dyn_cast<FModuleLike>(op)) {
234 auto direction = moduleLike.getPortDirection(blockArg.getArgNumber());
235 if (direction == Direction::Out)
238 return accumulatedFlow;
241 Operation *op = val.getDefiningOp();
243 return TypeSwitch<Operation *, Flow>(op)
244 .Case<SubfieldOp, OpenSubfieldOp>([&](
auto op) {
245 return foldFlow(op.getInput(), op.isFieldFlipped()
249 .Case<SubindexOp, SubaccessOp, OpenSubindexOp, RefSubOp>(
250 [&](
auto op) {
return foldFlow(op.getInput(), accumulatedFlow); })
252 .Case<RegOp, RegResetOp, WireOp, MemoryPortOp>(
253 [](
auto) {
return Flow::Duplex; })
254 .Case<InstanceOp, InstanceChoiceOp>([&](
auto inst) {
255 auto resultNo = cast<OpResult>(val).getResultNumber();
256 if (inst.getPortDirection(resultNo) == Direction::Out)
257 return accumulatedFlow;
260 .Case<MemOp>([&](
auto op) {
262 if (type_isa<RefType>(val.getType()))
266 .Case<ObjectSubfieldOp>([&](ObjectSubfieldOp op) {
267 auto input = op.getInput();
268 auto *inputOp = input.getDefiningOp();
271 if (
auto objectOp = dyn_cast_or_null<ObjectOp>(inputOp)) {
272 auto classType = input.getType();
273 auto direction = classType.getElement(op.getIndex()).direction;
274 if (direction == Direction::In)
285 auto classType = input.getType();
286 auto direction = classType.getElement(op.getIndex()).direction;
287 if (direction == Direction::In)
290 op = dyn_cast_or_null<ObjectSubfieldOp>(inputOp);
292 input = op.getInput();
293 inputOp = input.getDefiningOp();
297 return accumulatedFlow;
301 .Default([&](
auto) {
return accumulatedFlow; });
307 Operation *op = val.getDefiningOp();
309 return DeclKind::Port;
311 return TypeSwitch<Operation *, DeclKind>(op)
312 .Case<InstanceOp>([](
auto) {
return DeclKind::Instance; })
313 .Case<SubfieldOp, SubindexOp, SubaccessOp, OpenSubfieldOp, OpenSubindexOp,
315 .Default([](
auto) {
return DeclKind::Other; });
319 if (
auto module = dyn_cast<FModuleLike>(op))
320 return module.getNumPorts();
321 return op->getNumResults();
335 if (
auto *op = value.getDefiningOp())
337 auto arg = dyn_cast<BlockArgument>(value);
338 auto module = dyn_cast<FModuleOp>(arg.getOwner()->getParentOp());
341 return (module.getPortSymbolAttr(arg.getArgNumber())) ||
348 OpAsmSetValueNameFn setNameFn) {
352 auto *block = ®ion.front();
355 auto argAttr = parentOp->getAttrOfType<ArrayAttr>(
"portNames");
357 if (!argAttr || argAttr.size() != block->getNumArguments())
360 for (
size_t i = 0, e = block->getNumArguments(); i != e; ++i) {
361 auto str = cast<StringAttr>(argAttr[i]).getValue();
363 setNameFn(block->getArgument(i), str);
369 firrtl::NameKindEnumAttr &result);
380 for (; op !=
nullptr; op = op->getParentOp()) {
381 if (
auto module = dyn_cast<FModuleLike>(op)) {
382 auto layers =
module.getLayersAttr().getAsRange<SymbolRefAttr>();
383 result.insert(layers.begin(), layers.end());
386 if (
auto layerblock = dyn_cast<LayerBlockOp>(op)) {
387 result.insert(layerblock.getLayerName());
405 if (
auto type = dyn_cast<RefType>(value.getType()))
406 if (
auto layer = type.getLayer())
407 result.insert(type.getLayer());
416 mlir::SymbolRefAttr dstLayer) {
426 if (srcLayer.getRootReference() != dstLayer.getRootReference())
429 auto srcNames = srcLayer.getNestedReferences();
430 auto dstNames = dstLayer.getNestedReferences();
431 if (dstNames.size() < srcNames.size())
434 return llvm::all_of(llvm::zip_first(srcNames, dstNames),
435 [](
auto x) {
return std::get<0>(x) == std::get<1>(x); });
442 if (dstLayers.contains(srcLayer))
447 return any_of(dstLayers, [=](SymbolRefAttr dstLayer) {
456 SmallVectorImpl<SymbolRefAttr> &missing) {
457 for (
auto srcLayer : src)
459 missing.push_back(srcLayer);
462 return missing.empty();
467 const Twine &errorMsg,
468 const Twine ¬eMsg = Twine(
"missing layer requirements")) {
469 SmallVector<SymbolRefAttr> missing;
472 interleaveComma(missing, op->emitOpError(errorMsg).attachNote()
481void CircuitOp::build(OpBuilder &builder, OperationState &result,
482 StringAttr name, ArrayAttr annotations) {
484 result.getOrAddProperties<Properties>().setName(name);
487 annotations = builder.getArrayAttr({});
488 result.getOrAddProperties<Properties>().setAnnotations(annotations);
491 Region *bodyRegion = result.addRegion();
493 bodyRegion->push_back(body);
497 NamedAttrList &resultAttrs) {
498 auto result = parser.parseOptionalAttrDictWithKeyword(resultAttrs);
499 if (!resultAttrs.get(
"annotations"))
500 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
506 DictionaryAttr attr) {
508 SmallVector<StringRef> elidedAttrs = {
"name"};
510 auto annotationsAttr = op->getAttrOfType<ArrayAttr>(
"annotations");
511 if (annotationsAttr.empty())
512 elidedAttrs.push_back(
"annotations");
514 p.printOptionalAttrDictWithKeyword(op->getAttrs(), elidedAttrs);
517LogicalResult CircuitOp::verifyRegions() {
522 emitOpError(
"must have a non-empty name");
526 mlir::SymbolTable symtbl(getOperation());
528 auto *mainModule = symtbl.lookup(
main);
530 return emitOpError().append(
531 "does not contain module with same name as circuit");
532 if (!isa<FModuleLike>(mainModule))
533 return mainModule->emitError(
534 "entity with name of circuit must be a module");
535 if (symtbl.getSymbolVisibility(mainModule) !=
536 mlir::SymbolTable::Visibility::Public)
537 return mainModule->emitError(
"main module must be public");
542 llvm::DenseMap<Attribute, FExtModuleOp> defnameMap;
544 auto verifyExtModule = [&](FExtModuleOp extModule) -> LogicalResult {
548 auto defname = extModule.getDefnameAttr();
554 if (
auto collidingModule = symtbl.lookup<FModuleOp>(defname.getValue()))
555 return extModule.emitOpError()
556 .append(
"attribute 'defname' with value ", defname,
557 " conflicts with the name of another module in the circuit")
558 .attachNote(collidingModule.getLoc())
559 .append(
"previous module declared here");
567 FExtModuleOp collidingExtModule;
568 if (
auto &value = defnameMap[defname]) {
569 collidingExtModule = value;
570 if (!value.getParameters().empty() && extModule.getParameters().empty())
580 SmallVector<PortInfo> ports = extModule.getPorts();
581 SmallVector<PortInfo> collidingPorts = collidingExtModule.getPorts();
583 if (ports.size() != collidingPorts.size())
584 return extModule.emitOpError()
585 .append(
"with 'defname' attribute ", defname,
" has ", ports.size(),
586 " ports which is different from a previously defined "
587 "extmodule with the same 'defname' which has ",
588 collidingPorts.size(),
" ports")
589 .attachNote(collidingExtModule.getLoc())
590 .append(
"previous extmodule definition occurred here");
596 for (
auto p :
llvm::zip(ports, collidingPorts)) {
597 StringAttr aName = std::get<0>(p).name, bName = std::get<1>(p).name;
598 Type aType = std::get<0>(p).type, bType = std::get<1>(p).type;
601 return extModule.emitOpError()
602 .append(
"with 'defname' attribute ", defname,
603 " has a port with name ", aName,
604 " which does not match the name of the port in the same "
605 "position of a previously defined extmodule with the same "
606 "'defname', expected port to have name ",
608 .attachNote(collidingExtModule.getLoc())
609 .append(
"previous extmodule definition occurred here");
611 if (!extModule.getParameters().empty() ||
612 !collidingExtModule.getParameters().empty()) {
614 if (
auto base = type_dyn_cast<FIRRTLBaseType>(aType))
615 aType = base.getWidthlessType();
616 if (
auto base = type_dyn_cast<FIRRTLBaseType>(bType))
617 bType = base.getWidthlessType();
620 return extModule.emitOpError()
621 .append(
"with 'defname' attribute ", defname,
622 " has a port with name ", aName,
623 " which has a different type ", aType,
624 " which does not match the type of the port in the same "
625 "position of a previously defined extmodule with the same "
626 "'defname', expected port to have type ",
628 .attachNote(collidingExtModule.getLoc())
629 .append(
"previous extmodule definition occurred here");
634 SmallVector<FModuleOp, 1> dutModules;
637 if (
auto moduleOp = dyn_cast<FModuleOp>(op)) {
639 dutModules.push_back(moduleOp);
644 if (
auto extModule = dyn_cast<FExtModuleOp>(op)) {
645 if (verifyExtModule(extModule).failed())
651 if (dutModules.size() > 1) {
652 auto diag = dutModules[0]->emitOpError()
653 <<
"is annotated as the design-under-test (DUT), but other "
654 "modules are also annotated";
655 for (
auto moduleOp : ArrayRef(dutModules).drop_front())
656 diag.attachNote(moduleOp.
getLoc()) <<
"is also annotated as the DUT";
663Block *CircuitOp::getBodyBlock() {
return &getBody().front(); }
670 SmallVector<PortInfo> results;
671 ArrayRef<Attribute> domains =
module.getDomainInfo();
672 for (
unsigned i = 0, e = module.getNumPorts(); i < e; ++i) {
673 results.push_back({
module.getPortNameAttr(i), module.getPortType(i),
674 module.getPortDirection(i), module.getPortSymbolAttr(i),
675 module.getPortLocation(i),
676 AnnotationSet::forPort(module, i),
677 domains.empty() ? Attribute{} : domains[i]});
682SmallVector<PortInfo> FModuleOp::getPorts() { return ::getPortImpl(*
this); }
684SmallVector<PortInfo> FExtModuleOp::getPorts() { return ::getPortImpl(*
this); }
686SmallVector<PortInfo> FIntModuleOp::getPorts() { return ::getPortImpl(*
this); }
688SmallVector<PortInfo> FMemModuleOp::getPorts() { return ::getPortImpl(*
this); }
691 if (dir == Direction::In)
692 return hw::ModulePort::Direction::Input;
693 if (dir == Direction::Out)
694 return hw::ModulePort::Direction::Output;
695 assert(0 &&
"invalid direction");
700 SmallVector<hw::PortInfo> results;
701 auto aname = StringAttr::get(module.getContext(),
702 hw::HWModuleLike::getPortSymbolAttrName());
703 auto emptyDict = DictionaryAttr::get(module.getContext());
704 for (
unsigned i = 0, e =
getNumPorts(module); i < e; ++i) {
705 auto sym =
module.getPortSymbolAttr(i);
707 {{
module.getPortNameAttr(i), module.getPortType(i),
708 dirFtoH(module.getPortDirection(i))},
710 sym ? DictionaryAttr::get(
712 ArrayRef<mlir::NamedAttribute>{NamedAttribute{aname, sym}})
714 module.getPortLocation(i)});
719SmallVector<::circt::hw::PortInfo> FModuleOp::getPortList() {
720 return ::getPortListImpl(*
this);
723SmallVector<::circt::hw::PortInfo> FExtModuleOp::getPortList() {
724 return ::getPortListImpl(*
this);
727SmallVector<::circt::hw::PortInfo> FIntModuleOp::getPortList() {
728 return ::getPortListImpl(*
this);
731SmallVector<::circt::hw::PortInfo> FMemModuleOp::getPortList() {
732 return ::getPortListImpl(*
this);
736 auto sym =
module.getPortSymbolAttr(idx);
737 auto attrs = sym ? DictionaryAttr::getWithSorted(
739 ArrayRef(mlir::NamedAttribute(
740 hw::HWModuleLike::getPortSymbolAttrName(), sym)))
741 : DictionaryAttr::get(module.getContext());
742 return {{
module.getPortNameAttr(idx), module.getPortType(idx),
743 dirFtoH(module.getPortDirection(idx))},
746 module.getPortLocation(idx)};
750 return ::getPortImpl(*
this, idx);
754 return ::getPortImpl(*
this, idx);
758 return ::getPortImpl(*
this, idx);
762 return ::getPortImpl(*
this, idx);
766BlockArgument FModuleOp::getArgument(
size_t portNumber) {
773 Attribute domainInfoAttr,
774 ArrayRef<unsigned> indexMap) {
776 auto di = dyn_cast_or_null<ArrayAttr>(domainInfoAttr);
777 if (!di || di.empty())
778 return domainInfoAttr;
781 SmallVector<Attribute> domainInfo;
782 for (
auto attr : di) {
783 auto oldIdx = cast<IntegerAttr>(attr).getUInt();
784 auto newIdx = indexMap[oldIdx];
785 if (oldIdx == newIdx)
786 domainInfo.push_back(attr);
788 domainInfo.push_back(IntegerAttr::get(
789 IntegerType::get(
context, 32, IntegerType::Unsigned), newIdx));
791 return ArrayAttr::get(
context, domainInfo);
798 ArrayRef<std::pair<unsigned, PortInfo>> ports) {
801 unsigned oldNumArgs = op.getNumPorts();
802 unsigned newNumArgs = oldNumArgs + ports.size();
805 SmallVector<unsigned> indexMap(oldNumArgs);
807 for (
size_t i = 0; i < oldNumArgs; ++i) {
808 while (inserted < ports.size() && ports[inserted].first == i)
810 indexMap[i] = i + inserted;
814 auto existingDirections = op.getPortDirectionsAttr();
815 ArrayRef<Attribute> existingNames = op.getPortNames();
816 ArrayRef<Attribute> existingTypes = op.getPortTypes();
817 ArrayRef<Attribute> existingLocs = op.getPortLocations();
818 assert(existingDirections.size() == oldNumArgs);
819 assert(existingNames.size() == oldNumArgs);
820 assert(existingTypes.size() == oldNumArgs);
821 assert(existingLocs.size() == oldNumArgs);
823 SmallVector<bool> newDirections;
824 SmallVector<Attribute> newNames, newTypes, newDomains, newAnnos, newSyms,
826 newDirections.reserve(newNumArgs);
827 newNames.reserve(newNumArgs);
828 newTypes.reserve(newNumArgs);
829 newDomains.reserve(newNumArgs);
830 newAnnos.reserve(newNumArgs);
831 newSyms.reserve(newNumArgs);
832 newLocs.reserve(newNumArgs);
834 auto emptyArray = ArrayAttr::get(op.getContext(), {});
837 auto migrateOldPorts = [&](
unsigned untilOldIdx) {
838 while (oldIdx < oldNumArgs && oldIdx < untilOldIdx) {
839 newDirections.push_back(existingDirections[oldIdx]);
840 newNames.push_back(existingNames[oldIdx]);
841 newTypes.push_back(existingTypes[oldIdx]);
843 op.getContext(), op.getDomainInfoAttrForPort(oldIdx), indexMap));
844 newAnnos.push_back(op.getAnnotationsAttrForPort(oldIdx));
845 newSyms.push_back(op.getPortSymbolAttr(oldIdx));
846 newLocs.push_back(existingLocs[oldIdx]);
851 for (
auto [idx, port] : ports) {
852 migrateOldPorts(idx);
854 newNames.push_back(port.name);
855 newTypes.push_back(TypeAttr::get(port.type));
858 port.domains ? port.domains : ArrayAttr::get(op.getContext(), {}),
860 auto annos = port.annotations.getArrayAttr();
861 newAnnos.push_back(annos ? annos : emptyArray);
862 newSyms.push_back(port.sym);
863 newLocs.push_back(port.loc);
866 migrateOldPorts(oldNumArgs);
870 if (llvm::all_of(newAnnos, [](Attribute attr) {
871 return cast<ArrayAttr>(attr).empty();
877 if (llvm::all_of(newDomains, [](Attribute attr) {
880 if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr))
881 return arrayAttr.empty();
887 op->setAttr(
"portDirections",
889 op->setAttr(
"portNames", ArrayAttr::get(op.getContext(), newNames));
890 op->setAttr(
"portTypes", ArrayAttr::get(op.getContext(), newTypes));
891 op->setAttr(
"domainInfo", ArrayAttr::get(op.getContext(), newDomains));
892 op->setAttr(
"portAnnotations", ArrayAttr::get(op.getContext(), newAnnos));
893 FModuleLike::fixupPortSymsArray(newSyms, op.getContext());
894 op.setPortSymbols(newSyms);
895 op->setAttr(
"portLocations", ArrayAttr::get(op.getContext(), newLocs));
906 ArrayAttr domainInfoAttr,
907 const llvm::BitVector &portIndices,
908 bool supportsEmptyAttr) {
909 if (supportsEmptyAttr && domainInfoAttr.empty())
910 return domainInfoAttr;
913 SmallVector<unsigned> indexMap(portIndices.size());
915 for (
size_t i = 0, e = portIndices.size(); i != e; ++i) {
916 indexMap[i] = i - deleted;
923 auto getEmpty = [&]() {
925 eEmpty = ArrayAttr::get(
context, {});
930 SmallVector<Attribute> newDomainInfo;
931 newDomainInfo.reserve(portIndices.size() - portIndices.count());
932 for (
size_t i = 0, e = portIndices.size(); i != e; ++i) {
934 if (portIndices.test(i))
937 if (domainInfoAttr.empty()) {
938 newDomainInfo.push_back(getEmpty());
941 auto attr = domainInfoAttr[i];
943 auto domains = dyn_cast<ArrayAttr>(attr);
944 if (!domains || domains.empty()) {
945 newDomainInfo.push_back(attr);
949 SmallVector<Attribute> newDomains;
950 for (
auto domain : domains) {
952 auto oldIdx = cast<IntegerAttr>(domain).getUInt();
953 if (portIndices.test(oldIdx))
956 auto newIdx = indexMap[oldIdx];
957 if (oldIdx == newIdx) {
958 newDomains.push_back(domain);
962 newDomains.push_back(IntegerAttr::get(
963 IntegerType::get(
context, 32, IntegerType::Unsigned), newIdx));
965 newDomainInfo.push_back(ArrayAttr::get(
context, newDomains));
968 return ArrayAttr::get(
context, newDomainInfo);
972static void erasePorts(FModuleLike op,
const llvm::BitVector &portIndices) {
973 if (portIndices.none())
977 ArrayRef<bool> portDirections = op.getPortDirectionsAttr().asArrayRef();
978 ArrayRef<Attribute> portNames = op.getPortNames();
979 ArrayRef<Attribute> portTypes = op.getPortTypes();
980 ArrayRef<Attribute> portAnnos = op.getPortAnnotations();
981 ArrayRef<Attribute> portSyms = op.getPortSymbols();
982 ArrayRef<Attribute> portLocs = op.getPortLocations();
983 ArrayRef<Attribute> portDomains = op.getDomainInfo();
984 auto numPorts = op.getNumPorts();
986 assert(portDirections.size() == numPorts);
987 assert(portNames.size() == numPorts);
988 assert(portAnnos.size() == numPorts || portAnnos.empty());
989 assert(portTypes.size() == numPorts);
990 assert(portSyms.size() == numPorts || portSyms.empty());
991 assert(portLocs.size() == numPorts);
992 assert(portDomains.size() == numPorts || portDomains.empty());
994 SmallVector<bool> newPortDirections =
995 removeElementsAtIndices<bool>(portDirections, portIndices);
996 SmallVector<Attribute> newPortNames, newPortTypes, newPortAnnos, newPortSyms,
1004 op->setAttr(
"portDirections",
1006 op->setAttr(
"portNames", ArrayAttr::get(op.getContext(), newPortNames));
1007 op->setAttr(
"portAnnotations", ArrayAttr::get(op.getContext(), newPortAnnos));
1008 op->setAttr(
"portTypes", ArrayAttr::get(op.getContext(), newPortTypes));
1009 FModuleLike::fixupPortSymsArray(newPortSyms, op.getContext());
1010 op->setAttr(
"portSymbols", ArrayAttr::get(op.getContext(), newPortSyms));
1011 op->setAttr(
"portLocations", ArrayAttr::get(op.getContext(), newPortLocs));
1012 op->setAttr(
"domainInfo",
1014 portIndices,
true));
1017void FExtModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1018 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1021void FIntModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1022 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1025void FMemModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1026 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1029void FModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1030 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1037void FModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1038 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1042 for (
size_t i = 0, e = ports.size(); i < e; ++i) {
1045 auto &[index, port] = ports[i];
1046 body->insertArgument(index + i, port.type, port.loc);
1050void FExtModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1051 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1054void FIntModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1055 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1061void FMemModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1062 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1065template <
typename OpTy>
1067 StringAttr name, ArrayRef<PortInfo> ports) {
1069 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
1070 properties.setSymName(name);
1073 SmallVector<Direction, 4> portDirections;
1074 SmallVector<Attribute, 4> portNames;
1075 SmallVector<Attribute, 4> portTypes;
1076 SmallVector<Attribute, 4> portSyms;
1077 SmallVector<Attribute, 4> portLocs;
1078 SmallVector<Attribute, 4> portDomains;
1079 for (
const auto &port : ports) {
1080 portDirections.push_back(port.direction);
1081 portNames.push_back(port.name);
1082 portTypes.push_back(TypeAttr::get(port.type));
1083 portSyms.push_back(port.sym);
1084 portLocs.push_back(port.loc);
1085 portDomains.push_back(port.domains);
1087 if (llvm::all_of(portDomains, [](Attribute attr) {
1090 if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr))
1091 return arrayAttr.empty();
1094 portDomains.clear();
1096 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1099 properties.setPortDirections(
1101 properties.setPortNames(builder.getArrayAttr(portNames));
1102 properties.setPortTypes(builder.getArrayAttr(portTypes));
1103 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1104 properties.setPortLocations(builder.getArrayAttr(portLocs));
1105 properties.setDomainInfo(builder.getArrayAttr(portDomains));
1110template <
typename OpTy>
1112 StringAttr name, ArrayRef<PortInfo> ports,
1113 ArrayAttr annotations, ArrayAttr layers) {
1114 buildModuleLike<OpTy>(builder, result, name, ports);
1115 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
1118 annotations = builder.getArrayAttr({});
1119 properties.setAnnotations(annotations);
1123 SmallVector<Attribute, 4> portAnnotations;
1124 for (
const auto &port : ports)
1125 portAnnotations.push_back(port.annotations.getArrayAttr());
1126 if (llvm::all_of(portAnnotations, [](Attribute attr) {
1127 return cast<ArrayAttr>(attr).empty();
1129 portAnnotations.clear();
1130 properties.setPortAnnotations(builder.getArrayAttr(portAnnotations));
1134 layers = builder.getArrayAttr({});
1135 properties.setLayers(layers);
1138template <
typename OpTy>
1139static void buildClass(OpBuilder &builder, OperationState &result,
1140 StringAttr name, ArrayRef<PortInfo> ports) {
1141 return buildModuleLike<OpTy>(builder, result, name, ports);
1144void FModuleOp::build(OpBuilder &builder, OperationState &result,
1145 StringAttr name, ConventionAttr convention,
1146 ArrayRef<PortInfo> ports, ArrayAttr annotations,
1148 buildModule<FModuleOp>(builder, result, name, ports, annotations, layers);
1149 auto &properties = result.getOrAddProperties<Properties>();
1150 properties.setConvention(convention);
1153 auto *bodyRegion = result.regions[0].get();
1155 bodyRegion->push_back(body);
1158 for (
auto &elt : ports)
1159 body->addArgument(elt.type, elt.loc);
1162void FExtModuleOp::build(OpBuilder &builder, OperationState &result,
1163 StringAttr name, ConventionAttr convention,
1164 ArrayRef<PortInfo> ports, ArrayAttr knownLayers,
1165 StringRef defnameAttr, ArrayAttr annotations,
1166 ArrayAttr parameters, ArrayAttr layers) {
1167 buildModule<FExtModuleOp>(builder, result, name, ports, annotations, layers);
1168 auto &properties = result.getOrAddProperties<Properties>();
1169 properties.setConvention(convention);
1171 knownLayers = builder.getArrayAttr({});
1172 properties.setKnownLayers(knownLayers);
1173 if (!defnameAttr.empty())
1174 properties.setDefname(builder.getStringAttr(defnameAttr));
1176 parameters = builder.getArrayAttr({});
1177 properties.setParameters(parameters);
1180void FIntModuleOp::build(OpBuilder &builder, OperationState &result,
1181 StringAttr name, ArrayRef<PortInfo> ports,
1182 StringRef intrinsicNameStr, ArrayAttr annotations,
1183 ArrayAttr parameters, ArrayAttr layers) {
1184 buildModule<FIntModuleOp>(builder, result, name, ports, annotations, layers);
1185 auto &properties = result.getOrAddProperties<Properties>();
1186 properties.setIntrinsic(builder.getStringAttr(intrinsicNameStr));
1188 parameters = builder.getArrayAttr({});
1189 properties.setParameters(parameters);
1192void FMemModuleOp::build(OpBuilder &builder, OperationState &result,
1193 StringAttr name, ArrayRef<PortInfo> ports,
1194 uint32_t numReadPorts, uint32_t numWritePorts,
1195 uint32_t numReadWritePorts, uint32_t dataWidth,
1196 uint32_t maskBits, uint32_t readLatency,
1197 uint32_t writeLatency, uint64_t depth, RUWBehavior ruw,
1198 ArrayAttr annotations, ArrayAttr layers) {
1199 auto *
context = builder.getContext();
1200 buildModule<FMemModuleOp>(builder, result, name, ports, annotations, layers);
1201 auto ui32Type = IntegerType::get(
context, 32, IntegerType::Unsigned);
1202 auto ui64Type = IntegerType::get(
context, 64, IntegerType::Unsigned);
1203 auto &properties = result.getOrAddProperties<Properties>();
1204 properties.setNumReadPorts(IntegerAttr::get(ui32Type, numReadPorts));
1205 properties.setNumWritePorts(IntegerAttr::get(ui32Type, numWritePorts));
1206 properties.setNumReadWritePorts(
1207 IntegerAttr::get(ui32Type, numReadWritePorts));
1208 properties.setDataWidth(IntegerAttr::get(ui32Type, dataWidth));
1209 properties.setMaskBits(IntegerAttr::get(ui32Type, maskBits));
1210 properties.setReadLatency(IntegerAttr::get(ui32Type, readLatency));
1211 properties.setWriteLatency(IntegerAttr::get(ui32Type, writeLatency));
1212 properties.setDepth(IntegerAttr::get(ui64Type, depth));
1213 properties.setExtraPorts(ArrayAttr::get(
context, {}));
1214 properties.setRuw(RUWBehaviorAttr::get(
context, ruw));
1231 ArrayRef<Attribute> portNames, ArrayRef<Attribute> portTypes,
1232 ArrayRef<Attribute> portAnnotations,
1233 ArrayRef<Attribute> portSyms, ArrayRef<Attribute> portLocs,
1234 ArrayRef<Attribute> domainInfo) {
1237 bool printedNamesDontMatch =
false;
1239 mlir::OpPrintingFlags flags;
1242 DenseMap<unsigned, std::string> ssaNames;
1243 auto getSsaName = [&](
unsigned idx) -> StringRef {
1245 auto itr = ssaNames.find(idx);
1246 if (itr != ssaNames.end())
1247 return itr->getSecond();
1251 SmallString<32> resultNameStr;
1253 llvm::raw_svector_ostream tmpStream(resultNameStr);
1254 p.printOperand(block->getArgument(idx), tmpStream);
1257 auto portName = cast<StringAttr>(portNames[idx]).getValue();
1258 if (tmpStream.str().drop_front() != portName)
1259 printedNamesDontMatch =
true;
1260 return ssaNames.insert({idx, tmpStream.str().str()}).first->getSecond();
1263 auto name = cast<StringAttr>(portNames[idx]).getValue();
1264 return ssaNames.insert({idx, name.str()}).first->getSecond();
1270 for (
unsigned i = 0, e = portTypes.size(); i < e; ++i) {
1279 auto portType = cast<TypeAttr>(portTypes[i]).getValue();
1283 p.printKeywordOrString(getSsaName(i));
1288 p.printType(portType);
1291 if (!portSyms.empty()) {
1292 if (!cast<hw::InnerSymAttr>(portSyms[i]).
empty()) {
1294 cast<hw::InnerSymAttr>(portSyms[i]).print(p);
1299 if (!domainInfo.empty()) {
1300 if (
auto domainKind = dyn_cast<FlatSymbolRefAttr>(domainInfo[i])) {
1303 auto domains = cast<ArrayAttr>(domainInfo[i]);
1304 if (!domains.empty()) {
1306 llvm::interleaveComma(domains, p, [&](Attribute attr) {
1307 p << getSsaName(cast<IntegerAttr>(attr).getUInt());
1316 if (!portAnnotations.empty() &&
1317 !cast<ArrayAttr>(portAnnotations[i]).empty()) {
1319 p.printAttribute(portAnnotations[i]);
1326 if (flags.shouldPrintDebugInfo() && !portLocs.empty())
1327 p.printOptionalLocationSpecifier(cast<LocationAttr>(portLocs[i]));
1331 return printedNamesDontMatch;
1337 OpAsmParser &parser,
bool hasSSAIdentifiers,
bool supportsSymbols,
1338 bool supportsDomains, SmallVectorImpl<OpAsmParser::Argument> &entryArgs,
1339 SmallVectorImpl<Direction> &portDirections,
1340 SmallVectorImpl<Attribute> &portNames,
1341 SmallVectorImpl<Attribute> &portTypes,
1342 SmallVectorImpl<Attribute> &portAnnotations,
1343 SmallVectorImpl<Attribute> &portSyms, SmallVectorImpl<Attribute> &portLocs,
1344 SmallVectorImpl<Attribute> &domains) {
1345 auto *
context = parser.getContext();
1348 DenseMap<Attribute, size_t> domainIndex;
1351 using DomainAndLoc = std::pair<Attribute, llvm::SMLoc>;
1352 DenseMap<size_t, SmallVector<DomainAndLoc>> domainStrings;
1354 auto parseArgument = [&]() -> ParseResult {
1356 if (succeeded(parser.parseOptionalKeyword(
"out")))
1357 portDirections.push_back(Direction::Out);
1358 else if (succeeded(parser.parseKeyword(
"in",
" or 'out'")))
1359 portDirections.push_back(Direction::In);
1366 auto portIdx = portNames.size();
1368 if (hasSSAIdentifiers) {
1369 OpAsmParser::Argument arg;
1370 if (parser.parseArgument(arg))
1372 entryArgs.push_back(arg);
1376 assert(arg.ssaName.name.size() > 1 && arg.ssaName.name[0] ==
'%' &&
1377 "Unknown MLIR name");
1378 if (
isdigit(arg.ssaName.name[1]))
1379 portNames.push_back(StringAttr::get(
context,
""));
1381 portNames.push_back(
1382 StringAttr::get(
context, arg.ssaName.name.drop_front()));
1385 irLoc = arg.ssaName.location;
1389 irLoc = parser.getCurrentLocation();
1390 std::string portName;
1391 if (parser.parseKeywordOrString(&portName))
1393 portNames.push_back(StringAttr::get(
context, portName));
1398 if (parser.parseColonType(portType))
1400 portTypes.push_back(TypeAttr::get(portType));
1401 if (isa<DomainType>(portType))
1402 domainIndex[portNames.back()] = portIdx;
1404 if (hasSSAIdentifiers)
1405 entryArgs.back().type = portType;
1408 if (supportsSymbols) {
1409 hw::InnerSymAttr innerSymAttr;
1410 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
1411 NamedAttrList dummyAttrs;
1412 if (parser.parseCustomAttributeWithFallback(
1413 innerSymAttr, ::mlir::Type{},
1415 return ::mlir::failure();
1418 portSyms.push_back(innerSymAttr);
1426 Attribute domainInfo;
1427 if (supportsDomains) {
1428 if (isa<DomainType>(portType)) {
1429 FlatSymbolRefAttr domainKind;
1432 domainInfo = domainKind;
1433 }
else if (succeeded(parser.parseOptionalKeyword(
"domains"))) {
1434 auto result = parser.parseCommaSeparatedList(
1435 OpAsmParser::Delimiter::Square, [&]() -> ParseResult {
1437 if (hasSSAIdentifiers) {
1438 OpAsmParser::Argument arg;
1439 if (parser.parseArgument(arg))
1442 StringAttr::get(
context, arg.ssaName.name.drop_front());
1444 std::string portName;
1445 if (parser.parseKeywordOrString(&portName))
1447 argName = StringAttr::get(
context, portName);
1449 domainStrings[portIdx].push_back({argName, irLoc});
1456 domains.push_back(domainInfo);
1460 auto parseResult = parser.parseOptionalAttribute(annos);
1461 if (!parseResult.has_value())
1462 annos = parser.getBuilder().getArrayAttr({});
1463 else if (failed(*parseResult))
1465 portAnnotations.push_back(annos);
1468 std::optional<Location> maybeLoc;
1469 if (failed(parser.parseOptionalLocationSpecifier(maybeLoc)))
1471 Location loc = maybeLoc ? *maybeLoc : parser.getEncodedSourceLoc(irLoc);
1472 portLocs.push_back(loc);
1473 if (hasSSAIdentifiers)
1474 entryArgs.back().sourceLoc = loc;
1483 if (failed(parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
1489 for (
auto [portIdx, domainInfo] : llvm::enumerate(domains)) {
1494 SmallVector<Attribute> portDomains;
1495 for (
auto [domainName, loc] : domainStrings[portIdx]) {
1496 auto index = domainIndex.find(domainName);
1497 if (index == domainIndex.end()) {
1498 parser.emitError(loc) <<
"domain name '" << domainName <<
"' not found";
1501 portDomains.push_back(IntegerAttr::get(
1502 IntegerType::get(
context, 32, IntegerType::Unsigned), index->second));
1504 domains[portIdx] = parser.getBuilder().getArrayAttr(portDomains);
1512 ArrayAttr parameters) {
1513 if (!parameters || parameters.empty())
1517 llvm::interleaveComma(parameters, p, [&](Attribute param) {
1518 auto paramAttr = cast<ParamDeclAttr>(param);
1519 p << paramAttr.getName().getValue() <<
": " << paramAttr.getType();
1520 if (
auto value = paramAttr.getValue()) {
1522 p.printAttributeWithoutType(value);
1532 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
1533 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
1534 p << visibility.getValue() <<
' ';
1537 p.printSymbolName(op.getModuleName());
1544 Block *body =
nullptr;
1545 if (!op->getRegion(0).empty())
1546 body = &op->getRegion(0).front();
1549 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
1550 op.getPortAnnotations(), op.getPortSymbols(), op.getPortLocations(),
1551 op.getDomainInfo());
1553 SmallVector<StringRef, 13> omittedAttrs = {
1554 "sym_name",
"portDirections",
"portTypes",
1555 "portAnnotations",
"portSymbols",
"portLocations",
1556 "parameters", visibilityAttrName,
"domainInfo"};
1558 if (op.getConvention() == Convention::Internal)
1559 omittedAttrs.push_back(
"convention");
1563 if (!needPortNamesAttr)
1564 omittedAttrs.push_back(
"portNames");
1567 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
1568 omittedAttrs.push_back(
"annotations");
1571 if (
auto knownLayers = op->getAttrOfType<ArrayAttr>(
"knownLayers"))
1572 if (knownLayers.empty())
1573 omittedAttrs.push_back(
"knownLayers");
1576 if (
auto layers = op->getAttrOfType<ArrayAttr>(
"layers"))
1578 omittedAttrs.push_back(
"layers");
1580 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
1589void FModuleOp::print(OpAsmPrinter &p) {
1595 Region &fbody = getBody();
1596 if (!fbody.empty()) {
1598 p.printRegion(fbody,
false,
1610 SmallVectorImpl<Attribute> ¶meters) {
1612 return parser.parseCommaSeparatedList(
1613 OpAsmParser::Delimiter::OptionalLessGreater, [&]() {
1618 if (parser.parseKeywordOrString(&name) || parser.parseColonType(type))
1622 if (succeeded(parser.parseOptionalEqual())) {
1623 if (parser.parseAttribute(value, type))
1627 auto &builder = parser.getBuilder();
1628 parameters.push_back(ParamDeclAttr::get(
1629 builder.getContext(), builder.getStringAttr(name), type, value));
1636 ArrayAttr ¶meters) {
1637 SmallVector<Attribute> parseParameters;
1641 parameters = ArrayAttr::get(parser.getContext(), parseParameters);
1646template <
typename Properties,
typename =
void>
1649template <
typename Properties>
1651 Properties, std::void_t<decltype(std::declval<Properties>().parameters)>>
1652 : std::true_type {};
1654template <
typename OpTy>
1656 OperationState &result,
1657 bool hasSSAIdentifiers) {
1658 auto *
context = result.getContext();
1659 auto &builder = parser.getBuilder();
1660 using Properties =
typename OpTy::Properties;
1661 auto &properties = result.getOrAddProperties<Properties>();
1665 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
1668 StringAttr nameAttr;
1669 if (parser.parseSymbolName(nameAttr))
1671 properties.setSymName(nameAttr);
1675 SmallVector<Attribute, 4> parameters;
1678 properties.setParameters(builder.getArrayAttr(parameters));
1682 SmallVector<OpAsmParser::Argument> entryArgs;
1683 SmallVector<Direction, 4> portDirections;
1684 SmallVector<Attribute, 4> portNames;
1685 SmallVector<Attribute, 4> portTypes;
1686 SmallVector<Attribute, 4> portAnnotations;
1687 SmallVector<Attribute, 4> portSyms;
1688 SmallVector<Attribute, 4> portLocs;
1689 SmallVector<Attribute, 4> domains;
1691 true, entryArgs, portDirections,
1692 portNames, portTypes, portAnnotations, portSyms,
1697 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
1700 assert(portNames.size() == portTypes.size());
1706 properties.setPortDirections(
1710 properties.setPortNames(builder.getArrayAttr(portNames));
1713 properties.setPortTypes(ArrayAttr::get(
context, portTypes));
1717 if (llvm::any_of(portAnnotations, [&](Attribute anno) {
1718 return !cast<ArrayAttr>(anno).empty();
1720 properties.setPortAnnotations(ArrayAttr::get(
context, portAnnotations));
1722 properties.setPortAnnotations(builder.getArrayAttr({}));
1725 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1726 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1729 properties.setPortLocations(ArrayAttr::get(
context, portLocs));
1732 properties.setAnnotations(builder.getArrayAttr({}));
1735 if (llvm::all_of(domains, [&](Attribute attr) {
1736 auto arrayAttr = dyn_cast<ArrayAttr>(attr);
1737 return arrayAttr && arrayAttr.empty();
1739 properties.setDomainInfo(ArrayAttr::get(
context, {}));
1741 properties.setDomainInfo(ArrayAttr::get(
context, domains));
1744 auto *body = result.addRegion();
1746 if (hasSSAIdentifiers) {
1747 if (parser.parseRegion(*body, entryArgs))
1750 body->push_back(
new Block());
1755ParseResult FModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1756 if (parseFModuleLikeOp<FModuleOp>(parser, result,
1759 auto &properties = result.getOrAddProperties<Properties>();
1760 properties.setConvention(
1761 ConventionAttr::get(result.getContext(), Convention::Internal));
1762 properties.setLayers(ArrayAttr::get(parser.getContext(), {}));
1766ParseResult FExtModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1767 if (parseFModuleLikeOp<FExtModuleOp>(parser, result,
1770 auto &properties = result.getOrAddProperties<Properties>();
1771 properties.setConvention(
1772 ConventionAttr::get(result.getContext(), Convention::Internal));
1773 properties.setKnownLayers(ArrayAttr::get(result.getContext(), {}));
1777ParseResult FIntModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1778 return parseFModuleLikeOp<FIntModuleOp>(parser, result,
1782ParseResult FMemModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1783 return parseFModuleLikeOp<FMemModuleOp>(parser, result,
1787LogicalResult FModuleOp::verify() {
1790 auto portTypes = getPortTypes();
1791 auto portLocs = getPortLocations();
1792 auto numPorts = portTypes.size();
1795 if (body->getNumArguments() != numPorts)
1796 return emitOpError(
"entry block must have ")
1797 << numPorts <<
" arguments to match module signature";
1800 for (
auto [arg, type, loc] : zip(body->getArguments(), portTypes, portLocs)) {
1801 if (arg.getType() != cast<TypeAttr>(type).getValue())
1802 return emitOpError(
"block argument types should match signature types");
1803 if (arg.getLoc() != cast<LocationAttr>(loc))
1805 "block argument locations should match signature locations");
1811LogicalResult FExtModuleOp::verify() {
1812 auto params = getParameters();
1814 auto checkParmValue = [&](Attribute elt) ->
bool {
1815 auto param = cast<ParamDeclAttr>(elt);
1816 auto value = param.getValue();
1817 if (isa<IntegerAttr, StringAttr, FloatAttr, hw::ParamVerbatimAttr>(value))
1819 emitError() <<
"has unknown extmodule parameter value '"
1820 << param.getName().getValue() <<
"' = " << value;
1824 if (!llvm::all_of(params, checkParmValue))
1829 known.insert_range(getKnownLayersAttr().getAsRange<SymbolRefAttr>());
1832 referenced.insert_range(getLayersAttr().getAsRange<SymbolRefAttr>());
1833 for (
auto attr : getPortTypes()) {
1834 auto type = cast<TypeAttr>(attr).getValue();
1835 if (
auto refType = type_dyn_cast<RefType>(type))
1836 if (
auto layer = refType.getLayer())
1837 referenced.insert(layer);
1841 "references unknown layers",
"unknown layers");
1844LogicalResult FIntModuleOp::verify() {
1845 auto params = getParameters();
1849 auto checkParmValue = [&](Attribute elt) ->
bool {
1850 auto param = cast<ParamDeclAttr>(elt);
1851 auto value = param.getValue();
1852 if (isa<IntegerAttr, StringAttr, FloatAttr>(value))
1854 emitError() <<
"has unknown intmodule parameter value '"
1855 << param.getName().getValue() <<
"' = " << value;
1859 if (!llvm::all_of(params, checkParmValue))
1866 CircuitOp circuitOp,
1867 SymbolTableCollection &symbolTable,
1869 auto layer = refType.getLayer();
1872 auto *layerOp = symbolTable.lookupSymbolIn(circuitOp, layer);
1874 return emitError(loc) << start <<
" associated with layer '" << layer
1875 <<
"', but this layer was not defined";
1876 if (!isa<LayerOp>(layerOp)) {
1877 auto diag = emitError(loc)
1878 << start <<
" associated with layer '" << layer
1879 <<
"', but symbol '" << layer <<
"' does not refer to a '"
1880 << LayerOp::getOperationName() <<
"' op";
1881 return diag.attachNote(layerOp->getLoc()) <<
"symbol refers to this op";
1887 SymbolTableCollection &symbolTable) {
1889 auto circuitOp =
module->getParentOfType<CircuitOp>();
1890 for (
size_t i = 0, e = module.getNumPorts(); i < e; ++i) {
1891 auto type =
module.getPortType(i);
1893 if (
auto refType = type_dyn_cast<RefType>(type)) {
1895 refType, module.getPortLocation(i), circuitOp, symbolTable,
1896 Twine(
"probe port '") + module.getPortName(i) +
"' is")))
1901 if (
auto classType = dyn_cast<ClassType>(type)) {
1902 auto className = classType.getNameAttr();
1903 auto classOp = dyn_cast_or_null<ClassLike>(
1904 symbolTable.lookupSymbolIn(circuitOp, className));
1906 return module.emitOpError() << "references unknown class " << className;
1909 if (failed(classOp.verifyType(classType,
1910 [&]() { return module.emitOpError(); })))
1915 if (isa<DomainType>(type)) {
1916 auto domainInfo =
module.getDomainInfoAttrForPort(i);
1917 if (
auto kind = dyn_cast<FlatSymbolRefAttr>(domainInfo))
1918 if (!dyn_cast_or_null<DomainOp>(
1919 symbolTable.lookupSymbolIn(circuitOp, kind)))
1920 return mlir::emitError(module.getPortLocation(i))
1921 <<
"domain port '" <<
module.getPortName(i)
1922 << "' has undefined domain kind '" << kind.getValue() << "'";
1929LogicalResult FModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1933 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
1934 for (
auto layer : getLayers()) {
1935 if (!symbolTable.lookupSymbolIn(circuitOp, cast<SymbolRefAttr>(layer)))
1936 return emitOpError() <<
"enables undefined layer '" << layer <<
"'";
1943FExtModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1947 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
1948 for (
auto layer : getKnownLayersAttr().getAsRange<SymbolRefAttr>()) {
1949 if (!symbolTable.lookupSymbolIn(circuitOp, layer))
1950 return emitOpError() <<
"knows undefined layer '" << layer <<
"'";
1952 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>()) {
1953 if (!symbolTable.lookupSymbolIn(circuitOp, layer))
1954 return emitOpError() <<
"enables undefined layer '" << layer <<
"'";
1961FIntModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1966FMemModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1970void FModuleOp::getAsmBlockArgumentNames(mlir::Region ®ion,
1975void FExtModuleOp::getAsmBlockArgumentNames(
1980StringRef FExtModuleOp::getExtModuleName() {
1981 if (
auto defname = getDefname(); defname && !defname->empty())
1986void FIntModuleOp::getAsmBlockArgumentNames(
1991void FMemModuleOp::getAsmBlockArgumentNames(
1996ArrayAttr FMemModuleOp::getParameters() {
return {}; }
1998ArrayAttr FModuleOp::getParameters() {
return {}; }
2000Convention FIntModuleOp::getConvention() {
return Convention::Internal; }
2002ConventionAttr FIntModuleOp::getConventionAttr() {
2003 return ConventionAttr::get(getContext(), getConvention());
2006Convention FMemModuleOp::getConvention() {
return Convention::Internal; }
2008ConventionAttr FMemModuleOp::getConventionAttr() {
2009 return ConventionAttr::get(getContext(), getConvention());
2017 ClassLike classOp, ClassType type,
2018 function_ref<InFlightDiagnostic()> emitError) {
2020 auto name = type.getNameAttr().getAttr();
2021 auto expectedName = classOp.getModuleNameAttr();
2022 if (name != expectedName)
2023 return emitError() <<
"type has wrong name, got " << name <<
", expected "
2026 auto elements = type.getElements();
2028 auto expectedNumElements = classOp.getNumPorts();
2030 return emitError() <<
"has wrong number of ports, got " <<
numElements
2031 <<
", expected " << expectedNumElements;
2033 auto portNames = classOp.getPortNames();
2034 auto portDirections = classOp.getPortDirections();
2035 auto portTypes = classOp.getPortTypes();
2038 auto element = elements[i];
2040 auto name = element.name;
2041 auto expectedName = portNames[i];
2042 if (name != expectedName)
2043 return emitError() <<
"port #" << i <<
" has wrong name, got " << name
2044 <<
", expected " << expectedName;
2046 auto direction = element.direction;
2047 auto expectedDirection =
Direction(portDirections[i]);
2048 if (direction != expectedDirection)
2049 return emitError() <<
"port " << name <<
" has wrong direction, got "
2053 auto type = element.type;
2054 auto expectedType = cast<TypeAttr>(portTypes[i]).getValue();
2055 if (type != expectedType)
2056 return emitError() <<
"port " << name <<
" has wrong type, got " << type
2057 <<
", expected " << expectedType;
2064 auto n = classOp.getNumPorts();
2065 SmallVector<ClassElement> elements;
2066 elements.reserve(n);
2067 for (
size_t i = 0; i < n; ++i)
2068 elements.push_back({classOp.getPortNameAttr(i), classOp.getPortType(i),
2069 classOp.getPortDirection(i)});
2070 auto name = FlatSymbolRefAttr::get(classOp.getNameAttr());
2071 return ClassType::get(name, elements);
2074template <
typename OpTy>
2076 bool hasSSAIdentifiers) {
2077 auto *
context = result.getContext();
2078 auto &builder = parser.getBuilder();
2079 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
2083 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
2086 StringAttr nameAttr;
2087 if (parser.parseSymbolName(nameAttr))
2089 properties.setSymName(nameAttr);
2092 SmallVector<OpAsmParser::Argument> entryArgs;
2093 SmallVector<Direction, 4> portDirections;
2094 SmallVector<Attribute, 4> portNames;
2095 SmallVector<Attribute, 4> portTypes;
2096 SmallVector<Attribute, 4> portAnnotations;
2097 SmallVector<Attribute, 4> portSyms;
2098 SmallVector<Attribute, 4> portLocs;
2099 SmallVector<Attribute, 4> domains;
2102 entryArgs, portDirections, portNames, portTypes,
2103 portAnnotations, portSyms, portLocs, domains))
2107 for (
auto annos : portAnnotations)
2108 if (!cast<ArrayAttr>(annos).empty())
2112 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
2115 assert(portNames.size() == portTypes.size());
2121 properties.setPortDirections(
2125 properties.setPortNames(builder.getArrayAttr(portNames));
2128 properties.setPortTypes(builder.getArrayAttr(portTypes));
2131 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
2132 properties.setPortSymbols(builder.getArrayAttr(portSyms));
2135 properties.setPortLocations(ArrayAttr::get(
context, portLocs));
2141 auto *bodyRegion = result.addRegion();
2143 if (hasSSAIdentifiers) {
2144 if (parser.parseRegion(*bodyRegion, entryArgs))
2146 if (bodyRegion->empty())
2147 bodyRegion->push_back(
new Block());
2157 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
2158 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
2159 p << visibility.getValue() <<
' ';
2162 p.printSymbolName(op.getName());
2166 Region ®ion = op->getRegion(0);
2167 Block *body =
nullptr;
2168 if (!region.empty())
2169 body = ®ion.front();
2172 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
2173 {}, op.getPortSymbols(), op.getPortLocations(), {});
2176 SmallVector<StringRef, 8> omittedAttrs = {
2177 "sym_name",
"portNames",
"portTypes",
"portDirections",
2178 "portSymbols",
"portLocations", visibilityAttrName,
"domainInfo"};
2182 if (!needPortNamesAttr)
2183 omittedAttrs.push_back(
"portNames");
2185 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
2188 if (!region.empty()) {
2190 auto printEntryBlockArgs =
false;
2191 auto printBlockTerminators =
false;
2192 p.printRegion(region, printEntryBlockArgs, printBlockTerminators);
2200void ClassOp::build(OpBuilder &builder, OperationState &result, StringAttr name,
2201 ArrayRef<PortInfo> ports) {
2204 [](
const auto &port) {
return port.annotations.empty(); }) &&
2205 "class ports may not have annotations");
2207 buildClass<ClassOp>(builder, result, name, ports);
2210 auto *bodyRegion = result.regions[0].get();
2212 bodyRegion->push_back(body);
2215 for (
auto &elt : ports)
2216 body->addArgument(elt.type, elt.loc);
2219void ClassOp::build(::mlir::OpBuilder &odsBuilder,
2220 ::mlir::OperationState &odsState, Twine name,
2221 mlir::ArrayRef<mlir::StringRef> fieldNames,
2222 mlir::ArrayRef<mlir::Type> fieldTypes) {
2224 SmallVector<PortInfo, 10> ports;
2225 for (
auto [fieldName, fieldType] :
llvm::zip(fieldNames, fieldTypes)) {
2226 ports.emplace_back(odsBuilder.getStringAttr(fieldName +
"_in"), fieldType,
2228 ports.emplace_back(odsBuilder.getStringAttr(fieldName), fieldType,
2231 build(odsBuilder, odsState, odsBuilder.getStringAttr(name), ports);
2233 auto &body = odsState.regions[0]->getBlocks().front();
2234 auto prevLoc = odsBuilder.saveInsertionPoint();
2235 odsBuilder.setInsertionPointToEnd(&body);
2236 auto args = body.getArguments();
2237 auto loc = odsState.location;
2238 for (
unsigned i = 0, e = ports.size(); i != e; i += 2)
2239 PropAssignOp::create(odsBuilder, loc, args[i + 1], args[i]);
2241 odsBuilder.restoreInsertionPoint(prevLoc);
2243void ClassOp::print(OpAsmPrinter &p) {
2247ParseResult ClassOp::parse(OpAsmParser &parser, OperationState &result) {
2248 auto hasSSAIdentifiers =
true;
2249 return parseClassLike<ClassOp>(parser, result, hasSSAIdentifiers);
2252LogicalResult ClassOp::verify() {
2254 auto type = operand.getType();
2255 if (!isa<PropertyType>(type)) {
2256 emitOpError(
"ports on a class must be properties");
2265ClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2269void ClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2274SmallVector<PortInfo> ClassOp::getPorts() {
2275 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2278void ClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2279 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2283void ClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2284 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2287Convention ClassOp::getConvention() {
return Convention::Internal; }
2289ConventionAttr ClassOp::getConventionAttr() {
2290 return ConventionAttr::get(getContext(), getConvention());
2293ArrayAttr ClassOp::getParameters() {
return {}; }
2295ArrayAttr ClassOp::getPortAnnotationsAttr() {
2296 return ArrayAttr::get(getContext(), {});
2299ArrayRef<Attribute> ClassOp::getPortAnnotations() {
return {}; }
2301void ClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2302 llvm_unreachable(
"classes do not support annotations");
2305ArrayAttr ClassOp::getLayersAttr() {
return ArrayAttr::get(getContext(), {}); }
2307ArrayRef<Attribute> ClassOp::getLayers() {
return {}; }
2309SmallVector<::circt::hw::PortInfo> ClassOp::getPortList() {
2310 return ::getPortListImpl(*
this);
2314 return ::getPortImpl(*
this, idx);
2317BlockArgument ClassOp::getArgument(
size_t portNumber) {
2321bool ClassOp::canDiscardOnUseEmpty() {
2332void ExtClassOp::build(OpBuilder &builder, OperationState &result,
2333 StringAttr name, ArrayRef<PortInfo> ports) {
2336 [](
const auto &port) {
return port.annotations.empty(); }) &&
2337 "class ports may not have annotations");
2338 buildClass<ClassOp>(builder, result, name, ports);
2341void ExtClassOp::print(OpAsmPrinter &p) {
2345ParseResult ExtClassOp::parse(OpAsmParser &parser, OperationState &result) {
2346 auto hasSSAIdentifiers =
false;
2347 return parseClassLike<ExtClassOp>(parser, result, hasSSAIdentifiers);
2351ExtClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2355void ExtClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2360SmallVector<PortInfo> ExtClassOp::getPorts() {
2361 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2364void ExtClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2365 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2368void ExtClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2369 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2372Convention ExtClassOp::getConvention() {
return Convention::Internal; }
2374ConventionAttr ExtClassOp::getConventionAttr() {
2375 return ConventionAttr::get(getContext(), getConvention());
2378ArrayAttr ExtClassOp::getLayersAttr() {
2379 return ArrayAttr::get(getContext(), {});
2382ArrayRef<Attribute> ExtClassOp::getLayers() {
return {}; }
2384ArrayAttr ExtClassOp::getParameters() {
return {}; }
2386ArrayAttr ExtClassOp::getPortAnnotationsAttr() {
2387 return ArrayAttr::get(getContext(), {});
2390ArrayRef<Attribute> ExtClassOp::getPortAnnotations() {
return {}; }
2392void ExtClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2393 llvm_unreachable(
"classes do not support annotations");
2396SmallVector<::circt::hw::PortInfo> ExtClassOp::getPortList() {
2397 return ::getPortListImpl(*
this);
2401 return ::getPortImpl(*
this, idx);
2404bool ExtClassOp::canDiscardOnUseEmpty() {
2415void InstanceOp::build(
2416 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2417 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2418 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2419 ArrayRef<Attribute> domainInfo, ArrayRef<Attribute> annotations,
2420 ArrayRef<Attribute> portAnnotations, ArrayRef<Attribute> layers,
2421 bool lowerToBind,
bool doNotPrint, StringAttr innerSym) {
2422 build(builder, result, resultTypes, moduleName, name, nameKind,
2423 portDirections, portNames, domainInfo, annotations, portAnnotations,
2424 layers, lowerToBind, doNotPrint,
2425 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr());
2428void InstanceOp::build(
2429 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2430 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2431 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2432 ArrayRef<Attribute> domainInfo, ArrayRef<Attribute> annotations,
2433 ArrayRef<Attribute> portAnnotations, ArrayRef<Attribute> layers,
2434 bool lowerToBind,
bool doNotPrint, hw::InnerSymAttr innerSym) {
2435 result.addTypes(resultTypes);
2436 result.getOrAddProperties<Properties>().setModuleName(
2437 SymbolRefAttr::get(builder.getContext(), moduleName));
2438 result.getOrAddProperties<Properties>().setName(builder.getStringAttr(name));
2439 result.getOrAddProperties<Properties>().setPortDirections(
2441 result.getOrAddProperties<Properties>().setPortNames(
2442 builder.getArrayAttr(portNames));
2444 if (domainInfo.empty()) {
2445 SmallVector<Attribute, 16> domainInfoVec(resultTypes.size(),
2446 builder.getArrayAttr({}));
2447 result.getOrAddProperties<Properties>().setDomainInfo(
2448 builder.getArrayAttr(domainInfoVec));
2450 assert(domainInfo.size() == resultTypes.size());
2451 result.getOrAddProperties<Properties>().setDomainInfo(
2452 builder.getArrayAttr(domainInfo));
2455 result.getOrAddProperties<Properties>().setAnnotations(
2456 builder.getArrayAttr(annotations));
2457 result.getOrAddProperties<Properties>().setLayers(
2458 builder.getArrayAttr(layers));
2460 result.getOrAddProperties<Properties>().setLowerToBind(
2461 builder.getUnitAttr());
2463 result.getOrAddProperties<Properties>().setDoNotPrint(
2464 builder.getUnitAttr());
2466 result.getOrAddProperties<Properties>().setInnerSym(innerSym);
2468 result.getOrAddProperties<Properties>().setNameKind(
2469 NameKindEnumAttr::get(builder.getContext(), nameKind));
2471 if (portAnnotations.empty()) {
2472 SmallVector<Attribute, 16> portAnnotationsVec(resultTypes.size(),
2473 builder.getArrayAttr({}));
2474 result.getOrAddProperties<Properties>().setPortAnnotations(
2475 builder.getArrayAttr(portAnnotationsVec));
2477 assert(portAnnotations.size() == resultTypes.size());
2478 result.getOrAddProperties<Properties>().setPortAnnotations(
2479 builder.getArrayAttr(portAnnotations));
2483void InstanceOp::build(OpBuilder &builder, OperationState &result,
2484 FModuleLike module, StringRef name,
2485 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2486 ArrayRef<Attribute> portAnnotations,
bool lowerToBind,
2487 bool doNotPrint, hw::InnerSymAttr innerSym) {
2490 SmallVector<Type> resultTypes;
2491 resultTypes.reserve(module.getNumPorts());
2493 module.getPortTypes(), std::back_inserter(resultTypes),
2494 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2499 ArrayAttr portAnnotationsAttr;
2500 if (portAnnotations.empty()) {
2501 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2502 resultTypes.size(), builder.getArrayAttr({})));
2504 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2506 ArrayAttr domainInfoAttr =
module.getDomainInfoAttr();
2507 if (domainInfoAttr.empty()) {
2508 domainInfoAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2509 resultTypes.size(), builder.getArrayAttr({})));
2513 builder, result, resultTypes,
2514 SymbolRefAttr::get(builder.getContext(), module.getModuleNameAttr()),
2515 builder.getStringAttr(name),
2516 NameKindEnumAttr::get(builder.getContext(), nameKind),
2517 module.getPortDirectionsAttr(), module.getPortNamesAttr(), domainInfoAttr,
2518 builder.getArrayAttr(annotations), portAnnotationsAttr,
2519 module.getLayersAttr(), lowerToBind ? builder.getUnitAttr() : UnitAttr(),
2520 doNotPrint ? builder.getUnitAttr() : UnitAttr(), innerSym);
2523void InstanceOp::build(OpBuilder &builder, OperationState &odsState,
2524 ArrayRef<PortInfo> ports, StringRef moduleName,
2525 StringRef name, NameKindEnum nameKind,
2526 ArrayRef<Attribute> annotations,
2527 ArrayRef<Attribute> layers,
bool lowerToBind,
2528 bool doNotPrint, hw::InnerSymAttr innerSym) {
2530 SmallVector<Type> newResultTypes;
2531 SmallVector<Direction> newPortDirections;
2532 SmallVector<Attribute> newPortNames;
2533 SmallVector<Attribute> newPortAnnotations;
2534 SmallVector<Attribute> newDomainInfo;
2535 for (
auto &p : ports) {
2536 newResultTypes.push_back(p.type);
2537 newPortDirections.push_back(p.direction);
2538 newPortNames.push_back(p.name);
2539 newPortAnnotations.push_back(p.annotations.getArrayAttr());
2541 newDomainInfo.push_back(p.domains);
2543 newDomainInfo.push_back(builder.getArrayAttr({}));
2546 return build(builder, odsState, newResultTypes, moduleName, name, nameKind,
2547 newPortDirections, newPortNames, newDomainInfo, annotations,
2548 newPortAnnotations, layers, lowerToBind, doNotPrint, innerSym);
2551LogicalResult InstanceOp::verify() {
2554 SmallVector<SymbolRefAttr> missingLayers;
2555 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
2557 missingLayers.push_back(layer);
2559 if (missingLayers.empty())
2563 emitOpError(
"ambient layers are insufficient to instantiate module");
2564 auto ¬e = diag.attachNote();
2565 note <<
"missing layer requirements: ";
2566 interleaveComma(missingLayers, note);
2571 Operation *op1, Operation *op2,
2572 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2574 size_t n = insertions.size();
2575 size_t inserted = 0;
2576 for (
size_t i = 0, e = op1->getNumResults(); i < e; ++i) {
2577 while (inserted < n) {
2578 auto &[index, portInfo] = insertions[inserted];
2583 auto r1 = op1->getResult(i);
2584 auto r2 = op2->getResult(i + inserted);
2585 r1.replaceAllUsesWith(r2);
2590 const llvm::BitVector &erasures) {
2593 for (
size_t i = 0, e = op1->getNumResults(); i < e; ++i) {
2594 auto r1 = op1->getResult(i);
2596 assert(r1.use_empty() &&
"removed instance port has uses");
2600 auto r2 = op2->getResult(i - erased);
2601 r1.replaceAllUsesWith(r2);
2605InstanceOp InstanceOp::cloneWithErasedPorts(
const llvm::BitVector &erasures) {
2606 assert(erasures.size() >= getNumResults() &&
2607 "erasures is not at least as large as getNumResults()");
2609 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
2610 SmallVector<Type>(result_type_begin(), result_type_end()), erasures);
2611 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
2613 SmallVector<Attribute> newPortNames =
2615 SmallVector<Attribute> newPortAnnotations =
2617 ArrayAttr newDomainInfo =
2621 OpBuilder builder(*
this);
2622 auto clone = InstanceOp::create(
2623 builder,
getLoc(), newResultTypes, getModuleName(),
getName(),
2624 getNameKind(), newPortDirections, newPortNames, newDomainInfo.getValue(),
2625 getAnnotations().getValue(), newPortAnnotations, getLayers(),
2626 getLowerToBind(), getDoNotPrint(), getInnerSymAttr());
2628 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2629 clone->setAttr(
"output_file", outputFile);
2634InstanceOp InstanceOp::cloneWithErasedPortsAndReplaceUses(
2635 const llvm::BitVector &erasures) {
2636 auto clone = cloneWithErasedPorts(erasures);
2641ArrayAttr InstanceOp::getPortAnnotation(
unsigned portIdx) {
2642 assert(portIdx < getNumResults() &&
2643 "index should be smaller than result number");
2644 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
2647void InstanceOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
2648 assert(annotations.size() == getNumResults() &&
2649 "number of annotations is not equal to result number");
2650 (*this)->setAttr(
"portAnnotations",
2651 ArrayAttr::get(getContext(), annotations));
2654Attribute InstanceOp::getPortDomain(
unsigned portIdx) {
2655 assert(portIdx < getNumResults() &&
2656 "index should be smaller than result number");
2657 return getDomainInfo()[portIdx];
2660InstanceOp InstanceOp::cloneWithInsertedPorts(
2661 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2665 auto oldPortCount = getNumResults();
2666 auto numInsertions = insertions.size();
2667 auto newPortCount = oldPortCount + numInsertions;
2669 SmallVector<Direction> newPortDirections;
2670 SmallVector<Attribute> newPortNames;
2671 SmallVector<Type> newPortTypes;
2672 SmallVector<Attribute> newPortAnnos;
2673 SmallVector<Attribute> newDomainInfo;
2675 newPortDirections.reserve(newPortCount);
2676 newPortNames.reserve(newPortCount);
2677 newPortTypes.reserve(newPortCount);
2678 newPortAnnos.reserve(newPortCount);
2679 newDomainInfo.reserve(newPortCount);
2681 SmallVector<unsigned> indexMap(oldPortCount);
2683 size_t inserted = 0;
2684 for (
size_t i = 0; i < oldPortCount; ++i) {
2685 while (inserted < numInsertions) {
2686 auto &[index,
info] = insertions[inserted];
2692 newPortDirections.push_back(
info.direction);
2693 newPortNames.push_back(
info.name);
2694 newPortTypes.push_back(
info.type);
2695 newPortAnnos.push_back(
info.annotations.getArrayAttr());
2696 newDomainInfo.push_back(domains);
2700 newPortDirections.push_back(getPortDirection(i));
2701 newPortNames.push_back(getPortNameAttr(i));
2702 newPortTypes.push_back(getType(i));
2703 newPortAnnos.push_back(getPortAnnotation(i));
2704 newDomainInfo.push_back(getDomainInfo()[i]);
2705 indexMap[i] = i + inserted;
2708 while (inserted < numInsertions) {
2709 auto &[index,
info] = insertions[inserted];
2712 newPortDirections.push_back(
info.direction);
2713 newPortNames.push_back(
info.name);
2714 newPortTypes.push_back(
info.type);
2715 newPortAnnos.push_back(
info.annotations.getArrayAttr());
2716 newDomainInfo.push_back(domains);
2720 OpBuilder builder(*
this);
2721 auto clone = InstanceOp::create(
2722 builder,
getLoc(), newPortTypes, getModuleName(),
getName(),
2723 getNameKind(), newPortDirections, newPortNames, newDomainInfo,
2724 getAnnotations().getValue(), newPortAnnos, getLayers(), getLowerToBind(),
2725 getDoNotPrint(), getInnerSymAttr());
2727 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2728 clone->setAttr(
"output_file", outputFile);
2733InstanceOp InstanceOp::cloneWithInsertedPortsAndReplaceUses(
2734 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2735 auto clone = cloneWithInsertedPorts(insertions);
2740LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2742 getModuleNameAttr());
2745StringRef InstanceOp::getInstanceName() {
return getName(); }
2747StringAttr InstanceOp::getInstanceNameAttr() {
return getNameAttr(); }
2749void InstanceOp::print(OpAsmPrinter &p) {
2752 p.printKeywordOrString(
getName());
2753 if (
auto attr = getInnerSymAttr()) {
2755 p.printSymbolName(attr.getSymName());
2757 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2758 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2761 SmallVector<StringRef, 10> omittedAttrs = {
2762 "moduleName",
"name",
"portDirections",
2763 "portNames",
"portTypes",
"portAnnotations",
2764 "inner_sym",
"nameKind",
"domainInfo"};
2765 if (getAnnotations().
empty())
2766 omittedAttrs.push_back(
"annotations");
2767 if (getLayers().
empty())
2768 omittedAttrs.push_back(
"layers");
2769 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2773 p.printSymbolName(getModuleName());
2776 SmallVector<Attribute> portTypes;
2777 portTypes.reserve(getNumResults());
2778 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2782 getPortNames().getValue(), portTypes,
2783 getPortAnnotations().getValue(), {}, {},
2784 getDomainInfo().getValue());
2787ParseResult InstanceOp::parse(OpAsmParser &parser, OperationState &result) {
2788 auto *
context = parser.getContext();
2789 auto &properties = result.getOrAddProperties<Properties>();
2792 hw::InnerSymAttr innerSymAttr;
2793 FlatSymbolRefAttr moduleName;
2794 SmallVector<OpAsmParser::Argument> entryArgs;
2795 SmallVector<Direction, 4> portDirections;
2796 SmallVector<Attribute, 4> portNames;
2797 SmallVector<Attribute, 4> portTypes;
2798 SmallVector<Attribute, 4> portAnnotations;
2799 SmallVector<Attribute, 4> portSyms;
2800 SmallVector<Attribute, 4> portLocs;
2801 SmallVector<Attribute, 4> domains;
2802 NameKindEnumAttr nameKind;
2804 if (parser.parseKeywordOrString(&name))
2806 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
2807 if (parser.parseCustomAttributeWithFallback(
2808 innerSymAttr, ::mlir::Type{},
2810 result.attributes)) {
2811 return ::mlir::failure();
2815 parser.parseOptionalAttrDict(result.attributes) ||
2816 parser.parseAttribute(moduleName) ||
2819 entryArgs, portDirections, portNames, portTypes,
2820 portAnnotations, portSyms, portLocs, domains))
2826 properties.setModuleName(moduleName);
2827 properties.setName(StringAttr::get(
context, name));
2828 properties.setNameKind(nameKind);
2829 properties.setPortDirections(
2831 properties.setPortNames(ArrayAttr::get(
context, portNames));
2832 properties.setPortAnnotations(ArrayAttr::get(
context, portAnnotations));
2836 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
2837 properties.setLayers(parser.getBuilder().getArrayAttr({}));
2840 properties.setDomainInfo(ArrayAttr::get(
context, domains));
2843 result.types.reserve(portTypes.size());
2845 portTypes, std::back_inserter(result.types),
2846 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2851void InstanceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
2856 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
2857 setNameFn(getResult(i), (base +
"_" + getPortName(i)).str());
2861std::optional<size_t> InstanceOp::getTargetResultIndex() {
2863 return std::nullopt;
2870void InstanceChoiceOp::build(
2871 OpBuilder &builder, OperationState &result, FModuleLike defaultModule,
2872 ArrayRef<std::pair<OptionCaseOp, FModuleLike>> cases, StringRef name,
2873 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2874 ArrayRef<Attribute> portAnnotations, StringAttr innerSym) {
2876 SmallVector<Type> resultTypes;
2877 for (Attribute portType : defaultModule.getPortTypes())
2878 resultTypes.push_back(cast<TypeAttr>(portType).getValue());
2881 ArrayAttr portAnnotationsAttr;
2882 if (portAnnotations.empty()) {
2883 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2884 resultTypes.size(), builder.getArrayAttr({})));
2886 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2890 ArrayAttr domainInfoAttr = defaultModule.getDomainInfoAttr();
2891 if (domainInfoAttr.empty()) {
2892 domainInfoAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2893 resultTypes.size(), builder.getArrayAttr({})));
2897 SmallVector<Attribute> moduleNames, caseNames;
2898 moduleNames.push_back(SymbolRefAttr::get(defaultModule.getModuleNameAttr()));
2899 for (
auto [caseOption, caseModule] : cases) {
2900 auto caseGroup = caseOption->getParentOfType<OptionOp>();
2901 caseNames.push_back(SymbolRefAttr::get(caseGroup.getSymNameAttr(),
2902 {SymbolRefAttr::get(caseOption)}));
2903 moduleNames.push_back(SymbolRefAttr::get(caseModule.getModuleNameAttr()));
2906 return build(builder, result, resultTypes, builder.getArrayAttr(moduleNames),
2907 builder.getArrayAttr(caseNames), builder.getStringAttr(name),
2908 NameKindEnumAttr::get(builder.getContext(), nameKind),
2909 defaultModule.getPortDirectionsAttr(),
2910 defaultModule.getPortNamesAttr(), domainInfoAttr,
2911 builder.getArrayAttr(annotations), portAnnotationsAttr,
2912 defaultModule.getLayersAttr(),
2913 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr());
2916std::optional<size_t> InstanceChoiceOp::getTargetResultIndex() {
2917 return std::nullopt;
2920void InstanceChoiceOp::print(OpAsmPrinter &p) {
2923 p.printKeywordOrString(
getName());
2924 if (
auto attr = getInnerSymAttr()) {
2926 p.printSymbolName(attr.getSymName());
2928 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2929 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2932 SmallVector<StringRef, 11> omittedAttrs = {
2933 "moduleNames",
"caseNames",
"name",
2934 "portDirections",
"portNames",
"portTypes",
2935 "portAnnotations",
"inner_sym",
"nameKind",
2937 if (getAnnotations().
empty())
2938 omittedAttrs.push_back(
"annotations");
2939 if (getLayers().
empty())
2940 omittedAttrs.push_back(
"layers");
2941 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2946 auto moduleNames = getModuleNamesAttr();
2947 auto caseNames = getCaseNamesAttr();
2949 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[0]).getValue());
2951 p <<
" alternatives ";
2953 cast<SymbolRefAttr>(caseNames[0]).getRootReference().getValue());
2955 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
2959 auto symbol = cast<SymbolRefAttr>(caseNames[i]);
2960 p.printSymbolName(symbol.getNestedReferences()[0].getValue());
2962 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[i + 1]).getValue());
2968 SmallVector<Attribute> portTypes;
2969 portTypes.reserve(getNumResults());
2970 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2973 getPortNames().getValue(), portTypes,
2974 getPortAnnotations().getValue(), {}, {},
2975 getDomainInfo().getValue());
2978ParseResult InstanceChoiceOp::parse(OpAsmParser &parser,
2979 OperationState &result) {
2980 auto *
context = parser.getContext();
2981 auto &properties = result.getOrAddProperties<Properties>();
2984 hw::InnerSymAttr innerSymAttr;
2985 SmallVector<Attribute> moduleNames;
2986 SmallVector<Attribute> caseNames;
2987 SmallVector<OpAsmParser::Argument> entryArgs;
2988 SmallVector<Direction, 4> portDirections;
2989 SmallVector<Attribute, 4> portNames;
2990 SmallVector<Attribute, 4> portTypes;
2991 SmallVector<Attribute, 4> portAnnotations;
2992 SmallVector<Attribute, 4> portSyms;
2993 SmallVector<Attribute, 4> portLocs;
2994 SmallVector<Attribute, 4> domains;
2995 NameKindEnumAttr nameKind;
2997 if (parser.parseKeywordOrString(&name))
2999 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
3000 if (parser.parseCustomAttributeWithFallback(
3001 innerSymAttr, Type{},
3003 result.attributes)) {
3008 parser.parseOptionalAttrDict(result.attributes))
3011 FlatSymbolRefAttr defaultModuleName;
3012 if (parser.parseAttribute(defaultModuleName))
3014 moduleNames.push_back(defaultModuleName);
3018 FlatSymbolRefAttr optionName;
3019 if (parser.parseKeyword(
"alternatives") ||
3020 parser.parseAttribute(optionName) || parser.parseLBrace())
3023 FlatSymbolRefAttr moduleName;
3024 StringAttr caseName;
3025 while (succeeded(parser.parseOptionalSymbolName(caseName))) {
3026 if (parser.parseArrow() || parser.parseAttribute(moduleName))
3028 moduleNames.push_back(moduleName);
3029 caseNames.push_back(SymbolRefAttr::get(
3030 optionName.getAttr(), {FlatSymbolRefAttr::get(caseName)}));
3031 if (failed(parser.parseOptionalComma()))
3034 if (parser.parseRBrace())
3040 entryArgs, portDirections, portNames, portTypes,
3041 portAnnotations, portSyms, portLocs, domains))
3046 properties.setModuleNames(ArrayAttr::get(
context, moduleNames));
3047 properties.setCaseNames(ArrayAttr::get(
context, caseNames));
3048 properties.setName(StringAttr::get(
context, name));
3049 properties.setNameKind(nameKind);
3050 properties.setPortDirections(
3052 properties.setPortNames(ArrayAttr::get(
context, portNames));
3053 properties.setDomainInfo(ArrayAttr::get(
context, domains));
3054 properties.setPortAnnotations(ArrayAttr::get(
context, portAnnotations));
3058 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
3059 properties.setLayers(parser.getBuilder().getArrayAttr({}));
3062 result.types.reserve(portTypes.size());
3064 portTypes, std::back_inserter(result.types),
3065 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
3070void InstanceChoiceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3072 for (
auto [result, name] :
llvm::zip(getResults(), getPortNames()))
3073 setNameFn(result, (base +
"_" + cast<StringAttr>(name).getValue()).str());
3076LogicalResult InstanceChoiceOp::verify() {
3077 if (getCaseNamesAttr().
empty())
3078 return emitOpError() <<
"must have at least one case";
3079 if (getModuleNamesAttr().size() != getCaseNamesAttr().size() + 1)
3080 return emitOpError() <<
"number of referenced modules does not match the "
3081 "number of options";
3086 SmallVector<SymbolRefAttr> missingLayers;
3087 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
3089 missingLayers.push_back(layer);
3091 if (missingLayers.empty())
3095 emitOpError(
"ambient layers are insufficient to instantiate module");
3096 auto ¬e = diag.attachNote();
3097 note <<
"missing layer requirements: ";
3098 interleaveComma(missingLayers, note);
3103InstanceChoiceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3104 auto caseNames = getCaseNamesAttr();
3105 for (
auto moduleName : getModuleNamesAttr()) {
3107 *
this, symbolTable, cast<FlatSymbolRefAttr>(moduleName))))
3111 auto root = cast<SymbolRefAttr>(caseNames[0]).getRootReference();
3112 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3113 auto ref = cast<SymbolRefAttr>(caseNames[i]);
3114 auto refRoot = ref.getRootReference();
3115 if (ref.getRootReference() != root)
3116 return emitOpError() <<
"case " << ref
3117 <<
" is not in the same option group as "
3120 if (!symbolTable.lookupNearestSymbolFrom<OptionOp>(*
this, refRoot))
3121 return emitOpError() <<
"option " << refRoot <<
" does not exist";
3123 if (!symbolTable.lookupNearestSymbolFrom<OptionCaseOp>(*
this, ref))
3124 return emitOpError() <<
"option " << refRoot
3125 <<
" does not contain option case " << ref;
3132InstanceChoiceOp::getTargetOrDefaultAttr(OptionCaseOp option) {
3133 auto caseNames = getCaseNamesAttr();
3134 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3135 StringAttr caseSym = cast<SymbolRefAttr>(caseNames[i]).getLeafReference();
3136 if (caseSym == option.getSymName())
3137 return cast<FlatSymbolRefAttr>(getModuleNamesAttr()[i + 1]);
3139 return getDefaultTargetAttr();
3142SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1>
3143InstanceChoiceOp::getTargetChoices() {
3144 auto caseNames = getCaseNamesAttr();
3145 auto moduleNames = getModuleNamesAttr();
3146 SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1> choices;
3147 for (
size_t i = 0; i < caseNames.size(); ++i) {
3148 choices.emplace_back(cast<SymbolRefAttr>(caseNames[i]),
3149 cast<FlatSymbolRefAttr>(moduleNames[i + 1]));
3155InstanceChoiceOp InstanceChoiceOp::cloneWithInsertedPorts(
3156 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
3160 auto oldPortCount = getNumResults();
3161 auto numInsertions = insertions.size();
3162 auto newPortCount = oldPortCount + numInsertions;
3164 SmallVector<Direction> newPortDirections;
3165 SmallVector<Attribute> newPortNames;
3166 SmallVector<Type> newPortTypes;
3167 SmallVector<Attribute> newPortAnnos;
3168 SmallVector<Attribute> newDomainInfo;
3170 newPortDirections.reserve(newPortCount);
3171 newPortNames.reserve(newPortCount);
3172 newPortTypes.reserve(newPortCount);
3173 newPortAnnos.reserve(newPortCount);
3174 newDomainInfo.reserve(newPortCount);
3176 SmallVector<unsigned> indexMap(oldPortCount);
3178 size_t inserted = 0;
3179 for (
size_t i = 0; i < oldPortCount; ++i) {
3180 while (inserted < numInsertions) {
3181 auto &[index,
info] = insertions[inserted];
3187 newPortDirections.push_back(
info.direction);
3188 newPortNames.push_back(
info.name);
3189 newPortTypes.push_back(
info.type);
3190 newPortAnnos.push_back(
info.annotations.getArrayAttr());
3191 newDomainInfo.push_back(domains);
3195 newPortDirections.push_back(getPortDirection(i));
3196 newPortNames.push_back(getPortNameAttr(i));
3197 newPortTypes.push_back(getType(i));
3198 newPortAnnos.push_back(getPortAnnotations()[i]);
3199 newDomainInfo.push_back(getDomainInfo()[i]);
3200 indexMap[i] = i + inserted;
3203 while (inserted < numInsertions) {
3204 auto &[index,
info] = insertions[inserted];
3207 newPortDirections.push_back(
info.direction);
3208 newPortNames.push_back(
info.name);
3209 newPortTypes.push_back(
info.type);
3210 newPortAnnos.push_back(
info.annotations.getArrayAttr());
3211 newDomainInfo.push_back(domains);
3215 OpBuilder builder(*
this);
3216 auto clone = InstanceChoiceOp::create(
3217 builder,
getLoc(), newPortTypes, getModuleNames(), getCaseNames(),
3220 ArrayAttr::get(
context, newPortNames),
3221 ArrayAttr::get(
context, newDomainInfo), getAnnotationsAttr(),
3222 ArrayAttr::get(
context, newPortAnnos), getLayers(), getInnerSymAttr());
3224 if (
auto outputFile = (*this)->getAttr(
"output_file"))
3225 clone->setAttr(
"output_file", outputFile);
3230InstanceChoiceOp InstanceChoiceOp::cloneWithInsertedPortsAndReplaceUses(
3231 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
3232 auto clone = cloneWithInsertedPorts(insertions);
3238InstanceChoiceOp::cloneWithErasedPorts(
const llvm::BitVector &erasures) {
3239 assert(erasures.size() >= getNumResults() &&
3240 "erasures is not at least as large as getNumResults()");
3242 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
3243 SmallVector<Type>(result_type_begin(), result_type_end()), erasures);
3244 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
3246 SmallVector<Attribute> newPortNames =
3248 SmallVector<Attribute> newPortAnnotations =
3250 ArrayAttr newPortDomains =
3254 OpBuilder builder(*
this);
3255 auto clone = InstanceChoiceOp::create(
3256 builder,
getLoc(), newResultTypes, getModuleNames(), getCaseNames(),
3259 ArrayAttr::get(getContext(), newPortNames), newPortDomains,
3260 getAnnotationsAttr(), ArrayAttr::get(getContext(), newPortAnnotations),
3261 getLayers(), getInnerSymAttr());
3263 if (
auto outputFile = (*this)->getAttr(
"output_file"))
3264 clone->setAttr(
"output_file", outputFile);
3269InstanceChoiceOp InstanceChoiceOp::cloneWithErasedPortsAndReplaceUses(
3270 const llvm::BitVector &erasures) {
3271 auto clone = cloneWithErasedPorts(erasures);
3280ArrayAttr MemOp::getPortAnnotation(
unsigned portIdx) {
3281 assert(portIdx < getNumResults() &&
3282 "index should be smaller than result number");
3283 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
3286void MemOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
3287 assert(annotations.size() == getNumResults() &&
3288 "number of annotations is not equal to result number");
3289 (*this)->setAttr(
"portAnnotations",
3290 ArrayAttr::get(getContext(), annotations));
3294void MemOp::getNumPorts(
size_t &numReadPorts,
size_t &numWritePorts,
3295 size_t &numReadWritePorts,
size_t &numDbgsPorts) {
3298 numReadWritePorts = 0;
3300 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3301 auto portKind = getPortKind(i);
3302 if (portKind == MemOp::PortKind::Debug)
3304 else if (portKind == MemOp::PortKind::Read)
3306 else if (portKind == MemOp::PortKind::Write) {
3309 ++numReadWritePorts;
3314LogicalResult MemOp::verify() {
3318 llvm::SmallDenseSet<Attribute, 8> portNamesSet;
3324 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3325 auto portName = getPortNameAttr(i);
3330 BundleType portBundleType =
3331 type_dyn_cast<BundleType>(getResult(i).getType());
3334 if (!portNamesSet.insert(portName).second) {
3335 emitOpError() <<
"has non-unique port name " << portName;
3343 auto elt = getPortNamed(portName);
3345 emitOpError() <<
"could not get port with name " << portName;
3348 auto firrtlType = type_cast<FIRRTLType>(elt.getType());
3351 if (portKind == MemOp::PortKind::Debug &&
3352 !type_isa<RefType>(getResult(i).getType()))
3353 return emitOpError() <<
"has an invalid type on port " << portName
3354 <<
" (expected Read/Write/ReadWrite/Debug)";
3355 if (type_isa<RefType>(firrtlType) && e == 1)
3356 return emitOpError()
3357 <<
"cannot have only one port of debug type. Debug port can only "
3358 "exist alongside other read/write/read-write port";
3363 if (portKind == MemOp::PortKind::Debug) {
3364 auto resType = type_cast<RefType>(getResult(i).getType());
3365 if (!(resType && type_isa<FVectorType>(resType.getType())))
3366 return emitOpError() <<
"debug ports must be a RefType of FVectorType";
3367 dataType = type_cast<FVectorType>(resType.getType()).getElementType();
3369 auto dataTypeOption = portBundleType.getElement(
"data");
3370 if (!dataTypeOption && portKind == MemOp::PortKind::ReadWrite)
3371 dataTypeOption = portBundleType.getElement(
"wdata");
3372 if (!dataTypeOption) {
3373 emitOpError() <<
"has no data field on port " << portName
3374 <<
" (expected to see \"data\" for a read or write "
3375 "port or \"rdata\" for a read/write port)";
3378 dataType = dataTypeOption->type;
3380 if (portKind == MemOp::PortKind::Read) {
3387 emitOpError() <<
"has non-passive data type on port " << portName
3388 <<
" (memory types must be passive)";
3393 if (dataType.containsAnalog()) {
3394 emitOpError() <<
"has a data type that contains an analog type on port "
3396 <<
" (memory types cannot contain analog types)";
3404 getTypeForPort(getDepth(), dataType, portKind,
3405 dataType.isGround() ? getMaskBits() : 0);
3408 auto originalType = getResult(i).getType();
3409 if (originalType != expectedType) {
3410 StringRef portKindName;
3412 case MemOp::PortKind::Read:
3413 portKindName =
"read";
3415 case MemOp::PortKind::Write:
3416 portKindName =
"write";
3418 case MemOp::PortKind::ReadWrite:
3419 portKindName =
"readwrite";
3421 case MemOp::PortKind::Debug:
3422 portKindName =
"dbg";
3425 emitOpError() <<
"has an invalid type for port " << portName
3426 <<
" of determined kind \"" << portKindName
3427 <<
"\" (expected " << expectedType <<
", but got "
3428 << originalType <<
")";
3434 if (oldDataType && oldDataType != dataType) {
3435 emitOpError() <<
"port " << getPortNameAttr(i)
3436 <<
" has a different type than port "
3437 << getPortNameAttr(i - 1) <<
" (expected " << oldDataType
3438 <<
", but got " << dataType <<
")";
3442 oldDataType = dataType;
3445 auto maskWidth = getMaskBits();
3447 auto dataWidth = getDataType().getBitWidthOrSentinel();
3448 if (dataWidth > 0 && maskWidth > (
size_t)dataWidth)
3449 return emitOpError(
"the mask width cannot be greater than "
3452 if (getPortAnnotations().size() != getNumResults())
3453 return emitOpError(
"the number of result annotations should be "
3454 "equal to the number of results");
3460 return std::max(1U, llvm::Log2_64_Ceil(depth));
3466 PortKind portKind,
size_t maskBits) {
3468 auto *
context = dataType.getContext();
3469 if (portKind == PortKind::Debug)
3470 return RefType::get(FVectorType::get(dataType, depth));
3476 maskType = UIntType::get(
context, maskBits);
3478 auto getId = [&](StringRef name) -> StringAttr {
3479 return StringAttr::get(
context, name);
3482 SmallVector<BundleType::BundleElement, 7> portFields;
3486 portFields.push_back({getId(
"addr"),
false, addressType});
3487 portFields.push_back({getId(
"en"),
false, UIntType::get(
context, 1)});
3488 portFields.push_back({getId(
"clk"),
false, ClockType::get(
context)});
3491 case PortKind::Read:
3492 portFields.push_back({getId(
"data"),
true, dataType});
3495 case PortKind::Write:
3496 portFields.push_back({getId(
"data"),
false, dataType});
3497 portFields.push_back({getId(
"mask"),
false, maskType});
3500 case PortKind::ReadWrite:
3501 portFields.push_back({getId(
"rdata"),
true, dataType});
3502 portFields.push_back({getId(
"wmode"),
false, UIntType::get(
context, 1)});
3503 portFields.push_back({getId(
"wdata"),
false, dataType});
3504 portFields.push_back({getId(
"wmask"),
false, maskType});
3507 llvm::report_fatal_error(
"memory port kind not handled");
3511 return BundleType::get(
context, portFields);
3515SmallVector<MemOp::NamedPort> MemOp::getPorts() {
3516 SmallVector<MemOp::NamedPort> result;
3518 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3520 auto portType = type_cast<FIRRTLType>(getResult(i).getType());
3527MemOp::PortKind MemOp::getPortKind(StringRef portName) {
3529 type_cast<FIRRTLType>(getPortNamed(portName).getType()));
3533MemOp::PortKind MemOp::getPortKind(
size_t resultNo) {
3535 type_cast<FIRRTLType>(getResult(resultNo).getType()));
3539size_t MemOp::getMaskBits() {
3541 for (
auto res : getResults()) {
3542 if (type_isa<RefType>(res.getType()))
3544 auto firstPortType = type_cast<FIRRTLBaseType>(res.getType());
3551 if (t.name.getValue().contains(
"mask"))
3554 if (type_isa<UIntType>(mType))
3564 assert(getNumResults() != 0 &&
"Mems with no read/write ports are illegal");
3566 if (
auto refType = type_dyn_cast<RefType>(getResult(0).getType()))
3567 return type_cast<FVectorType>(refType.getType()).getElementType();
3568 auto firstPortType = type_cast<FIRRTLBaseType>(getResult(0).getType());
3570 StringRef dataFieldName =
"data";
3572 dataFieldName =
"rdata";
3574 return type_cast<BundleType>(firstPortType.getPassiveType())
3575 .getElementType(dataFieldName);
3578StringAttr MemOp::getPortNameAttr(
size_t resultNo) {
3579 return cast<StringAttr>(getPortNames()[resultNo]);
3583 return type_cast<FIRRTLBaseType>(getResults()[resultNo].getType());
3586Value MemOp::getPortNamed(StringAttr name) {
3587 auto namesArray = getPortNames();
3588 for (
size_t i = 0, e = namesArray.size(); i != e; ++i) {
3589 if (namesArray[i] == name) {
3590 assert(i < getNumResults() &&
" names array out of sync with results");
3591 return getResult(i);
3600 size_t numReadPorts = 0;
3601 size_t numWritePorts = 0;
3602 size_t numReadWritePorts = 0;
3604 SmallVector<int32_t> writeClockIDs;
3606 for (
size_t i = 0, e = op.getNumResults(); i != e; ++i) {
3607 auto portKind = op.getPortKind(i);
3608 if (portKind == MemOp::PortKind::Read)
3610 else if (portKind == MemOp::PortKind::Write) {
3611 for (
auto *a : op.getResult(i).getUsers()) {
3612 auto subfield = dyn_cast<SubfieldOp>(a);
3613 if (!subfield || subfield.getFieldIndex() != 2)
3615 auto clockPort = a->getResult(0);
3616 for (
auto *b : clockPort.getUsers()) {
3617 if (
auto connect = dyn_cast<FConnectLike>(b)) {
3618 if (
connect.getDest() == clockPort) {
3621 connect.getSrc(),
true,
true,
true),
3623 if (result.second) {
3624 writeClockIDs.push_back(numWritePorts);
3626 writeClockIDs.push_back(result.first->second);
3635 ++numReadWritePorts;
3642 op.emitError(
"'firrtl.mem' should have simple type and known width");
3643 MemoryInitAttr init = op->getAttrOfType<MemoryInitAttr>(
"init");
3645 if (op->hasAttr(
"modName"))
3646 modName = op->getAttrOfType<StringAttr>(
"modName");
3648 SmallString<8> clocks;
3649 for (
auto a : writeClockIDs)
3650 clocks.
append(Twine((char)(a +
'a')).str());
3651 SmallString<32> initStr;
3656 for (
auto c : init.getFilename().getValue())
3657 if ((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') ||
3658 (c >=
'0' && c <=
'9'))
3659 initStr.push_back(c);
3660 initStr.push_back(
'_');
3661 initStr.push_back(init.getIsBinary() ?
't' :
'f');
3662 initStr.push_back(
'_');
3663 initStr.push_back(init.getIsInline() ?
't' :
'f');
3665 modName = StringAttr::get(
3668 "{0}FIRRTLMem_{1}_{2}_{3}_{4}_{5}_{6}_{7}_{8}_{9}_{10}{11}{12}",
3669 op.getPrefix().value_or(
""), numReadPorts, numWritePorts,
3670 numReadWritePorts, (
size_t)width, op.getDepth(),
3671 op.getReadLatency(), op.getWriteLatency(), op.getMaskBits(),
3672 (
unsigned)op.getRuw(), (
unsigned)seq::WUW::PortOrder,
3673 clocks.empty() ?
"" :
"_" + clocks, init ? initStr.str() :
""));
3675 return {numReadPorts,
3680 op.getReadLatency(),
3681 op.getWriteLatency(),
3683 *seq::symbolizeRUW(
unsigned(op.getRuw())),
3684 seq::WUW::PortOrder,
3687 op.getMaskBits() > 1,
3693void MemOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3698 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
3699 setNameFn(getResult(i), (base +
"_" + getPortName(i)).str());
3703std::optional<size_t> MemOp::getTargetResultIndex() {
3705 return std::nullopt;
3713 OpAsmSetValueNameFn setNameFn) {
3716 setNameFn(op.getDataRaw(), name);
3717 if (op.isForceable())
3718 setNameFn(op.getDataRef(), (name +
"_ref").str());
3721void NodeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3725LogicalResult NodeOp::inferReturnTypes(
3726 mlir::MLIRContext *
context, std::optional<mlir::Location> location,
3727 ::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes,
3728 ::mlir::OpaqueProperties properties, ::mlir::RegionRange regions,
3729 ::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
3730 if (operands.empty())
3732 Adaptor adaptor(operands, attributes, properties, regions);
3733 inferredReturnTypes.push_back(adaptor.getInput().getType());
3734 if (adaptor.getForceable()) {
3736 true, adaptor.getInput().getType());
3737 if (!forceableType) {
3739 ::mlir::emitError(*location,
"cannot force a node of type ")
3740 << operands[0].getType();
3743 inferredReturnTypes.push_back(forceableType);
3748std::optional<size_t> NodeOp::getTargetResultIndex() {
return 0; }
3750void RegOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3754std::optional<size_t> RegOp::getTargetResultIndex() {
return 0; }
3756SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3757RegOp::computeDataFlow() {
3762LogicalResult RegResetOp::verify() {
3763 auto reset = getResetValue();
3770 return emitError(
"type mismatch between register ")
3771 << regType <<
" and reset value " << resetType;
3776std::optional<size_t> RegResetOp::getTargetResultIndex() {
return 0; }
3778void RegResetOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3787FormalOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3788 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3790 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3792 if (!isa<FModuleLike>(op)) {
3793 auto d = emitOpError() <<
"target " << getModuleNameAttr()
3794 <<
" is not a module";
3795 d.attachNote(op->getLoc()) <<
"target defined here";
3807SimulationOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3808 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3810 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3812 auto complain = [&] {
3813 auto d = emitOpError() <<
"target " << getModuleNameAttr() <<
" ";
3814 d.attachNote(op->getLoc()) <<
"target defined here";
3818 auto module = dyn_cast<FModuleLike>(op);
3820 return complain() <<
"is not a module";
3822 auto numPorts =
module.getPortDirections().size();
3824 return complain() <<
"must have 4 ports, got " << numPorts <<
" instead";
3826 auto checkPort = [&](
unsigned idx, StringRef expName,
Direction expDir,
3827 llvm::function_ref<bool(Type)> checkType,
3828 StringRef expType) {
3829 auto name =
module.getPortNameAttr(idx);
3830 if (name != expName) {
3831 complain() <<
"port " << idx <<
" must be called \"" << expName
3832 <<
"\", got " << name <<
" instead";
3835 if (
auto dir = module.getPortDirection(idx); dir != expDir) {
3839 complain() <<
"port " << name <<
" must be " << stringify(expDir)
3840 <<
", got " << stringify(dir) <<
" instead";
3843 if (
auto type = module.getPortType(idx); !checkType(type)) {
3844 complain() <<
"port " << name <<
" must be a '!firrtl." << expType
3845 <<
"', got " << type <<
" instead";
3851 auto isClock = [](Type type) {
return isa<ClockType>(type); };
3852 auto isBool = [](Type type) {
3853 if (
auto uintType = dyn_cast<UIntType>(type))
3854 return uintType.getWidth() == 1;
3857 return success(checkPort(0,
"clock",
Direction::In, isClock,
"clock") &&
3867void WireOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3871SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3872RegResetOp::computeDataFlow() {
3877std::optional<size_t> WireOp::getTargetResultIndex() {
return 0; }
3879LogicalResult WireOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3880 auto refType = type_dyn_cast<RefType>(getType(0));
3885 refType,
getLoc(), getOperation()->getParentOfType<CircuitOp>(),
3886 symbolTable, Twine(
"'") + getOperationName() +
"' op is");
3893LogicalResult ContractOp::verify() {
3894 if (getBody().getArgumentTypes() != getInputs().getType())
3895 return emitOpError(
"result types and region argument types must match");
3903void ObjectOp::build(OpBuilder &builder, OperationState &state, ClassLike klass,
3905 build(builder, state, klass.getInstanceType(),
3906 StringAttr::get(builder.getContext(), name));
3909LogicalResult ObjectOp::verify() {
return success(); }
3911LogicalResult ObjectOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3912 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
3913 auto classType = getType();
3914 auto className = classType.getNameAttr();
3917 auto classOp = dyn_cast_or_null<ClassLike>(
3918 symbolTable.lookupSymbolIn(circuitOp, className));
3920 return emitOpError() <<
"references unknown class " << className;
3923 if (failed(classOp.verifyType(classType, [&]() { return emitOpError(); })))
3929StringAttr ObjectOp::getClassNameAttr() {
3930 return getType().getNameAttr().getAttr();
3933StringRef ObjectOp::getClassName() {
return getType().getName(); }
3935ClassLike ObjectOp::getReferencedClass(
const SymbolTable &symbolTable) {
3936 auto symRef = getType().getNameAttr();
3937 return symbolTable.lookup<ClassLike>(symRef.getLeafReference());
3940Operation *ObjectOp::getReferencedOperation(
const SymbolTable &symtbl) {
3941 return getReferencedClass(symtbl);
3944StringRef ObjectOp::getInstanceName() {
return getName(); }
3946StringAttr ObjectOp::getInstanceNameAttr() {
return getNameAttr(); }
3948StringRef ObjectOp::getReferencedModuleName() {
return getClassName(); }
3950StringAttr ObjectOp::getReferencedModuleNameAttr() {
3951 return getClassNameAttr();
3954void ObjectOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3955 setNameFn(getResult(),
getName());
3962LogicalResult AttachOp::verify() {
3964 std::optional<int32_t> commonWidth;
3965 for (
auto operand : getOperands()) {
3966 auto thisWidth = type_cast<AnalogType>(operand.getType()).getWidth();
3970 commonWidth = thisWidth;
3973 if (commonWidth != thisWidth)
3974 return emitOpError(
"is inavlid as not all known operand widths match");
3981 Value dst = connect->getOperand(0);
3982 Value src = connect->getOperand(1);
3991 if (isa<PropertyType>(src.getType()) ||
3995 auto diag = emitError(connect->getLoc());
3996 diag <<
"connect has invalid flow: the source expression ";
3998 diag <<
"\"" << srcName <<
"\" ";
3999 diag <<
"has " <<
toString(srcFlow) <<
", expected source or duplex flow";
4000 return diag.attachNote(srcRef.getLoc()) <<
"the source was defined here";
4008 auto diag = emitError(connect->getLoc());
4009 diag <<
"connect has invalid flow: the destination expression ";
4011 diag <<
"\"" << dstName <<
"\" ";
4012 diag <<
"has " <<
toString(dstFlow) <<
", expected sink or duplex flow";
4013 return diag.attachNote(dstRef.getLoc())
4014 <<
"the destination was defined here";
4023 bool outerTypeIsConst =
false) {
4024 auto typeIsConst = outerTypeIsConst || type.
isConst();
4029 if (
auto bundleType = type_dyn_cast<BundleType>(type))
4030 return llvm::any_of(bundleType.getElements(), [&](
auto &element) {
4031 return isConstFieldDriven(element.type, isFlip ^ element.isFlip,
4035 if (
auto vectorType = type_dyn_cast<FVectorType>(type))
4047 auto dest = connect.getDest();
4048 auto destType = type_dyn_cast<FIRRTLBaseType>(dest.getType());
4049 auto src = connect.getSrc();
4050 auto srcType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4051 if (!destType || !srcType)
4054 auto destRefinedType = destType;
4055 auto srcRefinedType = srcType;
4060 auto findFieldDeclarationRefiningFieldType =
4062 while (
auto *definingOp = value.getDefiningOp()) {
4063 bool shouldContinue =
true;
4064 TypeSwitch<Operation *>(definingOp)
4065 .Case<SubfieldOp, SubindexOp>([&](
auto op) { value = op.getInput(); })
4066 .Case<SubaccessOp>([&](SubaccessOp op) {
4070 .getElementTypePreservingConst()
4072 originalFieldType = originalFieldType.getConstType(
true);
4073 value = op.getInput();
4075 .Default([&](Operation *) { shouldContinue =
false; });
4076 if (!shouldContinue)
4082 auto destDeclaration =
4083 findFieldDeclarationRefiningFieldType(dest, destRefinedType);
4084 auto srcDeclaration =
4085 findFieldDeclarationRefiningFieldType(src, srcRefinedType);
4087 auto checkConstConditionality = [&](Value value,
FIRRTLBaseType type,
4088 Value declaration) -> LogicalResult {
4089 auto *declarationBlock = declaration.getParentBlock();
4090 auto *block = connect->getBlock();
4091 while (block && block != declarationBlock) {
4092 auto *parentOp = block->getParentOp();
4094 if (
auto whenOp = dyn_cast<WhenOp>(parentOp);
4095 whenOp && !whenOp.getCondition().getType().isConst()) {
4097 return connect.emitOpError()
4098 <<
"assignment to 'const' type " << type
4099 <<
" is dependent on a non-'const' condition";
4100 return connect->emitOpError()
4101 <<
"assignment to nested 'const' member of type " << type
4102 <<
" is dependent on a non-'const' condition";
4105 block = parentOp->getBlock();
4110 auto emitSubaccessError = [&] {
4111 return connect.emitError(
4112 "assignment to non-'const' subaccess of 'const' type is disallowed");
4118 if (destType != destRefinedType)
4119 return emitSubaccessError();
4121 if (failed(checkConstConditionality(dest, destType, destDeclaration)))
4126 if (srcRefinedType.containsConst() &&
4129 if (srcType != srcRefinedType)
4130 return emitSubaccessError();
4131 if (failed(checkConstConditionality(src, srcType, srcDeclaration)))
4148 auto dest = connect.getDest();
4149 for (
auto *user : dest.getUsers()) {
4150 if (
auto c = dyn_cast<FConnectLike>(user);
4151 c && c.getDest() == dest && c != connect) {
4152 auto diag = connect.emitError(
"destination cannot be driven by multiple "
4154 diag.attachNote(c->getLoc()) <<
"other driver is here";
4161LogicalResult ConnectOp::verify() {
4162 auto dstType = getDest().getType();
4163 auto srcType = getSrc().getType();
4164 auto dstBaseType = type_dyn_cast<FIRRTLBaseType>(dstType);
4165 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(srcType);
4166 if (!dstBaseType || !srcBaseType) {
4167 if (dstType != srcType)
4168 return emitError(
"may not connect different non-base types");
4171 if (dstBaseType.containsAnalog() || srcBaseType.containsAnalog())
4172 return emitError(
"analog types may not be connected");
4176 return emitError(
"type mismatch between destination ")
4177 << dstBaseType <<
" and source " << srcBaseType;
4182 return emitError(
"destination ")
4183 << dstBaseType <<
" is not as wide as the source " << srcBaseType;
4196LogicalResult MatchingConnectOp::verify() {
4197 if (
auto type = type_dyn_cast<FIRRTLType>(getDest().getType())) {
4198 auto baseType = type_cast<FIRRTLBaseType>(type);
4201 if (baseType && baseType.containsAnalog())
4202 return emitError(
"analog types may not be connected");
4207 "`SameAnonTypeOperands` trait should have already rejected "
4208 "structurally non-equivalent types");
4221LogicalResult RefDefineOp::verify() {
4228 if (
auto *op = getDest().getDefiningOp()) {
4230 if (isa<RefSubOp>(op))
4232 "destination reference cannot be a sub-element of a reference");
4233 if (isa<RefCastOp>(op))
4235 "destination reference cannot be a cast of another reference");
4243 SmallVector<SymbolRefAttr> missingLayers;
4246 "has more layer requirements than destination",
4247 "additional layers required");
4250LogicalResult PropAssignOp::verify() {
4260template <
typename T>
4262 auto info = op.getDomainInfo();
4265 return dyn_cast<FlatSymbolRefAttr>(info[i]);
4269 if (!isa<DomainType>(value.getType()))
4272 if (
auto arg = dyn_cast<BlockArgument>(value)) {
4273 auto *parent = arg.getOwner()->getParentOp();
4274 if (
auto module = dyn_cast<FModuleLike>(parent)) {
4275 auto info =
module.getDomainInfo();
4278 auto attr = info[arg.getArgNumber()];
4279 return dyn_cast<FlatSymbolRefAttr>(attr);
4285 if (
auto result = dyn_cast<OpResult>(value)) {
4286 auto *op = result.getDefiningOp();
4287 if (
auto instance = dyn_cast<InstanceOp>(op))
4289 if (
auto instance = dyn_cast<InstanceChoiceOp>(op))
4291 if (
auto anonDomain = dyn_cast<DomainCreateAnonOp>(op))
4292 return anonDomain.getDomainAttr();
4299LogicalResult DomainDefineOp::verify() {
4306 auto dst = getDest();
4307 auto src = getSrc();
4315 if (
auto *srcDefOp = src.getDefiningOp())
4316 if (isa<WireOp>(srcDefOp))
4318 if (
auto *dstDefOp = dst.getDefiningOp())
4319 if (isa<WireOp>(dstDefOp))
4324 return emitError(
"could not determine domain-type of destination");
4328 return emitError(
"could not determine domain-type of source");
4330 if (dstDomain != srcDomain) {
4331 auto diag = emitError()
4332 <<
"source domain type " << srcDomain
4333 <<
" does not match destination domain type " << dstDomain;
4340void WhenOp::createElseRegion() {
4341 assert(!hasElseRegion() &&
"already has an else region");
4342 getElseRegion().push_back(
new Block());
4345void WhenOp::build(OpBuilder &builder, OperationState &result, Value condition,
4346 bool withElseRegion, std::function<
void()> thenCtor,
4347 std::function<
void()> elseCtor) {
4348 OpBuilder::InsertionGuard guard(builder);
4349 result.addOperands(condition);
4352 builder.createBlock(result.addRegion());
4357 Region *elseRegion = result.addRegion();
4358 if (withElseRegion) {
4359 builder.createBlock(elseRegion);
4369LogicalResult MatchOp::verify() {
4370 FEnumType type = getInput().getType();
4373 auto numCases = getTags().size();
4374 auto numRegions = getNumRegions();
4375 if (numRegions != numCases)
4376 return emitOpError(
"expected ")
4377 << numRegions <<
" tags but got " << numCases;
4379 auto numTags = type.getNumElements();
4381 SmallDenseSet<int64_t> seen;
4382 for (
const auto &[tag, region] :
llvm::zip(getTags(), getRegions())) {
4383 auto tagIndex = size_t(cast<IntegerAttr>(tag).
getInt());
4386 if (region.getNumArguments() != 1)
4387 return emitOpError(
"region should have exactly one argument");
4390 if (tagIndex >= numTags)
4391 return emitOpError(
"the tag index ")
4392 << tagIndex <<
" is out of the range of valid tags in " << type;
4395 auto [it, inserted] = seen.insert(tagIndex);
4397 return emitOpError(
"the tag ") << type.getElementNameAttr(tagIndex)
4398 <<
" is matched more than once";
4401 auto expectedType = type.getElementTypePreservingConst(tagIndex);
4402 auto regionType = region.getArgument(0).getType();
4403 if (regionType != expectedType)
4404 return emitOpError(
"region type ")
4405 << regionType <<
" does not match the expected type "
4410 for (
size_t i = 0, e = type.getNumElements(); i < e; ++i)
4411 if (!seen.contains(i))
4412 return emitOpError(
"missing case for tag ") << type.getElementNameAttr(i);
4417void MatchOp::print(OpAsmPrinter &p) {
4418 auto input = getInput();
4419 FEnumType type = input.getType();
4420 auto regions = getRegions();
4421 p <<
" " << input <<
" : " << type;
4422 SmallVector<StringRef> elided = {
"tags"};
4423 p.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elided);
4426 for (
const auto &[tag, region] :
llvm::zip(getTags(), regions)) {
4429 p.printKeywordOrString(
4430 type.getElementName(cast<IntegerAttr>(tag).getInt()));
4432 p.printRegionArgument(region.front().getArgument(0), {},
4435 p.printRegion(region,
false);
4442ParseResult MatchOp::parse(OpAsmParser &parser, OperationState &result) {
4443 auto *
context = parser.getContext();
4444 auto &properties = result.getOrAddProperties<Properties>();
4445 OpAsmParser::UnresolvedOperand input;
4446 if (parser.parseOperand(input) || parser.parseColon())
4449 auto loc = parser.getCurrentLocation();
4451 if (parser.parseType(type))
4453 auto enumType = type_dyn_cast<FEnumType>(type);
4455 return parser.emitError(loc,
"expected enumeration type but got") << type;
4457 if (parser.resolveOperand(input, type, result.operands) ||
4458 parser.parseOptionalAttrDictWithKeyword(result.attributes) ||
4459 parser.parseLBrace())
4462 auto i32Type = IntegerType::get(
context, 32);
4463 SmallVector<Attribute> tags;
4466 if (failed(parser.parseOptionalKeyword(
"case")))
4470 auto nameLoc = parser.getCurrentLocation();
4472 OpAsmParser::Argument arg;
4473 auto *region = result.addRegion();
4474 if (parser.parseKeywordOrString(&name) || parser.parseLParen() ||
4475 parser.parseArgument(arg) || parser.parseRParen())
4479 auto index = enumType.getElementIndex(name);
4481 return parser.emitError(nameLoc,
"the tag \"")
4482 << name <<
"\" is not a member of the enumeration " << enumType;
4483 tags.push_back(IntegerAttr::get(i32Type, *index));
4486 arg.type = enumType.getElementTypePreservingConst(*index);
4487 if (parser.parseRegion(*region, arg))
4490 properties.setTags(ArrayAttr::get(
context, tags));
4492 return parser.parseRBrace();
4495void MatchOp::build(OpBuilder &builder, OperationState &result, Value input,
4497 MutableArrayRef<std::unique_ptr<Region>> regions) {
4498 auto &properties = result.getOrAddProperties<Properties>();
4499 result.addOperands(input);
4500 properties.setTags(tags);
4501 result.addRegions(regions);
4510 struct IsExprClassifier :
public ExprVisitor<IsExprClassifier, bool> {
4511 bool visitInvalidExpr(Operation *op) {
return false; }
4512 bool visitUnhandledExpr(Operation *op) {
return true; }
4518void InvalidValueOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4521 if (
auto ty = type_dyn_cast<IntType>(getType())) {
4522 const char *base = ty.isSigned() ?
"invalid_si" :
"invalid_ui";
4523 auto width = ty.getWidthOrSentinel();
4527 name = (Twine(base) + Twine(width)).str();
4528 }
else if (
auto ty = type_dyn_cast<AnalogType>(getType())) {
4529 auto width = ty.getWidthOrSentinel();
4531 name =
"invalid_analog";
4533 name = (
"invalid_analog" + Twine(width)).str();
4534 }
else if (type_isa<AsyncResetType>(getType()))
4535 name =
"invalid_asyncreset";
4536 else if (type_isa<ResetType>(getType()))
4537 name =
"invalid_reset";
4538 else if (type_isa<ClockType>(getType()))
4539 name =
"invalid_clock";
4543 setNameFn(getResult(), name);
4546void ConstantOp::print(OpAsmPrinter &p) {
4548 p.printAttributeWithoutType(getValueAttr());
4550 p.printType(getType());
4551 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4554ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
4555 auto &properties = result.getOrAddProperties<Properties>();
4558 auto loc = parser.getCurrentLocation();
4559 auto valueResult = parser.parseOptionalInteger(value);
4560 if (!valueResult.has_value())
4561 return parser.emitError(loc,
"expected integer value");
4565 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4566 parser.parseOptionalAttrDict(result.attributes))
4568 result.addTypes(resultType);
4574 if (width > value.getBitWidth()) {
4578 value = value.sext(width);
4579 }
else if (width < value.getBitWidth()) {
4582 unsigned neededBits = value.isNegative() ? value.getSignificantBits()
4583 : value.getActiveBits();
4584 if (width < neededBits)
4585 return parser.emitError(loc,
"constant out of range for result type ")
4587 value = value.trunc(width);
4591 auto intType = parser.getBuilder().getIntegerType(value.getBitWidth(),
4593 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4594 properties.setValue(valueAttr);
4598LogicalResult ConstantOp::verify() {
4602 if (width != -1 && (
int)getValue().
getBitWidth() != width)
4604 "firrtl.constant attribute bitwidth doesn't match return type");
4607 auto attrType = type_cast<IntegerType>(getValueAttr().getType());
4608 if (attrType.isSignless() || attrType.isSigned() != intType.
isSigned())
4609 return emitError(
"firrtl.constant attribute has wrong sign");
4616void ConstantOp::build(OpBuilder &builder, OperationState &result,
IntType type,
4617 const APInt &value) {
4620 assert((width == -1 || (int32_t)value.getBitWidth() == width) &&
4621 "incorrect attribute bitwidth for firrtl.constant");
4624 IntegerAttr::get(type.getContext(), APSInt(value, !type.
isSigned()));
4625 return build(builder, result, type, attr);
4630void ConstantOp::build(OpBuilder &builder, OperationState &result,
4631 const APSInt &value) {
4632 auto attr = IntegerAttr::get(builder.getContext(), value);
4634 IntType::get(builder.getContext(), value.isSigned(), value.getBitWidth());
4635 return build(builder, result, type, attr);
4638void ConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4645 SmallString<32> specialNameBuffer;
4646 llvm::raw_svector_ostream specialName(specialNameBuffer);
4648 getValue().print(specialName, intTy.
isSigned());
4650 specialName << (intTy.
isSigned() ?
"_si" :
"_ui");
4653 specialName << width;
4654 setNameFn(getResult(), specialName.str());
4657void SpecialConstantOp::print(OpAsmPrinter &p) {
4660 p << static_cast<unsigned>(getValue());
4662 p.printType(getType());
4663 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4666ParseResult SpecialConstantOp::parse(OpAsmParser &parser,
4667 OperationState &result) {
4668 auto &properties = result.getOrAddProperties<Properties>();
4672 auto loc = parser.getCurrentLocation();
4673 auto valueResult = parser.parseOptionalInteger(value);
4674 if (!valueResult.has_value())
4675 return parser.emitError(loc,
"expected integer value");
4678 if (value != 0 && value != 1)
4679 return parser.emitError(loc,
"special constants can only be 0 or 1.");
4683 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4684 parser.parseOptionalAttrDict(result.attributes))
4686 result.addTypes(resultType);
4689 auto valueAttr = parser.getBuilder().getBoolAttr(value == 1);
4690 properties.setValue(valueAttr);
4694void SpecialConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4695 SmallString<32> specialNameBuffer;
4696 llvm::raw_svector_ostream specialName(specialNameBuffer);
4698 specialName << static_cast<unsigned>(getValue());
4699 auto type = getType();
4700 if (type_isa<ClockType>(type)) {
4701 specialName <<
"_clock";
4702 }
else if (type_isa<ResetType>(type)) {
4703 specialName <<
"_reset";
4704 }
else if (type_isa<AsyncResetType>(type)) {
4705 specialName <<
"_asyncreset";
4707 setNameFn(getResult(), specialName.str());
4714 if (type.isGround()) {
4715 if (!isa<IntegerAttr>(attr)) {
4716 op->emitOpError(
"Ground type is not an integer attribute");
4721 auto attrlist = dyn_cast<ArrayAttr>(attr);
4723 op->emitOpError(
"expected array attribute for aggregate constant");
4726 if (
auto array = type_dyn_cast<FVectorType>(type)) {
4727 if (array.getNumElements() != attrlist.size()) {
4728 op->emitOpError(
"array attribute (")
4729 << attrlist.size() <<
") has wrong size for vector constant ("
4730 << array.getNumElements() <<
")";
4733 return llvm::all_of(attrlist, [&array, op](Attribute attr) {
4737 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4738 if (bundle.getNumElements() != attrlist.size()) {
4739 op->emitOpError(
"array attribute (")
4740 << attrlist.size() <<
") has wrong size for bundle constant ("
4741 << bundle.getNumElements() <<
")";
4744 for (
size_t i = 0; i < bundle.getNumElements(); ++i) {
4745 if (bundle.getElement(i).isFlip) {
4746 op->emitOpError(
"Cannot have constant bundle type with flip");
4754 op->emitOpError(
"Unknown aggregate type");
4758LogicalResult AggregateConstantOp::verify() {
4764Attribute AggregateConstantOp::getAttributeFromFieldID(uint64_t fieldID) {
4766 Attribute value = getFields();
4767 while (fieldID != 0) {
4768 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4769 auto index = bundle.getIndexForFieldID(fieldID);
4770 fieldID -= bundle.getFieldID(index);
4771 type = bundle.getElementType(index);
4772 value = cast<ArrayAttr>(value)[index];
4774 auto vector = type_cast<FVectorType>(type);
4775 auto index = vector.getIndexForFieldID(fieldID);
4776 fieldID -= vector.getFieldID(index);
4777 type = vector.getElementType();
4778 value = cast<ArrayAttr>(value)[index];
4784void FIntegerConstantOp::print(OpAsmPrinter &p) {
4786 p.printAttributeWithoutType(getValueAttr());
4787 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4790ParseResult FIntegerConstantOp::parse(OpAsmParser &parser,
4791 OperationState &result) {
4792 auto *
context = parser.getContext();
4793 auto &properties = result.getOrAddProperties<Properties>();
4795 if (parser.parseInteger(value) ||
4796 parser.parseOptionalAttrDict(result.attributes))
4798 result.addTypes(FIntegerType::get(
context));
4800 IntegerType::get(
context, value.getBitWidth(), IntegerType::Signed);
4801 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4802 properties.setValue(valueAttr);
4806ParseResult ListCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4807 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
4810 if (parser.parseOperandList(operands) ||
4811 parser.parseOptionalAttrDict(result.attributes) ||
4812 parser.parseColonType(type))
4814 result.addTypes(type);
4816 return parser.resolveOperands(operands, type.getElementType(),
4820void ListCreateOp::print(OpAsmPrinter &p) {
4822 p.printOperands(getElements());
4823 p.printOptionalAttrDict((*this)->getAttrs());
4824 p <<
" : " << getType();
4827LogicalResult ListCreateOp::verify() {
4828 if (getElements().
empty())
4831 auto elementType = getElements().front().getType();
4832 auto listElementType = getType().getElementType();
4834 return emitOpError(
"has elements of type ")
4835 <<
elementType <<
" instead of " << listElementType;
4840LogicalResult BundleCreateOp::verify() {
4841 BundleType resultType = getType();
4842 if (resultType.getNumElements() != getFields().size())
4843 return emitOpError(
"number of fields doesn't match type");
4844 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4846 resultType.getElementTypePreservingConst(i),
4847 type_cast<FIRRTLBaseType>(getOperand(i).getType())))
4848 return emitOpError(
"type of element doesn't match bundle for field ")
4849 << resultType.getElement(i).name;
4854LogicalResult VectorCreateOp::verify() {
4855 FVectorType resultType = getType();
4856 if (resultType.getNumElements() != getFields().size())
4857 return emitOpError(
"number of fields doesn't match type");
4858 auto elemTy = resultType.getElementTypePreservingConst();
4859 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4861 elemTy, type_cast<FIRRTLBaseType>(getOperand(i).getType())))
4862 return emitOpError(
"type of element doesn't match vector element");
4871LogicalResult FEnumCreateOp::verify() {
4872 FEnumType resultType = getResult().getType();
4873 auto elementIndex = resultType.getElementIndex(
getFieldName());
4875 return emitOpError(
"label ")
4876 <<
getFieldName() <<
" is not a member of the enumeration type "
4879 resultType.getElementTypePreservingConst(*elementIndex),
4880 getInput().getType()))
4881 return emitOpError(
"type of element doesn't match enum element");
4885void FEnumCreateOp::print(OpAsmPrinter &printer) {
4888 printer <<
'(' << getInput() <<
')';
4889 SmallVector<StringRef> elidedAttrs = {
"fieldIndex"};
4890 printer.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elidedAttrs);
4892 printer.printFunctionalType(ArrayRef<Type>{getInput().getType()},
4893 ArrayRef<Type>{getResult().getType()});
4896ParseResult FEnumCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4897 auto *
context = parser.getContext();
4898 auto &properties = result.getOrAddProperties<Properties>();
4900 OpAsmParser::UnresolvedOperand input;
4901 std::string fieldName;
4902 mlir::FunctionType functionType;
4903 if (parser.parseKeywordOrString(&fieldName) || parser.parseLParen() ||
4904 parser.parseOperand(input) || parser.parseRParen() ||
4905 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4906 parser.parseType(functionType))
4909 if (functionType.getNumInputs() != 1)
4910 return parser.emitError(parser.getNameLoc(),
"single input type required");
4911 if (functionType.getNumResults() != 1)
4912 return parser.emitError(parser.getNameLoc(),
"single result type required");
4914 auto inputType = functionType.getInput(0);
4915 if (parser.resolveOperand(input, inputType, result.operands))
4918 auto outputType = functionType.getResult(0);
4919 auto enumType = type_dyn_cast<FEnumType>(outputType);
4921 return parser.emitError(parser.getNameLoc(),
4922 "output must be enum type, got ")
4924 auto fieldIndex = enumType.getElementIndex(fieldName);
4926 return parser.emitError(parser.getNameLoc(),
4927 "unknown field " + fieldName +
" in enum type ")
4930 properties.setFieldIndex(
4931 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
4933 result.addTypes(enumType);
4942LogicalResult IsTagOp::verify() {
4943 if (getFieldIndex() >= getInput().getType().base().getNumElements())
4944 return emitOpError(
"element index is greater than the number of fields in "
4949void IsTagOp::print(::mlir::OpAsmPrinter &printer) {
4950 printer <<
' ' << getInput() <<
' ';
4952 SmallVector<::llvm::StringRef, 1> elidedAttrs = {
"fieldIndex"};
4953 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
4954 printer <<
" : " << getInput().getType();
4957ParseResult IsTagOp::parse(OpAsmParser &parser, OperationState &result) {
4958 auto *
context = parser.getContext();
4959 auto &properties = result.getOrAddProperties<Properties>();
4961 OpAsmParser::UnresolvedOperand input;
4962 std::string fieldName;
4964 if (parser.parseOperand(input) || parser.parseKeywordOrString(&fieldName) ||
4965 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4966 parser.parseType(inputType))
4969 if (parser.resolveOperand(input, inputType, result.operands))
4972 auto enumType = type_dyn_cast<FEnumType>(inputType);
4974 return parser.emitError(parser.getNameLoc(),
4975 "input must be enum type, got ")
4977 auto fieldIndex = enumType.getElementIndex(fieldName);
4979 return parser.emitError(parser.getNameLoc(),
4980 "unknown field " + fieldName +
" in enum type ")
4983 properties.setFieldIndex(
4984 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
4986 result.addTypes(UIntType::get(
context, 1,
false));
4991FIRRTLType IsTagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
4992 OpaqueProperties properties,
4993 mlir::RegionRange regions,
4994 std::optional<Location> loc) {
4995 Adaptor adaptor(operands, attrs, properties, regions);
4996 return UIntType::get(attrs.getContext(), 1,
4997 isConst(adaptor.getInput().getType()));
5000template <
typename OpTy>
5002 auto *
context = parser.getContext();
5004 OpAsmParser::UnresolvedOperand input;
5005 std::string fieldName;
5007 if (parser.parseOperand(input) || parser.parseLSquare() ||
5008 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5009 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5010 parser.parseType(inputType))
5013 if (parser.resolveOperand(input, inputType, result.operands))
5016 auto bundleType = type_dyn_cast<typename OpTy::InputType>(inputType);
5018 return parser.emitError(parser.getNameLoc(),
5019 "input must be bundle type, got ")
5021 auto fieldIndex = bundleType.getElementIndex(fieldName);
5023 return parser.emitError(parser.getNameLoc(),
5024 "unknown field " + fieldName +
" in bundle type ")
5027 result.getOrAddProperties<
typename OpTy::Properties>().setFieldIndex(
5028 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5030 auto type = OpTy::inferReturnType(inputType, *fieldIndex, {});
5033 result.addTypes(type);
5038ParseResult SubtagOp::parse(OpAsmParser &parser, OperationState &result) {
5039 auto *
context = parser.getContext();
5041 OpAsmParser::UnresolvedOperand input;
5042 std::string fieldName;
5044 if (parser.parseOperand(input) || parser.parseLSquare() ||
5045 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5046 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5047 parser.parseType(inputType))
5050 if (parser.resolveOperand(input, inputType, result.operands))
5053 auto enumType = type_dyn_cast<FEnumType>(inputType);
5055 return parser.emitError(parser.getNameLoc(),
5056 "input must be enum type, got ")
5058 auto fieldIndex = enumType.getElementIndex(fieldName);
5060 return parser.emitError(parser.getNameLoc(),
5061 "unknown field " + fieldName +
" in enum type ")
5064 result.getOrAddProperties<Properties>().setFieldIndex(
5065 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5067 SmallVector<Type> inferredReturnTypes;
5068 if (failed(SubtagOp::inferReturnTypes(
5069 context, result.location, result.operands,
5070 result.attributes.getDictionary(
context), result.getRawProperties(),
5071 result.regions, inferredReturnTypes)))
5073 result.addTypes(inferredReturnTypes);
5078ParseResult SubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
5079 return parseSubfieldLikeOp<SubfieldOp>(parser, result);
5081ParseResult OpenSubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
5082 return parseSubfieldLikeOp<OpenSubfieldOp>(parser, result);
5085template <
typename OpTy>
5087 printer <<
' ' << op.getInput() <<
'[';
5088 printer.printKeywordOrString(op.getFieldName());
5090 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
5091 elidedAttrs.push_back(
"fieldIndex");
5092 printer.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
5093 printer <<
" : " << op.getInput().getType();
5095void SubfieldOp::print(::mlir::OpAsmPrinter &printer) {
5096 return printSubfieldLikeOp<SubfieldOp>(*
this, printer);
5098void OpenSubfieldOp::print(::mlir::OpAsmPrinter &printer) {
5099 return printSubfieldLikeOp<OpenSubfieldOp>(*
this, printer);
5102void SubtagOp::print(::mlir::OpAsmPrinter &printer) {
5103 printer <<
' ' << getInput() <<
'[';
5106 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
5107 elidedAttrs.push_back(
"fieldIndex");
5108 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
5109 printer <<
" : " << getInput().getType();
5112template <
typename OpTy>
5114 if (op.getFieldIndex() >=
5115 firrtl::type_cast<typename OpTy::InputType>(op.getInput().getType())
5117 return op.emitOpError(
"subfield element index is greater than the number "
5118 "of fields in the bundle type");
5121LogicalResult SubfieldOp::verify() {
5122 return verifySubfieldLike<SubfieldOp>(*
this);
5124LogicalResult OpenSubfieldOp::verify() {
5125 return verifySubfieldLike<OpenSubfieldOp>(*
this);
5128LogicalResult SubtagOp::verify() {
5129 if (getFieldIndex() >= getInput().getType().base().getNumElements())
5130 return emitOpError(
"subfield element index is greater than the number "
5131 "of fields in the bundle type");
5141 SmallVector<Operation *, 8> worklist({op});
5145 bool constant =
true;
5151 while (constant && !(worklist.empty()))
5152 TypeSwitch<Operation *>(worklist.pop_back_val())
5153 .Case<NodeOp, AsSIntPrimOp, AsUIntPrimOp>([&](
auto op) {
5154 if (
auto definingOp = op.getInput().getDefiningOp())
5155 worklist.push_back(definingOp);
5158 .Case<WireOp, SubindexOp, SubfieldOp>([&](
auto op) {
5159 for (
auto &use : op.getResult().getUses())
5160 worklist.push_back(use.getOwner());
5162 .Case<ConstantOp, SpecialConstantOp, AggregateConstantOp>([](
auto) {})
5163 .Default([&](
auto) { constant =
false; });
5172 if (
auto *op = value.getDefiningOp())
5177LogicalResult ConstCastOp::verify() {
5179 return emitOpError() << getInput().getType()
5180 <<
" is not 'const'-castable to "
5181 << getResult().getType();
5185FIRRTLType SubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
5186 std::optional<Location> loc) {
5187 auto inType = type_cast<BundleType>(type);
5189 if (fieldIndex >= inType.getNumElements())
5191 "subfield element index is greater than the "
5192 "number of fields in the bundle type");
5196 return inType.getElementTypePreservingConst(fieldIndex);
5199FIRRTLType OpenSubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
5200 std::optional<Location> loc) {
5201 auto inType = type_cast<OpenBundleType>(type);
5203 if (fieldIndex >= inType.getNumElements())
5205 "subfield element index is greater than the "
5206 "number of fields in the bundle type");
5210 return inType.getElementTypePreservingConst(fieldIndex);
5213bool SubfieldOp::isFieldFlipped() {
5214 BundleType bundle = getInput().getType();
5215 return bundle.getElement(getFieldIndex()).isFlip;
5217bool OpenSubfieldOp::isFieldFlipped() {
5218 auto bundle = getInput().getType();
5219 return bundle.getElement(getFieldIndex()).isFlip;
5222FIRRTLType SubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
5223 std::optional<Location> loc) {
5224 if (
auto vectorType = type_dyn_cast<FVectorType>(type)) {
5225 if (fieldIndex < vectorType.getNumElements())
5226 return vectorType.getElementTypePreservingConst();
5228 "' in vector type ", type);
5233FIRRTLType OpenSubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
5234 std::optional<Location> loc) {
5235 if (
auto vectorType = type_dyn_cast<OpenVectorType>(type)) {
5236 if (fieldIndex < vectorType.getNumElements())
5237 return vectorType.getElementTypePreservingConst();
5239 "' in vector type ", type);
5245FIRRTLType SubtagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5246 OpaqueProperties properties,
5247 mlir::RegionRange regions,
5248 std::optional<Location> loc) {
5249 Adaptor adaptor(operands, attrs, properties, regions);
5250 auto inType = type_cast<FEnumType>(adaptor.getInput().getType());
5251 auto fieldIndex = adaptor.getFieldIndex();
5253 if (fieldIndex >= inType.getNumElements())
5255 "subtag element index is greater than the "
5256 "number of fields in the enum type");
5260 auto elementType = inType.getElement(fieldIndex).type;
5264FIRRTLType SubaccessOp::inferReturnType(Type inType, Type indexType,
5265 std::optional<Location> loc) {
5266 if (!type_isa<UIntType>(indexType))
5270 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
5272 return vectorType.getElementTypePreservingConst();
5273 return vectorType.getElementType().getAllConstDroppedType();
5281 std::optional<Location> loc) {
5282 auto inType = type_cast<FEnumType>(input);
5283 return UIntType::get(inType.getContext(), inType.getTagWidth());
5286ParseResult MultibitMuxOp::parse(OpAsmParser &parser, OperationState &result) {
5287 OpAsmParser::UnresolvedOperand index;
5288 SmallVector<OpAsmParser::UnresolvedOperand, 16> inputs;
5289 Type indexType, elemType;
5291 if (parser.parseOperand(index) || parser.parseComma() ||
5292 parser.parseOperandList(inputs) ||
5293 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5294 parser.parseType(indexType) || parser.parseComma() ||
5295 parser.parseType(elemType))
5298 if (parser.resolveOperand(index, indexType, result.operands))
5301 result.addTypes(elemType);
5303 return parser.resolveOperands(inputs, elemType, result.operands);
5306void MultibitMuxOp::print(OpAsmPrinter &p) {
5307 p <<
" " << getIndex() <<
", ";
5308 p.printOperands(getInputs());
5309 p.printOptionalAttrDict((*this)->getAttrs());
5310 p <<
" : " << getIndex().getType() <<
", " << getType();
5313FIRRTLType MultibitMuxOp::inferReturnType(ValueRange operands,
5314 DictionaryAttr attrs,
5315 OpaqueProperties properties,
5316 mlir::RegionRange regions,
5317 std::optional<Location> loc) {
5318 if (operands.size() < 2)
5322 if (!llvm::all_of(operands.drop_front(2), [&](
auto op) {
5323 return operands[1].getType() == op.getType();
5327 return type_cast<FIRRTLType>(operands[1].getType());
5334LogicalResult ObjectSubfieldOp::inferReturnTypes(
5335 MLIRContext *
context, std::optional<mlir::Location> location,
5336 ValueRange operands, DictionaryAttr attributes, OpaqueProperties properties,
5337 RegionRange regions, llvm::SmallVectorImpl<Type> &inferredReturnTypes) {
5339 inferReturnType(operands, attributes, properties, regions, location);
5342 inferredReturnTypes.push_back(type);
5346Type ObjectSubfieldOp::inferReturnType(Type inType, uint32_t fieldIndex,
5347 std::optional<Location> loc) {
5348 auto classType = dyn_cast<ClassType>(inType);
5352 if (classType.getNumElements() <= fieldIndex)
5354 "number of fields in the object");
5355 return classType.getElement(fieldIndex).type;
5358void ObjectSubfieldOp::print(OpAsmPrinter &p) {
5359 auto input = getInput();
5360 auto classType = input.getType();
5361 p <<
' ' << input <<
"[";
5362 p.printKeywordOrString(classType.getElement(getIndex()).name);
5364 p.printOptionalAttrDict((*this)->getAttrs(), std::array{StringRef(
"index")});
5365 p <<
" : " << classType;
5368ParseResult ObjectSubfieldOp::parse(OpAsmParser &parser,
5369 OperationState &result) {
5370 auto *
context = parser.getContext();
5372 OpAsmParser::UnresolvedOperand input;
5373 std::string fieldName;
5374 ClassType inputType;
5375 if (parser.parseOperand(input) || parser.parseLSquare() ||
5376 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5377 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5378 parser.parseType(inputType) ||
5379 parser.resolveOperand(input, inputType, result.operands))
5382 auto index = inputType.getElementIndex(fieldName);
5384 return parser.emitError(parser.getNameLoc(),
5385 "unknown field " + fieldName +
" in class type ")
5387 result.getOrAddProperties<Properties>().setIndex(
5388 IntegerAttr::get(IntegerType::get(
context, 32), *index));
5390 SmallVector<Type> inferredReturnTypes;
5391 if (failed(inferReturnTypes(
context, result.location, result.operands,
5392 result.attributes.getDictionary(
context),
5393 result.getRawProperties(), result.regions,
5394 inferredReturnTypes)))
5396 result.addTypes(inferredReturnTypes);
5413 int32_t &rhsWidth,
bool &isConstResult,
5414 std::optional<Location> loc) {
5416 auto lhsi = type_dyn_cast<IntType>(lhs);
5417 auto rhsi = type_dyn_cast<IntType>(rhs);
5418 if (!lhsi || !rhsi || lhsi.isSigned() != rhsi.isSigned()) {
5421 mlir::emitError(*loc,
"second operand must be an integer type, not ")
5423 else if (!lhsi && rhsi)
5424 mlir::emitError(*loc,
"first operand must be an integer type, not ")
5426 else if (!lhsi && !rhsi)
5427 mlir::emitError(*loc,
"operands must be integer types, not ")
5428 << lhs <<
" and " << rhs;
5430 mlir::emitError(*loc,
"operand signedness must match");
5435 lhsWidth = lhsi.getWidthOrSentinel();
5436 rhsWidth = rhsi.getWidthOrSentinel();
5437 isConstResult = lhsi.isConst() && rhsi.isConst();
5442 assert(op->getNumOperands() == 2 &&
5443 "SameOperandsIntTypeKind on non-binary op");
5444 int32_t lhsWidth, rhsWidth;
5447 op->getOperand(1).getType(), lhsWidth,
5448 rhsWidth, isConstResult, op->getLoc()));
5452 std::optional<Location> loc) {
5453 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5454 bool isConstResult =
false;
5458 if (lhsWidth != -1 && rhsWidth != -1)
5459 resultWidth = std::max(lhsWidth, rhsWidth) + 1;
5460 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5465 std::optional<Location> loc) {
5466 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5467 bool isConstResult =
false;
5471 if (lhsWidth != -1 && rhsWidth != -1)
5472 resultWidth = lhsWidth + rhsWidth;
5474 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5479 std::optional<Location> loc) {
5480 int32_t lhsWidth, rhsWidth;
5481 bool isConstResult =
false;
5486 if (type_isa<UIntType>(lhs))
5487 return UIntType::get(lhs.getContext(), lhsWidth, isConstResult);
5490 int32_t resultWidth = lhsWidth != -1 ? lhsWidth + 1 : -1;
5491 return SIntType::get(lhs.getContext(), resultWidth, isConstResult);
5495 std::optional<Location> loc) {
5496 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5497 bool isConstResult =
false;
5501 if (lhsWidth != -1 && rhsWidth != -1)
5502 resultWidth = std::min(lhsWidth, rhsWidth);
5503 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5508 std::optional<Location> loc) {
5509 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5510 bool isConstResult =
false;
5514 if (lhsWidth != -1 && rhsWidth != -1) {
5515 resultWidth = std::max(lhsWidth, rhsWidth);
5516 if (lhsWidth == resultWidth && lhs.
isConst() == isConstResult &&
5519 if (rhsWidth == resultWidth && rhs.
isConst() == isConstResult &&
5523 return UIntType::get(lhs.getContext(), resultWidth, isConstResult);
5527 std::optional<Location> loc) {
5528 if (!type_isa<FVectorType>(lhs) || !type_isa<FVectorType>(rhs))
5531 auto lhsVec = type_cast<FVectorType>(lhs);
5532 auto rhsVec = type_cast<FVectorType>(rhs);
5534 if (lhsVec.getNumElements() != rhsVec.getNumElements())
5539 rhsVec.getElementTypePreservingConst(), loc);
5542 auto elemBaseType = type_cast<FIRRTLBaseType>(elemType);
5543 return FVectorType::get(elemBaseType, lhsVec.getNumElements(),
5544 lhsVec.isConst() && rhsVec.isConst() &&
5545 elemBaseType.isConst());
5549 std::optional<Location> loc) {
5550 return UIntType::get(lhs.getContext(), 1,
isConst(lhs) &&
isConst(rhs));
5553FIRRTLType CatPrimOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5554 OpaqueProperties properties,
5555 mlir::RegionRange regions,
5556 std::optional<Location> loc) {
5558 if (operands.empty())
5559 return UIntType::get(attrs.getContext(), 0);
5562 bool isSigned = type_isa<SIntType>(operands[0].getType());
5563 for (
auto operand : operands) {
5564 auto type = type_dyn_cast<IntType>(operand.getType());
5567 if (type.isSigned() != isSigned)
5569 "all operands must have same signedness");
5573 int32_t resultWidth = 0;
5574 bool isConstResult =
true;
5576 for (
auto operand : operands) {
5577 auto type = type_cast<IntType>(operand.getType());
5578 int32_t width = type.getWidthOrSentinel();
5585 if (resultWidth != -1)
5586 resultWidth += width;
5589 isConstResult &= type.isConst();
5593 return UIntType::get(attrs.getContext(), resultWidth, isConstResult);
5597 std::optional<Location> loc) {
5598 auto lhsi = type_dyn_cast<IntType>(lhs);
5599 auto rhsui = type_dyn_cast<UIntType>(rhs);
5600 if (!rhsui || !lhsi)
5602 loc,
"first operand should be integer, second unsigned int");
5606 auto width = lhsi.getWidthOrSentinel();
5607 if (width == -1 || !rhsui.getWidth().has_value()) {
5610 auto amount = *rhsui.getWidth();
5613 "shift amount too large: second operand of "
5614 "dshl is wider than 31 bits");
5615 int64_t newWidth = (int64_t)width + ((int64_t)1 << amount) - 1;
5616 if (newWidth > INT32_MAX)
5618 loc,
"shift amount too large: first operand shifted by maximum "
5619 "amount exceeds maximum width");
5622 return IntType::get(lhs.getContext(), lhsi.isSigned(), width,
5623 lhsi.
isConst() && rhsui.isConst());
5627 std::optional<Location> loc) {
5628 auto lhsi = type_dyn_cast<IntType>(lhs);
5629 auto rhsu = type_dyn_cast<UIntType>(rhs);
5632 loc,
"first operand should be integer, second unsigned int");
5633 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5637 std::optional<Location> loc) {
5638 auto lhsi = type_dyn_cast<IntType>(lhs);
5639 auto rhsu = type_dyn_cast<UIntType>(rhs);
5642 loc,
"first operand should be integer, second unsigned int");
5643 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5651 std::optional<Location> loc) {
5652 return UIntType::get(input.getContext(), 32);
5656 std::optional<Location> loc) {
5657 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5660 int32_t width = base.getBitWidthOrSentinel();
5663 return SIntType::get(input.getContext(), width, base.
isConst());
5667 std::optional<Location> loc) {
5668 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5671 int32_t width = base.getBitWidthOrSentinel();
5674 return UIntType::get(input.getContext(), width, base.
isConst());
5678 std::optional<Location> loc) {
5679 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5682 "operand must be single bit scalar base type");
5683 int32_t width = base.getBitWidthOrSentinel();
5684 if (width == -2 || width == 0 || width > 1)
5686 return AsyncResetType::get(input.getContext(), base.
isConst());
5690 std::optional<Location> loc) {
5691 return ClockType::get(input.getContext(),
isConst(input));
5695 std::optional<Location> loc) {
5696 if (
auto uiType = type_dyn_cast<UIntType>(input)) {
5697 auto width = uiType.getWidthOrSentinel();
5700 return SIntType::get(input.getContext(), width, uiType.
isConst());
5703 if (type_isa<SIntType>(input))
5710 std::optional<Location> loc) {
5711 auto inputi = type_dyn_cast<IntType>(input);
5714 int32_t width = inputi.getWidthOrSentinel();
5717 return SIntType::get(input.getContext(), width, inputi.
isConst());
5721 std::optional<Location> loc) {
5722 auto inputi = type_dyn_cast<IntType>(input);
5725 if (isa<UIntType>(inputi))
5727 return UIntType::get(input.getContext(), inputi.getWidthOrSentinel(),
5732 std::optional<Location> loc) {
5733 return UIntType::get(input.getContext(), 1,
isConst(input));
5742 std::optional<Location> loc) {
5743 auto inputi = type_dyn_cast<IntType>(input);
5746 loc,
"input type should be the int type but got ", input);
5751 loc,
"high must be equal or greater than low, but got high = ", high,
5759 int32_t width = inputi.getWidthOrSentinel();
5760 if (width != -1 && high >= width)
5763 "high must be smaller than the width of input, but got high = ", high,
5764 ", width = ", width);
5766 return UIntType::get(input.getContext(), high - low + 1, inputi.
isConst());
5770 std::optional<Location> loc) {
5772 auto inputi = type_dyn_cast<IntType>(input);
5773 if (amount < 0 || !inputi)
5775 loc,
"operand must have integer type and amount must be >= 0");
5777 int32_t width = inputi.getWidthOrSentinel();
5778 if (width != -1 && amount > width)
5781 return UIntType::get(input.getContext(), amount, inputi.
isConst());
5796 bool isConstCondition,
5797 std::optional<Location> loc) {
5803 if (high.getTypeID() != low.getTypeID())
5804 return emitInferRetTypeError<FIRRTLBaseType>(
5805 loc,
"incompatible mux operand types, true value type: ", high,
5806 ", false value type: ", low);
5808 bool outerTypeIsConst = isConstCondition && low.
isConst() && high.
isConst();
5813 if (type_isa<IntType>(low)) {
5818 if (highWidth == -1)
5820 return (lowWidth > highWidth ? low : high).getConstType(outerTypeIsConst);
5825 auto highEnum = type_dyn_cast<FEnumType>(high);
5826 auto lowEnum = type_dyn_cast<FEnumType>(low);
5827 if (lowEnum && highEnum) {
5828 if (lowEnum.getNumElements() != highEnum.getNumElements())
5829 return emitInferRetTypeError<FIRRTLBaseType>(
5830 loc,
"incompatible mux operand types, true value type: ", high,
5831 ", false value type: ", low);
5832 SmallVector<FEnumType::EnumElement> elements;
5833 for (
auto [high, low] : llvm::zip_equal(highEnum, lowEnum)) {
5835 if (high.name != low.name || high.value != low.value)
5836 return emitInferRetTypeError<FIRRTLBaseType>(
5837 loc,
"incompatible mux operand types, true value type: ", highEnum,
5838 ", false value type: ", lowEnum);
5845 elements.emplace_back(high.name, high.value, inner);
5847 return FEnumType::get(high.getContext(), elements, outerTypeIsConst);
5851 auto highVector = type_dyn_cast<FVectorType>(high);
5852 auto lowVector = type_dyn_cast<FVectorType>(low);
5853 if (highVector && lowVector &&
5854 highVector.getNumElements() == lowVector.getNumElements()) {
5856 lowVector.getElementTypePreservingConst(),
5857 isConstCondition, loc);
5860 return FVectorType::get(inner, lowVector.getNumElements(),
5865 auto highBundle = type_dyn_cast<BundleType>(high);
5866 auto lowBundle = type_dyn_cast<BundleType>(low);
5867 if (highBundle && lowBundle) {
5868 auto highElements = highBundle.getElements();
5869 auto lowElements = lowBundle.getElements();
5872 SmallVector<BundleType::BundleElement> newElements;
5874 bool failed =
false;
5876 if (highElements[i].name != lowElements[i].name ||
5877 highElements[i].isFlip != lowElements[i].isFlip) {
5881 auto element = highElements[i];
5883 highBundle.getElementTypePreservingConst(i),
5884 lowBundle.getElementTypePreservingConst(i), isConstCondition, loc);
5887 newElements.push_back(element);
5890 return BundleType::get(low.getContext(), newElements, outerTypeIsConst);
5892 return emitInferRetTypeError<FIRRTLBaseType>(
5893 loc,
"incompatible mux operand bundle fields, true value type: ", high,
5894 ", false value type: ", low);
5899 return emitInferRetTypeError<FIRRTLBaseType>(
5900 loc,
"invalid mux operand types, true value type: ", high,
5901 ", false value type: ", low);
5906 std::optional<Location> loc) {
5907 auto highType = type_dyn_cast<FIRRTLBaseType>(high);
5908 auto lowType = type_dyn_cast<FIRRTLBaseType>(low);
5909 if (!highType || !lowType)
5914FIRRTLType Mux2CellIntrinsicOp::inferReturnType(ValueRange operands,
5915 DictionaryAttr attrs,
5916 OpaqueProperties properties,
5917 mlir::RegionRange regions,
5918 std::optional<Location> loc) {
5919 auto highType = type_dyn_cast<FIRRTLBaseType>(operands[1].getType());
5920 auto lowType = type_dyn_cast<FIRRTLBaseType>(operands[2].getType());
5921 if (!highType || !lowType)
5927FIRRTLType Mux4CellIntrinsicOp::inferReturnType(ValueRange operands,
5928 DictionaryAttr attrs,
5929 OpaqueProperties properties,
5930 mlir::RegionRange regions,
5931 std::optional<Location> loc) {
5932 SmallVector<FIRRTLBaseType> types;
5934 for (
unsigned i = 1; i < 5; i++) {
5935 types.push_back(type_dyn_cast<FIRRTLBaseType>(operands[i].getType()));
5940 isConst(operands[0].getType()), loc);
5944 result = types.back();
5951 std::optional<Location> loc) {
5952 auto inputi = type_dyn_cast<IntType>(input);
5953 if (amount < 0 || !inputi)
5955 loc,
"pad input must be integer and amount must be >= 0");
5957 int32_t width = inputi.getWidthOrSentinel();
5961 width = std::max<int32_t>(width, amount);
5962 return IntType::get(input.getContext(), inputi.isSigned(), width,
5967 std::optional<Location> loc) {
5968 auto inputi = type_dyn_cast<IntType>(input);
5969 if (amount < 0 || !inputi)
5971 loc,
"shl input must be integer and amount must be >= 0");
5973 int32_t width = inputi.getWidthOrSentinel();
5977 return IntType::get(input.getContext(), inputi.isSigned(), width,
5982 std::optional<Location> loc) {
5983 auto inputi = type_dyn_cast<IntType>(input);
5984 if (amount < 0 || !inputi)
5986 loc,
"shr input must be integer and amount must be >= 0");
5988 int32_t width = inputi.getWidthOrSentinel();
5991 int32_t minWidth = inputi.isUnsigned() ? 0 : 1;
5992 width = std::max<int32_t>(minWidth, width - amount);
5995 return IntType::get(input.getContext(), inputi.isSigned(), width,
6000 std::optional<Location> loc) {
6002 auto inputi = type_dyn_cast<IntType>(input);
6003 if (amount < 0 || !inputi)
6005 loc,
"tail input must be integer and amount must be >= 0");
6007 int32_t width = inputi.getWidthOrSentinel();
6011 loc,
"amount must be less than or equal operand width");
6022void VerbatimExprOp::getAsmResultNames(
6023 function_ref<
void(Value, StringRef)> setNameFn) {
6027 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
6028 auto name = getText();
6030 if (name.starts_with(
"`"))
6031 name = name.drop_front();
6032 name = name.take_while(isOkCharacter);
6034 setNameFn(getResult(), name);
6041void VerbatimWireOp::getAsmResultNames(
6042 function_ref<
void(Value, StringRef)> setNameFn) {
6046 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
6047 auto name = getText();
6049 if (name.starts_with(
"`"))
6050 name = name.drop_front();
6051 name = name.take_while(isOkCharacter);
6053 setNameFn(getResult(), name);
6064 op->emitError() <<
"unknown width is not allowed for DPI";
6065 return WalkResult::interrupt();
6067 if (width == 1 || width == 8 || width == 16 || width == 32 ||
6069 return WalkResult::advance();
6071 <<
"integer types used by DPI functions must have a "
6072 "specific bit width; "
6073 "it must be equal to 1(bit), 8(byte), 16(shortint), "
6074 "32(int), 64(longint) "
6075 "or greater than 64, but got "
6077 return WalkResult::interrupt();
6082LogicalResult DPICallIntrinsicOp::verify() {
6083 if (
auto inputNames = getInputNames()) {
6084 if (getInputs().size() != inputNames->size())
6085 return emitError() <<
"inputNames has " << inputNames->size()
6086 <<
" elements but there are " << getInputs().size()
6087 <<
" input arguments";
6089 if (
auto outputName = getOutputName())
6090 if (getNumResults() == 0)
6091 return emitError() <<
"output name is given but there is no result";
6093 auto checkType = [
this](Type type) {
6096 return success(llvm::all_of(this->getResultTypes(), checkType) &&
6097 llvm::all_of(this->getOperandTypes(), checkType));
6100SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
6101DPICallIntrinsicOp::computeDataFlow() {
6105 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
6107 for (
auto operand : getOperands()) {
6108 auto type = type_cast<FIRRTLBaseType>(operand.getType());
6110 SmallVector<circt::FieldRef> operandFields;
6113 operandFields.push_back(baseFieldRef.getSubField(dstIndex));
6117 for (
auto result : getResults())
6120 for (
auto field : operandFields)
6121 deps.emplace_back(
circt::
FieldRef(result, dstIndex), field);
6131LogicalResult HWStructCastOp::verify() {
6133 BundleType bundleType;
6134 hw::StructType structType;
6135 if ((bundleType = type_dyn_cast<BundleType>(getOperand().getType()))) {
6136 structType = dyn_cast<hw::StructType>(getType());
6138 return emitError(
"result type must be a struct");
6139 }
else if ((bundleType = type_dyn_cast<BundleType>(getType()))) {
6140 structType = dyn_cast<hw::StructType>(getOperand().getType());
6142 return emitError(
"operand type must be a struct");
6144 return emitError(
"either source or result type must be a bundle type");
6147 auto firFields = bundleType.getElements();
6148 auto hwFields = structType.getElements();
6149 if (firFields.size() != hwFields.size())
6150 return emitError(
"bundle and struct have different number of fields");
6152 for (
size_t findex = 0, fend = firFields.size(); findex < fend; ++findex) {
6153 if (firFields[findex].name.getValue() != hwFields[findex].name)
6154 return emitError(
"field names don't match '")
6155 << firFields[findex].name.getValue() <<
"', '"
6156 << hwFields[findex].name.getValue() <<
"'";
6160 if (firWidth > 0 && hwWidth > 0 && firWidth != hwWidth)
6161 return emitError(
"size of field '")
6162 << hwFields[findex].name.getValue() <<
"' don't match " << firWidth
6169LogicalResult BitCastOp::verify() {
6170 auto inTypeBits =
getBitWidth(getInput().getType(),
true);
6172 if (inTypeBits.has_value() && resTypeBits.has_value()) {
6174 if (*inTypeBits == *resTypeBits) {
6177 return emitError(
"cannot cast non-'const' input type ")
6178 << getOperand().getType() <<
" to 'const' result type "
6182 return emitError(
"the bitwidth of input (")
6183 << *inTypeBits <<
") and result (" << *resTypeBits
6186 if (!inTypeBits.has_value())
6187 return emitError(
"bitwidth cannot be determined for input operand type ")
6188 << getInput().getType();
6189 return emitError(
"bitwidth cannot be determined for result type ")
6200 NamedAttrList &resultAttrs) {
6201 auto result = parser.parseOptionalAttrDict(resultAttrs);
6202 if (!resultAttrs.get(
"annotations"))
6203 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
6209 DictionaryAttr attr,
6210 ArrayRef<StringRef> extraElides = {}) {
6211 SmallVector<StringRef> elidedAttrs(extraElides.begin(), extraElides.end());
6213 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
6214 elidedAttrs.push_back(
"annotations");
6216 elidedAttrs.push_back(
"nameKind");
6218 p.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
6224 NamedAttrList &resultAttrs) {
6227 if (!resultAttrs.get(
"portAnnotations")) {
6228 SmallVector<Attribute, 16> portAnnotations(
6229 parser.getNumResults(), parser.getBuilder().getArrayAttr({}));
6230 resultAttrs.append(
"portAnnotations",
6231 parser.getBuilder().getArrayAttr(portAnnotations));
6238 DictionaryAttr attr,
6239 ArrayRef<StringRef> extraElides = {}) {
6240 SmallVector<StringRef, 2> elidedAttrs(extraElides.begin(), extraElides.end());
6242 if (llvm::all_of(op->getAttrOfType<ArrayAttr>(
"portAnnotations"),
6243 [&](Attribute a) { return cast<ArrayAttr>(a).empty(); }))
6244 elidedAttrs.push_back(
"portAnnotations");
6253 firrtl::NameKindEnumAttr &result) {
6256 if (!parser.parseOptionalKeyword(&keyword,
6257 {
"interesting_name",
"droppable_name"})) {
6258 auto kind = symbolizeNameKindEnum(keyword);
6259 result = NameKindEnumAttr::get(parser.getContext(), kind.value());
6265 NameKindEnumAttr::get(parser.getContext(), NameKindEnum::DroppableName);
6270 firrtl::NameKindEnumAttr attr,
6271 ArrayRef<StringRef> extraElides = {}) {
6272 if (attr.getValue() != NameKindEnum::DroppableName)
6273 p <<
" " << stringifyNameKindEnum(attr.getValue());
6281 NamedAttrList &resultAttrs) {
6289 DictionaryAttr attrs) {
6290 SmallVector<StringRef, 4> elides;
6292 elides.push_back(Forceable::getForceableAttrName());
6301static ParseResult
parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs) {
6306static void printMemOp(OpAsmPrinter &p, Operation *op, DictionaryAttr attr) {
6317 if (ClassType::parseInterface(parser, type))
6324 type.printInterface(p);
6332 NamedAttrList &resultAttrs) {
6333 auto result = p.parseOptionalAttrDict(resultAttrs);
6334 if (!resultAttrs.get(
"name"))
6335 resultAttrs.append(
"name", p.getBuilder().getStringAttr(
""));
6341 DictionaryAttr attr,
6342 ArrayRef<StringRef> extraElides = {}) {
6343 SmallVector<StringRef> elides(extraElides.begin(), extraElides.end());
6344 if (op->getAttrOfType<StringAttr>(
"name").getValue().empty())
6345 elides.push_back(
"name");
6347 p.printOptionalAttrDict(op->getAttrs(), elides);
6351 NamedAttrList &resultAttrs) {
6356 DictionaryAttr attr) {
6361 NamedAttrList &resultAttrs) {
6366 DictionaryAttr attr) {
6368 {
"formatString",
"outputFile",
"operandSegmentSizes"});
6376 DictionaryAttr attr) {
6385 DictionaryAttr attr) {
6394 OpAsmSetValueNameFn setNameFn) {
6397 if (op->getNumResults() == 1)
6398 if (
auto nameAttr = op->getAttrOfType<StringAttr>(
"name"))
6399 setNameFn(op->getResult(0), nameAttr.getValue());
6402void AddPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6406void AndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6410void AndRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6414void SizeOfIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6417void AsAsyncResetPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6420void AsClockPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6423void AsSIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6426void AsUIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6429void BitsPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6432void CatPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6435void CvtPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6438void DShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6441void DShlwPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6444void DShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6447void DivPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6450void EQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6453void GEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6456void GTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6459void GenericIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6462void HeadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6465void IntegerAddOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6468void IntegerMulOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6471void IntegerShrOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6474void IntegerShlOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6477void IsTagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6480void IsXIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6483void PlusArgsValueIntrinsicOp::getAsmResultNames(
6484 OpAsmSetValueNameFn setNameFn) {
6487void PlusArgsTestIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6490void LEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6493void LTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6496void MulPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6499void MultibitMuxOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6502void MuxPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6505void Mux4CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6508void Mux2CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6511void NEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6514void NegPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6517void NotPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6520void OrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6523void OrRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6526void PadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6529void RemPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6532void ShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6535void ShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6539void SubPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6543void SubaccessOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6547void SubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6551void OpenSubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6555void SubtagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6559void SubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6563void OpenSubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6567void TagExtractOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6571void TailPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6575void XorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6579void XorRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6583void UninferredResetCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6587void ConstCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6591void ElementwiseXorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6595void ElementwiseOrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6599void ElementwiseAndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6607void RefCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6611void RefResolveOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6615void RefSendOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6619void RefSubOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6623void RWProbeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6627FIRRTLType RefResolveOp::inferReturnType(ValueRange operands,
6628 DictionaryAttr attrs,
6629 OpaqueProperties properties,
6630 mlir::RegionRange regions,
6631 std::optional<Location> loc) {
6632 Type inType = operands[0].getType();
6633 auto inRefType = type_dyn_cast<RefType>(inType);
6636 loc,
"ref.resolve operand must be ref type, not ", inType);
6637 return inRefType.getType();
6640FIRRTLType RefSendOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
6641 OpaqueProperties properties,
6642 mlir::RegionRange regions,
6643 std::optional<Location> loc) {
6644 Type inType = operands[0].getType();
6645 auto inBaseType = type_dyn_cast<FIRRTLBaseType>(inType);
6648 loc,
"ref.send operand must be base type, not ", inType);
6649 return RefType::get(inBaseType.getPassiveType());
6652FIRRTLType RefSubOp::inferReturnType(Type type, uint32_t fieldIndex,
6653 std::optional<Location> loc) {
6654 auto refType = type_dyn_cast<RefType>(type);
6657 auto inType = refType.getType();
6663 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
6664 if (fieldIndex < vectorType.getNumElements())
6665 return RefType::get(
6666 vectorType.getElementType().getConstType(
6667 vectorType.isConst() || vectorType.getElementType().isConst()),
6668 refType.getForceable(), refType.getLayer());
6670 "' in RefType of vector type ", refType);
6672 if (
auto bundleType = type_dyn_cast<BundleType>(inType)) {
6673 if (fieldIndex >= bundleType.getNumElements()) {
6675 "subfield element index is greater than "
6676 "the number of fields in the bundle type");
6678 return RefType::get(
6679 bundleType.getElement(fieldIndex)
6681 bundleType.isConst() ||
6682 bundleType.getElement(fieldIndex).type.isConst()),
6683 refType.getForceable(), refType.getLayer());
6687 loc,
"ref.sub op requires a RefType of vector or bundle base type");
6690LogicalResult RefCastOp::verify() {
6694 getOperation(), srcLayers, dstLayers,
6695 "cannot discard layer requirements of input reference",
6696 "discarding layer requirements");
6699LogicalResult RefResolveOp::verify() {
6703 getOperation(), srcLayers, dstLayers,
6704 "ambient layers are insufficient to resolve reference");
6708 auto targetRef = getTarget();
6709 if (targetRef.getModule() !=
6710 (*this)->getParentOfType<FModuleLike>().getModuleNameAttr())
6711 return emitOpError() <<
"has non-local target";
6713 auto target = ns.
lookup(targetRef);
6715 return emitOpError() <<
"has target that cannot be resolved: " << targetRef;
6717 auto checkFinalType = [&](
auto type, Location loc) -> LogicalResult {
6722 auto baseType = type_dyn_cast<FIRRTLBaseType>(fType);
6723 if (!baseType || baseType.getPassiveType() != getType().getType()) {
6724 auto diag = emitOpError(
"has type mismatch: target resolves to ")
6725 << fType <<
" instead of expected " << getType().getType();
6726 diag.attachNote(loc) <<
"target resolves here";
6731 if (target.isPort()) {
6732 auto mod = cast<FModuleLike>(target.getOp());
6733 return checkFinalType(mod.getPortType(target.getPort()),
6734 mod.getPortLocation(target.getPort()));
6736 hw::InnerSymbolOpInterface symOp =
6737 cast<hw::InnerSymbolOpInterface>(target.getOp());
6738 if (!symOp.getTargetResult())
6739 return emitOpError(
"has target that cannot be probed")
6740 .attachNote(symOp.getLoc())
6741 .append(
"target resolves here");
6743 symOp.getTargetResult().getParentBlock()->findAncestorOpInBlock(**
this);
6744 if (!ancestor || !symOp->isBeforeInBlock(ancestor))
6745 return emitOpError(
"is not dominated by target")
6746 .attachNote(symOp.getLoc())
6747 .append(
"target here");
6748 return checkFinalType(symOp.getTargetResult().getType(), symOp.getLoc());
6751LogicalResult RefForceOp::verify() {
6755 getOperation(), destLayers, ambientLayers,
6756 "has insufficient ambient layers to force its reference");
6759LogicalResult RefForceInitialOp::verify() {
6763 getOperation(), destLayers, ambientLayers,
6764 "has insufficient ambient layers to force its reference");
6767LogicalResult RefReleaseOp::verify() {
6771 getOperation(), destLayers, ambientLayers,
6772 "has insufficient ambient layers to release its reference");
6775LogicalResult RefReleaseInitialOp::verify() {
6779 getOperation(), destLayers, ambientLayers,
6780 "has insufficient ambient layers to release its reference");
6783LogicalResult XMRRefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6784 auto *target = symbolTable.lookupNearestSymbolFrom(*
this, getRefAttr());
6786 return emitOpError(
"has an invalid symbol reference");
6788 if (!isa<hw::HierPathOp>(target))
6789 return emitOpError(
"does not target a hierpath op");
6795LogicalResult XMRDerefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6796 auto *target = symbolTable.lookupNearestSymbolFrom(*
this, getRefAttr());
6798 return emitOpError(
"has an invalid symbol reference");
6800 if (!isa<hw::HierPathOp>(target))
6801 return emitOpError(
"does not target a hierpath op");
6811LogicalResult LayerBlockOp::verify() {
6812 auto layerName = getLayerName();
6813 auto *parentOp = (*this)->getParentOp();
6816 while (isa<WhenOp, MatchOp>(parentOp))
6817 parentOp = parentOp->getParentOp();
6821 auto nestedReferences = layerName.getNestedReferences();
6822 if (nestedReferences.empty()) {
6823 if (!isa<FModuleOp>(parentOp)) {
6824 auto diag = emitOpError() <<
"has an un-nested layer symbol, but does "
6825 "not have a 'firrtl.module' op as a parent";
6826 return diag.attachNote(parentOp->getLoc())
6827 <<
"illegal parent op defined here";
6830 auto parentLayerBlock = dyn_cast<LayerBlockOp>(parentOp);
6831 if (!parentLayerBlock) {
6832 auto diag = emitOpError()
6833 <<
"has a nested layer symbol, but does not have a '"
6834 << getOperationName() <<
"' op as a parent'";
6835 return diag.attachNote(parentOp->getLoc())
6836 <<
"illegal parent op defined here";
6838 auto parentLayerBlockName = parentLayerBlock.getLayerName();
6839 if (parentLayerBlockName.getRootReference() !=
6840 layerName.getRootReference() ||
6841 parentLayerBlockName.getNestedReferences() !=
6842 layerName.getNestedReferences().drop_back()) {
6843 auto diag = emitOpError() <<
"is nested under an illegal layer block";
6844 return diag.attachNote(parentLayerBlock->getLoc())
6845 <<
"illegal parent layer block defined here";
6851 auto result = getBody(0)->walk<mlir::WalkOrder::PreOrder>(
6852 [&](Operation *op) -> WalkResult {
6854 if (isa<LayerBlockOp>(op))
6855 return WalkResult::skip();
6859 for (
auto operand : op->getOperands()) {
6861 if (
auto *definingOp = operand.getDefiningOp())
6865 auto type = operand.getType();
6868 if (isa<PropertyType>(type)) {
6869 auto diag = emitOpError() <<
"captures a property operand";
6870 diag.attachNote(operand.getLoc()) <<
"operand is defined here";
6871 diag.attachNote(op->getLoc()) <<
"operand is used here";
6872 return WalkResult::interrupt();
6877 if (
auto connect = dyn_cast<FConnectLike>(op)) {
6879 if (isa<RefDefineOp>(connect))
6880 return WalkResult::advance();
6887 bool passive =
true;
6889 type_dyn_cast<FIRRTLBaseType>(
connect.getDest().getType()))
6890 passive = type.isPassive();
6899 return WalkResult::advance();
6902 return WalkResult::advance();
6906 <<
"connects to a destination which is defined outside its "
6907 "enclosing layer block";
6908 diag.attachNote(
getLoc()) <<
"enclosing layer block is defined here";
6909 diag.attachNote(dest.getLoc()) <<
"destination is defined here";
6910 return WalkResult::interrupt();
6913 return WalkResult::advance();
6916 return failure(result.wasInterrupted());
6920LayerBlockOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6922 symbolTable.lookupNearestSymbolFrom<LayerOp>(*
this, getLayerNameAttr());
6924 return emitOpError(
"invalid symbol reference");
6934void TimeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6935 setNameFn(getResult(),
"time");
6938void HierarchicalModuleNameOp::getAsmResultNames(
6939 OpAsmSetValueNameFn setNameFn) {
6940 setNameFn(getResult(),
"hierarchicalmodulename");
6943ParseResult FPrintFOp::parse(::mlir::OpAsmParser &parser,
6944 ::mlir::OperationState &result) {
6946 OpAsmParser::UnresolvedOperand clock, cond;
6947 if (parser.parseOperand(clock) || parser.parseComma() ||
6948 parser.parseOperand(cond) || parser.parseComma())
6951 auto parseFormatString =
6952 [&parser](llvm::SMLoc &loc, StringAttr &result,
6953 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &operands)
6955 loc = parser.getCurrentLocation();
6958 std::string resultStr;
6959 if (parser.parseString(&resultStr))
6961 result = parser.getBuilder().getStringAttr(resultStr);
6964 if (parser.parseOperandList(operands, AsmParser::Delimiter::OptionalParen))
6970 SmallVector<OpAsmParser::UnresolvedOperand> outputFileSubstitutions,
6972 llvm::SMLoc outputFileLoc, formatStringLoc;
6974 if (parseFormatString(
6976 result.getOrAddProperties<FPrintFOp::Properties>().outputFile,
6977 outputFileSubstitutions) ||
6978 parser.parseComma() ||
6981 result.getOrAddProperties<FPrintFOp::Properties>().formatString,
6989 Type clockType, condType;
6990 SmallVector<Type> restTypes;
6992 if (parser.parseColon() || parser.parseType(clockType) ||
6993 parser.parseComma() || parser.parseType(condType))
6996 if (succeeded(parser.parseOptionalComma())) {
6997 if (parser.parseTypeList(restTypes))
7002 result.getOrAddProperties<FPrintFOp::Properties>().operandSegmentSizes = {
7003 1, 1,
static_cast<int32_t
>(outputFileSubstitutions.size()),
7004 static_cast<int32_t
>(substitutions.size())};
7007 if (parser.resolveOperand(clock, clockType, result.operands) ||
7008 parser.resolveOperand(cond, condType, result.operands) ||
7009 parser.resolveOperands(
7010 outputFileSubstitutions,
7011 ArrayRef(restTypes).take_front(outputFileSubstitutions.size()),
7012 outputFileLoc, result.operands) ||
7013 parser.resolveOperands(
7015 ArrayRef(restTypes).drop_front(outputFileSubstitutions.size()),
7016 formatStringLoc, result.operands))
7022void FPrintFOp::print(OpAsmPrinter &p) {
7023 p <<
" " << getClock() <<
", " << getCond() <<
", ";
7024 p.printAttributeWithoutType(getOutputFileAttr());
7025 if (!getOutputFileSubstitutions().
empty()) {
7027 p.printOperands(getOutputFileSubstitutions());
7031 p.printAttributeWithoutType(getFormatStringAttr());
7032 if (!getSubstitutions().
empty()) {
7034 p.printOperands(getSubstitutions());
7038 p <<
" : " << getClock().getType() <<
", " << getCond().getType();
7039 if (!getOutputFileSubstitutions().
empty() || !getSubstitutions().
empty()) {
7040 for (
auto type : getOperands().drop_front(2).getTypes()) {
7051LogicalResult FFlushOp::verify() {
7052 if (!getOutputFileAttr() && !getOutputFileSubstitutions().
empty())
7053 return emitOpError(
"substitutions without output file are not allowed");
7062 auto ref = getInstanceAttr();
7063 auto target = ns.
lookup(ref);
7065 return emitError() <<
"target " << ref <<
" cannot be resolved";
7067 if (!target.isOpOnly())
7068 return emitError() <<
"target " << ref <<
" is not an operation";
7070 auto instance = dyn_cast<InstanceOp>(target.getOp());
7072 return emitError() <<
"target " << ref <<
" is not an instance";
7074 if (!instance.getDoNotPrint())
7075 return emitError() <<
"target " << ref <<
" is not marked doNotPrint";
7085DomainCreateAnonOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7086 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
7087 auto domain = getDomainAttr();
7088 if (!symbolTable.lookupSymbolIn<DomainOp>(circuitOp, domain))
7089 return emitOpError() <<
"references undefined domain '" << domain <<
"'";
7099#define GET_OP_CLASSES
7100#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.